Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753717AbZL3VPL (ORCPT ); Wed, 30 Dec 2009 16:15:11 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1753369AbZL3VPJ (ORCPT ); Wed, 30 Dec 2009 16:15:09 -0500 Received: from out01.mta.xmission.com ([166.70.13.231]:45781 "EHLO out01.mta.xmission.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753340AbZL3VPF (ORCPT ); Wed, 30 Dec 2009 16:15:05 -0500 To: "Serge E. Hallyn" Cc: "Andrew G. Morgan" , Bryan Donlan , Alan Cox , Benny Amorsen , Michael Stone , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-security-module@vger.kernel.org, Andi Kleen , David Lang , Oliver Hartkopp , Herbert Xu , Valdis Kletnieks , Evgeniy Polyakov , "C. Scott Ananian" , James Morris , Bernie Innocenti , Mark Seaborn , Randy Dunlap , =?utf-8?Q?Am=C3=A9rico?= Wang , Tetsuo Handa , Samir Bellabes , Casey Schaufler , Pavel Machek , Al Viro Subject: [RFC][PATCH v3] Unprivileged: Disable raising of privileges References: <20091229223631.GB22578@us.ibm.com> <3e8340490912291954v5a837a26p64bd776102d281d7@mail.gmail.com> <3e8340490912292057g3e87eaabn115f85b78af2b08c@mail.gmail.com> <551280e50912300652r1007dee0j8de750bf33af9b3c@mail.gmail.com> <20091230183513.GC14493@us.ibm.com> <20091230201712.GA23999@us.ibm.com> From: ebiederm@xmission.com (Eric W. Biederman) Date: Wed, 30 Dec 2009 13:15:01 -0800 In-Reply-To: <20091230201712.GA23999@us.ibm.com> (Serge E. Hallyn's message of "Wed\, 30 Dec 2009 14\:17\:12 -0600") Message-ID: User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.2 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-XM-SPF: eid=;;;mid=;;;hst=in01.mta.xmission.com;;;ip=76.21.114.89;;;frm=ebiederm@xmission.com;;;spf=neutral X-SA-Exim-Connect-IP: 76.21.114.89 X-SA-Exim-Mail-From: ebiederm@xmission.com X-SA-Exim-Scanned: No (on in01.mta.xmission.com); SAEximRunCond expanded to false Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 6332 Lines: 185 If we can know that a process will never raise it's priveleges we can enable a lot of features without privilege (such as unsharing namespaces and unprivileged mounts) that otherwise would be unsafe, because they could break assumptions of existing suid executables. To allow this to be used as a sand boxing feature also disable ptracing other executables without this new restriction. For the moment I have used a per thread flag because we are out of per process flags. To ensure all descendants get this flag I rely on the default copying of procss structures. Added bprm->nosuid to make remove the need to add duplicate error prone checks. This ensures that the disabling of suid executables is exactly the same as MNT_NOSUID. Signed-off-by: Eric W. Biederman --- arch/x86/include/asm/thread_info.h | 2 ++ fs/exec.c | 6 ++++-- include/linux/binfmts.h | 1 + include/linux/prctl.h | 3 +++ kernel/ptrace.c | 4 ++++ kernel/sys.c | 21 +++++++++++++++++++++ security/commoncap.c | 3 +-- security/selinux/hooks.c | 2 +- 8 files changed, 37 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 375c917..e716203 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -82,6 +82,7 @@ struct thread_info { #define TIF_SYSCALL_EMU 6 /* syscall emulation active */ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ #define TIF_SECCOMP 8 /* secure computing */ +#define TIF_NOSUID 9 /* suid exec permanently disabled */ #define TIF_MCE_NOTIFY 10 /* notify userspace of an MCE */ #define TIF_USER_RETURN_NOTIFY 11 /* notify kernel of userspace return */ #define TIF_NOTSC 16 /* TSC is not accessible in userland */ @@ -107,6 +108,7 @@ struct thread_info { #define _TIF_SYSCALL_EMU (1 << TIF_SYSCALL_EMU) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_SECCOMP (1 << TIF_SECCOMP) +#define _TIF_NOSUID (1 << TIF_NOSUID) #define _TIF_MCE_NOTIFY (1 << TIF_MCE_NOTIFY) #define _TIF_USER_RETURN_NOTIFY (1 << TIF_USER_RETURN_NOTIFY) #define _TIF_NOTSC (1 << TIF_NOTSC) diff --git a/fs/exec.c b/fs/exec.c index 632b02e..5cba5ac 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1131,8 +1131,10 @@ int prepare_binprm(struct linux_binprm *bprm) /* clear any previous set[ug]id data from a previous binary */ bprm->cred->euid = current_euid(); bprm->cred->egid = current_egid(); - - if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) { + bprm->nosuid = + (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) || + test_tsk_thread_flag(current, TIF_NOSUID); + if (bprm->nosuid) { /* Set-uid? */ if (mode & S_ISUID) { bprm->per_clear |= PER_CLEAR_ON_SETID; diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index cd4349b..c3b5a30 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -44,6 +44,7 @@ struct linux_binprm{ #ifdef __alpha__ unsigned int taso:1; #endif + unsigned int nosuid:1; /* True if suid bits are ignored */ unsigned int recursion_depth; struct file * file; struct cred *cred; /* new credentials */ diff --git a/include/linux/prctl.h b/include/linux/prctl.h index a3baeb2..8adc517 100644 --- a/include/linux/prctl.h +++ b/include/linux/prctl.h @@ -102,4 +102,7 @@ #define PR_MCE_KILL_GET 34 +#define PR_SET_NOSUID 35 +#define PR_GET_NOSUID 36 + #endif /* _LINUX_PRCTL_H */ diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 23bd09c..b91040c 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -152,6 +152,10 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode) if (!dumpable && !capable(CAP_SYS_PTRACE)) return -EPERM; + if (test_tsk_thread_flag(current, TIF_NOSUID) && + !test_tsk_thread_flag(task, TIF_NOSUID)) + return -EPERM; + return security_ptrace_access_check(task, mode); } diff --git a/kernel/sys.c b/kernel/sys.c index 26a6b73..8731f2a 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1578,6 +1578,27 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, else error = PR_MCE_KILL_DEFAULT; break; + case PR_SET_NOSUID: + { + const struct cred *cred = current->cred; + error = -EINVAL; + /* Don't support cases that could be unsafe */ + if ( (cred->uid != cred->suid) || + (cred->uid != cred->euid) || + (cred->uid != cred->fsuid) || + (cred->gid != cred->sgid) || + (cred->gid != cred->egid) || + (cred->gid != cred->fsgid) || + !cap_isclear(cred->cap_permitted) || + (atomic_read(¤t->signal->count) != 1)) + break; + error = 0; + set_tsk_thread_flag(current, TIF_NOSUID); + break; + } + case PR_GET_NOSUID: + error = !!test_tsk_thread_flag(current, TIF_NOSUID); + break; default: error = -EINVAL; break; diff --git a/security/commoncap.c b/security/commoncap.c index f800fdb..34500e3 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -389,7 +389,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective) if (!file_caps_enabled) return 0; - if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID) + if (bprm->nosuid) return 0; dentry = dget(bprm->file->f_dentry); @@ -868,7 +868,6 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, else new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); goto changed; - default: /* No functionality available - continue with default */ error = -ENOSYS; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 7a374c2..bd77a2b 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2147,7 +2147,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path = bprm->file->f_path; - if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) + if (bprm->nosuid) new_tsec->sid = old_tsec->sid; if (new_tsec->sid == old_tsec->sid) { -- 1.6.5.2.143.g8cc62 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/