aboutsummaryrefslogtreecommitdiffstats
path: root/fs/exec.c
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@amacapital.net>2012-04-12 17:47:50 -0400
committerJames Morris <james.l.morris@oracle.com>2012-04-13 21:13:18 -0400
commit259e5e6c75a910f3b5e656151dc602f53f9d7548 (patch)
tree4405fdf68238f2e33f27b04e8c37c9e29a2493d8 /fs/exec.c
parent9ccf010f8172b699ea80178860e8ea228f7dce56 (diff)
Add PR_{GET,SET}_NO_NEW_PRIVS to prevent execve from granting privs
With this change, calling prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) disables privilege granting operations at execve-time. For example, a process will not be able to execute a setuid binary to change their uid or gid if this bit is set. The same is true for file capabilities. Additionally, LSM_UNSAFE_NO_NEW_PRIVS is defined to ensure that LSMs respect the requested behavior. To determine if the NO_NEW_PRIVS bit is set, a task may call prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0); It returns 1 if set and 0 if it is not set. If any of the arguments are non-zero, it will return -1 and set errno to -EINVAL. (PR_SET_NO_NEW_PRIVS behaves similarly.) This functionality is desired for the proposed seccomp filter patch series. By using PR_SET_NO_NEW_PRIVS, it allows a task to modify the system call behavior for itself and its child tasks without being able to impact the behavior of a more privileged task. Another potential use is making certain privileged operations unprivileged. For example, chroot may be considered "safe" if it cannot affect privileged tasks. Note, this patch causes execve to fail when PR_SET_NO_NEW_PRIVS is set and AppArmor is in use. It is fixed in a subsequent patch. Signed-off-by: Andy Lutomirski <luto@amacapital.net> Signed-off-by: Will Drewry <wad@chromium.org> Acked-by: Eric Paris <eparis@redhat.com> Acked-by: Kees Cook <keescook@chromium.org> v18: updated change desc v17: using new define values as per 3.4 Signed-off-by: James Morris <james.l.morris@oracle.com>
Diffstat (limited to 'fs/exec.c')
-rw-r--r--fs/exec.c10
1 files changed, 9 insertions, 1 deletions
diff --git a/fs/exec.c b/fs/exec.c
index b1fd2025e59a..d038968b54b4 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1245,6 +1245,13 @@ static int check_unsafe_exec(struct linux_binprm *bprm)
1245 bprm->unsafe |= LSM_UNSAFE_PTRACE; 1245 bprm->unsafe |= LSM_UNSAFE_PTRACE;
1246 } 1246 }
1247 1247
1248 /*
1249 * This isn't strictly necessary, but it makes it harder for LSMs to
1250 * mess up.
1251 */
1252 if (current->no_new_privs)
1253 bprm->unsafe |= LSM_UNSAFE_NO_NEW_PRIVS;
1254
1248 n_fs = 1; 1255 n_fs = 1;
1249 spin_lock(&p->fs->lock); 1256 spin_lock(&p->fs->lock);
1250 rcu_read_lock(); 1257 rcu_read_lock();
@@ -1288,7 +1295,8 @@ int prepare_binprm(struct linux_binprm *bprm)
1288 bprm->cred->euid = current_euid(); 1295 bprm->cred->euid = current_euid();
1289 bprm->cred->egid = current_egid(); 1296 bprm->cred->egid = current_egid();
1290 1297
1291 if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) { 1298 if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) &&
1299 !current->no_new_privs) {
1292 /* Set-uid? */ 1300 /* Set-uid? */
1293 if (mode & S_ISUID) { 1301 if (mode & S_ISUID) {
1294 bprm->per_clear |= PER_CLEAR_ON_SETID; 1302 bprm->per_clear |= PER_CLEAR_ON_SETID;