mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 03:36:19 +00:00
[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>
This commit is contained in:
parent
5cec56deb6
commit
f696a3659f
9 changed files with 30 additions and 44 deletions
|
@ -275,9 +275,12 @@ static int cifs_permission(struct inode *inode, int mask)
|
||||||
|
|
||||||
cifs_sb = CIFS_SB(inode->i_sb);
|
cifs_sb = CIFS_SB(inode->i_sb);
|
||||||
|
|
||||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) {
|
||||||
return 0;
|
if ((mask & MAY_EXEC) && !execute_ok(inode))
|
||||||
else /* file mode might have been restricted at mount time
|
return -EACCES;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
} else /* file mode might have been restricted at mount time
|
||||||
on the client (above and beyond ACL on servers) for
|
on the client (above and beyond ACL on servers) for
|
||||||
servers which do not support setting and viewing mode bits,
|
servers which do not support setting and viewing mode bits,
|
||||||
so allowing client to check permissions is useful */
|
so allowing client to check permissions is useful */
|
||||||
|
|
|
@ -146,6 +146,9 @@ int coda_permission(struct inode *inode, int mask)
|
||||||
if (!mask)
|
if (!mask)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if ((mask & MAY_EXEC) && !execute_ok(inode))
|
||||||
|
return -EACCES;
|
||||||
|
|
||||||
lock_kernel();
|
lock_kernel();
|
||||||
|
|
||||||
if (coda_cache_check(inode, mask))
|
if (coda_cache_check(inode, mask))
|
||||||
|
|
|
@ -43,7 +43,7 @@ const struct file_operations coda_ioctl_operations = {
|
||||||
/* the coda pioctl inode ops */
|
/* the coda pioctl inode ops */
|
||||||
static int coda_ioctl_permission(struct inode *inode, int mask)
|
static int coda_ioctl_permission(struct inode *inode, int mask)
|
||||||
{
|
{
|
||||||
return 0;
|
return (mask & MAY_EXEC) ? -EACCES : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int coda_pioctl(struct inode * inode, struct file * filp,
|
static int coda_pioctl(struct inode * inode, struct file * filp,
|
||||||
|
|
|
@ -511,13 +511,6 @@ void hfs_clear_inode(struct inode *inode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hfs_permission(struct inode *inode, int mask)
|
|
||||||
{
|
|
||||||
if (S_ISREG(inode->i_mode) && mask & MAY_EXEC)
|
|
||||||
return 0;
|
|
||||||
return generic_permission(inode, mask, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int hfs_file_open(struct inode *inode, struct file *file)
|
static int hfs_file_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
if (HFS_IS_RSRC(inode))
|
if (HFS_IS_RSRC(inode))
|
||||||
|
@ -616,7 +609,6 @@ static const struct inode_operations hfs_file_inode_operations = {
|
||||||
.lookup = hfs_file_lookup,
|
.lookup = hfs_file_lookup,
|
||||||
.truncate = hfs_file_truncate,
|
.truncate = hfs_file_truncate,
|
||||||
.setattr = hfs_inode_setattr,
|
.setattr = hfs_inode_setattr,
|
||||||
.permission = hfs_permission,
|
|
||||||
.setxattr = hfs_setxattr,
|
.setxattr = hfs_setxattr,
|
||||||
.getxattr = hfs_getxattr,
|
.getxattr = hfs_getxattr,
|
||||||
.listxattr = hfs_listxattr,
|
.listxattr = hfs_listxattr,
|
||||||
|
|
|
@ -238,18 +238,6 @@ static void hfsplus_set_perms(struct inode *inode, struct hfsplus_perm *perms)
|
||||||
perms->dev = cpu_to_be32(HFSPLUS_I(inode).dev);
|
perms->dev = cpu_to_be32(HFSPLUS_I(inode).dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hfsplus_permission(struct inode *inode, int mask)
|
|
||||||
{
|
|
||||||
/* MAY_EXEC is also used for lookup, if no x bit is set allow lookup,
|
|
||||||
* open_exec has the same test, so it's still not executable, if a x bit
|
|
||||||
* is set fall back to standard permission check.
|
|
||||||
*/
|
|
||||||
if (S_ISREG(inode->i_mode) && mask & MAY_EXEC && !(inode->i_mode & 0111))
|
|
||||||
return 0;
|
|
||||||
return generic_permission(inode, mask, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int hfsplus_file_open(struct inode *inode, struct file *file)
|
static int hfsplus_file_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
if (HFSPLUS_IS_RSRC(inode))
|
if (HFSPLUS_IS_RSRC(inode))
|
||||||
|
@ -281,7 +269,6 @@ static int hfsplus_file_release(struct inode *inode, struct file *file)
|
||||||
static const struct inode_operations hfsplus_file_inode_operations = {
|
static const struct inode_operations hfsplus_file_inode_operations = {
|
||||||
.lookup = hfsplus_file_lookup,
|
.lookup = hfsplus_file_lookup,
|
||||||
.truncate = hfsplus_file_truncate,
|
.truncate = hfsplus_file_truncate,
|
||||||
.permission = hfsplus_permission,
|
|
||||||
.setxattr = hfsplus_setxattr,
|
.setxattr = hfsplus_setxattr,
|
||||||
.getxattr = hfsplus_getxattr,
|
.getxattr = hfsplus_getxattr,
|
||||||
.listxattr = hfsplus_listxattr,
|
.listxattr = hfsplus_listxattr,
|
||||||
|
|
21
fs/namei.c
21
fs/namei.c
|
@ -212,8 +212,7 @@ int generic_permission(struct inode *inode, int mask,
|
||||||
* Read/write DACs are always overridable.
|
* Read/write DACs are always overridable.
|
||||||
* Executable DACs are overridable if at least one exec bit is set.
|
* Executable DACs are overridable if at least one exec bit is set.
|
||||||
*/
|
*/
|
||||||
if (!(mask & MAY_EXEC) ||
|
if (!(mask & MAY_EXEC) || execute_ok(inode))
|
||||||
(inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode))
|
|
||||||
if (capable(CAP_DAC_OVERRIDE))
|
if (capable(CAP_DAC_OVERRIDE))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -249,23 +248,11 @@ int inode_permission(struct inode *inode, int mask)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ordinary permission routines do not understand MAY_APPEND. */
|
/* Ordinary permission routines do not understand MAY_APPEND. */
|
||||||
if (inode->i_op && inode->i_op->permission) {
|
if (inode->i_op && inode->i_op->permission)
|
||||||
retval = inode->i_op->permission(inode, mask);
|
retval = inode->i_op->permission(inode, mask);
|
||||||
if (!retval) {
|
else
|
||||||
/*
|
|
||||||
* Exec permission on a regular file is denied if none
|
|
||||||
* of the execute bits are set.
|
|
||||||
*
|
|
||||||
* This check should be done by the ->permission()
|
|
||||||
* method.
|
|
||||||
*/
|
|
||||||
if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode) &&
|
|
||||||
!(inode->i_mode & S_IXUGO))
|
|
||||||
return -EACCES;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
retval = generic_permission(inode, mask, NULL);
|
retval = generic_permission(inode, mask, NULL);
|
||||||
}
|
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
|
|
@ -1957,6 +1957,9 @@ force_lookup:
|
||||||
} else
|
} else
|
||||||
res = PTR_ERR(cred);
|
res = PTR_ERR(cred);
|
||||||
out:
|
out:
|
||||||
|
if (!res && (mask & MAY_EXEC) && !execute_ok(inode))
|
||||||
|
res = -EACCES;
|
||||||
|
|
||||||
dfprintk(VFS, "NFS: permission(%s/%ld), mask=0x%x, res=%d\n",
|
dfprintk(VFS, "NFS: permission(%s/%ld), mask=0x%x, res=%d\n",
|
||||||
inode->i_sb->s_id, inode->i_ino, mask, res);
|
inode->i_sb->s_id, inode->i_ino, mask, res);
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -298,13 +298,19 @@ static int proc_sys_permission(struct inode *inode, int mask)
|
||||||
* sysctl entries that are not writeable,
|
* sysctl entries that are not writeable,
|
||||||
* are _NOT_ writeable, capabilities or not.
|
* are _NOT_ writeable, capabilities or not.
|
||||||
*/
|
*/
|
||||||
struct ctl_table_header *head = grab_header(inode);
|
struct ctl_table_header *head;
|
||||||
struct ctl_table *table = PROC_I(inode)->sysctl_entry;
|
struct ctl_table *table;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
/* Executable files are not allowed under /proc/sys/ */
|
||||||
|
if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))
|
||||||
|
return -EACCES;
|
||||||
|
|
||||||
|
head = grab_header(inode);
|
||||||
if (IS_ERR(head))
|
if (IS_ERR(head))
|
||||||
return PTR_ERR(head);
|
return PTR_ERR(head);
|
||||||
|
|
||||||
|
table = PROC_I(inode)->sysctl_entry;
|
||||||
if (!table) /* global root - r-xr-xr-x */
|
if (!table) /* global root - r-xr-xr-x */
|
||||||
error = mask & MAY_WRITE ? -EACCES : 0;
|
error = mask & MAY_WRITE ? -EACCES : 0;
|
||||||
else /* Use the permissions on the sysctl table entry */
|
else /* Use the permissions on the sysctl table entry */
|
||||||
|
|
|
@ -1851,6 +1851,11 @@ extern int inode_permission(struct inode *, int);
|
||||||
extern int generic_permission(struct inode *, int,
|
extern int generic_permission(struct inode *, int,
|
||||||
int (*check_acl)(struct inode *, int));
|
int (*check_acl)(struct inode *, int));
|
||||||
|
|
||||||
|
static inline bool execute_ok(struct inode *inode)
|
||||||
|
{
|
||||||
|
return (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode);
|
||||||
|
}
|
||||||
|
|
||||||
extern int get_write_access(struct inode *);
|
extern int get_write_access(struct inode *);
|
||||||
extern int deny_write_access(struct file *);
|
extern int deny_write_access(struct file *);
|
||||||
static inline void put_write_access(struct inode * inode)
|
static inline void put_write_access(struct inode * inode)
|
||||||
|
|
Loading…
Reference in a new issue