aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorSerge E. Hallyn <serge@hallyn.com>2011-03-23 19:43:25 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-23 22:47:08 -0400
commite795b71799ff0b27365020c9ddaa25d0d83f99c8 (patch)
treef3b628c2366f181380a8fbcd490910eb086a7b8e /fs
parentb0e77598f87107001a00b8a4ece9c95e4254ccc4 (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')
-rw-r--r--fs/inode.c17
-rw-r--r--fs/namei.c21
2 files changed, 33 insertions, 5 deletions
diff --git a/fs/inode.c b/fs/inode.c
index 16fefd373fc..a21d5a938a1 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -25,6 +25,7 @@
25#include <linux/async.h> 25#include <linux/async.h>
26#include <linux/posix_acl.h> 26#include <linux/posix_acl.h>
27#include <linux/ima.h> 27#include <linux/ima.h>
28#include <linux/cred.h>
28 29
29/* 30/*
30 * This is needed for the following functions: 31 * This is needed for the following functions:
@@ -1733,3 +1734,19 @@ void inode_init_owner(struct inode *inode, const struct inode *dir,
1733 inode->i_mode = mode; 1734 inode->i_mode = mode;
1734} 1735}
1735EXPORT_SYMBOL(inode_init_owner); 1736EXPORT_SYMBOL(inode_init_owner);
1737
1738/*
1739 * return true if current either has CAP_FOWNER to the
1740 * file, or owns the file.
1741 */
1742bool is_owner_or_cap(const struct inode *inode)
1743{
1744 struct user_namespace *ns = inode_userns(inode);
1745
1746 if (current_user_ns() == ns && current_fsuid() == inode->i_uid)
1747 return true;
1748 if (ns_capable(ns, CAP_FOWNER))
1749 return true;
1750 return false;
1751}
1752EXPORT_SYMBOL(is_owner_or_cap);
diff --git a/fs/namei.c b/fs/namei.c
index 5a9a6c3094d..dbb45a652ae 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
202other_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)
654static inline int exec_permission(struct inode *inode, unsigned int flags) 658static 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
1858other_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)