2006-09-10 13:38:05

by David Madore

[permalink] [raw]
Subject: [PATCH 1/4] security: capabilities patch (version 0.4.4), part 1/4: enlarge capability sets


Increase the size of capability sets to 64 bits:

* bits 32-47 are "regular", i.e., present by default on non-root
processes;

* maintain compatibility with former kernel interface for capset()
and capget().

See <URL: http://www.madore.org/~david/linux/newcaps/ > for more
detailed explanations.

Signed-off-by: David A. Madore <[email protected]>

---
fs/open.c | 3 ++-
fs/proc/array.c | 6 +++---
include/linux/capability.h | 30 ++++++++++++++++++-----------
kernel/capability.c | 46 +++++++++++++++++++++++++++++++++++---------
security/commoncap.c | 16 +++++++++++----
security/dummy.c | 6 +++---
6 files changed, 75 insertions(+), 32 deletions(-)

diff --git a/fs/open.c b/fs/open.c
index 303f06d..e58a525 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -515,7 +515,8 @@ asmlinkage long sys_faccessat(int dfd, c
* but we cannot because user_path_walk can sleep.
*/
if (current->uid)
- cap_clear(current->cap_effective);
+ current->cap_effective = cap_intersect(current->cap_effective,
+ CAP_REGULAR_SET);
else
current->cap_effective = current->cap_permitted;

diff --git a/fs/proc/array.c b/fs/proc/array.c
index 0b615d6..6724fc2 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -285,9 +285,9 @@ static inline char * task_sig(struct tas

static inline char *task_cap(struct task_struct *p, char *buffer)
{
- return buffer + sprintf(buffer, "CapInh:\t%016x\n"
- "CapPrm:\t%016x\n"
- "CapEff:\t%016x\n",
+ return buffer + sprintf(buffer, "CapInh:\t%016llx\n"
+ "CapPrm:\t%016llx\n"
+ "CapEff:\t%016llx\n",
cap_t(p->cap_inheritable),
cap_t(p->cap_permitted),
cap_t(p->cap_effective));
diff --git a/include/linux/capability.h b/include/linux/capability.h
index 6548b35..aa00b60 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -27,7 +27,8 @@ #include <linux/compiler.h>
library since the draft standard requires the use of malloc/free
etc.. */

-#define _LINUX_CAPABILITY_VERSION 0x19980330
+#define _LINUX_CAPABILITY_VERSION 0x20060903
+#define _LINUX_CAPABILITY_OLD_VERSION 0x19980330

typedef struct __user_cap_header_struct {
__u32 version;
@@ -35,10 +36,16 @@ typedef struct __user_cap_header_struct
} __user *cap_user_header_t;

typedef struct __user_cap_data_struct {
+ __u64 effective;
+ __u64 permitted;
+ __u64 inheritable;
+} __user *cap_user_data_t;
+
+typedef struct __user_cap_data_old_struct {
__u32 effective;
__u32 permitted;
__u32 inheritable;
-} __user *cap_user_data_t;
+} __user *cap_user_data_old_t;

#ifdef __KERNEL__

@@ -50,12 +57,12 @@ #include <asm/current.h>
#ifdef STRICT_CAP_T_TYPECHECKS

typedef struct kernel_cap_struct {
- __u32 cap;
+ __u64 cap;
} kernel_cap_t;

#else

-typedef __u32 kernel_cap_t;
+typedef __u64 kernel_cap_t;

#endif

@@ -310,12 +317,13 @@ #define cap_t(x) (x)

#endif

-#define CAP_EMPTY_SET to_cap_t(0)
-#define CAP_FULL_SET to_cap_t(~0)
-#define CAP_INIT_EFF_SET to_cap_t(~0 & ~CAP_TO_MASK(CAP_SETPCAP))
-#define CAP_INIT_INH_SET to_cap_t(0)
+#define CAP_EMPTY_SET to_cap_t(0ULL)
+#define CAP_FULL_SET to_cap_t(~0ULL)
+#define CAP_REGULAR_SET to_cap_t(0x0000ffff00000000ULL)
+#define CAP_INIT_EFF_SET to_cap_t(~0ULL)
+#define CAP_INIT_INH_SET to_cap_t(~0ULL)

-#define CAP_TO_MASK(x) (1 << (x))
+#define CAP_TO_MASK(x) (1ULL << (x))
#define cap_raise(c, flag) (cap_t(c) |= CAP_TO_MASK(flag))
#define cap_lower(c, flag) (cap_t(c) &= ~CAP_TO_MASK(flag))
#define cap_raised(c, flag) (cap_t(c) & CAP_TO_MASK(flag))
@@ -351,8 +359,8 @@ static inline kernel_cap_t cap_invert(ke
#define cap_isclear(c) (!cap_t(c))
#define cap_issubset(a,set) (!(cap_t(a) & ~cap_t(set)))

-#define cap_clear(c) do { cap_t(c) = 0; } while(0)
-#define cap_set_full(c) do { cap_t(c) = ~0; } while(0)
+#define cap_clear(c) do { cap_t(c) = 0ULL; } while(0)
+#define cap_set_full(c) do { cap_t(c) = ~0ULL; } while(0)
#define cap_mask(c,mask) do { cap_t(c) &= cap_t(mask); } while(0)

#define cap_is_fs_cap(c) (CAP_TO_MASK(c) & CAP_FS_MASK)
diff --git a/kernel/capability.c b/kernel/capability.c
index c7685ad..32b2521 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -52,7 +52,8 @@ asmlinkage long sys_capget(cap_user_head
if (get_user(version, &header->version))
return -EFAULT;

- if (version != _LINUX_CAPABILITY_VERSION) {
+ if (version != _LINUX_CAPABILITY_VERSION
+ && version != _LINUX_CAPABILITY_OLD_VERSION) {
if (put_user(_LINUX_CAPABILITY_VERSION, &header->version))
return -EFAULT;
return -EINVAL;
@@ -82,8 +83,18 @@ out:
read_unlock(&tasklist_lock);
spin_unlock(&task_capability_lock);

- if (!ret && copy_to_user(dataptr, &data, sizeof data))
- return -EFAULT;
+ if (!ret) {
+ if (version == _LINUX_CAPABILITY_OLD_VERSION) {
+ struct __user_cap_data_old_struct data_old;
+ data_old.effective = data_old.effective & 0xffffffffULL;
+ data_old.permitted = data_old.permitted & 0xffffffffULL;
+ data_old.inheritable = data_old.inheritable & 0xffffffffULL;
+ if (copy_to_user(dataptr, &data_old, sizeof data_old))
+ return -EFAULT;
+ } else
+ if (copy_to_user(dataptr, &data, sizeof data))
+ return -EFAULT;
+ }

return ret;
}
@@ -179,7 +190,8 @@ asmlinkage long sys_capset(cap_user_head
if (get_user(version, &header->version))
return -EFAULT;

- if (version != _LINUX_CAPABILITY_VERSION) {
+ if (version != _LINUX_CAPABILITY_VERSION
+ && version != _LINUX_CAPABILITY_OLD_VERSION) {
if (put_user(_LINUX_CAPABILITY_VERSION, &header->version))
return -EFAULT;
return -EINVAL;
@@ -191,10 +203,25 @@ asmlinkage long sys_capset(cap_user_head
if (pid && pid != current->pid && !capable(CAP_SETPCAP))
return -EPERM;

- if (copy_from_user(&effective, &data->effective, sizeof(effective)) ||
- copy_from_user(&inheritable, &data->inheritable, sizeof(inheritable)) ||
- copy_from_user(&permitted, &data->permitted, sizeof(permitted)))
- return -EFAULT;
+ if (version == _LINUX_CAPABILITY_OLD_VERSION) {
+ const cap_user_data_old_t data2 = (void *)data;
+ __u32 w;
+ /* Assume caller wants to keep all regular caps and clear
+ * all unknown additional caps. Is this right? */
+ if (copy_from_user(&w, &data2->effective, sizeof(w)))
+ return -EFAULT;
+ effective = (__u64)w | CAP_REGULAR_SET;
+ if (copy_from_user(&w, &data2->inheritable, sizeof(w)))
+ return -EFAULT;
+ inheritable = (__u64)w | CAP_REGULAR_SET;
+ if (copy_from_user(&w, &data2->permitted, sizeof(w)))
+ return -EFAULT;
+ permitted = (__u64)w | CAP_REGULAR_SET;
+ } else
+ if (copy_from_user(&effective, &data->effective, sizeof(effective)) ||
+ copy_from_user(&inheritable, &data->inheritable, sizeof(inheritable)) ||
+ copy_from_user(&permitted, &data->permitted, sizeof(permitted)))
+ return -EFAULT;

spin_lock(&task_capability_lock);
read_lock(&tasklist_lock);
@@ -237,7 +264,8 @@ out:
int __capable(struct task_struct *t, int cap)
{
if (security_capable(t, cap) == 0) {
- t->flags |= PF_SUPERPRIV;
+ if (!cap_raised(CAP_REGULAR_SET, cap))
+ t->flags |= PF_SUPERPRIV;
return 1;
}
return 0;
diff --git a/security/commoncap.c b/security/commoncap.c
index f50fc29..91dc53d 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -244,13 +244,19 @@ static inline void cap_emulate_setxuid (
int old_suid)
{
if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
- (current->uid != 0 && current->euid != 0 && current->suid != 0) &&
- !current->keep_capabilities) {
- cap_clear (current->cap_permitted);
- cap_clear (current->cap_effective);
+ (current->uid != 0 && current->euid != 0 && current->suid != 0)) {
+ if (!current->keep_capabilities) {
+ current->cap_permitted
+ = cap_intersect (current->cap_permitted,
+ CAP_REGULAR_SET);
+ current->cap_effective
+ = cap_intersect (current->cap_effective,
+ CAP_REGULAR_SET);
+ }
}
if (old_euid == 0 && current->euid != 0) {
- cap_clear (current->cap_effective);
+ current->cap_effective = cap_intersect (current->cap_effective,
+ CAP_REGULAR_SET);
}
if (old_euid != 0 && current->euid == 0) {
current->cap_effective = current->cap_permitted;
diff --git a/security/dummy.c b/security/dummy.c
index 58c6d39..572a15b 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -37,11 +37,11 @@ static int dummy_ptrace (struct task_str
static int dummy_capget (struct task_struct *target, kernel_cap_t * effective,
kernel_cap_t * inheritable, kernel_cap_t * permitted)
{
- *effective = *inheritable = *permitted = 0;
+ *effective = *inheritable = *permitted = CAP_REGULAR_SET;
if (!issecure(SECURE_NOROOT)) {
if (target->euid == 0) {
- *permitted |= (~0 & ~CAP_FS_MASK);
- *effective |= (~0 & ~CAP_TO_MASK(CAP_SETPCAP) & ~CAP_FS_MASK);
+ *permitted |= (CAP_FULL_SET & ~CAP_FS_MASK);
+ *effective |= (CAP_FULL_SET & ~CAP_TO_MASK(CAP_SETPCAP) & ~CAP_FS_MASK);
}
if (target->fsuid == 0) {
*permitted |= CAP_FS_MASK;


2006-09-10 13:41:07

by David Madore

[permalink] [raw]
Subject: [PATCH 2/4] security: capabilities patch (version 0.4.4), part 2/4: change inheritance semantics


Make capabilities inheritable by default. The following remarks
apply:

* executables are assumed by default to have a full set of
"inheritable" (allowed) and "effective" capabilities,

* w.r.t. capabilities(7)-documented behavior, inheritance of the
effective bits is changed (use P(eff) rather than F(eff) in half
of the formula),

* also, inheritance of the inheritable set is based on the new
permitted set rather than on the old inheritable.

Capability sets are now sanitized upon suid/sgid exec (even non-root).

See <URL: http://www.madore.org/~david/linux/newcaps/ > for more
detailed explanations.

Signed-off-by: David A. Madore <[email protected]>

---
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;
}
}

2006-09-10 13:43:00

by David Madore

[permalink] [raw]
Subject: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities


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 <[email protected]>

---
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;
}
}

2006-09-10 13:45:04

by David Madore

[permalink] [raw]
Subject: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities


[Sorry! Previous mail had the wrong patch... This one is correct.]

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 <[email protected]>

---
fs/exec.c | 5 +++++
fs/namei.c | 2 +-
fs/open.c | 26 ++++++++++++++++++++------
fs/xattr.c | 3 ++-
include/linux/capability.h | 23 +++++++++++++++++++++++
kernel/fork.c | 2 ++
kernel/ptrace.c | 2 ++
7 files changed, 55 insertions(+), 8 deletions(-)

diff --git a/fs/exec.c b/fs/exec.c
index e4d0a2c..1a7ff92 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -929,6 +929,9 @@ int prepare_binprm(struct linux_binprm *
bprm->is_sgid = 0;

if(!(bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)) {
+ if (!capable(CAP_REG_SXID))
+ return -EPERM;
+
/* Set-uid? */
if (mode & S_ISUID) {
bprm->is_suid = 1;
@@ -1137,6 +1140,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/namei.c b/fs/namei.c
index 432d6bc..69a3bae 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -242,7 +242,7 @@ int permission(struct inode *inode, int
/*
* Nobody gets write access to an immutable file.
*/
- if (IS_IMMUTABLE(inode))
+ if (IS_IMMUTABLE(inode) || !capable(CAP_REG_WRITE))
return -EACCES;
}

diff --git a/fs/open.c b/fs/open.c
index e58a525..77a12ba 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -253,7 +253,7 @@ static long do_sys_truncate(const char _
goto dput_and_out;

error = -EPERM;
- if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode) || !capable(CAP_REG_WRITE))
goto dput_and_out;

/*
@@ -382,6 +382,10 @@ asmlinkage long sys_utime(char __user *
if (IS_RDONLY(inode))
goto dput_and_out;

+ error = -EPERM;
+ if (!capable(CAP_REG_WRITE))
+ goto dput_and_out;
+
/* Don't worry, the checks are done in inode_change_ok() */
newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
if (times) {
@@ -439,6 +443,10 @@ long do_utimes(int dfd, char __user *fil
if (IS_RDONLY(inode))
goto dput_and_out;

+ error = -EPERM;
+ if (!capable(CAP_REG_WRITE))
+ goto dput_and_out;
+
/* Don't worry, the checks are done in inode_change_ok() */
newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
if (times) {
@@ -640,7 +648,7 @@ asmlinkage long sys_fchmod(unsigned int
if (IS_RDONLY(inode))
goto out_putf;
err = -EPERM;
- if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode) || !capable(CAP_REG_WRITE))
goto out_putf;
mutex_lock(&inode->i_mutex);
if (mode == (mode_t) -1)
@@ -674,7 +682,7 @@ asmlinkage long sys_fchmodat(int dfd, co
goto dput_and_out;

error = -EPERM;
- if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode) || !capable(CAP_REG_WRITE))
goto dput_and_out;

mutex_lock(&inode->i_mutex);
@@ -711,7 +719,7 @@ static int chown_common(struct dentry *
if (IS_RDONLY(inode))
goto out;
error = -EPERM;
- if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode) || !capable(CAP_REG_WRITE))
goto out;
newattrs.ia_valid = ATTR_CTIME;
if (user != (uid_t) -1) {
@@ -1105,7 +1113,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;
@@ -1120,7 +1131,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/fs/xattr.c b/fs/xattr.c
index c32f15b..33b70ce 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -35,7 +35,8 @@ xattr_permission(struct inode *inode, co
if (mask & MAY_WRITE) {
if (IS_RDONLY(inode))
return -EROFS;
- if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode)
+ || !capable(CAP_REG_WRITE))
return -EPERM;
}

diff --git a/include/linux/capability.h b/include/linux/capability.h
index aa00b60..efc268e 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -295,6 +295,29 @@ #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
+
+/* Perform write access to the filesystem */
+#define CAP_REG_WRITE 36
+
+/* Can use ptrace() */
+#define CAP_REG_PTRACE 37
+
#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;
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 9a111f7..093307d 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -132,6 +132,8 @@ static int may_attach(struct task_struct
/* Don't let security modules deny introspection */
if (task == current)
return 0;
+ if (!capable(CAP_REG_PTRACE))
+ return -EPERM;
if (((current->uid != task->euid) ||
(current->uid != task->suid) ||
(current->uid != task->uid) ||

2006-09-10 13:46:20

by David Madore

[permalink] [raw]
Subject: [PATCH 4/4] security: capabilities patch (version 0.4.4), part 4/4: add filesystem support

Add filesystem support for capabilities. This is controlled by the
security.capability extended attribute.

Originally a merge from <URL: http://lkml.org/lkml/2006/9/6/229 >.

Notes:

* mounting nosuid deactivates the permitted ("forced") set of
capabilities on executables, similarly if no CAP_REG_SXID.

See <URL: http://www.madore.org/~david/linux/newcaps/ > for more
detailed explanations.

Signed-off-by: David A. Madore <[email protected]>

---
include/linux/capability.h | 3 +
include/linux/security.h | 10 ++-
security/Kconfig | 10 +++
security/capability.c | 4 +
security/commoncap.c | 154 ++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 177 insertions(+), 4 deletions(-)

diff --git a/include/linux/capability.h b/include/linux/capability.h
index efc268e..428ccc5 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -295,6 +295,9 @@ #define CAP_AUDIT_WRITE 29

#define CAP_AUDIT_CONTROL 30

+/* Number of low (=system, =additional) caps */
+#define CAP_NUMCAPS_SYS 30
+

/**
** Regular capabilities (normally possessed by all processes).
diff --git a/include/linux/security.h b/include/linux/security.h
index 6bc2aad..265ab00 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -51,6 +51,10 @@ extern int cap_inode_setxattr(struct den
extern int cap_inode_removexattr(struct dentry *dentry, char *name);
extern int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags);
extern void cap_task_reparent_to_init (struct task_struct *p);
+extern int cap_task_kill(struct task_struct *p, struct siginfo *info, int sig, u32 secid);
+extern int cap_task_setscheduler (struct task_struct *p, int policy, struct sched_param *lp);
+extern int cap_task_setioprio (struct task_struct *p, int ioprio);
+extern int cap_task_setnice (struct task_struct *p, int nice);
extern int cap_syslog (int type);
extern int cap_vm_enough_memory (long pages);

@@ -2544,12 +2548,12 @@ static inline int security_task_setgroup

static inline int security_task_setnice (struct task_struct *p, int nice)
{
- return 0;
+ return cap_task_setnice(p, nice);
}

static inline int security_task_setioprio (struct task_struct *p, int ioprio)
{
- return 0;
+ return cap_task_setioprio(p, ioprio);
}

static inline int security_task_getioprio (struct task_struct *p)
@@ -2584,7 +2588,7 @@ static inline int security_task_kill (st
struct siginfo *info, int sig,
u32 secid)
{
- return 0;
+ return cap_task_kill(p, info, sig, secid);
}

static inline int security_task_wait (struct task_struct *p)
diff --git a/security/Kconfig b/security/Kconfig
index 67785df..ce2bac7 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -80,6 +80,16 @@ config SECURITY_CAPABILITIES
This enables the "default" Linux capabilities functionality.
If you are unsure how to answer this question, answer Y.

+config SECURITY_FS_CAPABILITIES
+ bool "Filesystem Capabilities"
+ depends on SECURITY_CAPABILITIES
+ default n
+ help
+ This enables filesystem capabilities, allowing you to give
+ binaries a subset of root's powers without using setuid 0.
+
+ If in doubt, answer N.
+
config SECURITY_ROOTPLUG
tristate "Root Plug Support"
depends on USB && SECURITY
diff --git a/security/capability.c b/security/capability.c
index b868e7e..14cb592 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -40,6 +40,10 @@ static struct security_operations capabi
.inode_setxattr = cap_inode_setxattr,
.inode_removexattr = cap_inode_removexattr,

+ .task_kill = cap_task_kill,
+ .task_setscheduler = cap_task_setscheduler,
+ .task_setioprio = cap_task_setioprio,
+ .task_setnice = cap_task_setnice,
.task_post_setuid = cap_task_post_setuid,
.task_reparent_to_init = cap_task_reparent_to_init,

diff --git a/security/commoncap.c b/security/commoncap.c
index 291a4bd..1988efc 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -24,6 +24,7 @@ #include <linux/netlink.h>
#include <linux/ptrace.h>
#include <linux/xattr.h>
#include <linux/hugetlb.h>
+#include <linux/mount.h>

int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
{
@@ -112,11 +113,55 @@ void cap_capset_set (struct task_struct
target->cap_permitted = *permitted;
}

+#define XATTR_CAPS_SUFFIX "capability"
+#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
+struct vfs_cap_data_struct {
+ __u32 version;
+ __u32 effective;
+ __u32 permitted;
+ __u32 inheritable;
+};
+
+static inline void convert_to_le(struct vfs_cap_data_struct *cap)
+{
+ cap->version = le32_to_cpu(cap->version);
+ cap->effective = le32_to_cpu(cap->effective);
+ cap->permitted = le32_to_cpu(cap->permitted);
+ cap->inheritable = le32_to_cpu(cap->inheritable);
+}
+
+static int check_cap_sanity(struct vfs_cap_data_struct *cap)
+{
+ int i;
+
+ if (cap->version != _LINUX_CAPABILITY_OLD_VERSION)
+ return -EPERM;
+
+ for (i=CAP_NUMCAPS_SYS; i<sizeof(cap->effective); i++) {
+ if (cap->effective & CAP_TO_MASK(i))
+ return -EPERM;
+ }
+ for (i=CAP_NUMCAPS_SYS; i<sizeof(cap->permitted); i++) {
+ if (cap->permitted & CAP_TO_MASK(i))
+ return -EPERM;
+ }
+ for (i=CAP_NUMCAPS_SYS; i<sizeof(cap->inheritable); i++) {
+ if (cap->inheritable & CAP_TO_MASK(i))
+ return -EPERM;
+ }
+
+ return 0;
+}
+
int cap_bprm_set_security (struct linux_binprm *bprm)
{
+ struct dentry *dentry;
+ ssize_t rc;
+ struct vfs_cap_data_struct cap_struct;
+ struct inode *inode;
+
/* Copied from fs/exec.c:prepare_binprm. */

- /* We don't have VFS support for capabilities yet */
cap_set_full (bprm->cap_inheritable);
cap_clear (bprm->cap_permitted);
cap_set_full (bprm->cap_effective);
@@ -152,6 +197,53 @@ int cap_bprm_set_security (struct linux_
}
}

+#ifdef CONFIG_SECURITY_FS_CAPABILITIES
+ /* Locate any VFS capabilities: */
+
+ dentry = dget(bprm->file->f_dentry);
+ inode = dentry->d_inode;
+ if (!inode->i_op || !inode->i_op->getxattr) {
+ dput(dentry);
+ return 0;
+ }
+
+ rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, &cap_struct,
+ sizeof(cap_struct));
+ dput(dentry);
+
+ if (rc == -ENODATA)
+ return 0;
+
+ if (rc < 0) {
+ printk(KERN_NOTICE "%s: Error (%ld) getting xattr\n",
+ __FUNCTION__, (long int)rc);
+ return rc;
+ }
+
+ if (rc != sizeof(cap_struct)) {
+ printk(KERN_NOTICE "%s: got wrong size for getxattr (%ld)\n",
+ __FUNCTION__, (long int)rc);
+ return -EPERM;
+ }
+
+ convert_to_le(&cap_struct);
+ if (check_cap_sanity(&cap_struct))
+ return -EPERM;
+
+ bprm->cap_effective = cap_combine (cap_intersect (bprm->cap_effective,
+ CAP_REGULAR_SET),
+ to_cap_t(cap_struct.effective));
+ bprm->cap_permitted = cap_combine (cap_intersect (bprm->cap_permitted,
+ CAP_REGULAR_SET),
+ to_cap_t(cap_struct.permitted));
+ if (!(bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)
+ || !capable(CAP_REG_SXID)) /* Don't allow to gain privileges! */
+ cap_clear (bprm->cap_permitted);
+ bprm->cap_inheritable = cap_combine (cap_intersect (bprm->cap_inheritable,
+ CAP_REGULAR_SET),
+ to_cap_t(cap_struct.inheritable));
+
+#endif
return 0;
}

@@ -340,6 +432,62 @@ int cap_task_post_setuid (uid_t old_ruid
return 0;
}

+/*
+ * Rationale: code calling task_setscheduler, task_setioprio, and
+ * task_setnice, assumes that
+ * . if capable(cap_sys_nice), then those actions should be allowed
+ * . if not capable(cap_sys_nice), but acting on your own processes,
+ * then those actions should be allowed
+ * This is insufficient now since you can call code without suid, but
+ * yet with increased caps.
+ * So we check for increased caps on the target process.
+ */
+static inline int cap_safe_nice(struct task_struct *p)
+{
+ if (!cap_issubset(p->cap_permitted, current->cap_permitted) &&
+ !__capable(current, CAP_SYS_NICE))
+ return -EPERM;
+ return 0;
+}
+
+int cap_task_setscheduler (struct task_struct *p, int policy,
+ struct sched_param *lp)
+{
+ return cap_safe_nice(p);
+}
+
+int cap_task_setioprio (struct task_struct *p, int ioprio)
+{
+ return cap_safe_nice(p);
+}
+
+int cap_task_setnice (struct task_struct *p, int nice)
+{
+ return cap_safe_nice(p);
+}
+
+int cap_task_kill(struct task_struct *p, struct siginfo *info,
+ int sig, u32 secid)
+{
+ if (info != SEND_SIG_NOINFO && (is_si_special(info) || SI_FROMKERNEL(info)))
+ return 0;
+
+ if (secid)
+ /*
+ * Signal sent as a particular user.
+ * Capabilities are ignored. May be wrong, but it's the
+ * only thing we can do at the moment.
+ * Used only by usb drivers?
+ */
+ return 0;
+ if (capable(CAP_KILL))
+ return 0;
+ if (cap_issubset(p->cap_permitted, current->cap_permitted))
+ return 0;
+
+ return -EPERM;
+}
+
void cap_task_reparent_to_init (struct task_struct *p)
{
p->cap_effective = CAP_INIT_EFF_SET;
@@ -377,6 +525,10 @@ EXPORT_SYMBOL(cap_bprm_secureexec);
EXPORT_SYMBOL(cap_inode_setxattr);
EXPORT_SYMBOL(cap_inode_removexattr);
EXPORT_SYMBOL(cap_task_post_setuid);
+EXPORT_SYMBOL(cap_task_kill);
+EXPORT_SYMBOL(cap_task_setscheduler);
+EXPORT_SYMBOL(cap_task_setioprio);
+EXPORT_SYMBOL(cap_task_setnice);
EXPORT_SYMBOL(cap_task_reparent_to_init);
EXPORT_SYMBOL(cap_syslog);
EXPORT_SYMBOL(cap_vm_enough_memory);

2006-09-10 16:00:04

by Alan

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities

Ar Sul, 2006-09-10 am 15:42 +0200, ysgrifennodd David Madore:
> 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_EXEC seems meaningless, I can do the same with mmap by hand for
most types of binary execution except setuid (which is separate it
seems)

Given the capability model is accepted as inferior to things like
SELinux policies why do we actually want to fix this anyway. It's
unfortunate we can't discard the existing capabilities model (which has
flaws) as well really.

Alan

2006-09-10 16:09:56

by David Madore

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities

On Sun, Sep 10, 2006 at 05:23:13PM +0100, Alan Cox wrote:
> CAP_REG_EXEC seems meaningless, I can do the same with mmap by hand for
> most types of binary execution except setuid (which is separate it
> seems)

Actually I meant those caps to be more of a proof of concept than as a
really useful set, so I have nothing against CAP_REG_EXEC being
deleted. However, it still performs one (small) function even in the
absence of suid/sgid executables: you can execute files with omde --x
which you can't do with mmap(). (Also, I'm not 100% sure the kernel
doesn't do some magic things on exec(), perhaps some magic forms of
accounting or whatever, which you couldn't do with mmap().)

> Given the capability model is accepted as inferior to things like
> SELinux policies why do we actually want to fix this anyway. It's
> unfortunate we can't discard the existing capabilities model (which has
> flaws) as well really.

Can a non-root user create limited-rights processes without assistance
from the sysadmin, under SElinux? I was under the impression that it
wasn't the case. Also, SElinux is immensely more difficult to
understand and operate with than a mere set of capabilities: and I
think that simplicity is (sometimes) of value.

--
David A. Madore
([email protected],
http://www.madore.org/~david/ )

2006-09-10 17:56:50

by Joshua Brindle

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities

Alan Cox wrote:
> Ar Sul, 2006-09-10 am 15:42 +0200, ysgrifennodd David Madore:
>
>> 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_EXEC seems meaningless, I can do the same with mmap by hand for
> most types of binary execution except setuid (which is separate it
> seems)
>
> Given the capability model is accepted as inferior to things like
> SELinux policies why do we actually want to fix this anyway. It's
> unfortunate we can't discard the existing capabilities model (which has
> flaws) as well really.
>
>
To expand on this a little, some of the capabilities you are looking to
add are of very little if any use without being able to specify objects.
For example, CAP_REG_OPEN is whether the process can open any file
instead of specific ones. How many applications open no files whatsoever
in practice? Even if there are some as soon as they change and need to
open a file they'll need this capability and will be able to open any.
CAP_REG_WRITE has the same problem. For a description of why
CAP_REG_EXEC is meaningless see the digsig thread on the LSM list from
earlier this year.

Further, adding more capabilities would likely make existing LSM's (like
SELinux) deal with them. Since most LSM's already handle these
permissions on a per-object basis these will be entirely redundant and
more disruptive than useful.

Additionally since dropping capabilities is entirely discretionary and
applications would be modified to actually drop the capabilities I can't
ever see this being used in practice. It also embeds the policy into
applications spread across the filesystem instead of having a
centralized policy. Since these are non-standard capabilities any
application modified to take advantage of them could only do so on Linux.

2006-09-10 20:03:49

by David Madore

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities

On Sun, Sep 10, 2006 at 01:56:43PM -0400, Joshua Brindle wrote:
> To expand on this a little, some of the capabilities you are looking to
> add are of very little if any use without being able to specify objects.
> For example, CAP_REG_OPEN is whether the process can open any file
> instead of specific ones. How many applications open no files whatsoever
> in practice? Even if there are some as soon as they change and need to
> open a file they'll need this capability and will be able to open any.
> CAP_REG_WRITE has the same problem. For a description of why
> CAP_REG_EXEC is meaningless see the digsig thread on the LSM list from
> earlier this year.

CAP_REG_OPEN and CAP_REG_EXEC might be useful only for demonstration
purposes, but I've *often* wished I could run a program without
CAP_REG_WRITE because I wasn't root and I wanted to make *sure* it
didn't write any file anywhere. Instead I had to run them from a
user-mode-linux, which is horribly messy and doesn't work well (and,
at best, with a noticeable slowdown).

Again, I ask: is SElinux useable if you aren't root? (Assuming it's
activated, of course: I mean, can you create new policies to make
certain programs run with restricted privileges?) I thought it
wasn't, but maybe I'm wrong.

--
David A. Madore
([email protected],
http://www.madore.org/~david/ )

2006-09-11 06:12:37

by Jan Engelhardt

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities


>> To expand on this a little, some of the capabilities you are looking to
>> add are of very little if any use without being able to specify objects.
>> For example, CAP_REG_OPEN is whether the process can open any file
>> instead of specific ones. How many applications open no files whatsoever
>> in practice? Even if there are some as soon as they change and need to
>> open a file they'll need this capability and will be able to open any.
>> CAP_REG_WRITE has the same problem. For a description of why
>> CAP_REG_EXEC is meaningless see the digsig thread on the LSM list from
>> earlier this year.
>
>CAP_REG_OPEN and CAP_REG_EXEC might be useful only for demonstration
>purposes, but I've *often* wished I could run a program without

You cannot reasonable run a program without CAP_REG_OPEN, because
ld.so, libc.so and libdl.so all may load a ton of required files
underneath you.

$ strace -e open ls 2>&1 >/dev/null | grep open | wc -l
36



Jan Engelhardt
--

2006-09-11 06:51:16

by David Madore

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities

On Mon, Sep 11, 2006 at 08:10:17AM +0200, Jan Engelhardt wrote:
> You cannot reasonable run a program without CAP_REG_OPEN, because
> ld.so, libc.so and libdl.so all may load a ton of required files
> underneath you.

A program might quite conceivably drop CAP_REG_OPEN willingly once
it's started, or the administrator might use capset() on it once it's
running. But, again, this cap is mostly a proof of concept: the
really useful ones are CAP_REG_WRITE and CAP_REG_SXID.

--
David A. Madore
([email protected],
http://www.madore.org/~david/ )

2006-09-11 08:06:10

by James Morris

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities

On Sun, 10 Sep 2006, David Madore wrote:

> Can a non-root user create limited-rights processes without assistance
> from the sysadmin, under SElinux?

SELinux uses a restrictive model, where privileges can only be removed,
not added.



- James
--
James Morris
<[email protected]>

2006-09-11 12:03:27

by Joshua Brindle

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities

James Morris wrote:
> On Sun, 10 Sep 2006, David Madore wrote:
>
>
>> Can a non-root user create limited-rights processes without assistance
>> from the sysadmin, under SElinux?
>>
>
> SELinux uses a restrictive model, where privileges can only be removed,
> not added.
>
>
I think he was asking if a non-admin user can create processes of less
privilege without becoming root. The answer is yes, however, it is
policy driven. Users will have numerous 'derived' types that are less
privilege than, for example, their interactive shell. For example,
user_irc_t or user_evolution_t. The transitions will happen when the
user runs irc or evolution and those apps will be limited to the rights
they require. These are fine grained though, and mandatory. These
capabilities are so course grained I just can't see anyone ever using them.

2006-09-11 13:40:56

by Stephen Smalley

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities

On Sun, 2006-09-10 at 22:03 +0200, David Madore wrote:
> On Sun, Sep 10, 2006 at 01:56:43PM -0400, Joshua Brindle wrote:
> > To expand on this a little, some of the capabilities you are looking to
> > add are of very little if any use without being able to specify objects.
> > For example, CAP_REG_OPEN is whether the process can open any file
> > instead of specific ones. How many applications open no files whatsoever
> > in practice? Even if there are some as soon as they change and need to
> > open a file they'll need this capability and will be able to open any.
> > CAP_REG_WRITE has the same problem. For a description of why
> > CAP_REG_EXEC is meaningless see the digsig thread on the LSM list from
> > earlier this year.
>
> CAP_REG_OPEN and CAP_REG_EXEC might be useful only for demonstration
> purposes, but I've *often* wished I could run a program without
> CAP_REG_WRITE because I wasn't root and I wanted to make *sure* it
> didn't write any file anywhere. Instead I had to run them from a
> user-mode-linux, which is horribly messy and doesn't work well (and,
> at best, with a noticeable slowdown).
>
> Again, I ask: is SElinux useable if you aren't root? (Assuming it's
> activated, of course: I mean, can you create new policies to make
> certain programs run with restricted privileges?) I thought it
> wasn't, but maybe I'm wrong.

At present, you can't load new policy into the kernel without being
privileged (where privileged == root + SELinux load_policy permission),
but there is ongoing work on a policy management daemon that will enable
delegation of control of portions of the policy to others, including the
ability to enable a user to define subtypes of his own authorized types
with more limited permissions via the already existing hierarchical type
support in the policy language.

In any event, I didn't see anything in your patches to allow SELinux to
continue working with your 64-bit capabilities, and I'm not sure why you
are implementing your changes as a direct patch vs. a new security
module (with additional LSM hooks if truly required, but trying to reuse
existing hooks whenever possible), so that your changes remain optional
at least until proven useful.

I also have to question whether it is a good idea to keep these new
unprivileged "regular" capabilities in the same vectors as the existing
privileged ones, given that they have rather different semantics. Also,
if you want capabilities to be more useful, you likely want to expand
the set of privileged capabilities in the future (e.g. to partition some
of the more coarse-grained ones), and you aren't leaving room for such
expansion. At least for SELinux, we would split them into a separate
security class altogether rather than expanding all access vectors to 64
bits. If you implement your changes in your own security module, then
you can store your regular capability bits in your own security
structure referenced via the security fields, and not have to touch the
base capability fields.

--
Stephen Smalley
National Security Agency

2006-09-11 16:22:36

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities



--- Joshua Brindle <[email protected]> wrote:

> These
> capabilities are so course grained I just can't see
> anyone ever using them.

The granularity of the capabilities in the POSIX
DRAFT is targeted at the security policy enforced
by the POSIX P1003.1 interface standard. Anywhere
that P1003.1 says "appropriate privilege" P1003.1e
identifies what that privilege ought to be. The
capability specification also addresses the audit,
MAC and INF portions of P1003.1e. Interfaces
that were outside the scope of P1003.1 at the
time (including, alas, sockets and SVIPC) could
not be included in P1003.1e by rule. Devices
and filesystems, where most of the granularity
issues arise, were excluded.

The 1e DRAFT specifies a granularity that is
appropriate to the kernel and the policies that
the kernel enforces. This is because the
capability mechanism is supposed to be a kernel
protection scheme for kernel objects.
It does not enforce a granularity that is
appropriate to a python based web interface
for financial management systems. That is an
application issue that is much better suited
to application controls like RBAC.



Casey Schaufler
[email protected]

2006-09-17 19:36:01

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities

Hi!

> >>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_EXEC seems meaningless, I can do the same with mmap by hand for
> >most types of binary execution except setuid (which is separate it
> >seems)
> >
> >Given the capability model is accepted as inferior to things like
> >SELinux policies why do we actually want to fix this anyway. It's
> >unfortunate we can't discard the existing capabilities model (which has
> >flaws) as well really.

> To expand on this a little, some of the capabilities you are looking to
> add are of very little if any use without being able to specify objects.
> For example, CAP_REG_OPEN is whether the process can open any file
> instead of specific ones. How many applications open no files whatsoever
> in practice?

Filters, for example. gzip -9 - and such stuff does not need to open
any files. These should be easy to lock down, and still very useful.

More applications could be made lock-down-aware, and for example ask
master daemon to open files for them over a (already opened) socket.

Pavel

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

2006-09-17 20:39:27

by Joshua Brindle

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities

Pavel Machek wrote:
> Hi!
>
>
>>>> 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_EXEC seems meaningless, I can do the same with mmap by hand for
>>> most types of binary execution except setuid (which is separate it
>>> seems)
>>>
>>> Given the capability model is accepted as inferior to things like
>>> SELinux policies why do we actually want to fix this anyway. It's
>>> unfortunate we can't discard the existing capabilities model (which has
>>> flaws) as well really.
>>>
>
>
>> To expand on this a little, some of the capabilities you are looking to
>> add are of very little if any use without being able to specify objects.
>> For example, CAP_REG_OPEN is whether the process can open any file
>> instead of specific ones. How many applications open no files whatsoever
>> in practice?
>>
>
> Filters, for example. gzip -9 - and such stuff does not need to open
> any files. These should be easy to lock down, and still very useful.
>
> More applications could be made lock-down-aware, and for example ask
> master daemon to open files for them over a (already opened) socket.
>
>
Unlikely.. As Jan pointed out in the last thread anything that links
against glibc does a dozen opens on invocation:
[jbrindle@twoface ~]$ strace -eopen gzip -9 -
open("/usr/lib64/fglrx/tls/x86_64/libc.so.6", O_RDONLY) = -1 ENOENT (No
such file or directory)
open("/usr/lib64/fglrx/tls/libc.so.6", O_RDONLY) = -1 ENOENT (No such
file or directory)
open("/usr/lib64/fglrx/x86_64/libc.so.6", O_RDONLY) = -1 ENOENT (No such
file or directory)
open("/usr/lib64/fglrx/libc.so.6", O_RDONLY) = -1 ENOENT (No such file
or directory)
open("/usr/lib/fglrx/tls/x86_64/libc.so.6", O_RDONLY) = -1 ENOENT (No
such file or directory)
open("/usr/lib/fglrx/tls/libc.so.6", O_RDONLY) = -1 ENOENT (No such file
or directory)
open("/usr/lib/fglrx/x86_64/libc.so.6", O_RDONLY) = -1 ENOENT (No such
file or directory)
open("/usr/lib/fglrx/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or
directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
open("/lib64/libc.so.6", O_RDONLY) = 3
gzip: compressed data not written to a terminal. Use -f to force
compression.
For help, type: gzip -h
Process 17519 detached

this wouldn't be able to run if it couldn't open libc.so so you'd be
limited to static binaries (with statically linked libs that don't do
any open() calls) that don't do any kind of name resolution (ip, uid),
have no config files, etc. very limited.. and my other point was that
even if you did have said binary (the limitations make this very
unlikely though) the binary could never be changed to open a file since
it would then get all open access since capabilities are not fine grained.

The benefits of this are so minuscule and the cost is so high if you are
ever to use it that it simply won't happen..

Joshua Brindle

2006-09-17 21:16:19

by David Madore

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities

On Sun, Sep 17, 2006 at 04:39:16PM -0400, Joshua Brindle wrote:
> The benefits of this are so minuscule and the cost is so high if you are
> ever to use it that it simply won't happen..

I'm withdrawing that patch anyway, in favor of a LSM-style approach,
the "cuppabilities" module (cf. the patch I posted a couple of hours
ago with that word in the title, and I'll be posting a new version in
a day or so, or cf. <URL:
http://www.madore.org/~david/linux/cuppabilities/
>). In this case, the relative cost will be lower since the
security_ops->inode_permission() hook is called no matter what.

But I agree that the value of restricting open() is very dubious and
it was intended mostly as a demonstration. So if there is strong
opposition to this sort of thing, I'll remove it.

Happy hacking,

--
David A. Madore
([email protected],
http://www.madore.org/~david/ )

2006-09-17 21:25:00

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities

Hi!

> >>Can a non-root user create limited-rights processes without assistance
> >>from the sysadmin, under SElinux?
> >
> >SELinux uses a restrictive model, where privileges can only be removed,
> >not added.
> >
> >
> I think he was asking if a non-admin user can create processes of less
> privilege without becoming root. The answer is yes, however, it is
> policy driven. Users will have numerous 'derived' types that are less
> privilege than, for example, their interactive shell. For example,
> user_irc_t or user_evolution_t. The transitions will happen when the
> user runs irc or evolution and those apps will be limited to the rights
> they require. These are fine grained though, and mandatory. These
> capabilities are so course grained I just can't see anyone ever using them.

Andrea already has his "seccomp" thing in kernel.... which is
basically "running without _any_ rights". So yes, this is useful.

Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

2006-09-18 11:44:38

by Joshua Brindle

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities

On Sun, 2006-09-17 at 23:16 +0200, David Madore wrote:
> On Sun, Sep 17, 2006 at 04:39:16PM -0400, Joshua Brindle wrote:
> > The benefits of this are so minuscule and the cost is so high if you are
> > ever to use it that it simply won't happen..
>
> I'm withdrawing that patch anyway, in favor of a LSM-style approach,
> the "cuppabilities" module (cf. the patch I posted a couple of hours
> ago with that word in the title, and I'll be posting a new version in
> a day or so, or cf. <URL:
> http://www.madore.org/~david/linux/cuppabilities/
> >). In this case, the relative cost will be lower since the
> security_ops->inode_permission() hook is called no matter what.
>

You misunderstand. I don't mean the performance cost is high, I mean the
cost of an application to actually be able to run without open() (what I
was saying before, static built, no glibc, no conf files, no name
lookups, etc). I never see this being used in the real world because of
the extreme limitations.

And that is just practical stuff, there are still problems with
embedding policy into binaries all over the system in an entirely
non-analyzable way, and this extends to all capabilities, not just the
open() one.

> But I agree that the value of restricting open() is very dubious and
> it was intended mostly as a demonstration. So if there is strong
> opposition to this sort of thing, I'll remove it.
>
> Happy hacking,
>

2006-09-18 11:58:59

by David Madore

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities

On Mon, Sep 18, 2006 at 07:46:06AM -0400, Joshua Brindle wrote:
> And that is just practical stuff, there are still problems with
> embedding policy into binaries all over the system in an entirely
> non-analyzable way, and this extends to all capabilities, not just the
> open() one.

Some people prefer the policy to be embedded into binaries all over
the system rather than centralized in one place. I think it's just a
question of choice: if you don't like this way of doing things, you
don't have to use it, of course (my "cuppabilities" module would be
entirely optional).

Happy hacking,

--
David A. Madore
([email protected],
http://www.madore.org/~david/ )

2006-09-18 12:04:24

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities

Hi!

> > > The benefits of this are so minuscule and the cost is so high if you are
> > > ever to use it that it simply won't happen..
> >
> > I'm withdrawing that patch anyway, in favor of a LSM-style approach,
> > the "cuppabilities" module (cf. the patch I posted a couple of hours
> > ago with that word in the title, and I'll be posting a new version in
> > a day or so, or cf. <URL:
> > http://www.madore.org/~david/linux/cuppabilities/
> > >). In this case, the relative cost will be lower since the
> > security_ops->inode_permission() hook is called no matter what.
> >
>
> You misunderstand. I don't mean the performance cost is high, I mean the
> cost of an application to actually be able to run without open() (what I
> was saying before, static built, no glibc, no conf files, no name
> lookups, etc). I never see this being used in the real world because of
> the extreme limitations.

It is already being used. See config_seccomp.
Pavel

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

2006-09-18 12:10:41

by Joshua Brindle

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities

On Mon, 2006-09-18 at 14:04 +0200, Pavel Machek wrote:
> Hi!
>
> > > > The benefits of this are so minuscule and the cost is so high if you are
> > > > ever to use it that it simply won't happen..
> > >
> > > I'm withdrawing that patch anyway, in favor of a LSM-style approach,
> > > the "cuppabilities" module (cf. the patch I posted a couple of hours
> > > ago with that word in the title, and I'll be posting a new version in
> > > a day or so, or cf. <URL:
> > > http://www.madore.org/~david/linux/cuppabilities/
> > > >). In this case, the relative cost will be lower since the
> > > security_ops->inode_permission() hook is called no matter what.
> > >
> >
> > You misunderstand. I don't mean the performance cost is high, I mean the
> > cost of an application to actually be able to run without open() (what I
> > was saying before, static built, no glibc, no conf files, no name
> > lookups, etc). I never see this being used in the real world because of
> > the extreme limitations.
>
> It is already being used. See config_seccomp.

Where are the users?

2006-09-18 16:02:19

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities


--- Joshua Brindle <[email protected]> wrote:

> And that is just practical stuff, there are still
> problems with
> embedding policy into binaries all over the system
> in an entirely
> non-analyzable way, and this extends to all
> capabilities, not just the
> open() one.

Your assertion that directly associating
the capabilities with the binary cannot
be analysed is demonstrably incorrect,
reference Common Criteria validation
reports CCEVS-VR-02-0019 and CCEVS-VR-02-0020.

The first system I took through evaluation
(that is, independent 3rd party analysis) stored
security attributes in a file while the second
and third systems attached the attributes
directly (XFS). The 1st evaluation required
5 years, the 2nd 1 year. It is possible that
I just got a lot smarter with age, but I
ascribe a significant amount of the improvement
to the direct association of the attributes
to the file.



Casey Schaufler
[email protected]

2006-09-19 00:25:36

by Joshua Brindle

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities

Casey Schaufler wrote:
> --- Joshua Brindle <[email protected]> wrote:
>
>
>> And that is just practical stuff, there are still
>> problems with
>> embedding policy into binaries all over the system
>> in an entirely
>> non-analyzable way, and this extends to all
>> capabilities, not just the
>> open() one.
>>
>
> Your assertion that directly associating
> the capabilities with the binary cannot
> be analysed is demonstrably incorrect,
> reference Common Criteria validation
> reports CCEVS-VR-02-0019 and CCEVS-VR-02-0020.
>
> The first system I took through evaluation
> (that is, independent 3rd party analysis) stored
> security attributes in a file while the second
> and third systems attached the attributes
> directly (XFS). The 1st evaluation required
> 5 years, the 2nd 1 year. It is possible that
> I just got a lot smarter with age, but I
> ascribe a significant amount of the improvement
> to the direct association of the attributes
> to the file.
Thats great but entirely irrelevant in this context. The patch and caps
in question are not attached to the file via some externally observable
property (eg., xattr) but instead are embedded in the source code so
that it can drop caps at certain points during the execution or before
executing another app, thus unanalyzable.

2006-09-19 03:46:05

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities



--- Joshua Brindle <[email protected]> wrote:


> > The first system I took through evaluation
> > (that is, independent 3rd party analysis) stored
> > security attributes in a file while the second
> > and third systems attached the attributes
> > directly (XFS). The 1st evaluation required
> > 5 years, the 2nd 1 year. It is possible that
> > I just got a lot smarter with age, but I
> > ascribe a significant amount of the improvement
> > to the direct association of the attributes
> > to the file.
> Thats great but entirely irrelevant in this context.
> The patch and caps
> in question are not attached to the file via some
> externally observable
> property (eg., xattr) but instead are embedded in
> the source code so
> that it can drop caps at certain points during the
> execution or before
> executing another app, thus unanalyzable.

Oh that. Sure, we used capability bracketing
in the code, too. That makes it easy to
determine when a capability is active. What,
you don't think that it's possible to analyze
source code? Of course it is. Refer to the
evaluation reports if you don't believe me.


Casey Schaufler
[email protected]

2006-09-19 04:09:53

by Joshua Brindle

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities

Casey Schaufler wrote:
> --- Joshua Brindle <[email protected]> wrote:
>
>>> The first system I took through evaluation
>>> (that is, independent 3rd party analysis) stored
>>> security attributes in a file while the second
>>> and third systems attached the attributes
>>> directly (XFS). The 1st evaluation required
>>> 5 years, the 2nd 1 year. It is possible that
>>> I just got a lot smarter with age, but I
>>> ascribe a significant amount of the improvement
>>> to the direct association of the attributes
>>> to the file.
>>>
>> Thats great but entirely irrelevant in this context.
>> The patch and caps
>> in question are not attached to the file via some
>> externally observable
>> property (eg., xattr) but instead are embedded in
>> the source code so
>> that it can drop caps at certain points during the
>> execution or before
>> executing another app, thus unanalyzable.
>>
>
> Oh that. Sure, we used capability bracketing
> in the code, too. That makes it easy to
> determine when a capability is active. What,
> you don't think that it's possible to analyze
> source code? Of course it is. Refer to the
> evaluation reports if you don't believe me.
>
>
When I see an analysis of every line of source code on an average Linux
machine then I might believe you (if you'll grant that no software can
ever be installed on it afterward without being analyzed) but until then
I'll stick with a centralized policy. I doubt many others will be
satisfied with that limitation.

Bracketing hardly makes it analyzable, how can you possibly know if the
bracketing happened? You *believe* it will and therefore you say that
the bracketed code is safe but in reality this is a discretionary
mechanism and you have zero assurance that there is any security
whatsoever, no thanks, I'll pass.

2006-09-19 15:54:43

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities



--- Joshua Brindle <[email protected]> wrote:

> Casey Schaufler wrote:
> > --- Joshua Brindle <[email protected]> wrote:
> >
> >>> The first system I took through evaluation
> >>> (that is, independent 3rd party analysis) stored
> >>> security attributes in a file while the second
> >>> and third systems attached the attributes
> >>> directly (XFS). The 1st evaluation required
> >>> 5 years, the 2nd 1 year. It is possible that
> >>> I just got a lot smarter with age, but I
> >>> ascribe a significant amount of the improvement
> >>> to the direct association of the attributes
> >>> to the file.
> >>>
> >> Thats great but entirely irrelevant in this
> context.
> >> The patch and caps
> >> in question are not attached to the file via some
> >> externally observable
> >> property (eg., xattr) but instead are embedded in
> >> the source code so
> >> that it can drop caps at certain points during
> the
> >> execution or before
> >> executing another app, thus unanalyzable.
> >>
> >
> > Oh that. Sure, we used capability bracketing
> > in the code, too. That makes it easy to
> > determine when a capability is active. What,
> > you don't think that it's possible to analyze
> > source code? Of course it is. Refer to the
> > evaluation reports if you don't believe me.
> >
> >
> When I see an analysis of every line of source code
> on an average Linux
> machine then I might believe you

Would an above average Unix system suffice?
How about MULTICS?

It's been done for:
Irix and Trusted Irix
Solaris and Trusted Solaris
UNICOS
HP/UX
AIX
SystemV
Xenix

> (if you'll grant
> that no software can
> ever be installed on it afterward without being
> analyzed)

Rubbish. No privileged software can be installed.
Software that runs as a user without capabilities
can be installed freely. It only requires analysis
if it violates policy, which on a system with
POSIX capabilities means running in possession
of capabilities.

> but until then
> I'll stick with a centralized policy.

OK. There is value in containment.

> I doubt many others will be
> satisfied with that limitation.

It's been selling in the marketplace for
the past 20 years.

> Bracketing hardly makes it analyzable, how can you
> possibly know if the
> bracketing happened?

Err, read the code?

> You *believe* it will and
> therefore you say that
> the bracketed code is safe but in reality this is a
> discretionary
> mechanism and you have zero assurance that there is
> any security whatsoever,

Ah, no. You don't seem to understand the concept.

> no thanks, I'll pass.

Probably just as well, all things considered.


Casey Schaufler
[email protected]

2006-09-19 18:27:37

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH 3/4] security: capabilities patch (version 0.4.4), part 3/4: introduce new capabilities

Hi!

> >The first system I took through evaluation
> >(that is, independent 3rd party analysis) stored
> >security attributes in a file while the second
> >and third systems attached the attributes
> >directly (XFS). The 1st evaluation required
> >5 years, the 2nd 1 year. It is possible that
> >I just got a lot smarter with age, but I
> >ascribe a significant amount of the improvement
> >to the direct association of the attributes
> >to the file.
> Thats great but entirely irrelevant in this context. The patch and caps
> in question are not attached to the file via some externally observable
> property (eg., xattr) but instead are embedded in the source code so
> that it can drop caps at certain points during the execution or before
> executing another app, thus unanalyzable.

I do not know why this is unanalyzable... It seems very analyzable
when reading the source code... and actually priviledge
operations in source code mean that you can't get them wrong with
wrong xattrs.

Plus systems like qmail already use setuid() in source this way.

Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html