diff options
| -rw-r--r-- | fs/cifs/cifsfs.c | 9 | ||||
| -rw-r--r-- | fs/coda/dir.c | 3 | ||||
| -rw-r--r-- | fs/coda/pioctl.c | 2 | ||||
| -rw-r--r-- | fs/hfs/inode.c | 8 | ||||
| -rw-r--r-- | fs/hfsplus/inode.c | 13 | ||||
| -rw-r--r-- | fs/namei.c | 21 | ||||
| -rw-r--r-- | fs/nfs/dir.c | 3 | ||||
| -rw-r--r-- | fs/proc/proc_sysctl.c | 10 | ||||
| -rw-r--r-- | include/linux/fs.h | 5 |
9 files changed, 30 insertions, 44 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 89c64a8dcb99..84cc011a16e4 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -275,9 +275,12 @@ static int cifs_permission(struct inode *inode, int mask) | |||
| 275 | 275 | ||
| 276 | cifs_sb = CIFS_SB(inode->i_sb); | 276 | cifs_sb = CIFS_SB(inode->i_sb); |
| 277 | 277 | ||
| 278 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) | 278 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) { |
| 279 | return 0; | 279 | if ((mask & MAY_EXEC) && !execute_ok(inode)) |
| 280 | else /* file mode might have been restricted at mount time | 280 | return -EACCES; |
| 281 | else | ||
| 282 | return 0; | ||
| 283 | } else /* file mode might have been restricted at mount time | ||
| 281 | on the client (above and beyond ACL on servers) for | 284 | on the client (above and beyond ACL on servers) for |
| 282 | servers which do not support setting and viewing mode bits, | 285 | servers which do not support setting and viewing mode bits, |
| 283 | so allowing client to check permissions is useful */ | 286 | so allowing client to check permissions is useful */ |
diff --git a/fs/coda/dir.c b/fs/coda/dir.c index c5916228243c..75b1fa90b2cb 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c | |||
| @@ -146,6 +146,9 @@ int coda_permission(struct inode *inode, int mask) | |||
| 146 | if (!mask) | 146 | if (!mask) |
| 147 | return 0; | 147 | return 0; |
| 148 | 148 | ||
| 149 | if ((mask & MAY_EXEC) && !execute_ok(inode)) | ||
| 150 | return -EACCES; | ||
| 151 | |||
| 149 | lock_kernel(); | 152 | lock_kernel(); |
| 150 | 153 | ||
| 151 | if (coda_cache_check(inode, mask)) | 154 | if (coda_cache_check(inode, mask)) |
diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c index c51365422aa8..773f2ce9aa06 100644 --- a/fs/coda/pioctl.c +++ b/fs/coda/pioctl.c | |||
| @@ -43,7 +43,7 @@ const struct file_operations coda_ioctl_operations = { | |||
| 43 | /* the coda pioctl inode ops */ | 43 | /* the coda pioctl inode ops */ |
| 44 | static int coda_ioctl_permission(struct inode *inode, int mask) | 44 | static int coda_ioctl_permission(struct inode *inode, int mask) |
| 45 | { | 45 | { |
| 46 | return 0; | 46 | return (mask & MAY_EXEC) ? -EACCES : 0; |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | static int coda_pioctl(struct inode * inode, struct file * filp, | 49 | static int coda_pioctl(struct inode * inode, struct file * filp, |
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index 7e19835efa2e..c69b7ac75bf7 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c | |||
| @@ -511,13 +511,6 @@ void hfs_clear_inode(struct inode *inode) | |||
| 511 | } | 511 | } |
| 512 | } | 512 | } |
| 513 | 513 | ||
| 514 | static int hfs_permission(struct inode *inode, int mask) | ||
| 515 | { | ||
| 516 | if (S_ISREG(inode->i_mode) && mask & MAY_EXEC) | ||
| 517 | return 0; | ||
| 518 | return generic_permission(inode, mask, NULL); | ||
| 519 | } | ||
| 520 | |||
| 521 | static int hfs_file_open(struct inode *inode, struct file *file) | 514 | static int hfs_file_open(struct inode *inode, struct file *file) |
| 522 | { | 515 | { |
| 523 | if (HFS_IS_RSRC(inode)) | 516 | if (HFS_IS_RSRC(inode)) |
| @@ -616,7 +609,6 @@ static const struct inode_operations hfs_file_inode_operations = { | |||
| 616 | .lookup = hfs_file_lookup, | 609 | .lookup = hfs_file_lookup, |
| 617 | .truncate = hfs_file_truncate, | 610 | .truncate = hfs_file_truncate, |
| 618 | .setattr = hfs_inode_setattr, | 611 | .setattr = hfs_inode_setattr, |
| 619 | .permission = hfs_permission, | ||
| 620 | .setxattr = hfs_setxattr, | 612 | .setxattr = hfs_setxattr, |
| 621 | .getxattr = hfs_getxattr, | 613 | .getxattr = hfs_getxattr, |
| 622 | .listxattr = hfs_listxattr, | 614 | .listxattr = hfs_listxattr, |
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 963be644297a..b207f0e6fc22 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c | |||
| @@ -238,18 +238,6 @@ static void hfsplus_set_perms(struct inode *inode, struct hfsplus_perm *perms) | |||
| 238 | perms->dev = cpu_to_be32(HFSPLUS_I(inode).dev); | 238 | perms->dev = cpu_to_be32(HFSPLUS_I(inode).dev); |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | static int hfsplus_permission(struct inode *inode, int mask) | ||
| 242 | { | ||
| 243 | /* MAY_EXEC is also used for lookup, if no x bit is set allow lookup, | ||
| 244 | * open_exec has the same test, so it's still not executable, if a x bit | ||
| 245 | * is set fall back to standard permission check. | ||
| 246 | */ | ||
| 247 | if (S_ISREG(inode->i_mode) && mask & MAY_EXEC && !(inode->i_mode & 0111)) | ||
| 248 | return 0; | ||
| 249 | return generic_permission(inode, mask, NULL); | ||
| 250 | } | ||
| 251 | |||
| 252 | |||
| 253 | static int hfsplus_file_open(struct inode *inode, struct file *file) | 241 | static int hfsplus_file_open(struct inode *inode, struct file *file) |
| 254 | { | 242 | { |
| 255 | if (HFSPLUS_IS_RSRC(inode)) | 243 | if (HFSPLUS_IS_RSRC(inode)) |
| @@ -281,7 +269,6 @@ static int hfsplus_file_release(struct inode *inode, struct file *file) | |||
| 281 | static const struct inode_operations hfsplus_file_inode_operations = { | 269 | static const struct inode_operations hfsplus_file_inode_operations = { |
| 282 | .lookup = hfsplus_file_lookup, | 270 | .lookup = hfsplus_file_lookup, |
| 283 | .truncate = hfsplus_file_truncate, | 271 | .truncate = hfsplus_file_truncate, |
| 284 | .permission = hfsplus_permission, | ||
| 285 | .setxattr = hfsplus_setxattr, | 272 | .setxattr = hfsplus_setxattr, |
| 286 | .getxattr = hfsplus_getxattr, | 273 | .getxattr = hfsplus_getxattr, |
| 287 | .listxattr = hfsplus_listxattr, | 274 | .listxattr = hfsplus_listxattr, |
diff --git a/fs/namei.c b/fs/namei.c index 9e2a534383d9..09ce58e49e72 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -212,8 +212,7 @@ int generic_permission(struct inode *inode, int mask, | |||
| 212 | * Read/write DACs are always overridable. | 212 | * Read/write DACs are always overridable. |
| 213 | * Executable DACs are overridable if at least one exec bit is set. | 213 | * Executable DACs are overridable if at least one exec bit is set. |
| 214 | */ | 214 | */ |
| 215 | if (!(mask & MAY_EXEC) || | 215 | if (!(mask & MAY_EXEC) || execute_ok(inode)) |
| 216 | (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode)) | ||
| 217 | if (capable(CAP_DAC_OVERRIDE)) | 216 | if (capable(CAP_DAC_OVERRIDE)) |
| 218 | return 0; | 217 | return 0; |
| 219 | 218 | ||
| @@ -249,23 +248,11 @@ int inode_permission(struct inode *inode, int mask) | |||
| 249 | } | 248 | } |
| 250 | 249 | ||
| 251 | /* Ordinary permission routines do not understand MAY_APPEND. */ | 250 | /* Ordinary permission routines do not understand MAY_APPEND. */ |
| 252 | if (inode->i_op && inode->i_op->permission) { | 251 | if (inode->i_op && inode->i_op->permission) |
| 253 | retval = inode->i_op->permission(inode, mask); | 252 | retval = inode->i_op->permission(inode, mask); |
| 254 | if (!retval) { | 253 | else |
| 255 | /* | ||
| 256 | * Exec permission on a regular file is denied if none | ||
| 257 | * of the execute bits are set. | ||
| 258 | * | ||
| 259 | * This check should be done by the ->permission() | ||
| 260 | * method. | ||
| 261 | */ | ||
| 262 | if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode) && | ||
| 263 | !(inode->i_mode & S_IXUGO)) | ||
| 264 | return -EACCES; | ||
| 265 | } | ||
| 266 | } else { | ||
| 267 | retval = generic_permission(inode, mask, NULL); | 254 | retval = generic_permission(inode, mask, NULL); |
| 268 | } | 255 | |
| 269 | if (retval) | 256 | if (retval) |
| 270 | return retval; | 257 | return retval; |
| 271 | 258 | ||
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index c216c8786c51..3e64b98f3a93 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
| @@ -1957,6 +1957,9 @@ force_lookup: | |||
| 1957 | } else | 1957 | } else |
| 1958 | res = PTR_ERR(cred); | 1958 | res = PTR_ERR(cred); |
| 1959 | out: | 1959 | out: |
| 1960 | if (!res && (mask & MAY_EXEC) && !execute_ok(inode)) | ||
| 1961 | res = -EACCES; | ||
| 1962 | |||
| 1960 | dfprintk(VFS, "NFS: permission(%s/%ld), mask=0x%x, res=%d\n", | 1963 | dfprintk(VFS, "NFS: permission(%s/%ld), mask=0x%x, res=%d\n", |
| 1961 | inode->i_sb->s_id, inode->i_ino, mask, res); | 1964 | inode->i_sb->s_id, inode->i_ino, mask, res); |
| 1962 | return res; | 1965 | return res; |
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 5fe210c09171..7b997754a25e 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
| @@ -298,13 +298,19 @@ static int proc_sys_permission(struct inode *inode, int mask) | |||
| 298 | * sysctl entries that are not writeable, | 298 | * sysctl entries that are not writeable, |
| 299 | * are _NOT_ writeable, capabilities or not. | 299 | * are _NOT_ writeable, capabilities or not. |
| 300 | */ | 300 | */ |
| 301 | struct ctl_table_header *head = grab_header(inode); | 301 | struct ctl_table_header *head; |
| 302 | struct ctl_table *table = PROC_I(inode)->sysctl_entry; | 302 | struct ctl_table *table; |
| 303 | int error; | 303 | int error; |
| 304 | 304 | ||
| 305 | /* Executable files are not allowed under /proc/sys/ */ | ||
| 306 | if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) | ||
| 307 | return -EACCES; | ||
| 308 | |||
| 309 | head = grab_header(inode); | ||
| 305 | if (IS_ERR(head)) | 310 | if (IS_ERR(head)) |
| 306 | return PTR_ERR(head); | 311 | return PTR_ERR(head); |
| 307 | 312 | ||
| 313 | table = PROC_I(inode)->sysctl_entry; | ||
| 308 | if (!table) /* global root - r-xr-xr-x */ | 314 | if (!table) /* global root - r-xr-xr-x */ |
| 309 | error = mask & MAY_WRITE ? -EACCES : 0; | 315 | error = mask & MAY_WRITE ? -EACCES : 0; |
| 310 | else /* Use the permissions on the sysctl table entry */ | 316 | else /* Use the permissions on the sysctl table entry */ |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 5f70aa62cf0f..025a4a251b64 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -1851,6 +1851,11 @@ extern int inode_permission(struct inode *, int); | |||
| 1851 | extern int generic_permission(struct inode *, int, | 1851 | extern int generic_permission(struct inode *, int, |
| 1852 | int (*check_acl)(struct inode *, int)); | 1852 | int (*check_acl)(struct inode *, int)); |
| 1853 | 1853 | ||
| 1854 | static inline bool execute_ok(struct inode *inode) | ||
| 1855 | { | ||
| 1856 | return (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode); | ||
| 1857 | } | ||
| 1858 | |||
| 1854 | extern int get_write_access(struct inode *); | 1859 | extern int get_write_access(struct inode *); |
| 1855 | extern int deny_write_access(struct file *); | 1860 | extern int deny_write_access(struct file *); |
| 1856 | static inline void put_write_access(struct inode * inode) | 1861 | static inline void put_write_access(struct inode * inode) |
