Commit 177be0a4 authored by Andrew Morton's avatar Andrew Morton Committed by Greg Kroah-Hartman

[PATCH] AT_SECURE auxv entry

From: Stephen Smalley <sds@epoch.ncsc.mil>

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.
parent b10b09be
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/security.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/param.h> #include <asm/param.h>
...@@ -191,6 +192,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec, ...@@ -191,6 +192,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec,
NEW_AUX_ENT(AT_EUID, (elf_addr_t) tsk->euid); NEW_AUX_ENT(AT_EUID, (elf_addr_t) tsk->euid);
NEW_AUX_ENT(AT_GID, (elf_addr_t) tsk->gid); NEW_AUX_ENT(AT_GID, (elf_addr_t) tsk->gid);
NEW_AUX_ENT(AT_EGID, (elf_addr_t) tsk->egid); 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) { if (k_platform) {
NEW_AUX_ENT(AT_PLATFORM, (elf_addr_t)(long)u_platform); NEW_AUX_ENT(AT_PLATFORM, (elf_addr_t)(long)u_platform);
} }
......
...@@ -163,6 +163,8 @@ typedef __s64 Elf64_Sxword; ...@@ -163,6 +163,8 @@ typedef __s64 Elf64_Sxword;
#define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */ #define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */
#define AT_CLKTCK 17 /* frequency at which times() increments */ #define AT_CLKTCK 17 /* frequency at which times() increments */
#define AT_SECURE 23 /* secure mode boolean */
typedef struct dynamic{ typedef struct dynamic{
Elf32_Sword d_tag; Elf32_Sword d_tag;
union{ union{
......
...@@ -45,6 +45,7 @@ extern int cap_capset_check (struct task_struct *target, kernel_cap_t *effective ...@@ -45,6 +45,7 @@ extern int cap_capset_check (struct task_struct *target, kernel_cap_t *effective
extern void cap_capset_set (struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); 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 int cap_bprm_set_security (struct linux_binprm *bprm);
extern void cap_bprm_compute_creds (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 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 void cap_task_reparent_to_init (struct task_struct *p);
extern int cap_syslog (int type); extern int cap_syslog (int type);
...@@ -131,6 +132,12 @@ struct swap_info_struct; ...@@ -131,6 +132,12 @@ struct swap_info_struct;
* first. * first.
* @bprm contains the linux_binprm structure. * @bprm contains the linux_binprm structure.
* Return 0 if the hook is successful and permission is granted. * 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. * Security hooks for filesystem operations.
* *
...@@ -988,6 +995,7 @@ struct security_operations { ...@@ -988,6 +995,7 @@ struct security_operations {
void (*bprm_compute_creds) (struct linux_binprm * bprm); void (*bprm_compute_creds) (struct linux_binprm * bprm);
int (*bprm_set_security) (struct linux_binprm * bprm); int (*bprm_set_security) (struct linux_binprm * bprm);
int (*bprm_check_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); int (*sb_alloc_security) (struct super_block * sb);
void (*sb_free_security) (struct super_block * sb); void (*sb_free_security) (struct super_block * sb);
...@@ -1246,11 +1254,17 @@ static inline int security_bprm_set (struct linux_binprm *bprm) ...@@ -1246,11 +1254,17 @@ static inline int security_bprm_set (struct linux_binprm *bprm)
{ {
return security_ops->bprm_set_security (bprm); return security_ops->bprm_set_security (bprm);
} }
static inline int security_bprm_check (struct linux_binprm *bprm) static inline int security_bprm_check (struct linux_binprm *bprm)
{ {
return security_ops->bprm_check_security (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) static inline int security_sb_alloc (struct super_block *sb)
{ {
return security_ops->sb_alloc_security (sb); return security_ops->sb_alloc_security (sb);
...@@ -1907,6 +1921,11 @@ static inline int security_bprm_check (struct linux_binprm *bprm) ...@@ -1907,6 +1921,11 @@ static inline int security_bprm_check (struct linux_binprm *bprm)
return 0; 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) static inline int security_sb_alloc (struct super_block *sb)
{ {
return 0; return 0;
......
...@@ -158,6 +158,17 @@ void cap_bprm_compute_creds (struct linux_binprm *bprm) ...@@ -158,6 +158,17 @@ void cap_bprm_compute_creds (struct linux_binprm *bprm)
current->keep_capabilities = 0; 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. */ /* moved from kernel/sys.c. */
/* /*
* cap_emulate_setxuid() fixes the effective / permitted capabilities of * cap_emulate_setxuid() fixes the effective / permitted capabilities of
...@@ -271,6 +282,7 @@ EXPORT_SYMBOL(cap_capset_check); ...@@ -271,6 +282,7 @@ EXPORT_SYMBOL(cap_capset_check);
EXPORT_SYMBOL(cap_capset_set); EXPORT_SYMBOL(cap_capset_set);
EXPORT_SYMBOL(cap_bprm_set_security); EXPORT_SYMBOL(cap_bprm_set_security);
EXPORT_SYMBOL(cap_bprm_compute_creds); EXPORT_SYMBOL(cap_bprm_compute_creds);
EXPORT_SYMBOL(cap_bprm_secureexec);
EXPORT_SYMBOL(cap_task_post_setuid); EXPORT_SYMBOL(cap_task_post_setuid);
EXPORT_SYMBOL(cap_task_reparent_to_init); EXPORT_SYMBOL(cap_task_reparent_to_init);
EXPORT_SYMBOL(cap_syslog); EXPORT_SYMBOL(cap_syslog);
...@@ -289,6 +301,7 @@ static struct security_operations capability_ops = { ...@@ -289,6 +301,7 @@ static struct security_operations capability_ops = {
.bprm_compute_creds = cap_bprm_compute_creds, .bprm_compute_creds = cap_bprm_compute_creds,
.bprm_set_security = cap_bprm_set_security, .bprm_set_security = cap_bprm_set_security,
.bprm_secureexec = cap_bprm_secureexec,
.task_post_setuid = cap_task_post_setuid, .task_post_setuid = cap_task_post_setuid,
.task_reparent_to_init = cap_task_reparent_to_init, .task_reparent_to_init = cap_task_reparent_to_init,
......
...@@ -122,6 +122,16 @@ static int dummy_bprm_check_security (struct linux_binprm *bprm) ...@@ -122,6 +122,16 @@ static int dummy_bprm_check_security (struct linux_binprm *bprm)
return 0; 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) static int dummy_sb_alloc_security (struct super_block *sb)
{ {
return 0; return 0;
...@@ -788,6 +798,7 @@ void security_fixup_ops (struct security_operations *ops) ...@@ -788,6 +798,7 @@ void security_fixup_ops (struct security_operations *ops)
set_to_dummy_if_null(ops, bprm_compute_creds); 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_set_security);
set_to_dummy_if_null(ops, bprm_check_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_alloc_security);
set_to_dummy_if_null(ops, sb_free_security); set_to_dummy_if_null(ops, sb_free_security);
set_to_dummy_if_null(ops, sb_kern_mount); set_to_dummy_if_null(ops, sb_kern_mount);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment