aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2008-07-31 07:41:58 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2008-10-23 05:13:25 -0400
commitf696a3659fc4b3a3bf4bc83d9dbec5e5a2ffd929 (patch)
tree738adf557608f26e881a710839de12b7527549b6 /fs
parent5cec56deb6d41b5b570306b17cd0b1590ebd0897 (diff)
[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>
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/cifsfs.c9
-rw-r--r--fs/coda/dir.c3
-rw-r--r--fs/coda/pioctl.c2
-rw-r--r--fs/hfs/inode.c8
-rw-r--r--fs/hfsplus/inode.c13
-rw-r--r--fs/namei.c21
-rw-r--r--fs/nfs/dir.c3
-rw-r--r--fs/proc/proc_sysctl.c10
8 files changed, 25 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 */
44static int coda_ioctl_permission(struct inode *inode, int mask) 44static 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
49static int coda_pioctl(struct inode * inode, struct file * filp, 49static 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
514static 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
521static int hfs_file_open(struct inode *inode, struct file *file) 514static 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
241static 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
253static int hfsplus_file_open(struct inode *inode, struct file *file) 241static 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)
281static const struct inode_operations hfsplus_file_inode_operations = { 269static 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);
1959out: 1959out:
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 */