diff --git a/fs/namei.c b/fs/namei.c index 7cba63295a82f4aec85e0ce1f52c9f0fb9bbc8d7..2792e0ca01d4f03effa44a304e477da9b5e706c0 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -227,10 +227,10 @@ int generic_permission(struct inode *inode, int mask, int permission(struct inode *inode, int mask, struct nameidata *nd) { - umode_t mode = inode->i_mode; int retval, submask; if (mask & MAY_WRITE) { + umode_t mode = inode->i_mode; /* * Nobody gets write access to a read-only fs. @@ -246,22 +246,34 @@ int permission(struct inode *inode, int mask, struct nameidata *nd) return -EACCES; } - - /* - * MAY_EXEC on regular files requires special handling: We override - * filesystem execute permissions if the mode bits aren't set or - * the fs is mounted with the "noexec" flag. - */ - if ((mask & MAY_EXEC) && S_ISREG(mode) && (!(mode & S_IXUGO) || - (nd && nd->mnt && (nd->mnt->mnt_flags & MNT_NOEXEC)))) - return -EACCES; + if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) { + /* + * MAY_EXEC on regular files is denied if the fs is mounted + * with the "noexec" flag. + */ + if (nd && nd->mnt && (nd->mnt->mnt_flags & MNT_NOEXEC)) + return -EACCES; + } /* Ordinary permission routines do not understand MAY_APPEND. */ submask = mask & ~MAY_APPEND; - if (inode->i_op && inode->i_op->permission) + if (inode->i_op && inode->i_op->permission) { retval = inode->i_op->permission(inode, submask, nd); - else + if (!retval) { + /* + * 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, submask, NULL); + } if (retval) return retval;