diff options
-rw-r--r-- | fs/inode.c | 6 | ||||
-rw-r--r-- | fs/namei.c | 18 | ||||
-rw-r--r-- | include/linux/capability.h | 2 | ||||
-rw-r--r-- | include/linux/fs.h | 6 | ||||
-rw-r--r-- | kernel/capability.c | 19 |
5 files changed, 28 insertions, 23 deletions
diff --git a/fs/inode.c b/fs/inode.c index 9f4f5fecc096..f0c4ace408e4 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -1732,11 +1732,9 @@ EXPORT_SYMBOL(inode_init_owner); | |||
1732 | */ | 1732 | */ |
1733 | bool inode_owner_or_capable(const struct inode *inode) | 1733 | bool inode_owner_or_capable(const struct inode *inode) |
1734 | { | 1734 | { |
1735 | struct user_namespace *ns = inode_userns(inode); | 1735 | if (current_fsuid() == inode->i_uid) |
1736 | |||
1737 | if (current_user_ns() == ns && current_fsuid() == inode->i_uid) | ||
1738 | return true; | 1736 | return true; |
1739 | if (ns_capable(ns, CAP_FOWNER)) | 1737 | if (inode_capable(inode, CAP_FOWNER)) |
1740 | return true; | 1738 | return true; |
1741 | return false; | 1739 | return false; |
1742 | } | 1740 | } |
diff --git a/fs/namei.c b/fs/namei.c index 701954d68ac7..941c4362e298 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -228,9 +228,6 @@ static int acl_permission_check(struct inode *inode, int mask) | |||
228 | { | 228 | { |
229 | unsigned int mode = inode->i_mode; | 229 | unsigned int mode = inode->i_mode; |
230 | 230 | ||
231 | if (current_user_ns() != inode_userns(inode)) | ||
232 | goto other_perms; | ||
233 | |||
234 | if (likely(current_fsuid() == inode->i_uid)) | 231 | if (likely(current_fsuid() == inode->i_uid)) |
235 | mode >>= 6; | 232 | mode >>= 6; |
236 | else { | 233 | else { |
@@ -244,7 +241,6 @@ static int acl_permission_check(struct inode *inode, int mask) | |||
244 | mode >>= 3; | 241 | mode >>= 3; |
245 | } | 242 | } |
246 | 243 | ||
247 | other_perms: | ||
248 | /* | 244 | /* |
249 | * If the DACs are ok we don't need any capability check. | 245 | * If the DACs are ok we don't need any capability check. |
250 | */ | 246 | */ |
@@ -280,10 +276,10 @@ int generic_permission(struct inode *inode, int mask) | |||
280 | 276 | ||
281 | if (S_ISDIR(inode->i_mode)) { | 277 | if (S_ISDIR(inode->i_mode)) { |
282 | /* DACs are overridable for directories */ | 278 | /* DACs are overridable for directories */ |
283 | if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE)) | 279 | if (inode_capable(inode, CAP_DAC_OVERRIDE)) |
284 | return 0; | 280 | return 0; |
285 | if (!(mask & MAY_WRITE)) | 281 | if (!(mask & MAY_WRITE)) |
286 | if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH)) | 282 | if (inode_capable(inode, CAP_DAC_READ_SEARCH)) |
287 | return 0; | 283 | return 0; |
288 | return -EACCES; | 284 | return -EACCES; |
289 | } | 285 | } |
@@ -293,7 +289,7 @@ int generic_permission(struct inode *inode, int mask) | |||
293 | * at least one exec bit set. | 289 | * at least one exec bit set. |
294 | */ | 290 | */ |
295 | if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO)) | 291 | 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)) |
297 | return 0; | 293 | return 0; |
298 | 294 | ||
299 | /* | 295 | /* |
@@ -301,7 +297,7 @@ int generic_permission(struct inode *inode, int mask) | |||
301 | */ | 297 | */ |
302 | mask &= MAY_READ | MAY_WRITE | MAY_EXEC; | 298 | mask &= MAY_READ | MAY_WRITE | MAY_EXEC; |
303 | if (mask == MAY_READ) | 299 | if (mask == MAY_READ) |
304 | if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH)) | 300 | if (inode_capable(inode, CAP_DAC_READ_SEARCH)) |
305 | return 0; | 301 | return 0; |
306 | 302 | ||
307 | return -EACCES; | 303 | return -EACCES; |
@@ -1964,15 +1960,11 @@ static inline int check_sticky(struct inode *dir, struct inode *inode) | |||
1964 | 1960 | ||
1965 | if (!(dir->i_mode & S_ISVTX)) | 1961 | if (!(dir->i_mode & S_ISVTX)) |
1966 | return 0; | 1962 | return 0; |
1967 | if (current_user_ns() != inode_userns(inode)) | ||
1968 | goto other_userns; | ||
1969 | if (inode->i_uid == fsuid) | 1963 | if (inode->i_uid == fsuid) |
1970 | return 0; | 1964 | return 0; |
1971 | if (dir->i_uid == fsuid) | 1965 | if (dir->i_uid == fsuid) |
1972 | return 0; | 1966 | return 0; |
1973 | 1967 | return !inode_capable(inode, CAP_FOWNER); | |
1974 | other_userns: | ||
1975 | return !ns_capable(inode_userns(inode), CAP_FOWNER); | ||
1976 | } | 1968 | } |
1977 | 1969 | ||
1978 | /* | 1970 | /* |
diff --git a/include/linux/capability.h b/include/linux/capability.h index 12d52dedb229..a76eca907470 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h | |||
@@ -374,6 +374,7 @@ struct cpu_vfs_cap_data { | |||
374 | 374 | ||
375 | #ifdef __KERNEL__ | 375 | #ifdef __KERNEL__ |
376 | 376 | ||
377 | struct inode; | ||
377 | struct dentry; | 378 | struct dentry; |
378 | struct user_namespace; | 379 | struct user_namespace; |
379 | 380 | ||
@@ -548,6 +549,7 @@ extern bool has_ns_capability_noaudit(struct task_struct *t, | |||
548 | extern bool capable(int cap); | 549 | extern bool capable(int cap); |
549 | extern bool ns_capable(struct user_namespace *ns, int cap); | 550 | extern bool ns_capable(struct user_namespace *ns, int cap); |
550 | extern bool nsown_capable(int cap); | 551 | extern bool nsown_capable(int cap); |
552 | extern bool inode_capable(const struct inode *inode, int cap); | ||
551 | 553 | ||
552 | /* audit system wants to get cap info from files as well */ | 554 | /* audit system wants to get cap info from files as well */ |
553 | extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps); | 555 | extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 135693e79f2b..a6c5efbee0d7 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1522,12 +1522,6 @@ enum { | |||
1522 | #define vfs_check_frozen(sb, level) \ | 1522 | #define vfs_check_frozen(sb, level) \ |
1523 | wait_event((sb)->s_wait_unfrozen, ((sb)->s_frozen < (level))) | 1523 | wait_event((sb)->s_wait_unfrozen, ((sb)->s_frozen < (level))) |
1524 | 1524 | ||
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) | ||
1531 | extern bool inode_owner_or_capable(const struct inode *inode); | 1525 | extern bool inode_owner_or_capable(const struct inode *inode); |
1532 | 1526 | ||
1533 | /* not quite ready to be deprecated, but... */ | 1527 | /* not quite ready to be deprecated, but... */ |
diff --git a/kernel/capability.c b/kernel/capability.c index 3f1adb6c6470..cc5f0718215d 100644 --- a/kernel/capability.c +++ b/kernel/capability.c | |||
@@ -419,3 +419,22 @@ bool nsown_capable(int cap) | |||
419 | { | 419 | { |
420 | return ns_capable(current_user_ns(), cap); | 420 | return ns_capable(current_user_ns(), cap); |
421 | } | 421 | } |
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 | } | ||