Commit f696a3659fc4b3a3bf4bc83d9dbec5e5a2ffd929
Committed by
Al Viro
1 parent
5cec56deb6
Exists in
master
and in
7 other branches
[PATCH] move executable checking into ->permission()
For execute permission on a regular files we need to check if file has any execute bits at all, regardless of capabilites. This check is normally performed by generic_permission() but was also added to the case when the filesystem defines its own ->permission() method. In the latter case the filesystem should be responsible for performing this check. Move the check from inode_permission() inside filesystems which are not calling generic_permission(). Create a helper function execute_ok() that returns true if the inode is a directory or if any execute bits are present in i_mode. Also fix up the following code: - coda control file is never executable - sysctl files are never executable - hfs_permission seems broken on MAY_EXEC, remove - hfsplus_permission is eqivalent to generic_permission(), remove Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Showing 9 changed files with 30 additions and 44 deletions Side-by-side Diff
fs/cifs/cifsfs.c
| ... | ... | @@ -275,9 +275,12 @@ |
| 275 | 275 | |
| 276 | 276 | cifs_sb = CIFS_SB(inode->i_sb); |
| 277 | 277 | |
| 278 | - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) | |
| 279 | - return 0; | |
| 280 | - else /* file mode might have been restricted at mount time | |
| 278 | + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) { | |
| 279 | + if ((mask & MAY_EXEC) && !execute_ok(inode)) | |
| 280 | + return -EACCES; | |
| 281 | + else | |
| 282 | + return 0; | |
| 283 | + } else /* file mode might have been restricted at mount time | |
| 281 | 284 | on the client (above and beyond ACL on servers) for |
| 282 | 285 | servers which do not support setting and viewing mode bits, |
| 283 | 286 | so allowing client to check permissions is useful */ |
fs/coda/dir.c
fs/coda/pioctl.c
fs/hfs/inode.c
| ... | ... | @@ -511,13 +511,6 @@ |
| 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 | 514 | static int hfs_file_open(struct inode *inode, struct file *file) |
| 522 | 515 | { |
| 523 | 516 | if (HFS_IS_RSRC(inode)) |
| ... | ... | @@ -616,7 +609,6 @@ |
| 616 | 609 | .lookup = hfs_file_lookup, |
| 617 | 610 | .truncate = hfs_file_truncate, |
| 618 | 611 | .setattr = hfs_inode_setattr, |
| 619 | - .permission = hfs_permission, | |
| 620 | 612 | .setxattr = hfs_setxattr, |
| 621 | 613 | .getxattr = hfs_getxattr, |
| 622 | 614 | .listxattr = hfs_listxattr, |
fs/hfsplus/inode.c
| ... | ... | @@ -238,18 +238,6 @@ |
| 238 | 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 | 241 | static int hfsplus_file_open(struct inode *inode, struct file *file) |
| 254 | 242 | { |
| 255 | 243 | if (HFSPLUS_IS_RSRC(inode)) |
| ... | ... | @@ -281,7 +269,6 @@ |
| 281 | 269 | static const struct inode_operations hfsplus_file_inode_operations = { |
| 282 | 270 | .lookup = hfsplus_file_lookup, |
| 283 | 271 | .truncate = hfsplus_file_truncate, |
| 284 | - .permission = hfsplus_permission, | |
| 285 | 272 | .setxattr = hfsplus_setxattr, |
| 286 | 273 | .getxattr = hfsplus_getxattr, |
| 287 | 274 | .listxattr = hfsplus_listxattr, |
fs/namei.c
| ... | ... | @@ -212,8 +212,7 @@ |
| 212 | 212 | * Read/write DACs are always overridable. |
| 213 | 213 | * Executable DACs are overridable if at least one exec bit is set. |
| 214 | 214 | */ |
| 215 | - if (!(mask & MAY_EXEC) || | |
| 216 | - (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode)) | |
| 215 | + if (!(mask & MAY_EXEC) || execute_ok(inode)) | |
| 217 | 216 | if (capable(CAP_DAC_OVERRIDE)) |
| 218 | 217 | return 0; |
| 219 | 218 | |
| 220 | 219 | |
| 221 | 220 | |
| ... | ... | @@ -249,23 +248,11 @@ |
| 249 | 248 | } |
| 250 | 249 | |
| 251 | 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 | 252 | retval = inode->i_op->permission(inode, mask); |
| 254 | - if (!retval) { | |
| 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 { | |
| 253 | + else | |
| 267 | 254 | retval = generic_permission(inode, mask, NULL); |
| 268 | - } | |
| 255 | + | |
| 269 | 256 | if (retval) |
| 270 | 257 | return retval; |
| 271 | 258 |
fs/nfs/dir.c
| ... | ... | @@ -1957,6 +1957,9 @@ |
| 1957 | 1957 | } else |
| 1958 | 1958 | res = PTR_ERR(cred); |
| 1959 | 1959 | out: |
| 1960 | + if (!res && (mask & MAY_EXEC) && !execute_ok(inode)) | |
| 1961 | + res = -EACCES; | |
| 1962 | + | |
| 1960 | 1963 | dfprintk(VFS, "NFS: permission(%s/%ld), mask=0x%x, res=%d\n", |
| 1961 | 1964 | inode->i_sb->s_id, inode->i_ino, mask, res); |
| 1962 | 1965 | return res; |
fs/proc/proc_sysctl.c
| ... | ... | @@ -298,13 +298,19 @@ |
| 298 | 298 | * sysctl entries that are not writeable, |
| 299 | 299 | * are _NOT_ writeable, capabilities or not. |
| 300 | 300 | */ |
| 301 | - struct ctl_table_header *head = grab_header(inode); | |
| 302 | - struct ctl_table *table = PROC_I(inode)->sysctl_entry; | |
| 301 | + struct ctl_table_header *head; | |
| 302 | + struct ctl_table *table; | |
| 303 | 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 | 310 | if (IS_ERR(head)) |
| 306 | 311 | return PTR_ERR(head); |
| 307 | 312 | |
| 313 | + table = PROC_I(inode)->sysctl_entry; | |
| 308 | 314 | if (!table) /* global root - r-xr-xr-x */ |
| 309 | 315 | error = mask & MAY_WRITE ? -EACCES : 0; |
| 310 | 316 | else /* Use the permissions on the sysctl table entry */ |
include/linux/fs.h
| ... | ... | @@ -1851,6 +1851,11 @@ |
| 1851 | 1851 | extern int generic_permission(struct inode *, int, |
| 1852 | 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 | 1859 | extern int get_write_access(struct inode *); |
| 1855 | 1860 | extern int deny_write_access(struct file *); |
| 1856 | 1861 | static inline void put_write_access(struct inode * inode) |