diff options
author | Serge E. Hallyn <serge@hallyn.com> | 2011-03-23 19:43:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-23 22:47:08 -0400 |
commit | e795b71799ff0b27365020c9ddaa25d0d83f99c8 (patch) | |
tree | f3b628c2366f181380a8fbcd490910eb086a7b8e /fs/namei.c | |
parent | b0e77598f87107001a00b8a4ece9c95e4254ccc4 (diff) |
userns: userns: check user namespace for task->file uid equivalence checks
Cheat for now and say all files belong to init_user_ns. Next step will be
to let superblocks belong to a user_ns, and derive inode_userns(inode)
from inode->i_sb->s_user_ns. Finally we'll introduce more flexible
arrangements.
Changelog:
Feb 15: make is_owner_or_cap take const struct inode
Feb 23: make is_owner_or_cap bool
[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Serge E. Hallyn <serge.hallyn@canonical.com>
Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
Acked-by: Daniel Lezcano <daniel.lezcano@free.fr>
Acked-by: David Howells <dhowells@redhat.com>
Cc: James Morris <jmorris@namei.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 21 |
1 files changed, 16 insertions, 5 deletions
diff --git a/fs/namei.c b/fs/namei.c index 5a9a6c3094da..dbb45a652ae3 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -183,6 +183,9 @@ static int acl_permission_check(struct inode *inode, int mask, unsigned int flag | |||
183 | 183 | ||
184 | mask &= MAY_READ | MAY_WRITE | MAY_EXEC; | 184 | mask &= MAY_READ | MAY_WRITE | MAY_EXEC; |
185 | 185 | ||
186 | if (current_user_ns() != inode_userns(inode)) | ||
187 | goto other_perms; | ||
188 | |||
186 | if (current_fsuid() == inode->i_uid) | 189 | if (current_fsuid() == inode->i_uid) |
187 | mode >>= 6; | 190 | mode >>= 6; |
188 | else { | 191 | else { |
@@ -196,6 +199,7 @@ static int acl_permission_check(struct inode *inode, int mask, unsigned int flag | |||
196 | mode >>= 3; | 199 | mode >>= 3; |
197 | } | 200 | } |
198 | 201 | ||
202 | other_perms: | ||
199 | /* | 203 | /* |
200 | * If the DACs are ok we don't need any capability check. | 204 | * If the DACs are ok we don't need any capability check. |
201 | */ | 205 | */ |
@@ -237,7 +241,7 @@ int generic_permission(struct inode *inode, int mask, unsigned int flags, | |||
237 | * Executable DACs are overridable if at least one exec bit is set. | 241 | * Executable DACs are overridable if at least one exec bit is set. |
238 | */ | 242 | */ |
239 | if (!(mask & MAY_EXEC) || execute_ok(inode)) | 243 | if (!(mask & MAY_EXEC) || execute_ok(inode)) |
240 | if (capable(CAP_DAC_OVERRIDE)) | 244 | if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE)) |
241 | return 0; | 245 | return 0; |
242 | 246 | ||
243 | /* | 247 | /* |
@@ -245,7 +249,7 @@ int generic_permission(struct inode *inode, int mask, unsigned int flags, | |||
245 | */ | 249 | */ |
246 | mask &= MAY_READ | MAY_WRITE | MAY_EXEC; | 250 | mask &= MAY_READ | MAY_WRITE | MAY_EXEC; |
247 | if (mask == MAY_READ || (S_ISDIR(inode->i_mode) && !(mask & MAY_WRITE))) | 251 | if (mask == MAY_READ || (S_ISDIR(inode->i_mode) && !(mask & MAY_WRITE))) |
248 | if (capable(CAP_DAC_READ_SEARCH)) | 252 | if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH)) |
249 | return 0; | 253 | return 0; |
250 | 254 | ||
251 | return -EACCES; | 255 | return -EACCES; |
@@ -654,6 +658,7 @@ static inline int handle_reval_path(struct nameidata *nd) | |||
654 | static inline int exec_permission(struct inode *inode, unsigned int flags) | 658 | static inline int exec_permission(struct inode *inode, unsigned int flags) |
655 | { | 659 | { |
656 | int ret; | 660 | int ret; |
661 | struct user_namespace *ns = inode_userns(inode); | ||
657 | 662 | ||
658 | if (inode->i_op->permission) { | 663 | if (inode->i_op->permission) { |
659 | ret = inode->i_op->permission(inode, MAY_EXEC, flags); | 664 | ret = inode->i_op->permission(inode, MAY_EXEC, flags); |
@@ -666,7 +671,8 @@ static inline int exec_permission(struct inode *inode, unsigned int flags) | |||
666 | if (ret == -ECHILD) | 671 | if (ret == -ECHILD) |
667 | return ret; | 672 | return ret; |
668 | 673 | ||
669 | if (capable(CAP_DAC_OVERRIDE) || capable(CAP_DAC_READ_SEARCH)) | 674 | if (ns_capable(ns, CAP_DAC_OVERRIDE) || |
675 | ns_capable(ns, CAP_DAC_READ_SEARCH)) | ||
670 | goto ok; | 676 | goto ok; |
671 | 677 | ||
672 | return ret; | 678 | return ret; |
@@ -1842,11 +1848,15 @@ static inline int check_sticky(struct inode *dir, struct inode *inode) | |||
1842 | 1848 | ||
1843 | if (!(dir->i_mode & S_ISVTX)) | 1849 | if (!(dir->i_mode & S_ISVTX)) |
1844 | return 0; | 1850 | return 0; |
1851 | if (current_user_ns() != inode_userns(inode)) | ||
1852 | goto other_userns; | ||
1845 | if (inode->i_uid == fsuid) | 1853 | if (inode->i_uid == fsuid) |
1846 | return 0; | 1854 | return 0; |
1847 | if (dir->i_uid == fsuid) | 1855 | if (dir->i_uid == fsuid) |
1848 | return 0; | 1856 | return 0; |
1849 | return !capable(CAP_FOWNER); | 1857 | |
1858 | other_userns: | ||
1859 | return !ns_capable(inode_userns(inode), CAP_FOWNER); | ||
1850 | } | 1860 | } |
1851 | 1861 | ||
1852 | /* | 1862 | /* |
@@ -2440,7 +2450,8 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) | |||
2440 | if (error) | 2450 | if (error) |
2441 | return error; | 2451 | return error; |
2442 | 2452 | ||
2443 | if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD)) | 2453 | if ((S_ISCHR(mode) || S_ISBLK(mode)) && |
2454 | !ns_capable(inode_userns(dir), CAP_MKNOD)) | ||
2444 | return -EPERM; | 2455 | return -EPERM; |
2445 | 2456 | ||
2446 | if (!dir->i_op->mknod) | 2457 | if (!dir->i_op->mknod) |