mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-07-06 06:21:31 +00:00
Add 64-bit capability support to the kernel
The patch supports legacy (32-bit) capability userspace, and where possible translates 32-bit capabilities to/from userspace and the VFS to 64-bit kernel space capabilities. If a capability set cannot be compressed into 32-bits for consumption by user space, the system call fails, with -ERANGE. FWIW libcap-2.00 supports this change (and earlier capability formats) http://www.kernel.org/pub/linux/libs/security/linux-privs/kernel-2.6/ [akpm@linux-foundation.org: coding-syle fixes] [akpm@linux-foundation.org: use get_task_comm()] [ezk@cs.sunysb.edu: build fix] [akpm@linux-foundation.org: do not initialise statics to 0 or NULL] [akpm@linux-foundation.org: unused var] [serue@us.ibm.com: export __cap_ symbols] Signed-off-by: Andrew G. Morgan <morgan@kernel.org> Cc: Stephen Smalley <sds@tycho.nsa.gov> Acked-by: Serge Hallyn <serue@us.ibm.com> Cc: Chris Wright <chrisw@sous-sol.org> Cc: James Morris <jmorris@namei.org> Cc: Casey Schaufler <casey@schaufler-ca.com> Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
8f6936f4d2
commit
e338d263a7
7 changed files with 349 additions and 125 deletions
|
@ -23,13 +23,20 @@ struct task_struct;
|
|||
kernel might be somewhat backwards compatible, but don't bet on
|
||||
it. */
|
||||
|
||||
/* XXX - Note, cap_t, is defined by POSIX to be an "opaque" pointer to
|
||||
/* Note, cap_t, is defined by POSIX (draft) to be an "opaque" pointer to
|
||||
a set of three capability sets. The transposition of 3*the
|
||||
following structure to such a composite is better handled in a user
|
||||
library since the draft standard requires the use of malloc/free
|
||||
etc.. */
|
||||
|
||||
#define _LINUX_CAPABILITY_VERSION 0x19980330
|
||||
#define _LINUX_CAPABILITY_VERSION_1 0x19980330
|
||||
#define _LINUX_CAPABILITY_U32S_1 1
|
||||
|
||||
#define _LINUX_CAPABILITY_VERSION_2 0x20071026
|
||||
#define _LINUX_CAPABILITY_U32S_2 2
|
||||
|
||||
#define _LINUX_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_2
|
||||
#define _LINUX_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_2
|
||||
|
||||
typedef struct __user_cap_header_struct {
|
||||
__u32 version;
|
||||
|
@ -42,43 +49,42 @@ typedef struct __user_cap_data_struct {
|
|||
__u32 inheritable;
|
||||
} __user *cap_user_data_t;
|
||||
|
||||
|
||||
#define XATTR_CAPS_SUFFIX "capability"
|
||||
#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
|
||||
|
||||
#define XATTR_CAPS_SZ (3*sizeof(__le32))
|
||||
#define VFS_CAP_REVISION_MASK 0xFF000000
|
||||
#define VFS_CAP_REVISION_1 0x01000000
|
||||
|
||||
#define VFS_CAP_REVISION VFS_CAP_REVISION_1
|
||||
|
||||
#define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK
|
||||
#define VFS_CAP_FLAGS_EFFECTIVE 0x000001
|
||||
|
||||
#define VFS_CAP_REVISION_1 0x01000000
|
||||
#define VFS_CAP_U32_1 1
|
||||
#define XATTR_CAPS_SZ_1 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_1))
|
||||
|
||||
#define VFS_CAP_REVISION_2 0x02000000
|
||||
#define VFS_CAP_U32_2 2
|
||||
#define XATTR_CAPS_SZ_2 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_2))
|
||||
|
||||
#define XATTR_CAPS_SZ XATTR_CAPS_SZ_2
|
||||
#define VFS_CAP_U32 VFS_CAP_U32_2
|
||||
#define VFS_CAP_REVISION VFS_CAP_REVISION_2
|
||||
|
||||
|
||||
struct vfs_cap_data {
|
||||
__u32 magic_etc; /* Little endian */
|
||||
__le32 magic_etc; /* Little endian */
|
||||
struct {
|
||||
__u32 permitted; /* Little endian */
|
||||
__u32 inheritable; /* Little endian */
|
||||
} data[1];
|
||||
__le32 permitted; /* Little endian */
|
||||
__le32 inheritable; /* Little endian */
|
||||
} data[VFS_CAP_U32];
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/* #define STRICT_CAP_T_TYPECHECKS */
|
||||
|
||||
#ifdef STRICT_CAP_T_TYPECHECKS
|
||||
|
||||
typedef struct kernel_cap_struct {
|
||||
__u32 cap;
|
||||
__u32 cap[_LINUX_CAPABILITY_U32S];
|
||||
} kernel_cap_t;
|
||||
|
||||
#else
|
||||
|
||||
typedef __u32 kernel_cap_t;
|
||||
|
||||
#endif
|
||||
|
||||
#define _USER_CAP_HEADER_SIZE (2*sizeof(__u32))
|
||||
#define _USER_CAP_HEADER_SIZE (sizeof(struct __user_cap_header_struct))
|
||||
#define _KERNEL_CAP_T_SIZE (sizeof(kernel_cap_t))
|
||||
|
||||
#endif
|
||||
|
@ -121,10 +127,6 @@ typedef __u32 kernel_cap_t;
|
|||
|
||||
#define CAP_FSETID 4
|
||||
|
||||
/* Used to decide between falling back on the old suser() or fsuser(). */
|
||||
|
||||
#define CAP_FS_MASK 0x1f
|
||||
|
||||
/* Overrides the restriction that the real or effective user ID of a
|
||||
process sending a signal must match the real or effective user ID
|
||||
of the process receiving the signal. */
|
||||
|
@ -147,8 +149,12 @@ typedef __u32 kernel_cap_t;
|
|||
** Linux-specific capabilities
|
||||
**/
|
||||
|
||||
/* Transfer any capability in your permitted set to any pid,
|
||||
remove any capability in your permitted set from any pid */
|
||||
/* Without VFS support for capabilities:
|
||||
* Transfer any capability in your permitted set to any pid,
|
||||
* remove any capability in your permitted set from any pid
|
||||
* With VFS support for capabilities (neither of above, but)
|
||||
* Add any capability to the current process' inheritable set
|
||||
*/
|
||||
|
||||
#define CAP_SETPCAP 8
|
||||
|
||||
|
@ -309,70 +315,153 @@ typedef __u32 kernel_cap_t;
|
|||
|
||||
#define CAP_SETFCAP 31
|
||||
|
||||
/*
|
||||
* Bit location of each capability (used by user-space library and kernel)
|
||||
*/
|
||||
|
||||
#define CAP_TO_INDEX(x) ((x) >> 5) /* 1 << 5 == bits in __u32 */
|
||||
#define CAP_TO_MASK(x) (1 << ((x) & 31)) /* mask for indexed __u32 */
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/*
|
||||
* Internal kernel functions only
|
||||
*/
|
||||
|
||||
#ifdef STRICT_CAP_T_TYPECHECKS
|
||||
#define CAP_FOR_EACH_U32(__capi) \
|
||||
for (__capi = 0; __capi < _LINUX_CAPABILITY_U32S; ++__capi)
|
||||
|
||||
#define to_cap_t(x) { x }
|
||||
#define cap_t(x) (x).cap
|
||||
# define CAP_FS_MASK_B0 (CAP_TO_MASK(CAP_CHOWN) \
|
||||
| CAP_TO_MASK(CAP_DAC_OVERRIDE) \
|
||||
| CAP_TO_MASK(CAP_DAC_READ_SEARCH) \
|
||||
| CAP_TO_MASK(CAP_FOWNER) \
|
||||
| CAP_TO_MASK(CAP_FSETID))
|
||||
|
||||
#else
|
||||
#if _LINUX_CAPABILITY_U32S != 2
|
||||
# error Fix up hand-coded capability macro initializers
|
||||
#else /* HAND-CODED capability initializers */
|
||||
|
||||
#define to_cap_t(x) (x)
|
||||
#define cap_t(x) (x)
|
||||
# define CAP_EMPTY_SET {{ 0, 0 }}
|
||||
# define CAP_FULL_SET {{ ~0, ~0 }}
|
||||
# define CAP_INIT_EFF_SET {{ ~CAP_TO_MASK(CAP_SETPCAP), ~0 }}
|
||||
# define CAP_FS_SET {{ CAP_FS_MASK_B0, 0 }}
|
||||
# define CAP_NFSD_SET {{ CAP_FS_MASK_B0|CAP_TO_MASK(CAP_SYS_RESOURCE), 0 }}
|
||||
|
||||
#endif
|
||||
#endif /* _LINUX_CAPABILITY_U32S != 2 */
|
||||
|
||||
#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_INIT_INH_SET CAP_EMPTY_SET
|
||||
|
||||
#define CAP_TO_MASK(x) (1 << (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))
|
||||
# define cap_clear(c) do { (c) = __cap_empty_set; } while (0)
|
||||
# define cap_set_full(c) do { (c) = __cap_full_set; } while (0)
|
||||
# define cap_set_init_eff(c) do { (c) = __cap_init_eff_set; } while (0)
|
||||
|
||||
static inline kernel_cap_t cap_combine(kernel_cap_t a, kernel_cap_t b)
|
||||
#define cap_raise(c, flag) ((c).cap[CAP_TO_INDEX(flag)] |= CAP_TO_MASK(flag))
|
||||
#define cap_lower(c, flag) ((c).cap[CAP_TO_INDEX(flag)] &= ~CAP_TO_MASK(flag))
|
||||
#define cap_raised(c, flag) ((c).cap[CAP_TO_INDEX(flag)] & CAP_TO_MASK(flag))
|
||||
|
||||
#define CAP_BOP_ALL(c, a, b, OP) \
|
||||
do { \
|
||||
unsigned __capi; \
|
||||
CAP_FOR_EACH_U32(__capi) { \
|
||||
c.cap[__capi] = a.cap[__capi] OP b.cap[__capi]; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CAP_UOP_ALL(c, a, OP) \
|
||||
do { \
|
||||
unsigned __capi; \
|
||||
CAP_FOR_EACH_U32(__capi) { \
|
||||
c.cap[__capi] = OP a.cap[__capi]; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static inline kernel_cap_t cap_combine(const kernel_cap_t a,
|
||||
const kernel_cap_t b)
|
||||
{
|
||||
kernel_cap_t dest;
|
||||
cap_t(dest) = cap_t(a) | cap_t(b);
|
||||
return dest;
|
||||
kernel_cap_t dest;
|
||||
CAP_BOP_ALL(dest, a, b, |);
|
||||
return dest;
|
||||
}
|
||||
|
||||
static inline kernel_cap_t cap_intersect(kernel_cap_t a, kernel_cap_t b)
|
||||
static inline kernel_cap_t cap_intersect(const kernel_cap_t a,
|
||||
const kernel_cap_t b)
|
||||
{
|
||||
kernel_cap_t dest;
|
||||
cap_t(dest) = cap_t(a) & cap_t(b);
|
||||
return dest;
|
||||
kernel_cap_t dest;
|
||||
CAP_BOP_ALL(dest, a, b, &);
|
||||
return dest;
|
||||
}
|
||||
|
||||
static inline kernel_cap_t cap_drop(kernel_cap_t a, kernel_cap_t drop)
|
||||
static inline kernel_cap_t cap_drop(const kernel_cap_t a,
|
||||
const kernel_cap_t drop)
|
||||
{
|
||||
kernel_cap_t dest;
|
||||
cap_t(dest) = cap_t(a) & ~cap_t(drop);
|
||||
return dest;
|
||||
kernel_cap_t dest;
|
||||
CAP_BOP_ALL(dest, a, drop, &~);
|
||||
return dest;
|
||||
}
|
||||
|
||||
static inline kernel_cap_t cap_invert(kernel_cap_t c)
|
||||
static inline kernel_cap_t cap_invert(const kernel_cap_t c)
|
||||
{
|
||||
kernel_cap_t dest;
|
||||
cap_t(dest) = ~cap_t(c);
|
||||
return dest;
|
||||
kernel_cap_t dest;
|
||||
CAP_UOP_ALL(dest, c, ~);
|
||||
return dest;
|
||||
}
|
||||
|
||||
#define cap_isclear(c) (!cap_t(c))
|
||||
#define cap_issubset(a,set) (!(cap_t(a) & ~cap_t(set)))
|
||||
static inline int cap_isclear(const kernel_cap_t a)
|
||||
{
|
||||
unsigned __capi;
|
||||
CAP_FOR_EACH_U32(__capi) {
|
||||
if (a.cap[__capi] != 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#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)
|
||||
static inline int cap_issubset(const kernel_cap_t a, const kernel_cap_t set)
|
||||
{
|
||||
kernel_cap_t dest;
|
||||
dest = cap_drop(a, set);
|
||||
return cap_isclear(dest);
|
||||
}
|
||||
|
||||
#define cap_is_fs_cap(c) (CAP_TO_MASK(c) & CAP_FS_MASK)
|
||||
/* Used to decide between falling back on the old suser() or fsuser(). */
|
||||
|
||||
static inline int cap_is_fs_cap(int cap)
|
||||
{
|
||||
const kernel_cap_t __cap_fs_set = CAP_FS_SET;
|
||||
return !!(CAP_TO_MASK(cap) & __cap_fs_set.cap[CAP_TO_INDEX(cap)]);
|
||||
}
|
||||
|
||||
static inline kernel_cap_t cap_drop_fs_set(const kernel_cap_t a)
|
||||
{
|
||||
const kernel_cap_t __cap_fs_set = CAP_FS_SET;
|
||||
return cap_drop(a, __cap_fs_set);
|
||||
}
|
||||
|
||||
static inline kernel_cap_t cap_raise_fs_set(const kernel_cap_t a,
|
||||
const kernel_cap_t permitted)
|
||||
{
|
||||
const kernel_cap_t __cap_fs_set = CAP_FS_SET;
|
||||
return cap_combine(a,
|
||||
cap_intersect(permitted, __cap_fs_set));
|
||||
}
|
||||
|
||||
static inline kernel_cap_t cap_drop_nfsd_set(const kernel_cap_t a)
|
||||
{
|
||||
const kernel_cap_t __cap_fs_set = CAP_NFSD_SET;
|
||||
return cap_drop(a, __cap_fs_set);
|
||||
}
|
||||
|
||||
static inline kernel_cap_t cap_raise_nfsd_set(const kernel_cap_t a,
|
||||
const kernel_cap_t permitted)
|
||||
{
|
||||
const kernel_cap_t __cap_nfsd_set = CAP_NFSD_SET;
|
||||
return cap_combine(a,
|
||||
cap_intersect(permitted, __cap_nfsd_set));
|
||||
}
|
||||
|
||||
extern const kernel_cap_t __cap_empty_set;
|
||||
extern const kernel_cap_t __cap_full_set;
|
||||
extern const kernel_cap_t __cap_init_eff_set;
|
||||
|
||||
int capable(int cap);
|
||||
int __capable(struct task_struct *t, int cap);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue