From: Stephen Smalley This patch adds an AT_SECURE auxv entry to pass a boolean flag indicating whether "secure mode" should be enabled (i.e. sanitize the environment, initial descriptors, etc) and allows each security module to specify the flag value via a new hook. New userland can then simply obey this flag when present rather than applying other methods of deciding (sample patch for glibc-2.3.2 can be found at http://www.cs.utah.edu/~sds/glibc-secureexec.patch). This change enables security modules like SELinux to request secure mode upon changes to other security attributes (e.g. capabilities, roles/domains, etc) in addition to uid/gid changes or even to completely override the legacy logic. The legacy decision algorithm is preserved in the default hook functions for the dummy and capability security modules. Credit for the idea of adding an AT_SECURE auxv entry goes to Roland McGrath. fs/binfmt_elf.c | 2 ++ include/linux/elf.h | 2 ++ include/linux/security.h | 19 +++++++++++++++++++ security/capability.c | 13 +++++++++++++ security/dummy.c | 11 +++++++++++ 5 files changed, 47 insertions(+) diff -puN fs/binfmt_elf.c~AT_SECURE-auxv-entry fs/binfmt_elf.c --- 25/fs/binfmt_elf.c~AT_SECURE-auxv-entry 2003-06-19 10:38:45.000000000 -0700 +++ 25-akpm/fs/binfmt_elf.c 2003-06-19 10:38:45.000000000 -0700 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -191,6 +192,7 @@ create_elf_tables(struct linux_binprm *b NEW_AUX_ENT(AT_EUID, (elf_addr_t) tsk->euid); NEW_AUX_ENT(AT_GID, (elf_addr_t) tsk->gid); NEW_AUX_ENT(AT_EGID, (elf_addr_t) tsk->egid); + NEW_AUX_ENT(AT_SECURE, (elf_addr_t) security_bprm_secureexec(bprm)); if (k_platform) { NEW_AUX_ENT(AT_PLATFORM, (elf_addr_t)(long)u_platform); } diff -puN include/linux/elf.h~AT_SECURE-auxv-entry include/linux/elf.h --- 25/include/linux/elf.h~AT_SECURE-auxv-entry 2003-06-19 10:38:45.000000000 -0700 +++ 25-akpm/include/linux/elf.h 2003-06-19 10:38:45.000000000 -0700 @@ -163,6 +163,8 @@ typedef __s64 Elf64_Sxword; #define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */ #define AT_CLKTCK 17 /* frequency at which times() increments */ +#define AT_SECURE 23 /* secure mode boolean */ + typedef struct dynamic{ Elf32_Sword d_tag; union{ diff -puN include/linux/security.h~AT_SECURE-auxv-entry include/linux/security.h --- 25/include/linux/security.h~AT_SECURE-auxv-entry 2003-06-19 10:38:45.000000000 -0700 +++ 25-akpm/include/linux/security.h 2003-06-19 10:38:45.000000000 -0700 @@ -45,6 +45,7 @@ extern int cap_capset_check (struct task extern void cap_capset_set (struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); extern int cap_bprm_set_security (struct linux_binprm *bprm); extern void cap_bprm_compute_creds (struct linux_binprm *bprm); +extern int cap_bprm_secureexec(struct linux_binprm *bprm); extern int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags); extern void cap_task_reparent_to_init (struct task_struct *p); extern int cap_syslog (int type); @@ -131,6 +132,12 @@ struct swap_info_struct; * first. * @bprm contains the linux_binprm structure. * Return 0 if the hook is successful and permission is granted. + * @bprm_secureexec: + * Return a boolean value (0 or 1) indicating whether a "secure exec" + * is required. The flag is passed in the auxiliary table + * on the initial stack to the ELF interpreter to indicate whether libc + * should enable secure mode. + * @bprm contains the linux_binprm structure. * * Security hooks for filesystem operations. * @@ -988,6 +995,7 @@ struct security_operations { void (*bprm_compute_creds) (struct linux_binprm * bprm); int (*bprm_set_security) (struct linux_binprm * bprm); int (*bprm_check_security) (struct linux_binprm * bprm); + int (*bprm_secureexec) (struct linux_binprm * bprm); int (*sb_alloc_security) (struct super_block * sb); void (*sb_free_security) (struct super_block * sb); @@ -1246,11 +1254,17 @@ static inline int security_bprm_set (str { return security_ops->bprm_set_security (bprm); } + static inline int security_bprm_check (struct linux_binprm *bprm) { return security_ops->bprm_check_security (bprm); } +static inline int security_bprm_secureexec (struct linux_binprm *bprm) +{ + return security_ops->bprm_secureexec (bprm); +} + static inline int security_sb_alloc (struct super_block *sb) { return security_ops->sb_alloc_security (sb); @@ -1907,6 +1921,11 @@ static inline int security_bprm_check (s return 0; } +static inline int security_bprm_secureexec (struct linux_binprm *bprm) +{ + return cap_bprm_secureexec(bprm); +} + static inline int security_sb_alloc (struct super_block *sb) { return 0; diff -puN security/capability.c~AT_SECURE-auxv-entry security/capability.c --- 25/security/capability.c~AT_SECURE-auxv-entry 2003-06-19 10:38:45.000000000 -0700 +++ 25-akpm/security/capability.c 2003-06-19 10:38:45.000000000 -0700 @@ -158,6 +158,17 @@ void cap_bprm_compute_creds (struct linu current->keep_capabilities = 0; } +int cap_bprm_secureexec (struct linux_binprm *bprm) +{ + /* If/when this module is enhanced to incorporate capability + bits on files, the test below should be extended to also perform a + test between the old and new capability sets. For now, + it simply preserves the legacy decision algorithm used by + the old userland. */ + return (current->euid != current->uid || + current->egid != current->gid); +} + /* moved from kernel/sys.c. */ /* * cap_emulate_setxuid() fixes the effective / permitted capabilities of @@ -271,6 +282,7 @@ EXPORT_SYMBOL(cap_capset_check); EXPORT_SYMBOL(cap_capset_set); EXPORT_SYMBOL(cap_bprm_set_security); EXPORT_SYMBOL(cap_bprm_compute_creds); +EXPORT_SYMBOL(cap_bprm_secureexec); EXPORT_SYMBOL(cap_task_post_setuid); EXPORT_SYMBOL(cap_task_reparent_to_init); EXPORT_SYMBOL(cap_syslog); @@ -289,6 +301,7 @@ static struct security_operations capabi .bprm_compute_creds = cap_bprm_compute_creds, .bprm_set_security = cap_bprm_set_security, + .bprm_secureexec = cap_bprm_secureexec, .task_post_setuid = cap_task_post_setuid, .task_reparent_to_init = cap_task_reparent_to_init, diff -puN security/dummy.c~AT_SECURE-auxv-entry security/dummy.c --- 25/security/dummy.c~AT_SECURE-auxv-entry 2003-06-19 10:38:45.000000000 -0700 +++ 25-akpm/security/dummy.c 2003-06-19 10:38:45.000000000 -0700 @@ -122,6 +122,16 @@ static int dummy_bprm_check_security (st return 0; } +static int dummy_bprm_secureexec (struct linux_binprm *bprm) +{ + /* The new userland will simply use the value provided + in the AT_SECURE field to decide whether secure mode + is required. Hence, this logic is required to preserve + the legacy decision algorithm used by the old userland. */ + return (current->euid != current->uid || + current->egid != current->gid); +} + static int dummy_sb_alloc_security (struct super_block *sb) { return 0; @@ -788,6 +798,7 @@ void security_fixup_ops (struct security set_to_dummy_if_null(ops, bprm_compute_creds); set_to_dummy_if_null(ops, bprm_set_security); set_to_dummy_if_null(ops, bprm_check_security); + set_to_dummy_if_null(ops, bprm_secureexec); set_to_dummy_if_null(ops, sb_alloc_security); set_to_dummy_if_null(ops, sb_free_security); set_to_dummy_if_null(ops, sb_kern_mount); _