Skip to content

Commit 1a48e2a

Browse files
committed
userns: Replace the hard to write inode_userns with inode_capable.
This represents a change in strategy of how to handle user namespaces. Instead of tagging everything explicitly with a user namespace and bulking up all of the comparisons of uids and gids in the kernel, all uids and gids in use will have a mapping to a flat kuid and kgid spaces respectively. This allows much more of the existing logic to be preserved and in general allows for faster code. In this new and improved world we allow someone to utiliize capabilities over an inode if the inodes owner mapps into the capabilities holders user namespace and the user has capabilities in their user namespace. Which is simple and efficient. Moving the fs uid comparisons to be comparisons in a flat kuid space follows in later patches, something that is only significant if you are using user namespaces. Acked-by: Serge Hallyn <[email protected]> Signed-off-by: Eric W. Biederman <[email protected]>
1 parent 973c591 commit 1a48e2a

File tree

5 files changed

+28
-23
lines changed

5 files changed

+28
-23
lines changed

fs/inode.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1732,11 +1732,9 @@ EXPORT_SYMBOL(inode_init_owner);
17321732
*/
17331733
bool inode_owner_or_capable(const struct inode *inode)
17341734
{
1735-
struct user_namespace *ns = inode_userns(inode);
1736-
1737-
if (current_user_ns() == ns && current_fsuid() == inode->i_uid)
1735+
if (current_fsuid() == inode->i_uid)
17381736
return true;
1739-
if (ns_capable(ns, CAP_FOWNER))
1737+
if (inode_capable(inode, CAP_FOWNER))
17401738
return true;
17411739
return false;
17421740
}

fs/namei.c

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,6 @@ static int acl_permission_check(struct inode *inode, int mask)
228228
{
229229
unsigned int mode = inode->i_mode;
230230

231-
if (current_user_ns() != inode_userns(inode))
232-
goto other_perms;
233-
234231
if (likely(current_fsuid() == inode->i_uid))
235232
mode >>= 6;
236233
else {
@@ -244,7 +241,6 @@ static int acl_permission_check(struct inode *inode, int mask)
244241
mode >>= 3;
245242
}
246243

247-
other_perms:
248244
/*
249245
* If the DACs are ok we don't need any capability check.
250246
*/
@@ -280,10 +276,10 @@ int generic_permission(struct inode *inode, int mask)
280276

281277
if (S_ISDIR(inode->i_mode)) {
282278
/* DACs are overridable for directories */
283-
if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE))
279+
if (inode_capable(inode, CAP_DAC_OVERRIDE))
284280
return 0;
285281
if (!(mask & MAY_WRITE))
286-
if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH))
282+
if (inode_capable(inode, CAP_DAC_READ_SEARCH))
287283
return 0;
288284
return -EACCES;
289285
}
@@ -293,15 +289,15 @@ int generic_permission(struct inode *inode, int mask)
293289
* at least one exec bit set.
294290
*/
295291
if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO))
296-
if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE))
292+
if (inode_capable(inode, CAP_DAC_OVERRIDE))
297293
return 0;
298294

299295
/*
300296
* Searching includes executable on directories, else just read.
301297
*/
302298
mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
303299
if (mask == MAY_READ)
304-
if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH))
300+
if (inode_capable(inode, CAP_DAC_READ_SEARCH))
305301
return 0;
306302

307303
return -EACCES;
@@ -1964,15 +1960,11 @@ static inline int check_sticky(struct inode *dir, struct inode *inode)
19641960

19651961
if (!(dir->i_mode & S_ISVTX))
19661962
return 0;
1967-
if (current_user_ns() != inode_userns(inode))
1968-
goto other_userns;
19691963
if (inode->i_uid == fsuid)
19701964
return 0;
19711965
if (dir->i_uid == fsuid)
19721966
return 0;
1973-
1974-
other_userns:
1975-
return !ns_capable(inode_userns(inode), CAP_FOWNER);
1967+
return !inode_capable(inode, CAP_FOWNER);
19761968
}
19771969

19781970
/*

include/linux/capability.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ struct cpu_vfs_cap_data {
374374

375375
#ifdef __KERNEL__
376376

377+
struct inode;
377378
struct dentry;
378379
struct user_namespace;
379380

@@ -548,6 +549,7 @@ extern bool has_ns_capability_noaudit(struct task_struct *t,
548549
extern bool capable(int cap);
549550
extern bool ns_capable(struct user_namespace *ns, int cap);
550551
extern bool nsown_capable(int cap);
552+
extern bool inode_capable(const struct inode *inode, int cap);
551553

552554
/* audit system wants to get cap info from files as well */
553555
extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps);

include/linux/fs.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,12 +1522,6 @@ enum {
15221522
#define vfs_check_frozen(sb, level) \
15231523
wait_event((sb)->s_wait_unfrozen, ((sb)->s_frozen < (level)))
15241524

1525-
/*
1526-
* until VFS tracks user namespaces for inodes, just make all files
1527-
* belong to init_user_ns
1528-
*/
1529-
extern struct user_namespace init_user_ns;
1530-
#define inode_userns(inode) (&init_user_ns)
15311525
extern bool inode_owner_or_capable(const struct inode *inode);
15321526

15331527
/* not quite ready to be deprecated, but... */

kernel/capability.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,3 +419,22 @@ bool nsown_capable(int cap)
419419
{
420420
return ns_capable(current_user_ns(), cap);
421421
}
422+
423+
/**
424+
* inode_capable - Check superior capability over inode
425+
* @inode: The inode in question
426+
* @cap: The capability in question
427+
*
428+
* Return true if the current task has the given superior capability
429+
* targeted at it's own user namespace and that the given inode is owned
430+
* by the current user namespace or a child namespace.
431+
*
432+
* Currently inodes can only be owned by the initial user namespace.
433+
*
434+
*/
435+
bool inode_capable(const struct inode *inode, int cap)
436+
{
437+
struct user_namespace *ns = current_user_ns();
438+
439+
return ns_capable(ns, cap) && (ns == &init_user_ns);
440+
}

0 commit comments

Comments
 (0)