diff --git a/module-nextgen/apparmor/apparmor.h b/module-nextgen/apparmor/apparmor.h index 477ece255..7acbd508f 100644 --- a/module-nextgen/apparmor/apparmor.h +++ b/module-nextgen/apparmor/apparmor.h @@ -13,6 +13,7 @@ #define __APPARMOR_H #include /* Include for defn of iattr */ +#include /* defn of linux_binprm */ #include #include "shared.h" @@ -101,15 +102,12 @@ struct aa_entry { struct list_head listp[POS_AA_FILE_MAX + 1]; }; -#define AA_EXEC_MODIFIER_MASK(mask) ((mask) & (AA_EXEC_UNCONSTRAINED |\ - AA_EXEC_INHERIT |\ - AA_EXEC_PROFILE)) - -#define AA_EXEC_MASK(mask) ((mask) & (AA_MAY_EXEC |\ - AA_EXEC_UNCONSTRAINED |\ - AA_EXEC_INHERIT |\ - AA_EXEC_PROFILE)) +#define AA_SECURE_EXEC_NEEDED 0x00000001 +#define AA_EXEC_MODIFIER_MASK(mask) ((mask) & AA_EXEC_MODIFIERS) +#define AA_EXEC_MASK(mask) ((mask) & (AA_MAY_EXEC | AA_EXEC_MODIFIERS)) +#define AA_EXEC_UNSAFE_MASK(mask) ((mask) & (AA_MAY_EXEC | AA_EXEC_MODIFIERS |\ + AA_EXEC_UNSAFE)) /* struct aaprofile - basic confinement data * @parent: non refcounted pointer to parent profile @@ -298,7 +296,7 @@ extern int aa_perm_dir(struct aaprofile *active, struct dentry *dentry, extern int aa_link(struct aaprofile *active, struct dentry *link, struct dentry *target); extern int aa_fork(struct task_struct *p); -extern int aa_register(struct file *file); +extern int aa_register(struct linux_binprm *bprm); extern void aa_release(struct task_struct *p); extern int aa_change_hat(const char *id, u32 hat_magic); extern int aa_associate_filp(struct file *filp); diff --git a/module-nextgen/apparmor/lsm.c b/module-nextgen/apparmor/lsm.c index e0f4f0539..ec215743d 100644 --- a/module-nextgen/apparmor/lsm.c +++ b/module-nextgen/apparmor/lsm.c @@ -194,7 +194,21 @@ static int apparmor_bprm_set_security(struct linux_binprm *bprm) /* already set based on script name */ if (bprm->sh_bang) return 0; - return aa_register(bprm->file); + return aa_register(bprm); +} + +static int apparmor_bprm_secureexec(struct linux_binprm *bprm) +{ + int ret = cap_bprm_secureexec(bprm); + + if (ret == 0 && + (unsigned long)bprm->security & AA_SECURE_EXEC_NEEDED) { + AA_DEBUG("%s: secureexec required for %s\n", + __FUNCTION__, bprm->filename); + ret = 1; + } + + return ret; } static int apparmor_sb_mount(char *dev_name, struct nameidata *nd, char *type, @@ -748,6 +762,7 @@ struct security_operations apparmor_ops = { .bprm_apply_creds = apparmor_bprm_apply_creds, .bprm_set_security = apparmor_bprm_set_security, + .bprm_secureexec = apparmor_bprm_secureexec, .sb_mount = apparmor_sb_mount, .sb_umount = apparmor_umount, diff --git a/module-nextgen/apparmor/main.c b/module-nextgen/apparmor/main.c index 79791631d..7aa223e85 100644 --- a/module-nextgen/apparmor/main.c +++ b/module-nextgen/apparmor/main.c @@ -119,22 +119,22 @@ out: * %AA_MAY_EXEC is returned indicating a naked x * if the has an exec qualifier then only the qualifier bit {pui} * is returned (%AA_MAY_EXEC) is not set. - * + * @unsafe: true if secure_exec should be overriden * Returns %0 (false): * if unable to find profile or there are conflicting pattern matches. * *xmod - is not modified + * *unsafe - is not modified * * Returns %1 (true): - * if not confined - * *xmod = %AA_MAY_EXEC * if exec rule matched * if the rule has an execution mode qualifier {pui} then * *xmod = the execution qualifier of the rule {pui} * else * *xmod = %AA_MAY_EXEC + * unsafe = presence of unsage flag */ static inline int aa_get_execmode(struct aaprofile *active, const char *name, - int *xmod) + int *xmod, int *unsafe) { struct aa_entry *entry; struct aa_entry *match = NULL; @@ -158,8 +158,8 @@ static inline int aa_get_execmode(struct aaprofile *active, const char *name, aamatch_match(name, entry->filename, entry->type, entry->extradata)) { if (match && - AA_EXEC_MASK(entry->mode) != - AA_EXEC_MASK(match->mode)) + AA_EXEC_UNSAFE_MASK(entry->mode) != + AA_EXEC_UNSAFE_MASK(match->mode)) pattern_match_invalid = 1; else /* keep searching for an exact match */ @@ -179,8 +179,8 @@ static inline int aa_get_execmode(struct aaprofile *active, const char *name, break; } else { if (match && - AA_EXEC_MASK(entry->mode) != - AA_EXEC_MASK(match->mode)) + AA_EXEC_UNSAFE_MASK(entry->mode) != + AA_EXEC_UNSAFE_MASK(match->mode)) pattern_match_invalid = 1; else /* got a tailglob match, keep searching @@ -204,6 +204,7 @@ static inline int aa_get_execmode(struct aaprofile *active, const char *name, mode = mode & ~AA_MAY_EXEC; *xmod = mode; + *unsafe = (match->mode & AA_EXEC_UNSAFE); } else if (!match) { AA_DEBUG("%s: Unable to find execute entry in profile " "for image '%s'\n", @@ -219,9 +220,6 @@ static inline int aa_get_execmode(struct aaprofile *active, const char *name, } return rc; - - *xmod = AA_MAY_EXEC; - return 1; } /** @@ -1203,14 +1201,15 @@ int aa_fork(struct task_struct *p) /** * aa_register - register a new program - * @filp: file of program being registered + * @bprm: binprm of program being registered * * Try to register a new program during execve(). This should give the * new program a valid subdomain. */ -int aa_register(struct file *filp) +int aa_register(struct linux_binprm *bprm) { char *filename; + struct file *filp = bprm->file; struct subdomain *sd; struct aaprofile *active; struct aaprofile *newprofile = NULL, unconstrained_flag; @@ -1218,6 +1217,7 @@ int aa_register(struct file *filp) exec_mode = 0, find_profile = 0, find_profile_mandatory = 0, + unsafe_exec = 0, complain = 0; AA_DEBUG("%s\n", __FUNCTION__); @@ -1260,7 +1260,7 @@ int aa_register(struct file *filp) /* Confined task, determine what mode inherit, unconstrained or * mandatory to load new profile */ - if (aa_get_execmode(active, filename, &exec_mode)) { + if (aa_get_execmode(active, filename, &exec_mode, &unsafe_exec)) { switch (exec_mode) { case AA_EXEC_INHERIT: /* do nothing - setting of profile @@ -1320,9 +1320,10 @@ int aa_register(struct file *filp) } else if (complain) { /* There was no entry in calling profile * describing mode to execute image in. - * Drop into null-profile + * Drop into null-profile (disabling secure exec). */ newprofile = get_aaprofile(null_complain_profile); + unsafe_exec = 1; } else { AA_WARN("%s: Rejecting exec(2) of image '%s'. " "Unable to determine exec qualifier " @@ -1429,6 +1430,23 @@ apply_profile: } } + /* Handle confined exec. + * Can be at this point for the following reasons: + * 1. unconfined switching to confined + * 2. confined switching to different confinement + * 3. confined switching to unconfined + * + * Cases 2 and 3 are marked as requiring secure exec + * (unless policy specified "unsafe exec") + */ + if (__aa_is_confined(sd) && !unsafe_exec) { + unsigned long bprm_flags; + + bprm_flags = AA_SECURE_EXEC_NEEDED; + bprm->security = (void*) + ((unsigned long)bprm->security | bprm_flags); + } + aa_switch(sd, newprofile); put_aaprofile(newprofile); diff --git a/module-nextgen/apparmor/shared.h b/module-nextgen/apparmor/shared.h index 52a8d5b2d..70dd25c88 100644 --- a/module-nextgen/apparmor/shared.h +++ b/module-nextgen/apparmor/shared.h @@ -25,7 +25,8 @@ #define POS_AA_EXEC_UNCONSTRAINED (POS_AA_EXEC_INHERIT + 1) #define POS_AA_EXEC_PROFILE (POS_AA_EXEC_UNCONSTRAINED + 1) #define POS_AA_EXEC_MMAP (POS_AA_EXEC_PROFILE + 1) -#define POS_AA_FILE_MAX POS_AA_EXEC_MMAP +#define POS_AA_EXEC_UNSAFE (POS_AA_EXEC_MMAP + 1) +#define POS_AA_FILE_MAX POS_AA_EXEC_UNSAFE /* Modeled after MAY_READ, MAY_WRITE, MAY_EXEC def'ns */ #define AA_MAY_EXEC (0x01 << POS_AA_MAY_EXEC) @@ -36,8 +37,10 @@ #define AA_EXEC_UNCONSTRAINED (0x01 << POS_AA_EXEC_UNCONSTRAINED) #define AA_EXEC_PROFILE (0x01 << POS_AA_EXEC_PROFILE) #define AA_EXEC_MMAP (0x01 << POS_AA_EXEC_MMAP) -#define AA_EXEC_MODIFIERS(X) (X & (AA_EXEC_INHERIT | \ - A_EXEC_UNCONSTRAINED | \ - AA_EXEC_PROFILE)) +#define AA_EXEC_UNSAFE (0x01 << POS_AA_EXEC_UNSAFE) + +#define AA_EXEC_MODIFIERS (AA_EXEC_INHERIT | \ + AA_EXEC_UNCONSTRAINED | \ + AA_EXEC_PROFILE) #endif /* _SHARED_H */