kernel: remove k_object_access_revoke() as syscall
Forthcoming patches will dual-purpose an object's permission bitfield as also reference tracking for kernel objects, used to handle automatic freeing of resources. We do not want to allow user thread A to revoke thread B's access to some object O if B is in the middle of an API call using O. However we do want to allow threads to revoke their own access to an object, so introduce a new API and syscall for that. Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
parent
a2480bd472
commit
e9cfc54d00
7 changed files with 33 additions and 46 deletions
|
@ -152,9 +152,10 @@ ways to do this.
|
||||||
access to a set of kernel objects at boot time.
|
access to a set of kernel objects at boot time.
|
||||||
|
|
||||||
Once a thread has been granted access to an object, such access may be
|
Once a thread has been granted access to an object, such access may be
|
||||||
removed with the :c:func:`k_object_access_revoke()` API. User threads using
|
removed with the :c:func:`k_object_access_revoke()` API. This API is not
|
||||||
this API must have permission on both the object in question, and the thread
|
available to user threads, however user threads may use
|
||||||
object that is having access revoked.
|
:c:func:`k_object_release()` to relinquish their own permissions on an
|
||||||
|
object.
|
||||||
|
|
||||||
API calls from supervisor mode to set permissions on kernel objects that are
|
API calls from supervisor mode to set permissions on kernel objects that are
|
||||||
not being tracked by the kernel will be no-ops. Doing the same from user mode
|
not being tracked by the kernel will be no-ops. Doing the same from user mode
|
||||||
|
|
|
@ -223,13 +223,21 @@ static inline void _impl_k_object_access_grant(void *object,
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
static inline void _impl_k_object_access_revoke(void *object,
|
static inline void k_object_access_revoke(void *object,
|
||||||
struct k_thread *thread)
|
struct k_thread *thread)
|
||||||
{
|
{
|
||||||
ARG_UNUSED(object);
|
ARG_UNUSED(object);
|
||||||
ARG_UNUSED(thread);
|
ARG_UNUSED(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
static inline void _impl_k_object_release(void *object)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(object);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void k_object_access_all_grant(void *object)
|
static inline void k_object_access_all_grant(void *object)
|
||||||
{
|
{
|
||||||
ARG_UNUSED(object);
|
ARG_UNUSED(object);
|
||||||
|
@ -258,7 +266,10 @@ __syscall void k_object_access_grant(void *object, struct k_thread *thread);
|
||||||
* @param object Address of kernel object
|
* @param object Address of kernel object
|
||||||
* @param thread Thread to remove access to the object
|
* @param thread Thread to remove access to the object
|
||||||
*/
|
*/
|
||||||
__syscall void k_object_access_revoke(void *object, struct k_thread *thread);
|
void k_object_access_revoke(void *object, struct k_thread *thread);
|
||||||
|
|
||||||
|
|
||||||
|
__syscall void k_object_release(void *object);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* grant all present and future threads access to an object
|
* grant all present and future threads access to an object
|
||||||
|
|
|
@ -350,7 +350,7 @@ void _impl_k_object_access_grant(void *object, struct k_thread *thread)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _impl_k_object_access_revoke(void *object, struct k_thread *thread)
|
void k_object_access_revoke(void *object, struct k_thread *thread)
|
||||||
{
|
{
|
||||||
struct _k_object *ko = _k_object_find(object);
|
struct _k_object *ko = _k_object_find(object);
|
||||||
|
|
||||||
|
@ -359,6 +359,11 @@ void _impl_k_object_access_revoke(void *object, struct k_thread *thread)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _impl_k_object_release(void *object)
|
||||||
|
{
|
||||||
|
k_object_access_revoke(object, _current);
|
||||||
|
}
|
||||||
|
|
||||||
void k_object_access_all_grant(void *object)
|
void k_object_access_all_grant(void *object)
|
||||||
{
|
{
|
||||||
struct _k_object *ko = _k_object_find(object);
|
struct _k_object *ko = _k_object_find(object);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
#include <syscall_handler.h>
|
#include <syscall_handler.h>
|
||||||
|
#include <kernel_structs.h>
|
||||||
|
|
||||||
static struct _k_object *validate_any_object(void *obj)
|
static struct _k_object *validate_any_object(void *obj)
|
||||||
{
|
{
|
||||||
|
@ -47,14 +48,13 @@ _SYSCALL_HANDLER(k_object_access_grant, object, thread)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_SYSCALL_HANDLER(k_object_access_revoke, object, thread)
|
_SYSCALL_HANDLER(k_object_release, object)
|
||||||
{
|
{
|
||||||
struct _k_object *ko;
|
struct _k_object *ko;
|
||||||
|
|
||||||
_SYSCALL_OBJ_INIT(thread, K_OBJ_THREAD);
|
|
||||||
ko = validate_any_object((void *)object);
|
ko = validate_any_object((void *)object);
|
||||||
_SYSCALL_VERIFY_MSG(ko, "object %p access denied", (void *)object);
|
_SYSCALL_VERIFY_MSG(ko, "object %p access denied", (void *)object);
|
||||||
_thread_perms_clear(ko, (struct k_thread *)thread);
|
_thread_perms_clear(ko, _current);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,7 +238,7 @@ void kobject_user_test7(void *p1, void *p2, void *p3)
|
||||||
USERSPACE_BARRIER;
|
USERSPACE_BARRIER;
|
||||||
|
|
||||||
k_sem_give(&kobject_sem);
|
k_sem_give(&kobject_sem);
|
||||||
k_object_access_revoke(&kobject_sem, k_current_get());
|
k_object_release(&kobject_sem);
|
||||||
|
|
||||||
valid_fault = true;
|
valid_fault = true;
|
||||||
USERSPACE_BARRIER;
|
USERSPACE_BARRIER;
|
||||||
|
@ -247,7 +247,7 @@ void kobject_user_test7(void *p1, void *p2, void *p3)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Test revoke permission of a k object from userspace. */
|
/* Test revoke permission of a k object from userspace. */
|
||||||
void test_kobject_revoke_access_from_user(void *p1, void *p2, void *p3)
|
void test_kobject_release_from_user(void *p1, void *p2, void *p3)
|
||||||
{
|
{
|
||||||
k_thread_access_grant(k_current_get(),
|
k_thread_access_grant(k_current_get(),
|
||||||
&kobject_sem, NULL);
|
&kobject_sem, NULL);
|
||||||
|
|
|
@ -32,7 +32,7 @@ extern void test_thread_without_kobject_permission(void);
|
||||||
extern void test_kobject_revoke_access(void);
|
extern void test_kobject_revoke_access(void);
|
||||||
extern void test_kobject_grant_access_kobj(void);
|
extern void test_kobject_grant_access_kobj(void);
|
||||||
extern void test_kobject_grant_access_kobj_invalid(void);
|
extern void test_kobject_grant_access_kobj_invalid(void);
|
||||||
extern void test_kobject_revoke_access_from_user(void);
|
extern void test_kobject_release_from_user(void);
|
||||||
extern void test_kobject_access_all_grant(void);
|
extern void test_kobject_access_all_grant(void);
|
||||||
extern void test_thread_has_residual_permissions(void);
|
extern void test_thread_has_residual_permissions(void);
|
||||||
extern void test_kobject_access_grant_to_invalid_thread(void);
|
extern void test_kobject_access_grant_to_invalid_thread(void);
|
||||||
|
@ -73,7 +73,7 @@ void test_main(void)
|
||||||
ztest_unit_test(test_kobject_revoke_access),
|
ztest_unit_test(test_kobject_revoke_access),
|
||||||
ztest_unit_test(test_kobject_grant_access_kobj),
|
ztest_unit_test(test_kobject_grant_access_kobj),
|
||||||
ztest_unit_test(test_kobject_grant_access_kobj_invalid),
|
ztest_unit_test(test_kobject_grant_access_kobj_invalid),
|
||||||
ztest_unit_test(test_kobject_revoke_access_from_user),
|
ztest_unit_test(test_kobject_release_from_user),
|
||||||
ztest_unit_test(test_kobject_access_all_grant),
|
ztest_unit_test(test_kobject_access_all_grant),
|
||||||
ztest_unit_test(test_thread_has_residual_permissions),
|
ztest_unit_test(test_thread_has_residual_permissions),
|
||||||
ztest_unit_test(test_kobject_access_grant_to_invalid_thread),
|
ztest_unit_test(test_kobject_access_grant_to_invalid_thread),
|
||||||
|
|
|
@ -418,7 +418,7 @@ static void revoke_noperms_object(void)
|
||||||
expect_fault = true;
|
expect_fault = true;
|
||||||
expected_reason = REASON_KERNEL_OOPS;
|
expected_reason = REASON_KERNEL_OOPS;
|
||||||
BARRIER();
|
BARRIER();
|
||||||
k_object_access_revoke(&ksem, k_current_get());
|
k_object_release(&ksem);
|
||||||
|
|
||||||
zassert_unreachable("Revoke access to unauthorized object "
|
zassert_unreachable("Revoke access to unauthorized object "
|
||||||
"did not fault\n");
|
"did not fault\n");
|
||||||
|
@ -426,7 +426,7 @@ static void revoke_noperms_object(void)
|
||||||
|
|
||||||
static void access_after_revoke(void)
|
static void access_after_revoke(void)
|
||||||
{
|
{
|
||||||
k_object_access_revoke(&test_revoke_sem, k_current_get());
|
k_object_release(&test_revoke_sem);
|
||||||
|
|
||||||
/* Try to access an object after revoking access to it */
|
/* Try to access an object after revoking access to it */
|
||||||
expect_fault = true;
|
expect_fault = true;
|
||||||
|
@ -437,35 +437,6 @@ static void access_after_revoke(void)
|
||||||
zassert_unreachable("Using revoked object did not fault\n");
|
zassert_unreachable("Using revoked object did not fault\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void revoke_from_parent(k_tid_t parentThread)
|
|
||||||
{
|
|
||||||
/* The following should cause a fault */
|
|
||||||
expect_fault = true;
|
|
||||||
expected_reason = REASON_KERNEL_OOPS;
|
|
||||||
BARRIER();
|
|
||||||
k_object_access_revoke(&test_revoke_sem, parentThread);
|
|
||||||
|
|
||||||
zassert_unreachable("Revoking from unauthorized thread did "
|
|
||||||
"not fault\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void revoke_other_thread(void)
|
|
||||||
{
|
|
||||||
/* Create user mode thread */
|
|
||||||
k_thread_create(&uthread_thread, uthread_stack, STACKSIZE,
|
|
||||||
(k_thread_entry_t)revoke_from_parent, k_current_get(),
|
|
||||||
NULL, NULL, -1, K_USER | K_INHERIT_PERMS, K_NO_WAIT);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Abort ztest thread so that it does not return to the caller
|
|
||||||
* and incorrectly signal a passing test. The thread created above
|
|
||||||
* will handle calling ztest_test_pass() or ztest_test_fail()
|
|
||||||
* to complete the test, either directly or from
|
|
||||||
* _SysFatalErrorHandler().
|
|
||||||
*/
|
|
||||||
k_thread_abort(k_current_get());
|
|
||||||
}
|
|
||||||
|
|
||||||
static void umode_enter_func(void)
|
static void umode_enter_func(void)
|
||||||
{
|
{
|
||||||
if (_is_user_context()) {
|
if (_is_user_context()) {
|
||||||
|
@ -560,7 +531,6 @@ void test_main(void)
|
||||||
ztest_user_unit_test(write_other_stack),
|
ztest_user_unit_test(write_other_stack),
|
||||||
ztest_user_unit_test(revoke_noperms_object),
|
ztest_user_unit_test(revoke_noperms_object),
|
||||||
ztest_user_unit_test(access_after_revoke),
|
ztest_user_unit_test(access_after_revoke),
|
||||||
ztest_user_unit_test(revoke_other_thread),
|
|
||||||
ztest_unit_test(user_mode_enter),
|
ztest_unit_test(user_mode_enter),
|
||||||
ztest_user_unit_test(write_kobject_user_pipe),
|
ztest_user_unit_test(write_kobject_user_pipe),
|
||||||
ztest_user_unit_test(read_kobject_user_pipe)
|
ztest_user_unit_test(read_kobject_user_pipe)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue