aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2012-06-25 07:55:46 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-07-14 08:38:36 -0400
commit0bdaea9017b9d2b9996e153a71ee03555969b80e (patch)
tree112d8c8a2f0adb0b68356b1e39209454a7a6ea71 /fs/namei.c
parent9249e17fe094d853d1ef7475dd559a2cc7e23d42 (diff)
VFS: Split inode_permission()
Split inode_permission() into inode- and superblock-dependent parts. This is aimed at unionmounts where the superblock from the upper layer has to be checked rather than the superblock from the lower layer as the upper layer may be writable, thus allowing an unwritable file from the lower layer to be copied up and modified. Original-author: Valerie Aurora <vaurora@redhat.com> Signed-off-by: David Howells <dhowells@redhat.com> (Further development) Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c66
1 files changed, 49 insertions, 17 deletions
diff --git a/fs/namei.c b/fs/namei.c
index c6dcb4c8f86c..1b6474687698 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -315,31 +315,22 @@ static inline int do_inode_permission(struct inode *inode, int mask)
315} 315}
316 316
317/** 317/**
318 * inode_permission - check for access rights to a given inode 318 * __inode_permission - Check for access rights to a given inode
319 * @inode: inode to check permission on 319 * @inode: Inode to check permission on
320 * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC, ...) 320 * @mask: Right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
321 * 321 *
322 * Used to check for read/write/execute permissions on an inode. 322 * Check for read/write/execute permissions on an inode.
323 * We use "fsuid" for this, letting us set arbitrary permissions
324 * for filesystem access without changing the "normal" uids which
325 * are used for other things.
326 * 323 *
327 * When checking for MAY_APPEND, MAY_WRITE must also be set in @mask. 324 * When checking for MAY_APPEND, MAY_WRITE must also be set in @mask.
325 *
326 * This does not check for a read-only file system. You probably want
327 * inode_permission().
328 */ 328 */
329int inode_permission(struct inode *inode, int mask) 329int __inode_permission(struct inode *inode, int mask)
330{ 330{
331 int retval; 331 int retval;
332 332
333 if (unlikely(mask & MAY_WRITE)) { 333 if (unlikely(mask & MAY_WRITE)) {
334 umode_t mode = inode->i_mode;
335
336 /*
337 * Nobody gets write access to a read-only fs.
338 */
339 if (IS_RDONLY(inode) &&
340 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
341 return -EROFS;
342
343 /* 334 /*
344 * Nobody gets write access to an immutable file. 335 * Nobody gets write access to an immutable file.
345 */ 336 */
@@ -359,6 +350,47 @@ int inode_permission(struct inode *inode, int mask)
359} 350}
360 351
361/** 352/**
353 * sb_permission - Check superblock-level permissions
354 * @sb: Superblock of inode to check permission on
355 * @mask: Right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
356 *
357 * Separate out file-system wide checks from inode-specific permission checks.
358 */
359static int sb_permission(struct super_block *sb, struct inode *inode, int mask)
360{
361 if (unlikely(mask & MAY_WRITE)) {
362 umode_t mode = inode->i_mode;
363
364 /* Nobody gets write access to a read-only fs. */
365 if ((sb->s_flags & MS_RDONLY) &&
366 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
367 return -EROFS;
368 }
369 return 0;
370}
371
372/**
373 * inode_permission - Check for access rights to a given inode
374 * @inode: Inode to check permission on
375 * @mask: Right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
376 *
377 * Check for read/write/execute permissions on an inode. We use fs[ug]id for
378 * this, letting us set arbitrary permissions for filesystem access without
379 * changing the "normal" UIDs which are used for other things.
380 *
381 * When checking for MAY_APPEND, MAY_WRITE must also be set in @mask.
382 */
383int inode_permission(struct inode *inode, int mask)
384{
385 int retval;
386
387 retval = sb_permission(inode->i_sb, inode, mask);
388 if (retval)
389 return retval;
390 return __inode_permission(inode, mask);
391}
392
393/**
362 * path_get - get a reference to a path 394 * path_get - get a reference to a path
363 * @path: path to get the reference to 395 * @path: path to get the reference to
364 * 396 *