[PATCH 01/11] exec: Reduce bprm->per_clear to a single bit
From: Eric W. Biederman
Date: Thu May 28 2020 - 11:45:46 EST
The bprm->per_clear field only takes the values 0 and
PER_CLEAR_ON_SETID. Reduce the field to a signle bit to make it clear
that the only question is should the dangerous personality bits be
cleared or not.
Update the documentation of the security lsm hooks.
Signed-off-by: "Eric W. Biederman" <ebiederm@xxxxxxxxxxxx>
---
fs/exec.c | 7 ++++---
include/linux/binfmts.h | 4 +++-
include/linux/lsm_hooks.h | 4 ++++
security/apparmor/domain.c | 2 +-
security/commoncap.c | 2 +-
security/selinux/hooks.c | 2 +-
security/smack/smack_lsm.c | 2 +-
7 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/fs/exec.c b/fs/exec.c
index c3c879a55d65..51fab62b9fca 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1354,7 +1354,8 @@ int begin_new_exec(struct linux_binprm * bprm)
me->flags &= ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD |
PF_NOFREEZE | PF_NO_SETAFFINITY);
flush_thread();
- me->personality &= ~bprm->per_clear;
+ if (bprm->per_clear)
+ me->personality &= ~PER_CLEAR_ON_SETID;
/*
* We have to apply CLOEXEC before we change whether the process is
@@ -1628,12 +1629,12 @@ static void bprm_fill_uid(struct linux_binprm *bprm)
return;
if (mode & S_ISUID) {
- bprm->per_clear |= PER_CLEAR_ON_SETID;
+ bprm->per_clear = 1;
bprm->cred->euid = uid;
}
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
- bprm->per_clear |= PER_CLEAR_ON_SETID;
+ bprm->per_clear = 1;
bprm->cred->egid = gid;
}
}
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index 7fc05929c967..e7959a6a895a 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -26,6 +26,9 @@ struct linux_binprm {
unsigned long p; /* current top of mem */
unsigned long argmin; /* rlimit marker for copy_strings() */
unsigned int
+ /* Should unsafe personality bits be cleared? */
+ per_clear:1,
+
/* Should an execfd be passed to userspace? */
have_execfd:1,
@@ -55,7 +58,6 @@ struct linux_binprm {
struct file * file;
struct cred *cred; /* new credentials */
int unsafe; /* how unsafe this exec is (mask of LSM_UNSAFE_*) */
- unsigned int per_clear; /* bits to clear in current->personality */
int argc, envc;
const char * filename; /* Name of binary as seen by procps */
const char * interp; /* Name of the binary really executed. Most
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index d618ecc4d660..0ca68ad53592 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -42,6 +42,8 @@
* (e.g. for transitions between security domains).
* The hook must set @bprm->secureexec to 1 if AT_SECURE should be set to
* request libc enable secure mode.
+ * The hook must set @bprm->per_clear to 1 if the dangerous personality
+ * bits must be cleared from current->personality.
* @bprm contains the linux_binprm structure.
* Return 0 if the hook is successful and permission is granted.
* @bprm_repopulate_creds:
@@ -55,6 +57,8 @@
* transitions between security domains).
* The hook must set @bprm->active_secureexec to 1 if AT_SECURE should be set to
* request libc enable secure mode.
+ * The hook must set @bprm->per_clear to 1 if the dangerous personality
+ * bits must be cleared from current->personality.
* @bprm contains the linux_binprm structure.
* Return 0 if the hook is successful and permission is granted.
* @bprm_check_security:
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index 0b870a647488..c6d00735a40a 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -962,7 +962,7 @@ int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm)
aa_label_printk(new, GFP_KERNEL);
dbg_printk("\n");
}
- bprm->per_clear |= PER_CLEAR_ON_SETID;
+ bprm->per_clear = 1;
}
aa_put_label(cred_label(bprm->cred));
/* transfer reference, released when cred is freed */
diff --git a/security/commoncap.c b/security/commoncap.c
index 77b04cb6feac..48b556046483 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -826,7 +826,7 @@ int cap_bprm_repopulate_creds(struct linux_binprm *bprm)
/* if we have fs caps, clear dangerous personality flags */
if (__cap_gained(permitted, new, old))
- bprm->per_clear |= PER_CLEAR_ON_SETID;
+ bprm->per_clear = 1;
/* Don't let someone trace a set[ug]id/setpcap binary with the revised
* credentials unless they have the appropriate permit.
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 718345dd76bb..6bea1b879fdb 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2385,7 +2385,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
}
/* Clear any possibly unsafe personality bits on exec: */
- bprm->per_clear |= PER_CLEAR_ON_SETID;
+ bprm->per_clear = 1;
/* Enable secure mode for SIDs transitions unless
the noatsecure permission is granted between
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 0ac8f4518d07..a0d2fad27b33 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -933,7 +933,7 @@ static int smack_bprm_creds_for_exec(struct linux_binprm *bprm)
return -EPERM;
bsp->smk_task = isp->smk_task;
- bprm->per_clear |= PER_CLEAR_ON_SETID;
+ bprm->per_clear = 1;
/* Decide if this is a secure exec. */
if (bsp->smk_task != bsp->smk_forked)
--
2.25.0