fs/exec.c | 7 +++++-- fs/open.c | 10 ++++++++-- include/linux/capability.h | 17 +++++++++++++++++ kernel/fork.c | 2 ++ 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index e4d0a2c..1cb5e34 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -930,7 +930,7 @@ int prepare_binprm(struct linux_binprm * if(!(bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)) { /* Set-uid? */ - if (mode & S_ISUID) { + if (mode & S_ISUID && capable(CAP_REG_SXID)) { bprm->is_suid = 1; current->personality &= ~PER_CLEAR_ON_SETID; bprm->e_uid = inode->i_uid; @@ -942,7 +942,8 @@ int prepare_binprm(struct linux_binprm * * is a candidate for mandatory locking, not a setgid * executable. */ - if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { + if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP) + && capable(CAP_REG_SXID)) { bprm->is_sgid = 1; current->personality &= ~PER_CLEAR_ON_SETID; bprm->e_gid = inode->i_gid; @@ -1137,6 +1138,8 @@ int do_execve(char * filename, int retval; int i; + if (!capable(CAP_REG_EXEC)) + return -EPERM; retval = -ENOMEM; bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); if (!bprm) diff --git a/fs/open.c b/fs/open.c index 303f06d..3d1fc1c 100644 --- a/fs/open.c +++ b/fs/open.c @@ -1104,7 +1104,10 @@ asmlinkage long sys_open(const char __us if (force_o_largefile()) flags |= O_LARGEFILE; - ret = do_sys_open(AT_FDCWD, filename, flags, mode); + if (capable(CAP_REG_OPEN)) + ret = do_sys_open(AT_FDCWD, filename, flags, mode); + else + ret = -EPERM; /* avoid REGPARM breakage on x86: */ prevent_tail_call(ret); return ret; @@ -1119,7 +1122,10 @@ asmlinkage long sys_openat(int dfd, cons if (force_o_largefile()) flags |= O_LARGEFILE; - ret = do_sys_open(dfd, filename, flags, mode); + if (capable(CAP_REG_OPEN)) + ret = do_sys_open(dfd, filename, flags, mode); + else + ret = -EPERM; /* avoid REGPARM breakage on x86: */ prevent_tail_call(ret); return ret; diff --git a/include/linux/capability.h b/include/linux/capability.h index e4f6065..b3a3b27 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -295,6 +295,23 @@ #define CAP_AUDIT_WRITE 29 #define CAP_AUDIT_CONTROL 30 + +/** + ** Regular capabilities (normally possessed by all processes). + **/ + +/* Can fork() */ +#define CAP_REG_FORK 32 + +/* Can open() */ +#define CAP_REG_OPEN 33 + +/* Can exec() */ +#define CAP_REG_EXEC 34 + +/* Might gain permissions on exec() */ +#define CAP_REG_SXID 35 + #ifdef __KERNEL__ /* * Bounding set diff --git a/kernel/fork.c b/kernel/fork.c index f9b014e..20f559f 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1347,6 +1347,8 @@ long do_fork(unsigned long clone_flags, struct pid *pid = alloc_pid(); long nr; + if (!capable(CAP_REG_FORK)) + return -EPERM; if (!pid) return -EAGAIN; nr = pid->nr;