Skip to content

Commit f122a08

Browse files
committed
capability: just use a 'u64' instead of a 'u32[2]' array
Back in 2008 we extended the capability bits from 32 to 64, and we did it by extending the single 32-bit capability word from one word to an array of two words. It was then obfuscated by hiding the "2" behind two macro expansions, with the reasoning being that maybe it gets extended further some day. That reasoning may have been valid at the time, but the last thing we want to do is to extend the capability set any more. And the array of values not only causes source code oddities (with loops to deal with it), but also results in worse code generation. It's a lose-lose situation. So just change the 'u32[2]' into a 'u64' and be done with it. We still have to deal with the fact that the user space interface is designed around an array of these 32-bit values, but that was the case before too, since the array layouts were different (ie user space doesn't use an array of 32-bit values for individual capability masks, but an array of 32-bit slices of multiple masks). So that marshalling of data is actually simplified too, even if it does remain somewhat obscure and odd. This was all triggered by my reaction to the new "cap_isidentical()" introduced recently. By just using a saner data structure, it went from unsigned __capi; CAP_FOR_EACH_U32(__capi) { if (a.cap[__capi] != b.cap[__capi]) return false; } return true; to just being return a.val == b.val; instead. Which is rather more obvious both to humans and to compilers. Cc: Mateusz Guzik <[email protected]> Cc: Casey Schaufler <[email protected]> Cc: Serge Hallyn <[email protected]> Cc: Al Viro <[email protected]> Cc: Paul Moore <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 1d2aea1 commit f122a08

File tree

9 files changed

+150
-239
lines changed

9 files changed

+150
-239
lines changed

fs/proc/array.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -300,13 +300,8 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p)
300300
static void render_cap_t(struct seq_file *m, const char *header,
301301
kernel_cap_t *a)
302302
{
303-
unsigned __capi;
304-
305303
seq_puts(m, header);
306-
CAP_FOR_EACH_U32(__capi) {
307-
seq_put_hex_ll(m, NULL,
308-
a->cap[CAP_LAST_U32 - __capi], 8);
309-
}
304+
seq_put_hex_ll(m, NULL, a->val, 16);
310305
seq_putc(m, '\n');
311306
}
312307

include/linux/capability.h

Lines changed: 29 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -15,45 +15,32 @@
1515

1616
#include <uapi/linux/capability.h>
1717
#include <linux/uidgid.h>
18+
#include <linux/bits.h>
1819

1920
#define _KERNEL_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_3
20-
#define _KERNEL_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_3
2121

2222
extern int file_caps_enabled;
2323

24-
typedef struct kernel_cap_struct {
25-
__u32 cap[_KERNEL_CAPABILITY_U32S];
26-
} kernel_cap_t;
24+
typedef struct { u64 val; } kernel_cap_t;
2725

2826
/* same as vfs_ns_cap_data but in cpu endian and always filled completely */
2927
struct cpu_vfs_cap_data {
3028
__u32 magic_etc;
29+
kuid_t rootid;
3130
kernel_cap_t permitted;
3231
kernel_cap_t inheritable;
33-
kuid_t rootid;
3432
};
3533

3634
#define _USER_CAP_HEADER_SIZE (sizeof(struct __user_cap_header_struct))
3735
#define _KERNEL_CAP_T_SIZE (sizeof(kernel_cap_t))
3836

39-
4037
struct file;
4138
struct inode;
4239
struct dentry;
4340
struct task_struct;
4441
struct user_namespace;
4542
struct mnt_idmap;
4643

47-
extern const kernel_cap_t __cap_empty_set;
48-
extern const kernel_cap_t __cap_init_eff_set;
49-
50-
/*
51-
* Internal kernel functions only
52-
*/
53-
54-
#define CAP_FOR_EACH_U32(__capi) \
55-
for (__capi = 0; __capi < _KERNEL_CAPABILITY_U32S; ++__capi)
56-
5744
/*
5845
* CAP_FS_MASK and CAP_NFSD_MASKS:
5946
*
@@ -67,104 +54,52 @@ extern const kernel_cap_t __cap_init_eff_set;
6754
* 2. The security.* and trusted.* xattrs are fs-related MAC permissions
6855
*/
6956

70-
# define CAP_FS_MASK_B0 (CAP_TO_MASK(CAP_CHOWN) \
71-
| CAP_TO_MASK(CAP_MKNOD) \
72-
| CAP_TO_MASK(CAP_DAC_OVERRIDE) \
73-
| CAP_TO_MASK(CAP_DAC_READ_SEARCH) \
74-
| CAP_TO_MASK(CAP_FOWNER) \
75-
| CAP_TO_MASK(CAP_FSETID))
76-
77-
# define CAP_FS_MASK_B1 (CAP_TO_MASK(CAP_MAC_OVERRIDE))
78-
79-
#if _KERNEL_CAPABILITY_U32S != 2
80-
# error Fix up hand-coded capability macro initializers
81-
#else /* HAND-CODED capability initializers */
57+
# define CAP_FS_MASK (BIT_ULL(CAP_CHOWN) \
58+
| BIT_ULL(CAP_MKNOD) \
59+
| BIT_ULL(CAP_DAC_OVERRIDE) \
60+
| BIT_ULL(CAP_DAC_READ_SEARCH) \
61+
| BIT_ULL(CAP_FOWNER) \
62+
| BIT_ULL(CAP_FSETID) \
63+
| BIT_ULL(CAP_MAC_OVERRIDE))
64+
#define CAP_VALID_MASK (BIT_ULL(CAP_LAST_CAP+1)-1)
8265

83-
#define CAP_LAST_U32 ((_KERNEL_CAPABILITY_U32S) - 1)
84-
#define CAP_LAST_U32_VALID_MASK (CAP_TO_MASK(CAP_LAST_CAP + 1) -1)
66+
# define CAP_EMPTY_SET ((kernel_cap_t) { 0 })
67+
# define CAP_FULL_SET ((kernel_cap_t) { CAP_VALID_MASK })
68+
# define CAP_FS_SET ((kernel_cap_t) { CAP_FS_MASK | BIT_ULL(CAP_LINUX_IMMUTABLE) })
69+
# define CAP_NFSD_SET ((kernel_cap_t) { CAP_FS_MASK | BIT_ULL(CAP_SYS_RESOURCE) })
8570

86-
# define CAP_EMPTY_SET ((kernel_cap_t){{ 0, 0 }})
87-
# define CAP_FULL_SET ((kernel_cap_t){{ ~0, CAP_LAST_U32_VALID_MASK }})
88-
# define CAP_FS_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \
89-
| CAP_TO_MASK(CAP_LINUX_IMMUTABLE), \
90-
CAP_FS_MASK_B1 } })
91-
# define CAP_NFSD_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \
92-
| CAP_TO_MASK(CAP_SYS_RESOURCE), \
93-
CAP_FS_MASK_B1 } })
71+
# define cap_clear(c) do { (c).val = 0; } while (0)
9472

95-
#endif /* _KERNEL_CAPABILITY_U32S != 2 */
96-
97-
# define cap_clear(c) do { (c) = __cap_empty_set; } while (0)
98-
99-
#define cap_raise(c, flag) ((c).cap[CAP_TO_INDEX(flag)] |= CAP_TO_MASK(flag))
100-
#define cap_lower(c, flag) ((c).cap[CAP_TO_INDEX(flag)] &= ~CAP_TO_MASK(flag))
101-
#define cap_raised(c, flag) ((c).cap[CAP_TO_INDEX(flag)] & CAP_TO_MASK(flag))
102-
103-
#define CAP_BOP_ALL(c, a, b, OP) \
104-
do { \
105-
unsigned __capi; \
106-
CAP_FOR_EACH_U32(__capi) { \
107-
c.cap[__capi] = a.cap[__capi] OP b.cap[__capi]; \
108-
} \
109-
} while (0)
110-
111-
#define CAP_UOP_ALL(c, a, OP) \
112-
do { \
113-
unsigned __capi; \
114-
CAP_FOR_EACH_U32(__capi) { \
115-
c.cap[__capi] = OP a.cap[__capi]; \
116-
} \
117-
} while (0)
73+
#define cap_raise(c, flag) ((c).val |= BIT_ULL(flag))
74+
#define cap_lower(c, flag) ((c).val &= ~BIT_ULL(flag))
75+
#define cap_raised(c, flag) (((c).val & BIT_ULL(flag)) != 0)
11876

11977
static inline kernel_cap_t cap_combine(const kernel_cap_t a,
12078
const kernel_cap_t b)
12179
{
122-
kernel_cap_t dest;
123-
CAP_BOP_ALL(dest, a, b, |);
124-
return dest;
80+
return (kernel_cap_t) { a.val | b.val };
12581
}
12682

12783
static inline kernel_cap_t cap_intersect(const kernel_cap_t a,
12884
const kernel_cap_t b)
12985
{
130-
kernel_cap_t dest;
131-
CAP_BOP_ALL(dest, a, b, &);
132-
return dest;
86+
return (kernel_cap_t) { a.val & b.val };
13387
}
13488

13589
static inline kernel_cap_t cap_drop(const kernel_cap_t a,
13690
const kernel_cap_t drop)
13791
{
138-
kernel_cap_t dest;
139-
CAP_BOP_ALL(dest, a, drop, &~);
140-
return dest;
141-
}
142-
143-
static inline kernel_cap_t cap_invert(const kernel_cap_t c)
144-
{
145-
kernel_cap_t dest;
146-
CAP_UOP_ALL(dest, c, ~);
147-
return dest;
92+
return (kernel_cap_t) { a.val &~ drop.val };
14893
}
14994

15095
static inline bool cap_isclear(const kernel_cap_t a)
15196
{
152-
unsigned __capi;
153-
CAP_FOR_EACH_U32(__capi) {
154-
if (a.cap[__capi] != 0)
155-
return false;
156-
}
157-
return true;
97+
return !a.val;
15898
}
15999

160100
static inline bool cap_isidentical(const kernel_cap_t a, const kernel_cap_t b)
161101
{
162-
unsigned __capi;
163-
CAP_FOR_EACH_U32(__capi) {
164-
if (a.cap[__capi] != b.cap[__capi])
165-
return false;
166-
}
167-
return true;
102+
return a.val == b.val;
168103
}
169104

170105
/*
@@ -176,39 +111,31 @@ static inline bool cap_isidentical(const kernel_cap_t a, const kernel_cap_t b)
176111
*/
177112
static inline bool cap_issubset(const kernel_cap_t a, const kernel_cap_t set)
178113
{
179-
kernel_cap_t dest;
180-
dest = cap_drop(a, set);
181-
return cap_isclear(dest);
114+
return !(a.val & ~set.val);
182115
}
183116

184117
/* Used to decide between falling back on the old suser() or fsuser(). */
185118

186119
static inline kernel_cap_t cap_drop_fs_set(const kernel_cap_t a)
187120
{
188-
const kernel_cap_t __cap_fs_set = CAP_FS_SET;
189-
return cap_drop(a, __cap_fs_set);
121+
return cap_drop(a, CAP_FS_SET);
190122
}
191123

192124
static inline kernel_cap_t cap_raise_fs_set(const kernel_cap_t a,
193125
const kernel_cap_t permitted)
194126
{
195-
const kernel_cap_t __cap_fs_set = CAP_FS_SET;
196-
return cap_combine(a,
197-
cap_intersect(permitted, __cap_fs_set));
127+
return cap_combine(a, cap_intersect(permitted, CAP_FS_SET));
198128
}
199129

200130
static inline kernel_cap_t cap_drop_nfsd_set(const kernel_cap_t a)
201131
{
202-
const kernel_cap_t __cap_fs_set = CAP_NFSD_SET;
203-
return cap_drop(a, __cap_fs_set);
132+
return cap_drop(a, CAP_NFSD_SET);
204133
}
205134

206135
static inline kernel_cap_t cap_raise_nfsd_set(const kernel_cap_t a,
207136
const kernel_cap_t permitted)
208137
{
209-
const kernel_cap_t __cap_nfsd_set = CAP_NFSD_SET;
210-
return cap_combine(a,
211-
cap_intersect(permitted, __cap_nfsd_set));
138+
return cap_combine(a, cap_intersect(permitted, CAP_NFSD_SET));
212139
}
213140

214141
#ifdef CONFIG_MULTIUSER

io_uring/fdinfo.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ static __cold int io_uring_show_cred(struct seq_file *m, unsigned int id,
2222
struct user_namespace *uns = seq_user_ns(m);
2323
struct group_info *gi;
2424
kernel_cap_t cap;
25-
unsigned __capi;
2625
int g;
2726

2827
seq_printf(m, "%5d\n", id);
@@ -42,8 +41,7 @@ static __cold int io_uring_show_cred(struct seq_file *m, unsigned int id,
4241
}
4342
seq_puts(m, "\n\tCapEff:\t");
4443
cap = cred->cap_effective;
45-
CAP_FOR_EACH_U32(__capi)
46-
seq_put_hex_ll(m, NULL, cap.cap[CAP_LAST_U32 - __capi], 8);
44+
seq_put_hex_ll(m, NULL, cap.val, 16);
4745
seq_putc(m, '\n');
4846
return 0;
4947
}

kernel/auditsc.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,15 +1295,11 @@ static void audit_log_execve_info(struct audit_context *context,
12951295
static void audit_log_cap(struct audit_buffer *ab, char *prefix,
12961296
kernel_cap_t *cap)
12971297
{
1298-
int i;
1299-
13001298
if (cap_isclear(*cap)) {
13011299
audit_log_format(ab, " %s=0", prefix);
13021300
return;
13031301
}
1304-
audit_log_format(ab, " %s=", prefix);
1305-
CAP_FOR_EACH_U32(i)
1306-
audit_log_format(ab, "%08x", cap->cap[CAP_LAST_U32 - i]);
1302+
audit_log_format(ab, " %s=%016llx", prefix, cap->val);
13071303
}
13081304

13091305
static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name)

0 commit comments

Comments
 (0)