LSM: Revive security_task_alloc() hook and per "struct task_struct" security blob.
Subsystems (5)
PATCH 1/1 LSM: Revive security_task_alloc() hook and per "struct task_struct" security blob.
We switched from "struct task_struct"->security to "struct cred"->security in Linux 2.6.29. But not all LSM modules were happy with that change. TOMOYO LSM module is an example which want to use per "struct task_struct" security blob, for TOMOYO's security context is defined based on "struct task_struct" rather than "struct cred". AppArmor LSM module is another example which want to use it, for AppArmor is currently abusing the cred a little bit to store the change_hat and setexeccon info. Although security_task_free() hook was revived in Linux 3.4 because Yama LSM module wanted to release per "struct task_struct" security blob, security_task_alloc() hook and "struct task_struct"->security field were not revived. Nowadays, we are getting proposals of lightweight LSM modules which want to use per "struct task_struct" security blob. PTAGS LSM module and CaitSith LSM module which are currently under proposal for inclusion also want to use it. Therefore, it will be time to revive security_task_alloc() hook and "struct task_struct"->security field.
We are already allowing multiple concurrent LSM modules (up to one fully armored module which uses "struct cred"->security field or exclusive hooks like security_xfrm_state_pol_flow_match(), plus unlimited number of lightweight modules which do not use "struct cred"->security nor exclusive hooks) as long as they are built into the kernel. But this patch does not implement variable length "struct task_struct"->security field which will become needed when multiple LSM modules want to use "struct task_struct"-> security field. Although it won't be difficult to implement variable length "struct task_struct"->security field, let's think about it after we merged this patch.
--- include/linux/init_task.h | 7 +++++++ include/linux/lsm_hooks.h | 9 ++++++++- include/linux/sched.h | 4 ++++ include/linux/security.h | 7 +++++++ kernel/fork.c | 7 ++++++- security/security.c | 6 ++++++ 6 files changed, 38 insertions(+), 2 deletions(-)
include/linux/init_task.h +7 -0
@@ -210,6 +210,12 @@# define INIT_TASK_TI (tsk)#endif +#ifdef CONFIG_SECURITY +#define INIT_TASK_SECURITY .security = NULL, +#else +#define INIT_TASK_SECURITY +#endif +/* * INIT_TASK is used to set up the first task table, touch at * your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -288,6 +294,7 @@ INIT_VTIME(tsk) \ INIT_NUMA_BALANCING(tsk) \ INIT_KASAN(tsk) \ + INIT_TASK_SECURITY \ }
include/linux/lsm_hooks.h +8 -1
@@ -533,8 +533,13 @@* manual page for definitions of the @clone_flags. * @clone_flags contains the flags indicating what should be shared. * Return 0 if permission is granted. +* @task_alloc: +* @task task being allocated. +* @clone_flags contains the flags indicating what should be shared. +* Handle allocation of task-related resources. +* Returns a zero on success, negative values on failure. * @task_free: -* @task task being freed +* @task task about to be freed. * Handle release of task-related resources. (Note that this can be called * from interrupt context.) * @cred_alloc_blank:
@@ -1482,6 +1487,7 @@int (*file_open)(struct file *file,const struct cred *cred);int (*task_create)(unsigned long clone_flags); +int (*task_alloc)(struct task_struct *task,unsigned long clone_flags);void (*task_free)(struct task_struct *task);int (*cred_alloc_blank)(struct cred *cred,gfp_t gfp);void (*cred_free)(struct cred *cred);
@@ -1748,6 +1754,7 @@ struct security_hook_heads {struct list_head file_receive;struct list_head file_open;struct list_head task_create; +struct list_head task_alloc;struct list_head task_free;struct list_head cred_alloc_blank;struct list_head cred_free;
include/linux/sched.h +4 -0
@@ -1038,6 +1038,10 @@ struct task_struct {/* A live task holds one reference: */ atomic_t stack_refcount;#endif +#ifdef CONFIG_SECURITY +/* Used by LSM modules for access restriction: */ +void *security; +#endif /* CPU-specific state of this task: */ struct thread_struct thread;
include/linux/security.h +7 -0
@@ -308,6 +308,7 @@ int security_file_send_sigiotask(struct task_struct *tsk,int security_file_receive (struct file *file);int security_file_open (struct file *file,const struct cred *cred);int security_task_create (unsigned long clone_flags); +int security_task_alloc (struct task_struct *task,unsigned long clone_flags);void security_task_free (struct task_struct *task);int security_cred_alloc_blank (struct cred *cred,gfp_t gfp);void security_cred_free (struct cred *cred);
@@ -861,6 +862,12 @@ static inline int security_task_create(unsigned long clone_flags)return 0 ; } +static inline int security_task_alloc (struct task_struct *task, +unsigned long clone_flags) +{ +return 0 ; +} +static inline void security_task_free (struct task_struct *task) { }
kernel/fork.c +6 -1
@@ -1679,9 +1679,12 @@ static __latent_entropy struct task_struct *copy_process( goto bad_fork_cleanup_perf;/* copy all the process information */ shm_init_task (p); - retval =copy_semundo (clone_flags, p); + retval =security_task_alloc (p, clone_flags);if (retval) goto bad_fork_cleanup_audit; + retval =copy_semundo (clone_flags, p); +if (retval) + goto bad_fork_cleanup_security; retval =copy_files (clone_flags, p);if (retval) goto bad_fork_cleanup_semundo;
@@ -1903,6 +1906,8 @@ static __latent_entropy struct task_struct *copy_process(exit_files (p);/* blocking */ bad_fork_cleanup_semundo:exit_sem (p); +bad_fork_cleanup_security: +security_task_free (p); bad_fork_cleanup_audit:audit_free (p); bad_fork_cleanup_perf:
security/security.c +6 -0
@@ -930,6 +930,11 @@ int security_task_create(unsigned long clone_flags)return call_int_hook (task_create,0 , clone_flags); } +int security_task_alloc (struct task_struct *task,unsigned long clone_flags) +{ +return call_int_hook (task_alloc,0 , task, clone_flags); +} +void security_task_free (struct task_struct *task) {call_void_hook (task_free, task);
@@ -1770,6 +1775,7 @@ struct security_hook_heads security_hook_heads __lsm_ro_after_init = { .file_receive = LIST_HEAD_INIT(security_hook_heads.file_receive), .file_open = LIST_HEAD_INIT(security_hook_heads.file_open), .task_create = LIST_HEAD_INIT(security_hook_heads.task_create), + .task_alloc = LIST_HEAD_INIT(security_hook_heads.task_alloc), .task_free = LIST_HEAD_INIT(security_hook_heads.task_free), .cred_alloc_blank = LIST_HEAD_INIT(security_hook_heads.cred_alloc_blank),
Signature · 6 lines
1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
John Johansen
maintainerPATCH 1/1 apparmor: move task specific domain change info out of cred
Now that security_task_alloc() hook and "struct task_struct"->security field are revived, move task specific domain change information for change_onexec (equiv of setexeccon) and change_hat out of the cred into a context off of the task_struct.
This cleans up apparmor's use of the cred structure so that it only carries the reference to current mediation.
--- security/apparmor/context.c | 129 +++++++++++++++++------------------- security/apparmor/domain.c | 28 ++++---- security/apparmor/include/context.h | 63 ++++++++---------- security/apparmor/lsm.c | 65 ++++++++++-------- security/apparmor/policy.c | 5 +- 5 files changed, 143 insertions(+), 147 deletions(-)
security/apparmor/context.c +62 -67
@@ -13,11 +13,9 @@* License. * * -* AppArmor sets confinement on every task, via the the aa_task_ctx and -* the aa_task_ctx.profile, both of which are required and are not allowed -* to be NULL. The aa_task_ctx is not reference counted and is unique -* to each cred (which is reference count). The profile pointed to by -* the task_ctx is reference counted. +* AppArmor sets confinement on every task, via the cred_profile() which +* is required and is not allowed to be NULL. The cred_profile is +* reference counted. * * TODO * If a task uses change_hat it currently does not return to the old
@@ -29,25 +27,42 @@#include "include/context.h" #include "include/policy.h" + +/** +* aa_get_task_profile - Get another task's profile +* @task: task to query (NOT NULL) +* +* Returns: counted reference to @task's profile +*/ +struct aa_profile *aa_get_task_profile (struct task_struct *task) +{ +struct aa_profile *p; + +rcu_read_lock (); + p =aa_get_profile (__aa_task_profile (task)); +rcu_read_unlock (); + +return p; +} +/** -* aa_alloc_task_context - allocate a new task_ctx +* aa_alloc_task_ctx - allocate a new task_ctx * @flags: gfp flags for allocation * * Returns: allocated buffer or NULL on failure */ -struct aa_task_ctx *aa_alloc_task_context (gfp_t flags) +struct aa_task_ctx *aa_alloc_task_ctx (gfp_t flags) {return kzalloc (sizeof (struct aa_task_ctx ), flags); }/** -* aa_free_task_context - free a task_ctx +* aa_free_task_ctx - free a task_ctx * @ctx: task_ctx to free (MAYBE NULL) */ -void aa_free_task_context (struct aa_task_ctx *ctx) +void aa_free_task_ctx (struct aa_task_ctx *ctx) {if (ctx) { -aa_put_profile (ctx->profile);aa_put_profile (ctx->previous);aa_put_profile (ctx->onexec);
@@ -56,36 +71,18 @@ void aa_free_task_context(struct aa_task_ctx *ctx) }/** -* aa_dup_task_context - duplicate a task context, incrementing reference counts +* aa_dup_task_ctx - duplicate a task context, incrementing reference counts * @new: a blank task context (NOT NULL) * @old: the task context to copy (NOT NULL) */ -void aa_dup_task_context (struct aa_task_ctx *new,const struct aa_task_ctx *old) +void aa_dup_task_ctx (struct aa_task_ctx *new,const struct aa_task_ctx *old) { *new = *old; -aa_get_profile (new->profile);aa_get_profile (new->previous);aa_get_profile (new->onexec); }/** -* aa_get_task_profile - Get another task's profile -* @task: task to query (NOT NULL) -* -* Returns: counted reference to @task's profile -*/ -struct aa_profile *aa_get_task_profile (struct task_struct *task) -{ -struct aa_profile *p; - -rcu_read_lock (); - p =aa_get_profile (__aa_task_profile (task)); -rcu_read_unlock (); - -return p; -} - -/** * aa_replace_current_profile - replace the current tasks profiles * @profile: new profile (NOT NULL) *
@@ -93,36 +90,37 @@ struct aa_profile *aa_get_task_profile(struct task_struct *task)*/ int aa_replace_current_profile (struct aa_profile *profile) { -struct aa_task_ctx *ctx =current_ctx (); +struct aa_profile *old =__aa_current_profile ();struct cred *new; +AA_BUG (!profile); -if (ctx->profile == profile) +if (old == profile)return 0 ;if (current_cred () !=current_real_cred ())return -EBUSY ; new =prepare_creds (); + old =cred_profile (new);if (!new)return -ENOMEM ; - ctx =cred_ctx (new); -if (unconfined (profile) || (ctx->profile->ns != profile->ns)) +if (unconfined (profile) || (old->ns != profile->ns))/* if switching to unconfined or a different profile namespace * clear out context state */ -aa_clear_task_ctx_trans (ctx); +aa_clear_task_ctx (current_task_ctx ());/* -* be careful switching ctx->profile, when racing replacement it -* is possible that ctx->profile->proxy->profile is the reference +* be careful switching cred profile, when racing replacement it +* is possible that the cred profile's->proxy->profile is the reference * keeping @profile valid, so make sure to get its reference before -* dropping the reference on ctx->profile +* dropping the reference on the cred's profile */ aa_get_profile (profile); -aa_put_profile (ctx->profile); - ctx->profile = profile; +aa_put_profile (old); +cred_profile (new) = profile;commit_creds (new);return 0 ;
@@ -137,16 +135,12 @@ int aa_replace_current_profile(struct aa_profile *profile)int aa_set_current_onexec (struct aa_profile *profile) {struct aa_task_ctx *ctx; -struct cred *new =prepare_creds (); -if (!new) -return -ENOMEM ; - ctx =cred_ctx (new); + ctx =current_task_ctx ();aa_get_profile (profile);aa_put_profile (ctx->onexec); ctx->onexec = profile; -commit_creds (new);return 0 ; }
@@ -162,25 +156,28 @@ int aa_set_current_onexec(struct aa_profile *profile)*/ int aa_set_current_hat (struct aa_profile *profile,u64 token) { -struct aa_task_ctx *ctx; -struct cred *new =prepare_creds (); +struct aa_task_ctx *ctx =current_task_ctx (); +struct cred *new; + +AA_BUG (!profile); + + new =prepare_creds ();if (!new)return -ENOMEM ; -AA_BUG (!profile); - ctx =cred_ctx (new);if (!ctx->previous) {/* transfer refcount */ - ctx->previous = ctx->profile; + ctx->previous =cred_profile (new); ctx->token = token; }else if (ctx->token == token) { -aa_put_profile (ctx->profile); +aa_put_profile (cred_profile (new)); }else {/* previous_profile && ctx->token != token */ abort_creds (new);return -EACCES ; } - ctx->profile =aa_get_newest_profile (profile); + +cred_profile (new) =aa_get_newest_profile (profile);/* clear exec on switching context */ aa_put_profile (ctx->onexec); ctx->onexec =NULL ;
@@ -200,28 +197,26 @@ int aa_set_current_hat(struct aa_profile *profile, u64 token)*/ int aa_restore_previous_profile (u64 token) { -struct aa_task_ctx *ctx; -struct cred *new =prepare_creds (); -if (!new) -return -ENOMEM ; +struct aa_task_ctx *ctx =current_task_ctx (); +struct cred *new; - ctx =cred_ctx (new); -if (ctx->token != token) { -abort_creds (new); +if (ctx->token != token)return -EACCES ; - }/* ignore restores when there is no saved profile */ -if (!ctx->previous) { -abort_creds (new); +if (!ctx->previous)return 0 ; - } -aa_put_profile (ctx->profile); - ctx->profile =aa_get_newest_profile (ctx->previous); -AA_BUG (!ctx->profile); + new =prepare_creds (); +if (!new) +return -ENOMEM ; + +aa_put_profile (cred_profile (new)); +cred_profile (new) =aa_get_newest_profile (ctx->previous); +AA_BUG (!cred_profile (new));/* clear exec && prev information when restoring to previous context */ -aa_clear_task_ctx_trans (ctx); +aa_clear_task_ctx (ctx);commit_creds (new); +return 0 ; }
security/apparmor/domain.c +14 -14
@@ -353,10 +353,10 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)if (bprm->cred_prepared)return 0 ; - ctx =cred_ctx (bprm->cred); + ctx =current_task_ctx ();AA_BUG (!ctx); - - profile =aa_get_newest_profile (ctx->profile); +AA_BUG (!cred_profile (bprm->cred)); + profile =aa_get_newest_profile (cred_profile (bprm->cred));/* * get the namespace from the replacement profile as replacement * can change the namespace
@@ -499,14 +499,11 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) bprm->per_clear |=PER_CLEAR_ON_SETID ; x_clear: -aa_put_profile (ctx->profile); -/* transfer new profile reference will be released when ctx is freed */ - ctx->profile = new_profile; +aa_put_profile (profile); +/* transfer new profile reference will be released when cred is freed */ +cred_profile (bprm->cred) = new_profile; new_profile =NULL ; -/* clear out all temporary/transitional state from the context */ -aa_clear_task_ctx_trans (ctx); - audit: error = aa_audit_file(profile, &perms, OP_EXEC, MAY_EXEC, name, new_profile ? new_profile->base.hname : NULL,
@@ -544,17 +541,16 @@ int apparmor_bprm_secureexec(struct linux_binprm *bprm)void apparmor_bprm_committing_creds (struct linux_binprm *bprm) {struct aa_profile *profile =__aa_current_profile (); -struct aa_task_ctx *new_ctx =cred_ctx (bprm->cred); +struct aa_profile *new =cred_profile (bprm->cred);/* bail out if unconfined or not changing profile */ -if ((new_ctx->profile == profile) || - (unconfined (new_ctx->profile))) +if (new == profile ||unconfined (new))return ; current->pdeath_signal =0 ;/* reset soft limits and set hard limits for the new profile */ -__aa_transition_rlimits (profile, new_ctx->profile); +__aa_transition_rlimits (profile, new); }/**
@@ -564,6 +560,10 @@ void apparmor_bprm_committing_creds(struct linux_binprm *bprm)void apparmor_bprm_committed_creds (struct linux_binprm *bprm) {/* TODO: cleanup signals - ipc mediation */ + +/* clear out all temporary/transitional state from the context */ +aa_clear_task_ctx (current_task_ctx ()); +return ; }
@@ -621,7 +621,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)/* released below */ cred =get_current_cred (); - ctx =cred_ctx (cred); + ctx =current_task_ctx (); profile =aa_get_newest_profile (aa_cred_profile (cred)); previous_profile =aa_get_newest_profile (ctx->previous);
security/apparmor/include/context.h +26 -37
120 lines not on this page · raw message
security/apparmor/lsm.c +38 -27
119 lines not on this page · raw message
security/apparmor/policy.c +3 -2
@@ -827,8 +827,9 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname,* @udata: serialized data stream (NOT NULL) * * unpack and replace a profile on the profile list and uses of that profile -* by any aa_task_ctx. If the profile does not exist on the profile list -* it is added. +* by any task creds via invalidating the old version of the profile, which +* tasks will notice to update their own cred. If the profile does not exist +* on the profile list it is added. * * Returns: size of data consumed else error code on failure. */
Signature · 6 lines
2.9.3 -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Serge E. Hallyn
maintainerPATCH 1/1 apparmor: move task specific domain change info out of cred
Quoted 9 lines · John Johansen
Now that
security_task_alloc()hook and "struct task_struct"->security field are revived, move task specific domain change information forchange_onexec(equiv of setexeccon) andchange_hatout of the cred into a context off of thetask_struct.This cleans up apparmor's use of the cred structure so that it only carries the reference to current mediation.
Signed-off-by John Johansen <[email protected]>
Thanks, John, that helps in compelling a review of the previous patch :)
So the task_struct->security pointer is only to store requested transition profiles right?
Quoted 612 lines
--- security/apparmor/context.c | 129 +++++++++++++++++------------------- security/apparmor/domain.c | 28 ++++---- security/apparmor/include/context.h | 63 ++++++++---------- security/apparmor/lsm.c | 65 ++++++++++-------- security/apparmor/policy.c | 5 +- 5 files changed, 143 insertions(+), 147 deletions(-)security/apparmor/context.c +62
-67@@ -13,11 +13,9 @@* License. * * -* AppArmor sets confinement on every task, via the the aa_task_ctx and -* the aa_task_ctx.profile, both of which are required and are not allowed -* to be NULL. The aa_task_ctx is not reference counted and is unique -* to each cred (which is reference count). The profile pointed to by -* the task_ctx is reference counted. +* AppArmor sets confinement on every task, via the cred_profile() which +* is required and is not allowed to be NULL. The cred_profile is +* reference counted. * * TODO * If a task uses change_hat it currently does not return to the old @@ -29,25 +27,42 @@#include "include/context.h" #include "include/policy.h" + +/** +* aa_get_task_profile - Get another task's profile +* @task: task to query (NOT NULL) +* +* Returns: counted reference to @task's profile +*/ +struct aa_profile *aa_get_task_profile (struct task_struct *task) +{ +struct aa_profile *p; + +rcu_read_lock (); + p =aa_get_profile (__aa_task_profile (task)); +rcu_read_unlock (); + +return p; +} +/** -* aa_alloc_task_context - allocate a new task_ctx +* aa_alloc_task_ctx - allocate a new task_ctx * @flags: gfp flags for allocation * * Returns: allocated buffer or NULL on failure */ -struct aa_task_ctx *aa_alloc_task_context (gfp_t flags) +struct aa_task_ctx *aa_alloc_task_ctx (gfp_t flags) {return kzalloc (sizeof (struct aa_task_ctx ), flags); }/** -* aa_free_task_context - free a task_ctx +* aa_free_task_ctx - free a task_ctx * @ctx: task_ctx to free (MAYBE NULL) */ -void aa_free_task_context (struct aa_task_ctx *ctx) +void aa_free_task_ctx (struct aa_task_ctx *ctx) {if (ctx) { -aa_put_profile (ctx->profile);aa_put_profile (ctx->previous);aa_put_profile (ctx->onexec);@@ -56,36 +71,18 @@ void aa_free_task_context(struct aa_task_ctx *ctx) }/** -* aa_dup_task_context - duplicate a task context, incrementing reference counts +* aa_dup_task_ctx - duplicate a task context, incrementing reference counts * @new: a blank task context (NOT NULL) * @old: the task context to copy (NOT NULL) */ -void aa_dup_task_context (struct aa_task_ctx *new,const struct aa_task_ctx *old) +void aa_dup_task_ctx (struct aa_task_ctx *new,const struct aa_task_ctx *old) { *new = *old; -aa_get_profile (new->profile);aa_get_profile (new->previous);aa_get_profile (new->onexec); }/** -* aa_get_task_profile - Get another task's profile -* @task: task to query (NOT NULL) -* -* Returns: counted reference to @task's profile -*/ -struct aa_profile *aa_get_task_profile (struct task_struct *task) -{ -struct aa_profile *p; - -rcu_read_lock (); - p =aa_get_profile (__aa_task_profile (task)); -rcu_read_unlock (); - -return p; -} - -/** * aa_replace_current_profile - replace the current tasks profiles * @profile: new profile (NOT NULL) * @@ -93,36 +90,37 @@ struct aa_profile *aa_get_task_profile(struct task_struct *task)*/ int aa_replace_current_profile (struct aa_profile *profile) { -struct aa_task_ctx *ctx =current_ctx (); +struct aa_profile *old =__aa_current_profile ();struct cred *new; +AA_BUG (!profile); -if (ctx->profile == profile) +if (old == profile)return 0 ;if (current_cred () !=current_real_cred ())return -EBUSY ; new =prepare_creds (); + old =cred_profile (new);if (!new)return -ENOMEM ; - ctx =cred_ctx (new); -if (unconfined (profile) || (ctx->profile->ns != profile->ns)) +if (unconfined (profile) || (old->ns != profile->ns))/* if switching to unconfined or a different profile namespace * clear out context state */ -aa_clear_task_ctx_trans (ctx); +aa_clear_task_ctx (current_task_ctx ());/* -* be careful switching ctx->profile, when racing replacement it -* is possible that ctx->profile->proxy->profile is the reference +* be careful switching cred profile, when racing replacement it +* is possible that the cred profile's->proxy->profile is the reference * keeping @profile valid, so make sure to get its reference before -* dropping the reference on ctx->profile +* dropping the reference on the cred's profile */ aa_get_profile (profile); -aa_put_profile (ctx->profile); - ctx->profile = profile; +aa_put_profile (old); +cred_profile (new) = profile;commit_creds (new);return 0 ;@@ -137,16 +135,12 @@ int aa_replace_current_profile(struct aa_profile *profile)int aa_set_current_onexec (struct aa_profile *profile) {struct aa_task_ctx *ctx; -struct cred *new =prepare_creds (); -if (!new) -return -ENOMEM ; - ctx =cred_ctx (new); + ctx =current_task_ctx ();aa_get_profile (profile);aa_put_profile (ctx->onexec); ctx->onexec = profile; -commit_creds (new);return 0 ; }@@ -162,25 +156,28 @@ int aa_set_current_onexec(struct aa_profile *profile)*/ int aa_set_current_hat (struct aa_profile *profile,u64 token) { -struct aa_task_ctx *ctx; -struct cred *new =prepare_creds (); +struct aa_task_ctx *ctx =current_task_ctx (); +struct cred *new; + +AA_BUG (!profile); + + new =prepare_creds ();if (!new)return -ENOMEM ; -AA_BUG (!profile); - ctx =cred_ctx (new);if (!ctx->previous) {/* transfer refcount */ - ctx->previous = ctx->profile; + ctx->previous =cred_profile (new); ctx->token = token; }else if (ctx->token == token) { -aa_put_profile (ctx->profile); +aa_put_profile (cred_profile (new)); }else {/* previous_profile && ctx->token != token */ abort_creds (new);return -EACCES ; } - ctx->profile =aa_get_newest_profile (profile); + +cred_profile (new) =aa_get_newest_profile (profile);/* clear exec on switching context */ aa_put_profile (ctx->onexec); ctx->onexec =NULL ;@@ -200,28 +197,26 @@ int aa_set_current_hat(struct aa_profile *profile, u64 token)*/ int aa_restore_previous_profile (u64 token) { -struct aa_task_ctx *ctx; -struct cred *new =prepare_creds (); -if (!new) -return -ENOMEM ; +struct aa_task_ctx *ctx =current_task_ctx (); +struct cred *new; - ctx =cred_ctx (new); -if (ctx->token != token) { -abort_creds (new); +if (ctx->token != token)return -EACCES ; - }/* ignore restores when there is no saved profile */ -if (!ctx->previous) { -abort_creds (new); +if (!ctx->previous)return 0 ; - } -aa_put_profile (ctx->profile); - ctx->profile =aa_get_newest_profile (ctx->previous); -AA_BUG (!ctx->profile); + new =prepare_creds (); +if (!new) +return -ENOMEM ; + +aa_put_profile (cred_profile (new)); +cred_profile (new) =aa_get_newest_profile (ctx->previous); +AA_BUG (!cred_profile (new));/* clear exec && prev information when restoring to previous context */ -aa_clear_task_ctx_trans (ctx); +aa_clear_task_ctx (ctx);commit_creds (new); +return 0 ; }security/apparmor/domain.c +14
-14@@ -353,10 +353,10 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)if (bprm->cred_prepared)return 0 ; - ctx =cred_ctx (bprm->cred); + ctx =current_task_ctx ();AA_BUG (!ctx); - - profile =aa_get_newest_profile (ctx->profile); +AA_BUG (!cred_profile (bprm->cred)); + profile =aa_get_newest_profile (cred_profile (bprm->cred));/* * get the namespace from the replacement profile as replacement * can change the namespace @@ -499,14 +499,11 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) bprm->per_clear |=PER_CLEAR_ON_SETID ; x_clear: -aa_put_profile (ctx->profile); -/* transfer new profile reference will be released when ctx is freed */ - ctx->profile = new_profile; +aa_put_profile (profile); +/* transfer new profile reference will be released when cred is freed */ +cred_profile (bprm->cred) = new_profile; new_profile =NULL ; -/* clear out all temporary/transitional state from the context */ -aa_clear_task_ctx_trans (ctx); - audit: error = aa_audit_file(profile, &perms, OP_EXEC, MAY_EXEC, name, new_profile ? new_profile->base.hname : NULL,@@ -544,17 +541,16 @@ int apparmor_bprm_secureexec(struct linux_binprm *bprm)void apparmor_bprm_committing_creds (struct linux_binprm *bprm) {struct aa_profile *profile =__aa_current_profile (); -struct aa_task_ctx *new_ctx =cred_ctx (bprm->cred); +struct aa_profile *new =cred_profile (bprm->cred);/* bail out if unconfined or not changing profile */ -if ((new_ctx->profile == profile) || - (unconfined (new_ctx->profile))) +if (new == profile ||unconfined (new))return ; current->pdeath_signal =0 ;/* reset soft limits and set hard limits for the new profile */ -__aa_transition_rlimits (profile, new_ctx->profile); +__aa_transition_rlimits (profile, new); }/** @@ -564,6 +560,10 @@ void apparmor_bprm_committing_creds(struct linux_binprm *bprm)void apparmor_bprm_committed_creds (struct linux_binprm *bprm) {/* TODO: cleanup signals - ipc mediation */ + +/* clear out all temporary/transitional state from the context */ +aa_clear_task_ctx (current_task_ctx ()); +return ; }@@ -621,7 +621,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)/* released below */ cred =get_current_cred (); - ctx =cred_ctx (cred); + ctx =current_task_ctx (); profile =aa_get_newest_profile (aa_cred_profile (cred)); previous_profile =aa_get_newest_profile (ctx->previous);security/apparmor/include/context.h +26
-37@@ -22,8 +22,9 @@#include "policy.h" #include "policy_ns.h" -#define cred_ctx (X ) ((X)->security) -#define current_ctx () cred_ctx(current_cred()) +#define task_ctx (X ) ((X)->security) +#define current_task_ctx () (task_ctx(current)) +#define cred_profile (X ) ((X)->security)/* struct aa_file_ctx - the AppArmor context the file was opened in * @perms: the permission the file was opened with @@ -58,28 +59,23 @@ static inline void aa_free_file_context(struct aa_file_ctx *ctx) }/** -* struct aa_task_ctx - primary label for confined tasks -* @profile: the current profile (NOT NULL) -* @exec: profile to transition to on next exec (MAYBE NULL) -* @previous: profile the task may return to (MAYBE NULL) +* struct aa_task_ctx - information for current task label change +* @onexec: profile to transition to on next exec (MAY BE NULL) +* @previous: profile the task may return to (MAY BE NULL) * @token: magic value the task must know for returning to @previous_profile * -* Contains the task's current profile (which could change due to -* change_hat). Plus the hat_magic needed during change_hat. -* * TODO: make so a task can be confined by a stack of contexts */ struct aa_task_ctx { -struct aa_profile *profile;struct aa_profile *onexec;struct aa_profile *previous;u64 token; }; -struct aa_task_ctx *aa_alloc_task_context (gfp_t flags); -void aa_free_task_context (struct aa_task_ctx *ctx); -void aa_dup_task_context (struct aa_task_ctx *new, -const struct aa_task_ctx *old); +struct aa_task_ctx *aa_alloc_task_ctx (gfp_t flags); +void aa_free_task_ctx (struct aa_task_ctx *ctx); +void aa_dup_task_ctx (struct aa_task_ctx *new,const struct aa_task_ctx *old); +int aa_replace_current_profile (struct aa_profile *profile);int aa_set_current_onexec (struct aa_profile *profile);int aa_set_current_hat (struct aa_profile *profile,u64 token);@@ -97,10 +93,11 @@ struct aa_profile *aa_get_task_profile(struct task_struct *task);*/ static inline struct aa_profile *aa_cred_profile (const struct cred *cred) { -struct aa_task_ctx *ctx =cred_ctx (cred); +struct aa_profile *profile =cred_profile (cred); -AA_BUG (!ctx || !ctx->profile); -return ctx->profile; +AA_BUG (!profile); + +return profile; }/** @@ -117,17 +114,6 @@ static inline struct aa_profile *__aa_task_profile(struct task_struct *task) }/** -* __aa_task_is_confined - determine if @task has any confinement -* @task: task to check confinement of (NOT NULL) -* -* If @task != current needs to be called in RCU safe critical section -*/ -static inline bool __aa_task_is_confined (struct task_struct *task) -{ -return !unconfined (__aa_task_profile (task)); -} - -/** * __aa_current_profile - find the current tasks confining profile * * Returns: up to date confining profile or the ns unconfined profile (NOT NULL) @@ -150,19 +136,17 @@ static inline struct aa_profile *__aa_current_profile(void)*/ static inline struct aa_profile *aa_current_profile (void ) { -const struct aa_task_ctx *ctx =current_ctx (); -struct aa_profile *profile; +struct aa_profile *profile =__aa_current_profile (); -AA_BUG (!ctx || !ctx->profile); +AA_BUG (!profile); -if (profile_is_stale (ctx->profile)) { - profile =aa_get_newest_profile (ctx->profile); +if (profile_is_stale (profile)) { + profile =aa_get_newest_profile (profile);aa_replace_current_profile (profile);aa_put_profile (profile); - ctx =current_ctx (); } -return ctx->profile; +return profile; }static inline struct aa_ns *aa_get_current_ns (void )@@ -170,12 +154,17 @@ static inline struct aa_ns *aa_get_current_ns(void)return aa_get_ns (__aa_current_profile ()->ns); } + + +/** -* aa_clear_task_ctx_trans - clear transition tracking info from the ctx +* aa_clear_task_ctx - clear transition tracking info from the ctx * @ctx: task context to clear (NOT NULL) */ -static inline void aa_clear_task_ctx_trans (struct aa_task_ctx *ctx) +static inline void aa_clear_task_ctx (struct aa_task_ctx *ctx) { +AA_BUG (!ctx); +aa_put_profile (ctx->previous);aa_put_profile (ctx->onexec); ctx->previous =NULL ;security/apparmor/lsm.c +38
-27@@ -49,12 +49,12 @@ DEFINE_PER_CPU(struct aa_buffers, aa_buffers);*/ /* -* free the associated aa_task_ctx and put its profiles +* put the associated profiles */ static void apparmor_cred_free (struct cred *cred) { -aa_free_task_context (cred_ctx (cred)); -cred_ctx (cred) =NULL ; +aa_put_profile (cred_profile (cred)); +cred_profile (cred) =NULL ; }/* @@ -62,30 +62,19 @@ static void apparmor_cred_free(struct cred *cred)*/ static int apparmor_cred_alloc_blank (struct cred *cred,gfp_t gfp) { -/* freed by apparmor_cred_free */ -struct aa_task_ctx *ctx =aa_alloc_task_context (gfp); - -if (!ctx) -return -ENOMEM ; - -cred_ctx (cred) = ctx; +cred_profile (cred) =NULL ;return 0 ; }/* -* prepare new aa_task_ctx for modification by prepare_cred block +* prepare new cred profile for modification by prepare_cred block */ static int apparmor_cred_prepare (struct cred *new,const struct cred *old,gfp_t gfp) { -/* freed by apparmor_cred_free */ -struct aa_task_ctx *ctx =aa_alloc_task_context (gfp); - -if (!ctx) -return -ENOMEM ; - -aa_dup_task_context (ctx,cred_ctx (old)); -cred_ctx (new) = ctx; +struct aa_profile *tmp =cred_profile (new); +cred_profile (new) =aa_get_newest_profile (cred_profile (old)); +aa_put_profile (tmp);return 0 ; }@@ -94,10 +83,30 @@ static int apparmor_cred_prepare(struct cred *new, const struct cred *old,*/ static void apparmor_cred_transfer (struct cred *new,const struct cred *old) { -const struct aa_task_ctx *old_ctx =cred_ctx (old); -struct aa_task_ctx *new_ctx =cred_ctx (new); +struct aa_profile *tmp =cred_profile (new); +cred_profile (new) =aa_get_newest_profile (cred_profile (old)); +aa_put_profile (tmp); +} -aa_dup_task_context (new_ctx, old_ctx); +static void apparmor_task_free (struct task_struct *task) +{ + +aa_free_task_ctx (task_ctx (task)); +task_ctx (task) =NULL ; +} + +static int apparmor_task_alloc (struct task_struct *task, +unsigned long clone_flags) +{ +struct aa_task_ctx *new =aa_alloc_task_ctx (GFP_KERNEL ); + +if (!new) +return -ENOMEM ; + +aa_dup_task_ctx (new,current_task_ctx ()); +task_ctx (task) = new; + +return 0 ; } static int apparmor_ptrace_access_check(struct task_struct *child,@@ -484,11 +493,11 @@ static int apparmor_getprocattr(struct task_struct *task, char *name,int error = -ENOENT ;/* released below */ const struct cred *cred =get_task_cred (task); -struct aa_task_ctx *ctx =cred_ctx (cred); +struct aa_task_ctx *ctx =current_task_ctx ();struct aa_profile *profile =NULL ;if (strcmp (name,"current" ) ==0 ) - profile =aa_get_newest_profile (ctx->profile); + profile =aa_get_newest_profile (cred_profile (cred));else if (strcmp (name,"prev" ) ==0 && ctx->previous) profile =aa_get_newest_profile (ctx->previous);else if (strcmp (name,"exec" ) ==0 && ctx->onexec)@@ -629,6 +638,8 @@ static struct security_hook_list apparmor_hooks[] = {LSM_HOOK_INIT (bprm_committed_creds, apparmor_bprm_committed_creds),LSM_HOOK_INIT (bprm_secureexec, apparmor_bprm_secureexec), +LSM_HOOK_INIT (task_free, apparmor_task_free), +LSM_HOOK_INIT (task_alloc, apparmor_task_alloc), LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit), };@@ -871,12 +882,12 @@ static int __init set_init_ctx(void)struct cred *cred = (struct cred *)current->real_cred;struct aa_task_ctx *ctx; - ctx =aa_alloc_task_context (GFP_KERNEL ); + ctx =aa_alloc_task_ctx (GFP_KERNEL );if (!ctx)return -ENOMEM ; - ctx->profile =aa_get_profile (root_ns->unconfined); -cred_ctx (cred) = ctx; +cred_profile (cred) =aa_get_profile (root_ns->unconfined); +task_ctx (current) = ctx;return 0 ; }security/apparmor/policy.c +3
-2@@ -827,8 +827,9 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname,* @udata: serialized data stream (NOT NULL) * * unpack and replace a profile on the profile list and uses of that profile -* by any aa_task_ctx. If the profile does not exist on the profile list -* it is added. +* by any task creds via invalidating the old version of the profile, which +* tasks will notice to update their own cred. If the profile does not exist +* on the profile list it is added. * * Returns: size of data consumed else error code on failure. */ Signature · 1 line
2.9.3
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
John Johansen
maintainerPATCH 1/1 apparmor: move task specific domain change info out of cred
Quoted 9 lines · Serge E. Hallyn
Quoted 8 lines · John Johansen
Now that
security_task_alloc()hook and "struct task_struct"->security field are revived, move task specific domain change information forchange_onexec(equiv of setexeccon) andchange_hatout of the cred into a context off of thetask_struct.This cleans up apparmor's use of the cred structure so that it only carries the reference to current mediation.
Quoted 7 lines
Quoted 1 line
Signed-off-by John Johansen <[email protected]>Thanks, John, that helps in compelling a review of the previous patch :)
So the
task_struct->securitypointer is only to store requested transition profiles right?
correct, well and support information for the transition like the random magic token for change_hat.
Quoted 604 lines
Quoted 604 lines
--- security/apparmor/context.c | 129 +++++++++++++++++------------------- security/apparmor/domain.c | 28 ++++---- security/apparmor/include/context.h | 63 ++++++++---------- security/apparmor/lsm.c | 65 ++++++++++-------- security/apparmor/policy.c | 5 +- 5 files changed, 143 insertions(+), 147 deletions(-)security/apparmor/context.c +62
-67@@ -13,11 +13,9 @@* License. * * -* AppArmor sets confinement on every task, via the the aa_task_ctx and -* the aa_task_ctx.profile, both of which are required and are not allowed -* to be NULL. The aa_task_ctx is not reference counted and is unique -* to each cred (which is reference count). The profile pointed to by -* the task_ctx is reference counted. +* AppArmor sets confinement on every task, via the cred_profile() which +* is required and is not allowed to be NULL. The cred_profile is +* reference counted. * * TODO * If a task uses change_hat it currently does not return to the old @@ -29,25 +27,42 @@#include "include/context.h" #include "include/policy.h" + +/** +* aa_get_task_profile - Get another task's profile +* @task: task to query (NOT NULL) +* +* Returns: counted reference to @task's profile +*/ +struct aa_profile *aa_get_task_profile (struct task_struct *task) +{ +struct aa_profile *p; + +rcu_read_lock (); + p =aa_get_profile (__aa_task_profile (task)); +rcu_read_unlock (); + +return p; +} +/** -* aa_alloc_task_context - allocate a new task_ctx +* aa_alloc_task_ctx - allocate a new task_ctx * @flags: gfp flags for allocation * * Returns: allocated buffer or NULL on failure */ -struct aa_task_ctx *aa_alloc_task_context (gfp_t flags) +struct aa_task_ctx *aa_alloc_task_ctx (gfp_t flags) {return kzalloc (sizeof (struct aa_task_ctx ), flags); }/** -* aa_free_task_context - free a task_ctx +* aa_free_task_ctx - free a task_ctx * @ctx: task_ctx to free (MAYBE NULL) */ -void aa_free_task_context (struct aa_task_ctx *ctx) +void aa_free_task_ctx (struct aa_task_ctx *ctx) {if (ctx) { -aa_put_profile (ctx->profile);aa_put_profile (ctx->previous);aa_put_profile (ctx->onexec);@@ -56,36 +71,18 @@ void aa_free_task_context(struct aa_task_ctx *ctx) }/** -* aa_dup_task_context - duplicate a task context, incrementing reference counts +* aa_dup_task_ctx - duplicate a task context, incrementing reference counts * @new: a blank task context (NOT NULL) * @old: the task context to copy (NOT NULL) */ -void aa_dup_task_context (struct aa_task_ctx *new,const struct aa_task_ctx *old) +void aa_dup_task_ctx (struct aa_task_ctx *new,const struct aa_task_ctx *old) { *new = *old; -aa_get_profile (new->profile);aa_get_profile (new->previous);aa_get_profile (new->onexec); }/** -* aa_get_task_profile - Get another task's profile -* @task: task to query (NOT NULL) -* -* Returns: counted reference to @task's profile -*/ -struct aa_profile *aa_get_task_profile (struct task_struct *task) -{ -struct aa_profile *p; - -rcu_read_lock (); - p =aa_get_profile (__aa_task_profile (task)); -rcu_read_unlock (); - -return p; -} - -/** * aa_replace_current_profile - replace the current tasks profiles * @profile: new profile (NOT NULL) * @@ -93,36 +90,37 @@ struct aa_profile *aa_get_task_profile(struct task_struct *task)*/ int aa_replace_current_profile (struct aa_profile *profile) { -struct aa_task_ctx *ctx =current_ctx (); +struct aa_profile *old =__aa_current_profile ();struct cred *new; +AA_BUG (!profile); -if (ctx->profile == profile) +if (old == profile)return 0 ;if (current_cred () !=current_real_cred ())return -EBUSY ; new =prepare_creds (); + old =cred_profile (new);if (!new)return -ENOMEM ; - ctx =cred_ctx (new); -if (unconfined (profile) || (ctx->profile->ns != profile->ns)) +if (unconfined (profile) || (old->ns != profile->ns))/* if switching to unconfined or a different profile namespace * clear out context state */ -aa_clear_task_ctx_trans (ctx); +aa_clear_task_ctx (current_task_ctx ());/* -* be careful switching ctx->profile, when racing replacement it -* is possible that ctx->profile->proxy->profile is the reference +* be careful switching cred profile, when racing replacement it +* is possible that the cred profile's->proxy->profile is the reference * keeping @profile valid, so make sure to get its reference before -* dropping the reference on ctx->profile +* dropping the reference on the cred's profile */ aa_get_profile (profile); -aa_put_profile (ctx->profile); - ctx->profile = profile; +aa_put_profile (old); +cred_profile (new) = profile;commit_creds (new);return 0 ;@@ -137,16 +135,12 @@ int aa_replace_current_profile(struct aa_profile *profile)int aa_set_current_onexec (struct aa_profile *profile) {struct aa_task_ctx *ctx; -struct cred *new =prepare_creds (); -if (!new) -return -ENOMEM ; - ctx =cred_ctx (new); + ctx =current_task_ctx ();aa_get_profile (profile);aa_put_profile (ctx->onexec); ctx->onexec = profile; -commit_creds (new);return 0 ; }@@ -162,25 +156,28 @@ int aa_set_current_onexec(struct aa_profile *profile)*/ int aa_set_current_hat (struct aa_profile *profile,u64 token) { -struct aa_task_ctx *ctx; -struct cred *new =prepare_creds (); +struct aa_task_ctx *ctx =current_task_ctx (); +struct cred *new; + +AA_BUG (!profile); + + new =prepare_creds ();if (!new)return -ENOMEM ; -AA_BUG (!profile); - ctx =cred_ctx (new);if (!ctx->previous) {/* transfer refcount */ - ctx->previous = ctx->profile; + ctx->previous =cred_profile (new); ctx->token = token; }else if (ctx->token == token) { -aa_put_profile (ctx->profile); +aa_put_profile (cred_profile (new)); }else {/* previous_profile && ctx->token != token */ abort_creds (new);return -EACCES ; } - ctx->profile =aa_get_newest_profile (profile); + +cred_profile (new) =aa_get_newest_profile (profile);/* clear exec on switching context */ aa_put_profile (ctx->onexec); ctx->onexec =NULL ;@@ -200,28 +197,26 @@ int aa_set_current_hat(struct aa_profile *profile, u64 token)*/ int aa_restore_previous_profile (u64 token) { -struct aa_task_ctx *ctx; -struct cred *new =prepare_creds (); -if (!new) -return -ENOMEM ; +struct aa_task_ctx *ctx =current_task_ctx (); +struct cred *new; - ctx =cred_ctx (new); -if (ctx->token != token) { -abort_creds (new); +if (ctx->token != token)return -EACCES ; - }/* ignore restores when there is no saved profile */ -if (!ctx->previous) { -abort_creds (new); +if (!ctx->previous)return 0 ; - } -aa_put_profile (ctx->profile); - ctx->profile =aa_get_newest_profile (ctx->previous); -AA_BUG (!ctx->profile); + new =prepare_creds (); +if (!new) +return -ENOMEM ; + +aa_put_profile (cred_profile (new)); +cred_profile (new) =aa_get_newest_profile (ctx->previous); +AA_BUG (!cred_profile (new));/* clear exec && prev information when restoring to previous context */ -aa_clear_task_ctx_trans (ctx); +aa_clear_task_ctx (ctx);commit_creds (new); +return 0 ; }security/apparmor/domain.c +14
-14@@ -353,10 +353,10 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)if (bprm->cred_prepared)return 0 ; - ctx =cred_ctx (bprm->cred); + ctx =current_task_ctx ();AA_BUG (!ctx); - - profile =aa_get_newest_profile (ctx->profile); +AA_BUG (!cred_profile (bprm->cred)); + profile =aa_get_newest_profile (cred_profile (bprm->cred));/* * get the namespace from the replacement profile as replacement * can change the namespace @@ -499,14 +499,11 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) bprm->per_clear |=PER_CLEAR_ON_SETID ; x_clear: -aa_put_profile (ctx->profile); -/* transfer new profile reference will be released when ctx is freed */ - ctx->profile = new_profile; +aa_put_profile (profile); +/* transfer new profile reference will be released when cred is freed */ +cred_profile (bprm->cred) = new_profile; new_profile =NULL ; -/* clear out all temporary/transitional state from the context */ -aa_clear_task_ctx_trans (ctx); - audit: error = aa_audit_file(profile, &perms, OP_EXEC, MAY_EXEC, name, new_profile ? new_profile->base.hname : NULL,@@ -544,17 +541,16 @@ int apparmor_bprm_secureexec(struct linux_binprm *bprm)void apparmor_bprm_committing_creds (struct linux_binprm *bprm) {struct aa_profile *profile =__aa_current_profile (); -struct aa_task_ctx *new_ctx =cred_ctx (bprm->cred); +struct aa_profile *new =cred_profile (bprm->cred);/* bail out if unconfined or not changing profile */ -if ((new_ctx->profile == profile) || - (unconfined (new_ctx->profile))) +if (new == profile ||unconfined (new))return ; current->pdeath_signal =0 ;/* reset soft limits and set hard limits for the new profile */ -__aa_transition_rlimits (profile, new_ctx->profile); +__aa_transition_rlimits (profile, new); }/** @@ -564,6 +560,10 @@ void apparmor_bprm_committing_creds(struct linux_binprm *bprm)void apparmor_bprm_committed_creds (struct linux_binprm *bprm) {/* TODO: cleanup signals - ipc mediation */ + +/* clear out all temporary/transitional state from the context */ +aa_clear_task_ctx (current_task_ctx ()); +return ; }@@ -621,7 +621,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)/* released below */ cred =get_current_cred (); - ctx =cred_ctx (cred); + ctx =current_task_ctx (); profile =aa_get_newest_profile (aa_cred_profile (cred)); previous_profile =aa_get_newest_profile (ctx->previous);security/apparmor/include/context.h +26
-37@@ -22,8 +22,9 @@#include "policy.h" #include "policy_ns.h" -#define cred_ctx (X ) ((X)->security) -#define current_ctx () cred_ctx(current_cred()) +#define task_ctx (X ) ((X)->security) +#define current_task_ctx () (task_ctx(current)) +#define cred_profile (X ) ((X)->security)/* struct aa_file_ctx - the AppArmor context the file was opened in * @perms: the permission the file was opened with @@ -58,28 +59,23 @@ static inline void aa_free_file_context(struct aa_file_ctx *ctx) }/** -* struct aa_task_ctx - primary label for confined tasks -* @profile: the current profile (NOT NULL) -* @exec: profile to transition to on next exec (MAYBE NULL) -* @previous: profile the task may return to (MAYBE NULL) +* struct aa_task_ctx - information for current task label change +* @onexec: profile to transition to on next exec (MAY BE NULL) +* @previous: profile the task may return to (MAY BE NULL) * @token: magic value the task must know for returning to @previous_profile * -* Contains the task's current profile (which could change due to -* change_hat). Plus the hat_magic needed during change_hat. -* * TODO: make so a task can be confined by a stack of contexts */ struct aa_task_ctx { -struct aa_profile *profile;struct aa_profile *onexec;struct aa_profile *previous;u64 token; }; -struct aa_task_ctx *aa_alloc_task_context (gfp_t flags); -void aa_free_task_context (struct aa_task_ctx *ctx); -void aa_dup_task_context (struct aa_task_ctx *new, -const struct aa_task_ctx *old); +struct aa_task_ctx *aa_alloc_task_ctx (gfp_t flags); +void aa_free_task_ctx (struct aa_task_ctx *ctx); +void aa_dup_task_ctx (struct aa_task_ctx *new,const struct aa_task_ctx *old); +int aa_replace_current_profile (struct aa_profile *profile);int aa_set_current_onexec (struct aa_profile *profile);int aa_set_current_hat (struct aa_profile *profile,u64 token);@@ -97,10 +93,11 @@ struct aa_profile *aa_get_task_profile(struct task_struct *task);*/ static inline struct aa_profile *aa_cred_profile (const struct cred *cred) { -struct aa_task_ctx *ctx =cred_ctx (cred); +struct aa_profile *profile =cred_profile (cred); -AA_BUG (!ctx || !ctx->profile); -return ctx->profile; +AA_BUG (!profile); + +return profile; }/** @@ -117,17 +114,6 @@ static inline struct aa_profile *__aa_task_profile(struct task_struct *task) }/** -* __aa_task_is_confined - determine if @task has any confinement -* @task: task to check confinement of (NOT NULL) -* -* If @task != current needs to be called in RCU safe critical section -*/ -static inline bool __aa_task_is_confined (struct task_struct *task) -{ -return !unconfined (__aa_task_profile (task)); -} - -/** * __aa_current_profile - find the current tasks confining profile * * Returns: up to date confining profile or the ns unconfined profile (NOT NULL) @@ -150,19 +136,17 @@ static inline struct aa_profile *__aa_current_profile(void)*/ static inline struct aa_profile *aa_current_profile (void ) { -const struct aa_task_ctx *ctx =current_ctx (); -struct aa_profile *profile; +struct aa_profile *profile =__aa_current_profile (); -AA_BUG (!ctx || !ctx->profile); +AA_BUG (!profile); -if (profile_is_stale (ctx->profile)) { - profile =aa_get_newest_profile (ctx->profile); +if (profile_is_stale (profile)) { + profile =aa_get_newest_profile (profile);aa_replace_current_profile (profile);aa_put_profile (profile); - ctx =current_ctx (); } -return ctx->profile; +return profile; }static inline struct aa_ns *aa_get_current_ns (void )@@ -170,12 +154,17 @@ static inline struct aa_ns *aa_get_current_ns(void)return aa_get_ns (__aa_current_profile ()->ns); } + + +/** -* aa_clear_task_ctx_trans - clear transition tracking info from the ctx +* aa_clear_task_ctx - clear transition tracking info from the ctx * @ctx: task context to clear (NOT NULL) */ -static inline void aa_clear_task_ctx_trans (struct aa_task_ctx *ctx) +static inline void aa_clear_task_ctx (struct aa_task_ctx *ctx) { +AA_BUG (!ctx); +aa_put_profile (ctx->previous);aa_put_profile (ctx->onexec); ctx->previous =NULL ;security/apparmor/lsm.c +38
-27@@ -49,12 +49,12 @@ DEFINE_PER_CPU(struct aa_buffers, aa_buffers);*/ /* -* free the associated aa_task_ctx and put its profiles +* put the associated profiles */ static void apparmor_cred_free (struct cred *cred) { -aa_free_task_context (cred_ctx (cred)); -cred_ctx (cred) =NULL ; +aa_put_profile (cred_profile (cred)); +cred_profile (cred) =NULL ; }/* @@ -62,30 +62,19 @@ static void apparmor_cred_free(struct cred *cred)*/ static int apparmor_cred_alloc_blank (struct cred *cred,gfp_t gfp) { -/* freed by apparmor_cred_free */ -struct aa_task_ctx *ctx =aa_alloc_task_context (gfp); - -if (!ctx) -return -ENOMEM ; - -cred_ctx (cred) = ctx; +cred_profile (cred) =NULL ;return 0 ; }/* -* prepare new aa_task_ctx for modification by prepare_cred block +* prepare new cred profile for modification by prepare_cred block */ static int apparmor_cred_prepare (struct cred *new,const struct cred *old,gfp_t gfp) { -/* freed by apparmor_cred_free */ -struct aa_task_ctx *ctx =aa_alloc_task_context (gfp); - -if (!ctx) -return -ENOMEM ; - -aa_dup_task_context (ctx,cred_ctx (old)); -cred_ctx (new) = ctx; +struct aa_profile *tmp =cred_profile (new); +cred_profile (new) =aa_get_newest_profile (cred_profile (old)); +aa_put_profile (tmp);return 0 ; }@@ -94,10 +83,30 @@ static int apparmor_cred_prepare(struct cred *new, const struct cred *old,*/ static void apparmor_cred_transfer (struct cred *new,const struct cred *old) { -const struct aa_task_ctx *old_ctx =cred_ctx (old); -struct aa_task_ctx *new_ctx =cred_ctx (new); +struct aa_profile *tmp =cred_profile (new); +cred_profile (new) =aa_get_newest_profile (cred_profile (old)); +aa_put_profile (tmp); +} -aa_dup_task_context (new_ctx, old_ctx); +static void apparmor_task_free (struct task_struct *task) +{ + +aa_free_task_ctx (task_ctx (task)); +task_ctx (task) =NULL ; +} + +static int apparmor_task_alloc (struct task_struct *task, +unsigned long clone_flags) +{ +struct aa_task_ctx *new =aa_alloc_task_ctx (GFP_KERNEL ); + +if (!new) +return -ENOMEM ; + +aa_dup_task_ctx (new,current_task_ctx ()); +task_ctx (task) = new; + +return 0 ; } static int apparmor_ptrace_access_check(struct task_struct *child,@@ -484,11 +493,11 @@ static int apparmor_getprocattr(struct task_struct *task, char *name,int error = -ENOENT ;/* released below */ const struct cred *cred =get_task_cred (task); -struct aa_task_ctx *ctx =cred_ctx (cred); +struct aa_task_ctx *ctx =current_task_ctx ();struct aa_profile *profile =NULL ;if (strcmp (name,"current" ) ==0 ) - profile =aa_get_newest_profile (ctx->profile); + profile =aa_get_newest_profile (cred_profile (cred));else if (strcmp (name,"prev" ) ==0 && ctx->previous) profile =aa_get_newest_profile (ctx->previous);else if (strcmp (name,"exec" ) ==0 && ctx->onexec)@@ -629,6 +638,8 @@ static struct security_hook_list apparmor_hooks[] = {LSM_HOOK_INIT (bprm_committed_creds, apparmor_bprm_committed_creds),LSM_HOOK_INIT (bprm_secureexec, apparmor_bprm_secureexec), +LSM_HOOK_INIT (task_free, apparmor_task_free), +LSM_HOOK_INIT (task_alloc, apparmor_task_alloc), LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit), };@@ -871,12 +882,12 @@ static int __init set_init_ctx(void)struct cred *cred = (struct cred *)current->real_cred;struct aa_task_ctx *ctx; - ctx =aa_alloc_task_context (GFP_KERNEL ); + ctx =aa_alloc_task_ctx (GFP_KERNEL );if (!ctx)return -ENOMEM ; - ctx->profile =aa_get_profile (root_ns->unconfined); -cred_ctx (cred) = ctx; +cred_profile (cred) =aa_get_profile (root_ns->unconfined); +task_ctx (current) = ctx;return 0 ; }security/apparmor/policy.c +0
-2@@ -827,8 +827,9 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname,* @udata: serialized data stream (NOT NULL) * * unpack and replace a profile on the profile list and uses of that profile -* by any aa_task_ctx. If the profile does not exist on the profile list -* it is added.
Quoted 8 lines
Quoted 8 lines
security/apparmor/policy.c +3
-0+* by any task creds via invalidating the old version of the profile, which +* tasks will notice to update their own cred. If the profile does not exist +* on the profile list it is added. * * Returns: size of data consumed else error code on failure. */ Signature · 1 line
2.9.3
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 apparmor: move task specific domain change info out of cred
Quoted 19 lines · John Johansen
Quoted 18 lines · Serge E. Hallyn
Quoted 8 lines · John Johansen
Now that
security_task_alloc()hook and "struct task_struct"-Quoted 1 line
security
field are revived, move task specific domain change information for
change_onexec(equiv of setexeccon) andchange_hatout of the cred
into a context off of thetask_struct.Quoted 5 lines
This cleans up apparmor's use of the cred structure so that it only
carries the reference to current mediation.Signed-off-by John Johansen <[email protected]>Thanks, John, that helps in compelling a review of the previous patch :)
Quoted 7 lines
Quoted 3 lines
So the
task_struct->securitypointer is only to store requested transition profiles right?correct, well and support information for the transition like the random
magic token forchange_hat.
Is it really a net win for AA? You save some space in the per-cred structure (but that was already shared by most tasks, particularly any that are not using change_onexec/change_hat), but won't you end up using more space overall since you will now be allocating space for (onexec, previous, token) for every task, even ones that don't use those operations?
Quoted 692 lines
Quoted 692 lines
Quoted 692 lines
---
?security/apparmor/context.c?????????| 129 +++++++++++++++++-----
--------------?security/apparmor/domain.c??????????|??28 ++++---- ?security/apparmor/include/context.h |??63 ++++++++---------- ?security/apparmor/lsm.c?????????????|??65 ++++++++++-------- ?security/apparmor/policy.c??????????|???5 +-?5 files changed, 143 insertions(+), 147 deletions(-)
security/apparmor/context.c +0
-0@@ -13,11 +13,9 @@? * License.
? *
? *
- * AppArmor sets confinement on every task, via the theaa_task_ctxand
- * the aa_task_ctx.profile, both of which are required and are not allowed
- * to be NULL.??Theaa_task_ctxis not reference counted and is unique
- * to each cred (which is reference count).??The profile pointed to by
- * thetask_ctxis reference counted.
+ * AppArmor sets confinement on every task, via thecred_profile()which
+ * is required and is not allowed to be NULL.??Thecred_profileis
+ * reference counted.
? *
? * TODO
? * If a task useschange_hatit currently does not return to the oldsecurity/apparmor/context.c +0
-0@@ -29,25 +27,42 @@?#include "
include/context.h"
?#include "include/policy.h"
?security/apparmor/context.c +18
-0+ +/** +* aa_get_task_profile - Get another task's profile +* @task: task to query??(NOT NULL) +* +* Returns: counted reference to @task's profile +*/ +struct aa_profile *aa_get_task_profile (struct task_struct *task) +{ +struct aa_profile *p; + +rcu_read_lock (); + p =aa_get_profile (__aa_task_profile (task)); +rcu_read_unlock (); + +return p; +} +?/**
- *aa_alloc_task_context- allocate a newtask_ctx
+ *aa_alloc_task_ctx- allocate a newtask_ctx? * @flags: gfp flags for allocation
? *
? * Returns: allocated buffer or NULL on failure ? */security/apparmor/context.c +1
-1-struct aa_task_ctx *aa_alloc_task_context (gfp_t flags) +struct aa_task_ctx *aa_alloc_task_ctx (gfp_t flags)?{
? returnkzalloc(sizeof(struct aa_task_ctx), flags);
?}
?
?/**
- *aa_free_task_context- free atask_ctx
+ *aa_free_task_ctx- free atask_ctx
? * @ctx:task_ctxto free (MAYBE NULL)
? */security/apparmor/context.c +1
-1-void aa_free_task_context (struct aa_task_ctx *ctx) +void aa_free_task_ctx (struct aa_task_ctx *ctx)?{
? if (ctx) {security/apparmor/context.c +0
-1-aa_put_profile (ctx->profile);?
aa_put_profile(ctx->previous);
?aa_put_profile(ctx->onexec);
?security/apparmor/context.c +0
-0@@ -56,36 +71,18 @@ void aa_free_task_context(struct aa_task_ctx *ctx) ?}?
?/**
- *aa_dup_task_context- duplicate a task context, incrementing reference counts
+ *aa_dup_task_ctx- duplicate a task context, incrementing reference counts
? * @new: a blank task context??????(NOT NULL)
? * @old: the task context to copy??(NOT NULL)
? */
-voidaa_dup_task_context(struct aa_task_ctx *new, const struct aa_task_ctx *old)
+voidaa_dup_task_ctx(struct aa_task_ctx *new, const struct aa_task_ctx *old)
?{
? *new = *old;security/apparmor/context.c +0
-1-aa_get_profile (new->profile);?
aa_get_profile(new->previous);
?aa_get_profile(new->onexec);
?}
?
?/**
- *aa_get_task_profile- Get another task's profile
- * @task: task to query??(NOT NULL)
- *
- * Returns: counted reference to @task's profile
- */security/apparmor/context.c +0
-12-struct aa_profile *aa_get_task_profile (struct task_struct *task) -{ -struct aa_profile *p; - -rcu_read_lock (); - p =aa_get_profile (__aa_task_profile (task)); -rcu_read_unlock (); - -return p; -} - -/** ? *
aa_replace_current_profile- replace the current tasks profiles
? * @profile: new profile??(NOT NULL)
? *security/apparmor/context.c +0
-0@@ -93,36 +90,37 @@ struct aa_profile *aa_get_task_profile(struct task_struct *task)? */
?intaa_replace_current_profile(struct aa_profile *profile)?{security/apparmor/context.c +1
-1-struct aa_task_ctx *ctx =current_ctx (); +struct aa_profile *old =__aa_current_profile ();? struct cred *new;
+
?AA_BUG(!profile);
?security/apparmor/context.c +1
-1-if (ctx->profile == profile) +if (old == profile)? return 0;
?
? if (current_cred()!=current_real_cred())
? return-EBUSY;
?
? new??=prepare_creds();security/apparmor/context.c +1
-0+ old =cred_profile (new);? if (!new)
? return-ENOMEM;
?security/apparmor/context.c +0
-2- ctx =cred_ctx (new); - if (unconfined(profile) || (ctx->profile->ns != profile-Quoted 1 line
ns))
security/apparmor/context.c +1
-0+if (unconfined (profile) || (old->ns != profile->ns))? /* if switching to unconfined or a different
profile namespace
? ?* clear out context state
? ?*/security/apparmor/context.c +1
-1-aa_clear_task_ctx_trans (ctx); +aa_clear_task_ctx (current_task_ctx ());?
? /*security/apparmor/context.c +0
-1- ?* be careful switching ctx->profile, when racingreplacement it
security/apparmor/context.c +0
-1- ?* is possible that ctx->profile->proxy->profile is thereference
security/apparmor/context.c +1
-0+ ?* be careful switching cred profile, when racingreplacement it
security/apparmor/context.c +1
-0+ ?* is possible that the cred profile's->proxy->profileis the reference
? ?* keeping @profile valid, so make sure to get its
reference beforesecurity/apparmor/context.c +1
-1- ?* dropping the reference on ctx->profile + ?* dropping the reference on the cred's profile? ?*/
?aa_get_profile(profile);security/apparmor/context.c +2
-2-aa_put_profile (ctx->profile); - ctx->profile = profile; +aa_put_profile (old); +cred_profile (new) = profile;?
?commit_creds(new);
? return 0;security/apparmor/context.c +0
-3@@ -137,16 +135,12 @@ int aa_replace_current_profile(struct aa_profile *profile) ?int aa_set_current_onexec(struct aa_profile *profile) ?{ ? struct aa_task_ctx *ctx; -struct cred *new =prepare_creds (); -if (!new) -return -ENOMEM ;?
security/apparmor/context.c +1
-1- ctx =cred_ctx (new); + ctx =current_task_ctx ();?
aa_get_profile(profile);
?aa_put_profile(ctx->onexec);
?ctx->onexec= profile;
?security/apparmor/context.c +0
-1-commit_creds (new);? return 0;
?}
?security/apparmor/context.c +0
-0@@ -162,25 +156,28 @@ int aa_set_current_onexec(struct aa_profile *profile)? */
?intaa_set_current_hat(struct aa_profile *profile, u64 token)?{security/apparmor/context.c +6
-2-struct aa_task_ctx *ctx; -struct cred *new =prepare_creds (); +struct aa_task_ctx *ctx =current_task_ctx (); +struct cred *new; + +AA_BUG (!profile); + + new =prepare_creds ();? if (!new)
? return-ENOMEM;security/apparmor/context.c +0
-1-AA_BUG (!profile);?
security/apparmor/context.c +0
-1- ctx =cred_ctx (new);? if (!ctx->previous) {
? /* transfer refcount */security/apparmor/context.c +1
-1- ctx->previous = ctx->profile; + ctx->previous =cred_profile (new);?
ctx->token= token;
? } else if (ctx->token== token) {security/apparmor/context.c +1
-1-aa_put_profile (ctx->profile); +aa_put_profile (cred_profile (new));? } else {
? /*previous_profile&&ctx->token!= token */
?abort_creds(new);
? return-EACCES;
? }security/apparmor/context.c +2
-1- ctx->profile =aa_get_newest_profile (profile); + +cred_profile (new) =aa_get_newest_profile (profile);? /* clear exec on switching context */
?aa_put_profile(ctx->onexec);
?ctx->onexec= NULL;security/apparmor/context.c +0
-0@@ -200,28 +197,26 @@ int aa_set_current_hat(struct aa_profile *profile, u64 token)? */
?intaa_restore_previous_profile(u64 token)
?{security/apparmor/context.c +2
-4-struct aa_task_ctx *ctx; -struct cred *new =prepare_creds (); -if (!new) -return -ENOMEM ; +struct aa_task_ctx *ctx =current_task_ctx (); +struct cred *new;?
security/apparmor/context.c +1
-3- ctx =cred_ctx (new); -if (ctx->token != token) { -abort_creds (new); +if (ctx->token != token)? return
-EACCES;security/apparmor/context.c +0
-1- }? /* ignore restores when there is no saved profile */
security/apparmor/context.c +1
-2-if (!ctx->previous) { -abort_creds (new); +if (!ctx->previous)? return 0;
security/apparmor/context.c +0
-1- }?
security/apparmor/context.c +6
-3-aa_put_profile (ctx->profile); - ctx->profile =aa_get_newest_profile (ctx->previous); -AA_BUG (!ctx->profile); + new =prepare_creds (); +if (!new) +return -ENOMEM ; + +aa_put_profile (cred_profile (new)); + cred_profile(new) = aa_get_newest_profile(ctx-Quoted 1 line
previous);
security/apparmor/context.c +1
-0+AA_BUG (!cred_profile (new));? /* clear exec && prev information when restoring to
previous context */security/apparmor/context.c +1
-1-aa_clear_task_ctx_trans (ctx); +aa_clear_task_ctx (ctx);?
?commit_creds(new);
+
? return 0;
?}security/apparmor/domain.c +0
-0@@ -353,10 +353,10 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) ? if (bprm->cred_prepared) ? return 0;?
security/apparmor/domain.c +1
-1- ctx =cred_ctx (bprm->cred); + ctx =current_task_ctx ();?
AA_BUG(!ctx);security/apparmor/domain.c +2
-2- - profile =aa_get_newest_profile (ctx->profile); +AA_BUG (!cred_profile (bprm->cred)); + profile = aa_get_newest_profile(cred_profile(bprm-Quoted 1 line
cred));
? /*
? ?* get the namespace from the replacement profile as
replacement
? ?* can change the namespacesecurity/apparmor/domain.c +0
-0@@ -499,14 +499,11 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) ? bprm->per_clear |= PER_CLEAR_ON_SETID;?
?x_clear:security/apparmor/domain.c +0
-2-aa_put_profile (ctx->profile); -/* transfer new profile reference will be released when ctx is freed */
security/apparmor/domain.c +2
-1- ctx->profile = new_profile; +aa_put_profile (profile); +/* transfer new profile reference will be released when cred is freed */
security/apparmor/domain.c +1
-0+cred_profile (bprm->cred) = new_profile;?
new_profile= NULL;
?security/apparmor/domain.c +0
-1-/* clear out all temporary/transitional state from the context */
security/apparmor/domain.c +0
-2-aa_clear_task_ctx_trans (ctx); -?audit:
? error = aa_audit_file(profile, &perms,OP_EXEC,MAY_EXEC, name,
? ??????new_profile ? new_profile-Quoted 1 line
base.hname : NULL,
security/apparmor/domain.c +1
-1@@ -544,17 +541,16 @@ int apparmor_bprm_secureexec(struct linux_binprm *bprm) ?void apparmor_bprm_committing_creds(struct linux_binprm *bprm) ?{ ? struct aa_profile *profile = __aa_current_profile(); -struct aa_task_ctx *new_ctx =cred_ctx (bprm->cred); +struct aa_profile *new =cred_profile (bprm->cred);?
? /* bail out if unconfined or not changing profile */security/apparmor/domain.c +1
-2- if ((new_ctx->profile == profile) || - ????(unconfined(new_ctx->profile))) +if (new == profile ||unconfined (new))? return;
?
?current->pdeath_signal= 0;
?
? /* reset soft limits and set hard limits for the new
profile */security/apparmor/domain.c +1
-1-__aa_transition_rlimits (profile, new_ctx->profile); +__aa_transition_rlimits (profile, new);?}
?
?/**security/apparmor/domain.c +0
-0@@ -564,6 +560,10 @@ void apparmor_bprm_committing_creds(struct linux_binprm *bprm) ?void apparmor_bprm_committed_creds(struct linux_binprm *bprm) ?{? /* TODO: cleanup signals - ipc mediation */
security/apparmor/domain.c +2
-0+ +/* clear out all temporary/transitional state from the context */
security/apparmor/domain.c +2
-0+aa_clear_task_ctx (current_task_ctx ()); +? return;
?}
?security/apparmor/domain.c +0
-0@@ -621,7 +621,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)?
? /* released below */
? cred =get_current_cred();security/apparmor/domain.c +1
-1- ctx =cred_ctx (cred); + ctx =current_task_ctx ();? profile = aa_get_newest_profile(aa_cred_profile(cred));
?previous_profile=aa_get_newest_profile(ctx->previous);
?security/apparmor/include/context.h +0
-0@@ -22,8 +22,9 @@?#include "
policy.h"
?#include "policy_ns.h"
?security/apparmor/include/context.h +3
-2-#define cred_ctx (X ) ((X)->security) -#define current_ctx () cred_ctx(current_cred()) +#define task_ctx (X ) ((X)->security) +#define current_task_ctx () (task_ctx(current)) +#define cred_profile (X ) ((X)->security)?
?/* structaa_file_ctx- the AppArmor context the file was opened in
? * @perms: the permission the file was opened withsecurity/apparmor/include/context.h +0
-0@@ -58,28 +59,23 @@ static inline void aa_free_file_context(struct aa_file_ctx *ctx) ?}?
?/**
- * structaa_task_ctx- primary label for confined tasks
- * @profile: the current profile???(NOT NULL)
- * @exec: profile to transition to on next exec??(MAYBE NULL)
- * @previous: profile the task may return to?????(MAYBE NULL)
+ * structaa_task_ctx- information for current task label change
+ * @onexec: profile to transition to on next exec??(MAY BE NULL)
+ * @previous: profile the task may return to?????(MAY BE NULL) ? * @token: magic value the task must know for returning to @previous_profile
? *
- * Contains the task's current profile (which could change due to
- * change_hat).??Plus thehat_magicneeded duringchange_hat.
- *
? * TODO: make so a task can be confined by a stack of contexts ? */
?structaa_task_ctx{security/apparmor/include/context.h +0
-1-struct aa_profile *profile;? struct
aa_profile*onexec;
? structaa_profile*previous;
? u64 token;
?};
?security/apparmor/include/context.h +3
-4-struct aa_task_ctx *aa_alloc_task_context (gfp_t flags); -void aa_free_task_context (struct aa_task_ctx *ctx); -void aa_dup_task_context (struct aa_task_ctx *new, - ?const struct aa_task_ctx *old); +struct aa_task_ctx *aa_alloc_task_ctx (gfp_t flags); +void aa_free_task_ctx (struct aa_task_ctx *ctx); +void aa_dup_task_ctx(struct aa_task_ctx *new, const struct
aa_task_ctx*old);
+
?intaa_replace_current_profile(struct aa_profile *profile); ?intaa_set_current_onexec(struct aa_profile *profile); ?intaa_set_current_hat(struct aa_profile *profile, u64 token);security/apparmor/include/context.h +0
-0@@ -97,10 +93,11 @@ struct aa_profile *aa_get_task_profile(struct task_struct *task);? */
?static inline structaa_profile*aa_cred_profile(const struct cred *cred)
?{security/apparmor/include/context.h +1
-1-struct aa_task_ctx *ctx =cred_ctx (cred); +struct aa_profile *profile =cred_profile (cred);?
security/apparmor/include/context.h +3
-2-AA_BUG (!ctx || !ctx->profile); -return ctx->profile; +AA_BUG (!profile); + +return profile;?}
?
?/**security/apparmor/include/context.h +0
-0@@ -117,17 +114,6 @@ static inline struct aa_profile *__aa_task_profile(struct task_struct *task) ?}?
?/**
- *__aa_task_is_confined- determine if @task has any confinement
- * @task: task to check confinement of??(NOT NULL)
- *
- * If @task != current needs to be called in RCU safe critical section
- */
-static inline bool__aa_task_is_confined(struct task_struct *task)security/apparmor/include/context.h +0
-5-{ -return !unconfined (__aa_task_profile (task)); -} - -/** ? *
__aa_current_profile- find the current tasks confining profile
? *
? * Returns: up to date confining profile or the ns unconfined profile (NOT NULL)security/apparmor/include/context.h +0
-0@@ -150,19 +136,17 @@ static inline struct aa_profile *__aa_current_profile (void)? */
?static inline structaa_profile*aa_current_profile(void)?{security/apparmor/include/context.h +1
-2-const struct aa_task_ctx *ctx =current_ctx (); -struct aa_profile *profile; +struct aa_profile *profile =__aa_current_profile ();?
security/apparmor/include/context.h +1
-1-AA_BUG (!ctx || !ctx->profile); +AA_BUG (!profile);?
security/apparmor/include/context.h +2
-2-if (profile_is_stale (ctx->profile)) { - profile =aa_get_newest_profile (ctx->profile); +if (profile_is_stale (profile)) { + profile =aa_get_newest_profile (profile);?
aa_replace_current_profile(profile);
?aa_put_profile(profile);security/apparmor/include/context.h +0
-1- ctx =current_ctx ();? }
?security/apparmor/include/context.h +1
-1-return ctx->profile; +return profile;?}
?
?static inline structaa_ns*aa_get_current_ns(void)security/apparmor/include/context.h +0
-0@@ -170,12 +154,17 @@ static inline struct aa_ns *aa_get_current_ns(void) ? return aa_get_ns(__aa_current_profile()->ns); ?}?
security/apparmor/include/context.h +3
-0+ + +?/**
- *aa_clear_task_ctx_trans- clear transition tracking info from the ctx
+ *aa_clear_task_ctx- clear transition tracking info from the ctx
? * @ctx: task context to clear (NOT NULL)
? */
-static inline voidaa_clear_task_ctx_trans(struct aa_task_ctx *ctx)
+static inline voidaa_clear_task_ctx(struct aa_task_ctx *ctx)?{security/apparmor/include/context.h +2
-0+AA_BUG (!ctx); +?
aa_put_profile(ctx->previous);
?aa_put_profile(ctx->onexec);
?ctx->previous= NULL;security/apparmor/lsm.c +0
-0@@ -49,12 +49,12 @@ DEFINE_PER_CPU(struct aa_buffers, aa_buffers);? */
?
?/*
- * free the associatedaa_task_ctxand put its profiles
+ * put the associated profiles
? */
?static voidapparmor_cred_free(struct cred *cred)?{security/apparmor/lsm.c +2
-2-aa_free_task_context (cred_ctx (cred)); -cred_ctx (cred) =NULL ; +aa_put_profile (cred_profile (cred)); +cred_profile (cred) =NULL ;?}
?
?/*security/apparmor/lsm.c +0
-0@@ -62,30 +62,19 @@ static void apparmor_cred_free(struct cred *cred)? */
?static intapparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp)
?{security/apparmor/lsm.c +1
-7-/* freed by apparmor_cred_free */ -struct aa_task_ctx *ctx =aa_alloc_task_context (gfp); - -if (!ctx) -return -ENOMEM ; - -cred_ctx (cred) = ctx; +cred_profile (cred) =NULL ;? return 0;
?}
?
?/*
- * prepare newaa_task_ctxfor modification byprepare_credblock
+ * prepare new cred profile for modification byprepare_credblock
? */
?static int apparmor_cred_prepare(struct cred *new, const struct cred *old,
? ?gfp_t gfp)
?{security/apparmor/lsm.c +2
-8-/* freed by apparmor_cred_free */ -struct aa_task_ctx *ctx =aa_alloc_task_context (gfp); - -if (!ctx) -return -ENOMEM ; - -aa_dup_task_context (ctx,cred_ctx (old)); -cred_ctx (new) = ctx; +struct aa_profile *tmp =cred_profile (new); + cred_profile(new) =aa_get_newest_profile(cred_profile(old));
security/apparmor/lsm.c +1
-0+aa_put_profile (tmp);? return 0;
?}
?security/apparmor/lsm.c +0
-0@@ -94,10 +83,30 @@ static int apparmor_cred_prepare(struct cred *new, const struct cred *old,? */
?static voidapparmor_cred_transfer(struct cred *new, const struct cred *old)
?{security/apparmor/lsm.c +2
-2-const struct aa_task_ctx *old_ctx =cred_ctx (old); -struct aa_task_ctx *new_ctx =cred_ctx (new); +struct aa_profile *tmp =cred_profile (new); + cred_profile(new) =aa_get_newest_profile(cred_profile(old));
security/apparmor/lsm.c +2
-0+aa_put_profile (tmp); +}?
security/apparmor/lsm.c +19
-1-aa_dup_task_context (new_ctx, old_ctx); +static void apparmor_task_free (struct task_struct *task) +{ + +aa_free_task_ctx (task_ctx (task)); +task_ctx (task) =NULL ; +} + +static int apparmor_task_alloc (struct task_struct *task, + ???????unsigned long clone_flags) +{ +struct aa_task_ctx *new =aa_alloc_task_ctx (GFP_KERNEL ); + +if (!new) +return -ENOMEM ; + +aa_dup_task_ctx (new,current_task_ctx ()); +task_ctx (task) = new; + +return 0 ;?}
?
?static int apparmor_ptrace_access_check(structtask_struct*child,security/apparmor/lsm.c +0
-0@@ -484,11 +493,11 @@ static int apparmor_getprocattr(struct task_struct *task, char *name, ? int error = -ENOENT;? /* released below */
? const struct cred *cred =get_task_cred(task);security/apparmor/lsm.c +1
-1-struct aa_task_ctx *ctx =cred_ctx (cred); +struct aa_task_ctx *ctx =current_task_ctx ();? struct
aa_profile*profile = NULL;
?
? if (strcmp(name, "current")== 0)security/apparmor/lsm.c +1
-1- profile =aa_get_newest_profile (ctx->profile); + profile =aa_get_newest_profile(cred_profile(cred));
? else if (strcmp(name, "prev")== 0??&&ctx->previous)
? profile =aa_get_newest_profile(ctx->previous);
? else if (strcmp(name, "exec")== 0 &&ctx->onexec)security/apparmor/lsm.c +0
-0@@ -629,6 +638,8 @@ static struct security_hook_list apparmor_hooks[] = { ? LSM_HOOK_INIT(bprm_committed_creds, apparmor_bprm_committed_creds), ? LSM_HOOK_INIT(bprm_secureexec, apparmor_bprm_secureexec),?
security/apparmor/lsm.c +2
-0+LSM_HOOK_INIT (task_free, apparmor_task_free), + LSM_HOOK_INIT(task_alloc, apparmor_task_alloc),?
LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit),
?};
?security/apparmor/lsm.c +0
-0@@ -871,12 +882,12 @@ static int __init set_init_ctx(void) ? struct cred *cred = (struct cred *)current->real_cred; ? struct aa_task_ctx *ctx;?
security/apparmor/lsm.c +1
-1- ctx =aa_alloc_task_context (GFP_KERNEL ); + ctx =aa_alloc_task_ctx (GFP_KERNEL );? if (!ctx)
? return-ENOMEM;
?security/apparmor/lsm.c +1
-2- ctx->profile =aa_get_profile (root_ns->unconfined); -cred_ctx (cred) = ctx; + cred_profile(cred) = aa_get_profile(root_ns-Quoted 1 line
unconfined);
security/apparmor/lsm.c +1
-0+task_ctx (current) = ctx;?
? return 0;
?}security/apparmor/policy.c +0
-0@@ -827,8 +827,9 @@ static int __lookup_replace(struct aa_ns *ns,const char *hname, ? * @udata: serialized data stream??(NOT NULL)? *
? * unpack and replace a profile on the profile list and uses of that profile
- * by any aa_task_ctx.??If the profile does not exist on the profile list
- * it is added.
+ * by any task creds via invalidating the old version of the profile, which
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
+ * tasks will notice to update their own cred.??If the profile does not exist
+ * on the profile list it is added.
? *
? * Returns: size of data consumed else error code on failure. ? */
--?
2.9.3
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
John Johansen
maintainerPATCH 1/1 apparmor: move task specific domain change info out of cred
Quoted 28 lines · Stephen Smalley
Quoted 19 lines · John Johansen
Quoted 18 lines · Serge E. Hallyn
Quoted 8 lines · John Johansen
Now that
security_task_alloc()hook and "struct task_struct"-Quoted 1 line
security
field are revived, move task specific domain change information for
change_onexec(equiv of setexeccon) andchange_hatout of the cred
into a context off of thetask_struct.Quoted 5 lines
This cleans up apparmor's use of the cred structure so that it only
carries the reference to current mediation.Signed-off-by John Johansen <[email protected]>Thanks, John, that helps in compelling a review of the previous patch :)
Quoted 7 lines
Quoted 3 lines
So the
task_struct->securitypointer is only to store requested transition profiles right?correct, well and support information for the transition like the random
magic token forchange_hat.
Quoted 7 lines
Is it really a net win for AA? You save some space in the per-cred structure (but that was already shared by most tasks, particularly any that are not using change_onexec/change_hat), but won't you end up using more space overall since you will now be allocating space for (onexec, previous, token) for every task, even ones that don't use those operations?
atm its more of a wash. Its a win for cred related operations but allocating per task, instead of per cred does increase memory usage. However this is just a first pass that is a fairly direct mapping of onto the current code paths. There is no reason the task->security struct couldn't be shared by tasks, or even more likely not allocated at all except by those tasks using change_onexec/change_hat.
I just haven't had a chance to work on the improvements, long term it will be a win for AA.
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Serge E. Hallyn
maintainerPATCH 1/1 LSM: Revive security_task_alloc() hook and per "struct task_struct" security blob.
In reply to Tetsuo HandaQuoted 27 lines · Tetsuo Handa
We switched from "struct task_struct"->security to "struct cred"->security in Linux 2.6.29. But not all LSM modules were happy with that change. TOMOYO LSM module is an example which want to use per "struct
task_struct" security blob, for TOMOYO's security context is defined based on "structtask_struct" rather than "struct cred". AppArmor LSM module is another example which want to use it, for AppArmor is currently abusing the cred a little bit to store thechange_hatand setexeccon info. Althoughsecurity_task_free()hook was revived in Linux 3.4 because Yama LSM module wanted to release per "structtask_struct" security blob,security_task_alloc()hook and "struct task_struct"->security field were not revived. Nowadays, we are getting proposals of lightweight LSM modules which want to use per "structtask_struct" security blob. PTAGS LSM module and CaitSith LSM module which are currently under proposal for inclusion also want to use it. Therefore, it will be time to revivesecurity_task_alloc()hook and "struct task_struct"->security field.We are already allowing multiple concurrent LSM modules (up to one fully armored module which uses "struct cred"->security field or exclusive hooks like
security_xfrm_state_pol_flow_match(), plus unlimited number of lightweight modules which do not use "struct cred"->security nor exclusive hooks) as long as they are built into the kernel. But this patch does not implement variable length "struct task_struct"->security field which will become needed when multiple LSM modules want to use "struct task_struct"-> security field. Although it won't be difficult to implement variable length "struct task_struct"->security field, let's think about it after we merged this patch.
Quoted 10 lines
Signed-off-by Tetsuo Handa <[email protected]>Acked-by John Johansen <[email protected]>Tested-by Djalal Harouni <[email protected]>Cc Paul Moore <[email protected]>Cc Stephen Smalley <[email protected]>Cc Eric Paris <[email protected]>Cc Casey Schaufler <[email protected]>Cc Kees Cook <[email protected]>Cc James Morris <[email protected]>Cc Serge E. Hallyn <[email protected]>
nit below,
Quoted 40 lines
Cc Jos? Bollo <[email protected]>--- include/linux/init_task.h | 7 +++++++ include/linux/lsm_hooks.h | 9 ++++++++- include/linux/sched.h | 4 ++++ include/linux/security.h | 7 +++++++ kernel/fork.c | 7 ++++++- security/security.c | 6 ++++++ 6 files changed, 38 insertions(+), 2 deletions(-)include/linux/init_task.h +7
-0@@ -210,6 +210,12 @@# define INIT_TASK_TI (tsk)#endif +#ifdef CONFIG_SECURITY +#define INIT_TASK_SECURITY .security = NULL, +#else +#define INIT_TASK_SECURITY +#endif +/* * INIT_TASK is used to set up the first task table, touch at * your own risk!. Base=0, limit=0x1fffff (=2MB) @@ -288,6 +294,7 @@ INIT_VTIME(tsk) \ INIT_NUMA_BALANCING(tsk) \ INIT_KASAN(tsk) \ + INIT_TASK_SECURITY \ }include/linux/lsm_hooks.h +0
-0
include/linux/lsm_hooks.h line 537
Quoted 5 lines
include/linux/lsm_hooks.h +2
-0@@ -533,8 +533,13 @@* manual page for definitions of the @clone_flags. * @clone_flags contains the flags indicating what should be shared. * Return 0 if permission is granted. +* @task_alloc: +* @task task being allocated.
Note that here you have spaces not tabs
Quoted 118 lines
include/linux/lsm_hooks.h +6
-1+* @clone_flags contains the flags indicating what should be shared. +* Handle allocation of task-related resources. +* Returns a zero on success, negative values on failure. * @task_free: -* @task task being freed +* @task task about to be freed. * Handle release of task-related resources. (Note that this can be called * from interrupt context.) * @cred_alloc_blank: @@ -1482,6 +1487,7 @@int (*file_open)(struct file *file,const struct cred *cred);int (*task_create)(unsigned long clone_flags); +int (*task_alloc)(struct task_struct *task,unsigned long clone_flags);void (*task_free)(struct task_struct *task);int (*cred_alloc_blank)(struct cred *cred,gfp_t gfp);void (*cred_free)(struct cred *cred);@@ -1748,6 +1754,7 @@ struct security_hook_heads {struct list_head file_receive;struct list_head file_open;struct list_head task_create; +struct list_head task_alloc;struct list_head task_free;struct list_head cred_alloc_blank;struct list_head cred_free;include/linux/sched.h +4
-0@@ -1038,6 +1038,10 @@ struct task_struct {/* A live task holds one reference: */ atomic_t stack_refcount;#endif +#ifdef CONFIG_SECURITY +/* Used by LSM modules for access restriction: */ +void *security; +#endif /* CPU-specific state of this task: */ struct thread_struct thread;include/linux/security.h +7
-0@@ -308,6 +308,7 @@ int security_file_send_sigiotask(struct task_struct *tsk,int security_file_receive (struct file *file);int security_file_open (struct file *file,const struct cred *cred);int security_task_create (unsigned long clone_flags); +int security_task_alloc (struct task_struct *task,unsigned long clone_flags);void security_task_free (struct task_struct *task);int security_cred_alloc_blank (struct cred *cred,gfp_t gfp);void security_cred_free (struct cred *cred);@@ -861,6 +862,12 @@ static inline int security_task_create(unsigned long clone_flags)return 0 ; } +static inline int security_task_alloc (struct task_struct *task, +unsigned long clone_flags) +{ +return 0 ; +} +static inline void security_task_free (struct task_struct *task) { }kernel/fork.c +6
-1@@ -1679,9 +1679,12 @@ static __latent_entropy struct task_struct *copy_process( goto bad_fork_cleanup_perf;/* copy all the process information */ shm_init_task (p); - retval =copy_semundo (clone_flags, p); + retval =security_task_alloc (p, clone_flags);if (retval) goto bad_fork_cleanup_audit; + retval =copy_semundo (clone_flags, p); +if (retval) + goto bad_fork_cleanup_security; retval =copy_files (clone_flags, p);if (retval) goto bad_fork_cleanup_semundo;@@ -1903,6 +1906,8 @@ static __latent_entropy struct task_struct *copy_process(exit_files (p);/* blocking */ bad_fork_cleanup_semundo:exit_sem (p); +bad_fork_cleanup_security: +security_task_free (p); bad_fork_cleanup_audit:audit_free (p); bad_fork_cleanup_perf:security/security.c +6
-0@@ -930,6 +930,11 @@ int security_task_create(unsigned long clone_flags)return call_int_hook (task_create,0 , clone_flags); } +int security_task_alloc (struct task_struct *task,unsigned long clone_flags) +{ +return call_int_hook (task_alloc,0 , task, clone_flags); +} +void security_task_free (struct task_struct *task) {call_void_hook (task_free, task);@@ -1770,6 +1775,7 @@ struct security_hook_heads security_hook_heads __lsm_ro_after_init = { .file_receive = LIST_HEAD_INIT(security_hook_heads.file_receive), .file_open = LIST_HEAD_INIT(security_hook_heads.file_open), .task_create = LIST_HEAD_INIT(security_hook_heads.task_create), + .task_alloc = LIST_HEAD_INIT(security_hook_heads.task_alloc), .task_free = LIST_HEAD_INIT(security_hook_heads.task_free), .cred_alloc_blank = LIST_HEAD_INIT(security_hook_heads.cred_alloc_blank),Signature · 1 line
1.8.3.1
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 LSM: Revive security_task_alloc() hook and per "struct task_struct" security blob.
Quoted 9 lines · Serge E. Hallyn
include/linux/lsm_hooks.h line 537
Quoted 6 lines
include/linux/lsm_hooks.h +2
-0@@ -533,8 +533,13 @@* manual page for definitions of the @clone_flags. * @clone_flags contains the flags indicating what should be shared. * Return 0 if permission is granted. +* @task_alloc: +* @task task being allocated. Note that here you have spaces not tabs
Oh, thanks.
I think this patch got enough Acked-by:s.
Serge Hallyn <[email protected]>
Casey Schaufler <[email protected]>
James, should I repost with spaces fixed?
Also, I appreciate if you can update #next to 4.11-rc2 because 4.11-rc1 is not suitable for testing due to memory corruption bug.
http://lkml.kernel.org/r/201703090625.v296PNFI070895 at www262.sakura.ne.jp --
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 LSM: Revive security_task_alloc() hook and per "struct task_struct" security blob.
In reply to Tetsuo HandaQuoted 27 lines · Tetsuo Handa
We switched from "struct task_struct"->security to "struct cred"->security in Linux 2.6.29. But not all LSM modules were happy with that change. TOMOYO LSM module is an example which want to use per "struct
task_struct" security blob, for TOMOYO's security context is defined based on "structtask_struct" rather than "struct cred". AppArmor LSM module is another example which want to use it, for AppArmor is currently abusing the cred a little bit to store thechange_hatand setexeccon info. Althoughsecurity_task_free()hook was revived in Linux 3.4 because Yama LSM module wanted to release per "structtask_struct" security blob,security_task_alloc()hook and "struct task_struct"->security field were not revived. Nowadays, we are getting proposals of lightweight LSM modules which want to use per "structtask_struct" security blob. PTAGS LSM module and CaitSith LSM module which are currently under proposal for inclusion also want to use it. Therefore, it will be time to revivesecurity_task_alloc()hook and "struct task_struct"->security field.We are already allowing multiple concurrent LSM modules (up to one fully armored module which uses "struct cred"->security field or exclusive hooks like
security_xfrm_state_pol_flow_match(), plus unlimited number of lightweight modules which do not use "struct cred"->security nor exclusive hooks) as long as they are built into the kernel. But this patch does not implement variable length "struct task_struct"->security field which will become needed when multiple LSM modules want to use "struct task_struct"-> security field. Although it won't be difficult to implement variable length "struct task_struct"->security field, let's think about it after we merged this patch.
Quoted 7 lines
Signed-off-by Tetsuo Handa <[email protected]>Acked-by John Johansen <[email protected]>Tested-by Djalal Harouni <[email protected]>Cc Paul Moore <[email protected]>Cc Stephen Smalley <[email protected]>Cc Eric Paris <[email protected]>Cc Casey Schaufler <[email protected]>
Quoted 157 lines
Cc Kees Cook <[email protected]>Cc James Morris <[email protected]>Cc Serge E. Hallyn <[email protected]>Cc Jos? Bollo <[email protected]>--- include/linux/init_task.h | 7 +++++++ include/linux/lsm_hooks.h | 9 ++++++++- include/linux/sched.h | 4 ++++ include/linux/security.h | 7 +++++++ kernel/fork.c | 7 ++++++- security/security.c | 6 ++++++ 6 files changed, 38 insertions(+), 2 deletions(-)include/linux/init_task.h +7
-0@@ -210,6 +210,12 @@# define INIT_TASK_TI (tsk)#endif +#ifdef CONFIG_SECURITY +#define INIT_TASK_SECURITY .security = NULL, +#else +#define INIT_TASK_SECURITY +#endif +/* * INIT_TASK is used to set up the first task table, touch at * your own risk!. Base=0, limit=0x1fffff (=2MB) @@ -288,6 +294,7 @@ INIT_VTIME(tsk) \ INIT_NUMA_BALANCING(tsk) \ INIT_KASAN(tsk) \ + INIT_TASK_SECURITY \ }include/linux/lsm_hooks.h +8
-1@@ -533,8 +533,13 @@* manual page for definitions of the @clone_flags. * @clone_flags contains the flags indicating what should be shared. * Return 0 if permission is granted. +* @task_alloc: +* @task task being allocated. +* @clone_flags contains the flags indicating what should be shared. +* Handle allocation of task-related resources. +* Returns a zero on success, negative values on failure. * @task_free: -* @task task being freed +* @task task about to be freed. * Handle release of task-related resources. (Note that this can be called * from interrupt context.) * @cred_alloc_blank: @@ -1482,6 +1487,7 @@int (*file_open)(struct file *file,const struct cred *cred);int (*task_create)(unsigned long clone_flags); +int (*task_alloc)(struct task_struct *task,unsigned long clone_flags);void (*task_free)(struct task_struct *task);int (*cred_alloc_blank)(struct cred *cred,gfp_t gfp);void (*cred_free)(struct cred *cred);@@ -1748,6 +1754,7 @@ struct security_hook_heads {struct list_head file_receive;struct list_head file_open;struct list_head task_create; +struct list_head task_alloc;struct list_head task_free;struct list_head cred_alloc_blank;struct list_head cred_free;include/linux/sched.h +4
-0@@ -1038,6 +1038,10 @@ struct task_struct {/* A live task holds one reference: */ atomic_t stack_refcount;#endif +#ifdef CONFIG_SECURITY +/* Used by LSM modules for access restriction: */ +void *security; +#endif /* CPU-specific state of this task: */ struct thread_struct thread;include/linux/security.h +7
-0@@ -308,6 +308,7 @@ int security_file_send_sigiotask(struct task_struct *tsk,int security_file_receive (struct file *file);int security_file_open (struct file *file,const struct cred *cred);int security_task_create (unsigned long clone_flags); +int security_task_alloc (struct task_struct *task,unsigned long clone_flags);void security_task_free (struct task_struct *task);int security_cred_alloc_blank (struct cred *cred,gfp_t gfp);void security_cred_free (struct cred *cred);@@ -861,6 +862,12 @@ static inline int security_task_create(unsigned long clone_flags)return 0 ; } +static inline int security_task_alloc (struct task_struct *task, +unsigned long clone_flags) +{ +return 0 ; +} +static inline void security_task_free (struct task_struct *task) { }kernel/fork.c +6
-1@@ -1679,9 +1679,12 @@ static __latent_entropy struct task_struct *copy_process( goto bad_fork_cleanup_perf;/* copy all the process information */ shm_init_task (p); - retval =copy_semundo (clone_flags, p); + retval =security_task_alloc (p, clone_flags);if (retval) goto bad_fork_cleanup_audit; + retval =copy_semundo (clone_flags, p); +if (retval) + goto bad_fork_cleanup_security; retval =copy_files (clone_flags, p);if (retval) goto bad_fork_cleanup_semundo;@@ -1903,6 +1906,8 @@ static __latent_entropy struct task_struct *copy_process(exit_files (p);/* blocking */ bad_fork_cleanup_semundo:exit_sem (p); +bad_fork_cleanup_security: +security_task_free (p); bad_fork_cleanup_audit:audit_free (p); bad_fork_cleanup_perf:security/security.c +5
-0@@ -930,6 +930,11 @@ int security_task_create(unsigned long clone_flags)return call_int_hook (task_create,0 , clone_flags); } +int security_task_alloc (struct task_struct *task,unsigned long clone_flags) +{ +return call_int_hook (task_alloc,0 , task, clone_flags); +} +void security_task_free (struct task_struct *task) {call_void_hook (task_free, task);
security/security.c struct security_hook_heads security_hook_heads __lsm_ro_after_init = { · line 1781
Quoted 7 lines
security/security.c +1
-0@@ -1770,6 +1775,7 @@ struct security_hook_heads security_hook_heads __lsm_ro_after_init = { .file_receive = LIST_HEAD_INIT(security_hook_heads.file_receive), .file_open = LIST_HEAD_INIT(security_hook_heads.file_open), .task_create = LIST_HEAD_INIT(security_hook_heads.task_create), + .task_alloc = LIST_HEAD_INIT(security_hook_heads.task_alloc), .task_free = LIST_HEAD_INIT(security_hook_heads.task_free), .cred_alloc_blank = LIST_HEAD_INIT(security_hook_heads.cred_alloc_blank),
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 LSM: Revive security_task_alloc() hook and per "struct task_struct" security blob.
In reply to Tetsuo HandaWe switched from "struct task_struct"->security to "struct cred"->security in Linux 2.6.29. But not all LSM modules were happy with that change. TOMOYO LSM module is an example which want to use per "struct task_struct" security blob, for TOMOYO's security context is defined based on "struct task_struct" rather than "struct cred". AppArmor LSM module is another example which want to use it, for AppArmor is currently abusing the cred a little bit to store the change_hat and setexeccon info. Although security_task_free() hook was revived in Linux 3.4 because Yama LSM module wanted to release per "struct task_struct" security blob, security_task_alloc() hook and "struct task_struct"->security field were not revived. Nowadays, we are getting proposals of lightweight LSM modules which want to use per "struct task_struct" security blob. PTAGS LSM module and CaitSith LSM module which are currently under proposal for inclusion also want to use it. Therefore, it will be time to revive security_task_alloc() hook and "struct task_struct"->security field.
We are already allowing multiple concurrent LSM modules (up to one fully armored module which uses "struct cred"->security field or exclusive hooks like security_xfrm_state_pol_flow_match(), plus unlimited number of lightweight modules which do not use "struct cred"->security nor exclusive hooks) as long as they are built into the kernel. But this patch does not implement variable length "struct task_struct"->security field which will become needed when multiple LSM modules want to use "struct task_struct"-> security field. Although it won't be difficult to implement variable length "struct task_struct"->security field, let's think about it after we merged this patch.
--- include/linux/init_task.h | 7 +++++++ include/linux/lsm_hooks.h | 9 ++++++++- include/linux/sched.h | 4 ++++ include/linux/security.h | 7 +++++++ kernel/fork.c | 7 ++++++- security/security.c | 6 ++++++ 6 files changed, 38 insertions(+), 2 deletions(-)
include/linux/init_task.h +7 -0
@@ -210,6 +210,12 @@# define INIT_TASK_TI (tsk)#endif +#ifdef CONFIG_SECURITY +#define INIT_TASK_SECURITY .security = NULL, +#else +#define INIT_TASK_SECURITY +#endif +/* * INIT_TASK is used to set up the first task table, touch at * your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -288,6 +294,7 @@ INIT_VTIME(tsk) \ INIT_NUMA_BALANCING(tsk) \ INIT_KASAN(tsk) \ + INIT_TASK_SECURITY \ }
include/linux/lsm_hooks.h +8 -1
@@ -533,8 +533,13 @@* manual page for definitions of the @clone_flags. * @clone_flags contains the flags indicating what should be shared. * Return 0 if permission is granted. +* @task_alloc: +* @task task being allocated. +* @clone_flags contains the flags indicating what should be shared. +* Handle allocation of task-related resources. +* Returns a zero on success, negative values on failure. * @task_free: -* @task task being freed +* @task task about to be freed. * Handle release of task-related resources. (Note that this can be called * from interrupt context.) * @cred_alloc_blank:
@@ -1482,6 +1487,7 @@int (*file_open)(struct file *file,const struct cred *cred);int (*task_create)(unsigned long clone_flags); +int (*task_alloc)(struct task_struct *task,unsigned long clone_flags);void (*task_free)(struct task_struct *task);int (*cred_alloc_blank)(struct cred *cred,gfp_t gfp);void (*cred_free)(struct cred *cred);
@@ -1748,6 +1754,7 @@ struct security_hook_heads {struct list_head file_receive;struct list_head file_open;struct list_head task_create; +struct list_head task_alloc;struct list_head task_free;struct list_head cred_alloc_blank;struct list_head cred_free;
include/linux/sched.h +4 -0
@@ -1038,6 +1038,10 @@ struct task_struct {/* A live task holds one reference: */ atomic_t stack_refcount;#endif +#ifdef CONFIG_SECURITY +/* Used by LSM modules for access restriction: */ +void *security; +#endif /* CPU-specific state of this task: */ struct thread_struct thread;
include/linux/security.h +7 -0
@@ -308,6 +308,7 @@ int security_file_send_sigiotask(struct task_struct *tsk,int security_file_receive (struct file *file);int security_file_open (struct file *file,const struct cred *cred);int security_task_create (unsigned long clone_flags); +int security_task_alloc (struct task_struct *task,unsigned long clone_flags);void security_task_free (struct task_struct *task);int security_cred_alloc_blank (struct cred *cred,gfp_t gfp);void security_cred_free (struct cred *cred);
@@ -861,6 +862,12 @@ static inline int security_task_create(unsigned long clone_flags)return 0 ; } +static inline int security_task_alloc (struct task_struct *task, +unsigned long clone_flags) +{ +return 0 ; +} +static inline void security_task_free (struct task_struct *task) { }
kernel/fork.c +6 -1
@@ -1679,9 +1679,12 @@ static __latent_entropy struct task_struct *copy_process( goto bad_fork_cleanup_perf;/* copy all the process information */ shm_init_task (p); - retval =copy_semundo (clone_flags, p); + retval =security_task_alloc (p, clone_flags);if (retval) goto bad_fork_cleanup_audit; + retval =copy_semundo (clone_flags, p); +if (retval) + goto bad_fork_cleanup_security; retval =copy_files (clone_flags, p);if (retval) goto bad_fork_cleanup_semundo;
@@ -1903,6 +1906,8 @@ static __latent_entropy struct task_struct *copy_process(exit_files (p);/* blocking */ bad_fork_cleanup_semundo:exit_sem (p); +bad_fork_cleanup_security: +security_task_free (p); bad_fork_cleanup_audit:audit_free (p); bad_fork_cleanup_perf:
security/security.c +6 -0
@@ -930,6 +930,11 @@ int security_task_create(unsigned long clone_flags)return call_int_hook (task_create,0 , clone_flags); } +int security_task_alloc (struct task_struct *task,unsigned long clone_flags) +{ +return call_int_hook (task_alloc,0 , task, clone_flags); +} +void security_task_free (struct task_struct *task) {call_void_hook (task_free, task);
@@ -1770,6 +1775,7 @@ struct security_hook_heads security_hook_heads __lsm_ro_after_init = { .file_receive = LIST_HEAD_INIT(security_hook_heads.file_receive), .file_open = LIST_HEAD_INIT(security_hook_heads.file_open), .task_create = LIST_HEAD_INIT(security_hook_heads.task_create), + .task_alloc = LIST_HEAD_INIT(security_hook_heads.task_alloc), .task_free = LIST_HEAD_INIT(security_hook_heads.task_free), .cred_alloc_blank = LIST_HEAD_INIT(security_hook_heads.cred_alloc_blank),
Signature · 6 lines
1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html