diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/inode.c | 17 | ||||
-rw-r--r-- | fs/namei.c | 21 |
2 files changed, 33 insertions, 5 deletions
diff --git a/fs/inode.c b/fs/inode.c index 16fefd373fc2..a21d5a938a17 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 | } |
1735 | EXPORT_SYMBOL(inode_init_owner); | 1736 | EXPORT_SYMBOL(inode_init_owner); |
1737 | |||
1738 | /* | ||
1739 | * return true if current either has CAP_FOWNER to the | ||
1740 | * file, or owns the file. | ||
1741 | */ | ||
1742 | bool 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 | } | ||
1752 | EXPORT_SYMBOL(is_owner_or_cap); | ||
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) |