[PATCH] Capabilities & Root Core dumps

Alexander Kjeldaas (astor@guardian.no)
Mon, 19 Oct 1998 11:03:29 +0200


--k1lZvvs/B4yU6o8G
Content-Type: text/plain; charset=us-ascii

This patch fixes the following _bugs_:

* Jakub Jelinek noted that on sparc, gcc won't inline the kernel_cap_t
structure when used as return value from an inlined function. This
patch therefore converts to using the same scheme used for pte_t's.

* Root core dumps works. Note that completely removing the isclear()
can be dangerous since it will be possible (with file-system
support) to have an executable "suid" without changing uids during
exec. This should be handeled even if this is an impossible case
today. A better fix is to check whether the new permitted set is a
subset of the old or not - so that's what I did.

astor

-- 
 Alexander Kjeldaas, Guardian Networks AS, Trondheim, Norway
 http://www.guardian.no/

--k1lZvvs/B4yU6o8G Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="patch-cap-fix.1"

diff -ur linux-2.1.125/fs/exec.c l125/fs/exec.c --- linux-2.1.125/fs/exec.c Thu Aug 27 23:30:50 1998 +++ l125/fs/exec.c Mon Oct 19 10:24:27 1998 @@ -702,17 +702,17 @@ void compute_creds(struct linux_binprm *bprm) { + int new_permitted = cap_t(bprm->cap_permitted) | + (cap_t(bprm->cap_inheritable) & + cap_t(current->cap_inheritable)); + /* 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) { - int new_permitted = bprm->cap_permitted.cap | - (bprm->cap_inheritable.cap & - current->cap_inheritable.cap); - - current->cap_permitted.cap = new_permitted; - current->cap_effective.cap = new_permitted & - bprm->cap_effective.cap; + cap_t(current->cap_permitted) = new_permitted; + cap_t(current->cap_effective) = new_permitted & + cap_t(bprm->cap_effective); } /* AUD: Audit candidate if current->cap_effective is set */ @@ -720,7 +720,7 @@ current->suid = current->euid = current->fsuid = bprm->e_uid; current->sgid = current->egid = current->fsgid = bprm->e_gid; if (current->euid != current->uid || current->egid != current->gid || - !cap_isclear(current->cap_permitted)) + !cap_issubset(new_permitted, current->cap_permitted)) current->dumpable = 0; } Only in l125/fs: exec.c~ diff -ur linux-2.1.125/fs/proc/array.c l125/fs/proc/array.c --- linux-2.1.125/fs/proc/array.c Mon Oct 12 12:45:45 1998 +++ l125/fs/proc/array.c Mon Oct 19 09:35:48 1998 @@ -799,9 +799,9 @@ return buffer + sprintf(buffer, "CapInh:\t%016x\n" "CapPrm:\t%016x\n" "CapEff:\t%016x\n", - p->cap_inheritable.cap, - p->cap_permitted.cap, - p->cap_effective.cap); + cap_t(p->cap_inheritable), + cap_t(p->cap_permitted), + cap_t(p->cap_effective)); } diff -ur linux-2.1.125/include/linux/capability.h l125/include/linux/capability.h --- linux-2.1.125/include/linux/capability.h Mon Oct 12 12:56:45 1998 +++ l125/include/linux/capability.h Mon Oct 19 10:25:01 1998 @@ -38,9 +38,19 @@ #ifdef __KERNEL__ +/* #define STRICT_CAP_T_TYPECHECKS */ + +#ifdef STRICT_CAP_T_TYPECHECKS + typedef struct kernel_cap_struct { __u32 cap; } kernel_cap_t; + +#else + +typedef __u32 kernel_cap_t; + +#endif #define _USER_CAP_HEADER_SIZE (2*sizeof(__u32)) #define _KERNEL_CAP_T_SIZE (sizeof(kernel_cap_t)) @@ -259,51 +269,63 @@ /* * Internal kernel functions only */ + +#ifdef STRICT_CAP_T_TYPECHECKS + +#define to_cap_t(x) { x } +#define cap_t(x) (x).cap + +#else + +#define to_cap_t(x) (x) +#define cap_t(x) (x) + +#endif -#define CAP_EMPTY_SET { 0 } -#define CAP_FULL_SET { ~0 } -#define CAP_INIT_EFF_SET { ~0 & ~CAP_TO_MASK(CAP_SETPCAP) } -#define CAP_INIT_INH_SET { ~0 & ~CAP_TO_MASK(CAP_SETPCAP) } +#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 & ~CAP_TO_MASK(CAP_SETPCAP)) #define CAP_TO_MASK(x) (1 << (x)) -#define cap_raise(c, flag) ((c).cap |= CAP_TO_MASK(flag)) -#define cap_lower(c, flag) ((c).cap &= ~CAP_TO_MASK(flag)) -#define cap_raised(c, flag) ((c).cap & CAP_TO_MASK(flag)) +#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)) static inline kernel_cap_t cap_combine(kernel_cap_t a, kernel_cap_t b) { kernel_cap_t dest; - dest.cap = a.cap | b.cap; + cap_t(dest) = cap_t(a) | cap_t(b); return dest; } static inline kernel_cap_t cap_intersect(kernel_cap_t a, kernel_cap_t b) { kernel_cap_t dest; - dest.cap = a.cap & b.cap; + cap_t(dest) = cap_t(a) & cap_t(b); return dest; } static inline kernel_cap_t cap_drop(kernel_cap_t a, kernel_cap_t drop) { kernel_cap_t dest; - dest.cap = a.cap & ~drop.cap; + cap_t(dest) = cap_t(a) & ~cap_t(drop); return dest; } static inline kernel_cap_t cap_invert(kernel_cap_t c) { kernel_cap_t dest; - dest.cap = ~c.cap; + cap_t(dest) = ~cap_t(c); return dest; } -#define cap_isclear(c) (!(c).cap) -#define cap_issubset(a,set) (!((a).cap & ~(set).cap)) +#define cap_isclear(c) (!cap_t(c)) +#define cap_issubset(a,set) (!(cap_t(a) & ~cap_t(set))) -#define cap_clear(c) do { (c).cap = 0; } while(0) -#define cap_set_full(c) do { (c).cap = ~0; } while(0) -#define cap_mask(c,mask) do { (c).cap &= (mask).cap; } while(0) +#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_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 -ur linux-2.1.125/kernel/capability.c l125/kernel/capability.c --- linux-2.1.125/kernel/capability.c Sun Aug 23 20:45:57 1998 +++ l125/kernel/capability.c Mon Oct 19 09:35:48 1998 @@ -61,9 +61,9 @@ } if (!error) { - data.permitted = target->cap_permitted.cap; - data.inheritable = target->cap_inheritable.cap; - data.effective = target->cap_effective.cap; + data.permitted = cap_t(target->cap_permitted); + data.inheritable = cap_t(target->cap_inheritable); + data.effective = cap_t(target->cap_effective); } if (target != current) diff -ur linux-2.1.125/kernel/sys.c l125/kernel/sys.c --- linux-2.1.125/kernel/sys.c Sun Aug 16 01:01:13 1998 +++ l125/kernel/sys.c Mon Oct 19 09:35:48 1998 @@ -586,11 +586,11 @@ if (!issecure(SECURE_NO_SETUID_FIXUP)) { if (old_fsuid == 0 && current->fsuid != 0) { - current->cap_effective.cap &= ~CAP_FS_MASK; + cap_t(current->cap_effective) &= ~CAP_FS_MASK; } if (old_fsuid != 0 && current->fsuid == 0) { - current->cap_effective.cap |= - (current->cap_permitted.cap & CAP_FS_MASK); + cap_t(current->cap_effective) |= + (cap_t(current->cap_permitted) & CAP_FS_MASK); } }

--k1lZvvs/B4yU6o8G--

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/