From: David Madore <david.madore@ens.fr>
To: Linux Kernel mailing-list <linux-kernel@vger.kernel.org>,
LSM mailing-list <linux-security-module@vger.kernel.org>
Subject: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities
Date: Sun, 10 Sep 2006 15:42:57 +0200 [thread overview]
Message-ID: <20060910134257.GC12086@clipper.ens.fr> (raw)
In-Reply-To: <20060910133759.GA12086@clipper.ens.fr>
Introduce six new "regular" (=on-by-default) capabilities:
* CAP_REG_FORK, CAP_REG_OPEN, CAP_REG_EXEC allow access to the
fork(), open() and exec() syscalls,
* CAP_REG_SXID allows privilege gain on suid/sgid exec,
* CAP_REG_WRITE controls any write-access to the filesystem,
* CAP_REG_PTRACE allows ptrace().
See <URL: http://www.madore.org/~david/linux/newcaps/ > for more
detailed explanations.
Signed-off-by: David A. Madore <david.madore@ens.fr>
---
fs/exec.c | 4 ++
include/linux/binfmts.h | 1
include/linux/securebits.h | 4 ++
kernel/capability.c | 2 -
security/commoncap.c | 90 ++++++++++++++++++++++++++++++--------------
5 files changed, 72 insertions(+), 29 deletions(-)
diff --git a/fs/exec.c b/fs/exec.c
index 54135df..e4d0a2c 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -925,10 +925,13 @@ int prepare_binprm(struct linux_binprm *
bprm->e_uid = current->euid;
bprm->e_gid = current->egid;
+ bprm->is_suid = 0;
+ bprm->is_sgid = 0;
if(!(bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)) {
/* Set-uid? */
if (mode & S_ISUID) {
+ bprm->is_suid = 1;
current->personality &= ~PER_CLEAR_ON_SETID;
bprm->e_uid = inode->i_uid;
}
@@ -940,6 +943,7 @@ int prepare_binprm(struct linux_binprm *
* executable.
*/
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
+ bprm->is_sgid = 1;
current->personality &= ~PER_CLEAR_ON_SETID;
bprm->e_gid = inode->i_gid;
}
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index c1e82c5..c7fb183 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -29,6 +29,7 @@ struct linux_binprm{
struct file * file;
int e_uid, e_gid;
kernel_cap_t cap_inheritable, cap_permitted, cap_effective;
+ char is_suid, is_sgid;
void *security;
int argc, envc;
char * filename; /* Name of binary as seen by procps */
diff --git a/include/linux/securebits.h b/include/linux/securebits.h
index 5b06178..0092332 100644
--- a/include/linux/securebits.h
+++ b/include/linux/securebits.h
@@ -18,6 +18,10 @@ #define SECURE_NOROOT 0
privileges. When unset, setuid doesn't change privileges. */
#define SECURE_NO_SETUID_FIXUP 2
+/* When set, exec()ing a suid/sgid program does not force reinstate
+ all "regular" capabilities. */
+#define SECURE_NO_SXID_SANITIZE 4
+
/* Each securesetting is implemented using two bits. One bit specify
whether the setting is on or off. The other bit specify whether the
setting is fixed or not. A setting which is fixed cannot be changed
diff --git a/kernel/capability.c b/kernel/capability.c
index 32b2521..2bb802a 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -15,7 +15,7 @@ #include <linux/syscalls.h>
#include <asm/uaccess.h>
unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */
-kernel_cap_t cap_bset = CAP_INIT_EFF_SET;
+kernel_cap_t cap_bset = CAP_INIT_INH_SET;
EXPORT_SYMBOL(securebits);
EXPORT_SYMBOL(cap_bset);
diff --git a/security/commoncap.c b/security/commoncap.c
index 91dc53d..291a4bd 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -12,6 +12,7 @@ #include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/security.h>
+#include <linux/securebits.h>
#include <linux/file.h>
#include <linux/mm.h>
#include <linux/mman.h>
@@ -97,6 +98,8 @@ int cap_capset_check (struct task_struct
if (!cap_issubset (*effective, *permitted)) {
return -EPERM;
}
+ /* we allow Inheritable not to be a subset of Permitted:
+ * cap_capset_set will intersect them anyway */
return 0;
}
@@ -105,7 +108,7 @@ void cap_capset_set (struct task_struct
kernel_cap_t *inheritable, kernel_cap_t *permitted)
{
target->cap_effective = *effective;
- target->cap_inheritable = *inheritable;
+ target->cap_inheritable = cap_intersect (*permitted, *inheritable);
target->cap_permitted = *permitted;
}
@@ -114,39 +117,66 @@ int cap_bprm_set_security (struct linux_
/* Copied from fs/exec.c:prepare_binprm. */
/* We don't have VFS support for capabilities yet */
- cap_clear (bprm->cap_inheritable);
+ cap_set_full (bprm->cap_inheritable);
cap_clear (bprm->cap_permitted);
- cap_clear (bprm->cap_effective);
+ cap_set_full (bprm->cap_effective);
+
+ /* Sanitize caps for all suid/sgid programs. */
+ if (!issecure (SECURE_NO_SXID_SANITIZE) && (bprm->is_suid
+ || bprm->is_sgid)) {
+ /* Ensure that they get _at least_ regular caps. */
+ bprm->cap_permitted = CAP_REGULAR_SET;
+ if ((current->uid != 0 && current->euid != 0
+ && current->suid != 0)
+ || issecure (SECURE_NOROOT)) {
+ /* Ensure that they don't get _more_ caps when they
+ might not expect it. Note that dropping
+ capabilities on change of ?uid from ==0 to !=0 will
+ be handled by cap_task_post_setuid() called from
+ cap_bprm_apply_creds() below. Yuck!!!!!! This is
+ soooooo ugly! */
+ bprm->cap_inheritable = CAP_REGULAR_SET;
+ bprm->cap_effective = CAP_REGULAR_SET;
+ }
+ }
/* To support inheritance of root-permissions and suid-root
* executables under compatibility mode, we raise all three
* capability sets for the file.
- *
- * If only the real uid is 0, we only raise the inheritable
- * and permitted sets of the executable file.
*/
-
if (!issecure (SECURE_NOROOT)) {
- if (bprm->e_uid == 0 || current->uid == 0) {
+ if (bprm->is_suid && bprm->e_uid == 0) {
cap_set_full (bprm->cap_inheritable);
cap_set_full (bprm->cap_permitted);
- }
- if (bprm->e_uid == 0)
cap_set_full (bprm->cap_effective);
+ }
}
+
return 0;
}
void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
{
/* Derived from fs/exec.c:compute_creds. */
- kernel_cap_t new_permitted, working;
+ kernel_cap_t new_permitted, new_effective, working;
+ uid_t old_ruid, old_euid, old_suid;
+ /* P'(per) = (P(inh) & F(inh)) | (F(per) & bset) */
new_permitted = cap_intersect (bprm->cap_permitted, cap_bset);
working = cap_intersect (bprm->cap_inheritable,
current->cap_inheritable);
new_permitted = cap_combine (new_permitted, working);
+ /* P'(eff) = (P(inh) & P(eff) & F(inh)) | (F(per) & F(eff) & bset) */
+ new_effective = cap_intersect (bprm->cap_permitted, bprm->cap_effective);
+ new_effective = cap_intersect (new_effective, cap_bset);
+ working = cap_intersect (bprm->cap_inheritable,
+ current->cap_effective);
+ working = cap_intersect (working, current->cap_inheritable);
+ new_effective = cap_combine (new_effective, working);
+
+ /* P'(inh) = P'(per) */
+
if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
!cap_issubset (new_permitted, current->cap_permitted)) {
current->mm->dumpable = suid_dumpable;
@@ -159,36 +189,37 @@ void cap_bprm_apply_creds (struct linux_
if (!capable (CAP_SETPCAP)) {
new_permitted = cap_intersect (new_permitted,
current->cap_permitted);
+ new_effective = cap_intersect (new_permitted,
+ new_effective);
}
}
}
+ old_ruid = current->uid;
+ old_euid = current->euid;
+ old_suid = current->suid;
current->suid = current->euid = current->fsuid = bprm->e_uid;
current->sgid = current->egid = current->fsgid = bprm->e_gid;
- /* For init, we want to retain the capabilities set
- * in the init_task struct. Thus we skip the usual
- * capability rules */
- if (current->pid != 1) {
- current->cap_permitted = new_permitted;
- current->cap_effective =
- cap_intersect (new_permitted, bprm->cap_effective);
- }
-
- /* AUD: Audit candidate if current->cap_effective is set */
+ current->cap_permitted = new_permitted;
+ current->cap_effective = new_effective;
+ current->cap_inheritable = new_permitted;
current->keep_capabilities = 0;
+ /* Make sure we drop capabilities if required by suid. */
+ cap_task_post_setuid (old_ruid, old_euid, old_suid, LSM_SETID_RES);
+
+ /* AUD: Audit candidate if current->cap_effective is set */
}
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);
+ test between the old and new capability sets. */
+ return ((bprm->is_suid || bprm->is_sgid)
+ && !cap_issubset (bprm->cap_permitted,
+ current->cap_permitted));
}
int cap_inode_setxattr(struct dentry *dentry, char *name, void *value,
@@ -253,12 +284,15 @@ static inline void cap_emulate_setxuid (
= cap_intersect (current->cap_effective,
CAP_REGULAR_SET);
}
+ current->cap_inheritable
+ = cap_intersect (current->cap_inheritable,
+ CAP_REGULAR_SET);
}
- if (old_euid == 0 && current->euid != 0) {
+ if (old_euid == 0 && current->euid != 0 && !current->keep_capabilities) {
current->cap_effective = cap_intersect (current->cap_effective,
CAP_REGULAR_SET);
}
- if (old_euid != 0 && current->euid == 0) {
+ if (old_euid != 0 && current->euid == 0 && !current->keep_capabilities) {
current->cap_effective = current->cap_permitted;
}
}
next prev parent reply other threads:[~2006-09-10 13:43 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-09-10 13:37 [PATCH 1/4] security: capabilities patch (version 0.4.4), part 1/4: enlarge capability sets David Madore
2006-09-10 13:41 ` [PATCH 2/4] security: capabilities patch (version 0.4.4), part 2/4: change inheritance semantics David Madore
2006-09-10 13:42 ` David Madore [this message]
2006-09-10 16:23 ` [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities Alan Cox
2006-09-10 16:09 ` David Madore
2006-09-11 8:06 ` James Morris
2006-09-11 12:03 ` Joshua Brindle
2006-09-11 16:22 ` Casey Schaufler
2006-09-17 18:06 ` Pavel Machek
2006-09-10 17:56 ` Joshua Brindle
2006-09-10 20:03 ` David Madore
2006-09-11 6:10 ` Jan Engelhardt
2006-09-11 6:51 ` David Madore
2006-09-11 13:42 ` Stephen Smalley
2006-09-17 18:14 ` Pavel Machek
2006-09-17 20:39 ` Joshua Brindle
2006-09-17 21:16 ` David Madore
2006-09-18 11:46 ` Joshua Brindle
2006-09-18 11:58 ` David Madore
2006-09-18 12:04 ` Pavel Machek
2006-09-18 12:12 ` Joshua Brindle
2006-09-18 16:02 ` Casey Schaufler
2006-09-19 0:25 ` Joshua Brindle
2006-09-19 3:46 ` Casey Schaufler
2006-09-19 4:09 ` Joshua Brindle
2006-09-19 15:54 ` Casey Schaufler
2006-09-19 18:27 ` Pavel Machek
2006-09-10 13:44 ` David Madore
2006-09-10 13:46 ` [PATCH 4/4] security: capabilities patch (version 0.4.4), part 4/4: add filesystem support David Madore
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20060910134257.GC12086@clipper.ens.fr \
--to=david.madore@ens.fr \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.