diff options
author | Miklos Szeredi <mszeredi@suse.cz> | 2007-10-17 02:27:08 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-17 11:42:52 -0400 |
commit | 22590e41cb569add194829c08dc0ceea74b38a65 (patch) | |
tree | 0db73fe0e78bcde816dcf289e0aa5323abf73833 /fs/namei.c | |
parent | 043f46f6151df2c518988b5e41376e42491257b5 (diff) |
fix execute checking in permission()
permission() checks that MAY_EXEC is only allowed on regular files if at least
one execute bit is set in the file mode.
generic_permission() already ensures this, so the extra check in permission()
is superfluous.
If the filesystem defines it's own ->permission() the check may still be
needed. In this case move it after ->permission(). This is needed because
filesystems such as FUSE may need to refresh the inode attributes before
checking permissions.
This check should be moved inside ->permission(), but that's another story.
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 36 |
1 files changed, 24 insertions, 12 deletions
diff --git a/fs/namei.c b/fs/namei.c index 7cba63295a82..2792e0ca01d4 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -227,10 +227,10 @@ int generic_permission(struct inode *inode, int mask, | |||
227 | 227 | ||
228 | int permission(struct inode *inode, int mask, struct nameidata *nd) | 228 | int permission(struct inode *inode, int mask, struct nameidata *nd) |
229 | { | 229 | { |
230 | umode_t mode = inode->i_mode; | ||
231 | int retval, submask; | 230 | int retval, submask; |
232 | 231 | ||
233 | if (mask & MAY_WRITE) { | 232 | if (mask & MAY_WRITE) { |
233 | umode_t mode = inode->i_mode; | ||
234 | 234 | ||
235 | /* | 235 | /* |
236 | * Nobody gets write access to a read-only fs. | 236 | * Nobody gets write access to a read-only fs. |
@@ -246,22 +246,34 @@ int permission(struct inode *inode, int mask, struct nameidata *nd) | |||
246 | return -EACCES; | 246 | return -EACCES; |
247 | } | 247 | } |
248 | 248 | ||
249 | 249 | if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) { | |
250 | /* | 250 | /* |
251 | * MAY_EXEC on regular files requires special handling: We override | 251 | * MAY_EXEC on regular files is denied if the fs is mounted |
252 | * filesystem execute permissions if the mode bits aren't set or | 252 | * with the "noexec" flag. |
253 | * the fs is mounted with the "noexec" flag. | 253 | */ |
254 | */ | 254 | if (nd && nd->mnt && (nd->mnt->mnt_flags & MNT_NOEXEC)) |
255 | if ((mask & MAY_EXEC) && S_ISREG(mode) && (!(mode & S_IXUGO) || | 255 | return -EACCES; |
256 | (nd && nd->mnt && (nd->mnt->mnt_flags & MNT_NOEXEC)))) | 256 | } |
257 | return -EACCES; | ||
258 | 257 | ||
259 | /* Ordinary permission routines do not understand MAY_APPEND. */ | 258 | /* Ordinary permission routines do not understand MAY_APPEND. */ |
260 | submask = mask & ~MAY_APPEND; | 259 | submask = mask & ~MAY_APPEND; |
261 | if (inode->i_op && inode->i_op->permission) | 260 | if (inode->i_op && inode->i_op->permission) { |
262 | retval = inode->i_op->permission(inode, submask, nd); | 261 | retval = inode->i_op->permission(inode, submask, nd); |
263 | else | 262 | if (!retval) { |
263 | /* | ||
264 | * Exec permission on a regular file is denied if none | ||
265 | * of the execute bits are set. | ||
266 | * | ||
267 | * This check should be done by the ->permission() | ||
268 | * method. | ||
269 | */ | ||
270 | if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode) && | ||
271 | !(inode->i_mode & S_IXUGO)) | ||
272 | return -EACCES; | ||
273 | } | ||
274 | } else { | ||
264 | retval = generic_permission(inode, submask, NULL); | 275 | retval = generic_permission(inode, submask, NULL); |
276 | } | ||
265 | if (retval) | 277 | if (retval) |
266 | return retval; | 278 | return retval; |
267 | 279 | ||