Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8c50902e authored by Daniel Rosenberg's avatar Daniel Rosenberg
Browse files

vfs: Add permission2 for filesystems with per mount permissions



This allows filesystems to use their mount private data to
influence the permssions they return in permission2. It has
been separated into a new call to avoid disrupting current
permission users.

Change-Id: I9d416e3b8b6eca84ef3e336bd2af89ddd51df6ca
Signed-off-by: default avatarDaniel Rosenberg <drosen@google.com>
parent b859254b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1089,7 +1089,7 @@ EXPORT_SYMBOL(flush_old_exec);

void would_dump(struct linux_binprm *bprm, struct file *file)
{
	if (inode_permission(file_inode(file), MAY_READ) < 0)
	if (inode_permission2(file->f_path.mnt, file_inode(file), MAY_READ) < 0)
		bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
}
EXPORT_SYMBOL(would_dump);
+126 −51
Original line number Diff line number Diff line
@@ -368,9 +368,11 @@ EXPORT_SYMBOL(generic_permission);
 * flag in inode->i_opflags, that says "this has not special
 * permission function, use the fast case".
 */
static inline int do_inode_permission(struct inode *inode, int mask)
static inline int do_inode_permission(struct vfsmount *mnt, struct inode *inode, int mask)
{
	if (unlikely(!(inode->i_opflags & IOP_FASTPERM))) {
		if (likely(mnt && inode->i_op->permission2))
			return inode->i_op->permission2(mnt, inode, mask);
		if (likely(inode->i_op->permission))
			return inode->i_op->permission(inode, mask);

@@ -394,7 +396,7 @@ static inline int do_inode_permission(struct inode *inode, int mask)
 * This does not check for a read-only file system.  You probably want
 * inode_permission().
 */
int __inode_permission(struct inode *inode, int mask)
int __inode_permission2(struct vfsmount *mnt, struct inode *inode, int mask)
{
	int retval;

@@ -406,7 +408,7 @@ int __inode_permission(struct inode *inode, int mask)
			return -EACCES;
	}

	retval = do_inode_permission(inode, mask);
	retval = do_inode_permission(mnt, inode, mask);
	if (retval)
		return retval;

@@ -414,7 +416,14 @@ int __inode_permission(struct inode *inode, int mask)
	if (retval)
		return retval;

	return security_inode_permission(inode, mask);
	retval = security_inode_permission(inode, mask);
	return retval;
}
EXPORT_SYMBOL(__inode_permission2);

int __inode_permission(struct inode *inode, int mask)
{
	return __inode_permission2(NULL, inode, mask);
}
EXPORT_SYMBOL(__inode_permission);

@@ -450,14 +459,20 @@ static int sb_permission(struct super_block *sb, struct inode *inode, int mask)
 *
 * When checking for MAY_APPEND, MAY_WRITE must also be set in @mask.
 */
int inode_permission(struct inode *inode, int mask)
int inode_permission2(struct vfsmount *mnt, struct inode *inode, int mask)
{
	int retval;

	retval = sb_permission(inode->i_sb, inode, mask);
	if (retval)
		return retval;
	return __inode_permission(inode, mask);
	return __inode_permission2(mnt, inode, mask);
}
EXPORT_SYMBOL(inode_permission2);

int inode_permission(struct inode *inode, int mask)
{
	return inode_permission2(NULL, inode, mask);
}
EXPORT_SYMBOL(inode_permission);

@@ -1487,13 +1502,13 @@ static int lookup_slow(struct nameidata *nd, struct path *path)
static inline int may_lookup(struct nameidata *nd)
{
	if (nd->flags & LOOKUP_RCU) {
		int err = inode_permission(nd->inode, MAY_EXEC|MAY_NOT_BLOCK);
		int err = inode_permission2(nd->path.mnt, nd->inode, MAY_EXEC|MAY_NOT_BLOCK);
		if (err != -ECHILD)
			return err;
		if (unlazy_walk(nd, NULL))
			return -ECHILD;
	}
	return inode_permission(nd->inode, MAY_EXEC);
	return inode_permission2(nd->path.mnt, nd->inode, MAY_EXEC);
}

static inline int handle_dots(struct nameidata *nd, int type)
@@ -1830,11 +1845,12 @@ static int path_init(int dfd, const char *name, unsigned int flags,
	nd->depth = 0;
	if (flags & LOOKUP_ROOT) {
		struct dentry *root = nd->root.dentry;
		struct vfsmount *mnt = nd->root.mnt;
		struct inode *inode = root->d_inode;
		if (*name) {
			if (!d_can_lookup(root))
				return -ENOTDIR;
			retval = inode_permission(inode, MAY_EXEC);
			retval = inode_permission2(mnt, inode, MAY_EXEC);
			if (retval)
				return retval;
		}
@@ -2088,6 +2104,7 @@ static struct dentry *lookup_hash(struct nameidata *nd)
/**
 * lookup_one_len - filesystem helper to lookup single pathname component
 * @name:	pathname component to lookup
 * @mnt:	mount we are looking up on
 * @base:	base directory to lookup from
 * @len:	maximum length @len should be interpreted to
 *
@@ -2096,7 +2113,7 @@ static struct dentry *lookup_hash(struct nameidata *nd)
 * nameidata argument is passed to the filesystem methods and a filesystem
 * using this helper needs to be prepared for that.
 */
struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
struct dentry *lookup_one_len2(const char *name, struct vfsmount *mnt, struct dentry *base, int len)
{
	struct qstr this;
	unsigned int c;
@@ -2130,12 +2147,18 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
			return ERR_PTR(err);
	}

	err = inode_permission(base->d_inode, MAY_EXEC);
	err = inode_permission2(mnt, base->d_inode, MAY_EXEC);
	if (err)
		return ERR_PTR(err);

	return __lookup_hash(&this, base, 0);
}
EXPORT_SYMBOL(lookup_one_len2);

struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
{
	return lookup_one_len2(name, NULL, base, len);
}
EXPORT_SYMBOL(lookup_one_len);

int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
@@ -2415,7 +2438,7 @@ EXPORT_SYMBOL(__check_sticky);
 * 10. We don't allow removal of NFS sillyrenamed files; it's handled by
 *     nfs_async_unlink().
 */
static int may_delete(struct inode *dir, struct dentry *victim, bool isdir)
static int may_delete(struct vfsmount *mnt, struct inode *dir, struct dentry *victim, bool isdir)
{
	struct inode *inode = victim->d_inode;
	int error;
@@ -2427,7 +2450,7 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir)
	BUG_ON(victim->d_parent->d_inode != dir);
	audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);

	error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
	error = inode_permission2(mnt, dir, MAY_WRITE | MAY_EXEC);
	if (error)
		return error;
	if (IS_APPEND(dir))
@@ -2458,14 +2481,14 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir)
 *  3. We should have write and exec permissions on dir
 *  4. We can't do it if dir is immutable (done in permission())
 */
static inline int may_create(struct inode *dir, struct dentry *child)
static inline int may_create(struct vfsmount *mnt, struct inode *dir, struct dentry *child)
{
	audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE);
	if (child->d_inode)
		return -EEXIST;
	if (IS_DEADDIR(dir))
		return -ENOENT;
	return inode_permission(dir, MAY_WRITE | MAY_EXEC);
	return inode_permission2(mnt, dir, MAY_WRITE | MAY_EXEC);
}

/*
@@ -2512,10 +2535,10 @@ void unlock_rename(struct dentry *p1, struct dentry *p2)
}
EXPORT_SYMBOL(unlock_rename);

int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
		bool want_excl)
int vfs_create2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry,
		umode_t mode, bool want_excl)
{
	int error = may_create(dir, dentry);
	int error = may_create(mnt, dir, dentry);
	if (error)
		return error;

@@ -2531,11 +2554,19 @@ int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
		fsnotify_create(dir, dentry);
	return error;
}
EXPORT_SYMBOL(vfs_create2);

int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
		bool want_excl)
{
	return vfs_create2(NULL, dir, dentry, mode, want_excl);
}
EXPORT_SYMBOL(vfs_create);

static int may_open(struct path *path, int acc_mode, int flag)
{
	struct dentry *dentry = path->dentry;
	struct vfsmount *mnt = path->mnt;
	struct inode *inode = dentry->d_inode;
	int error;

@@ -2564,7 +2595,7 @@ static int may_open(struct path *path, int acc_mode, int flag)
		break;
	}

	error = inode_permission(inode, acc_mode);
	error = inode_permission2(mnt, inode, acc_mode);
	if (error)
		return error;

@@ -2599,7 +2630,7 @@ static int handle_truncate(struct file *filp)
	if (!error)
		error = security_path_truncate(path);
	if (!error) {
		error = do_truncate(path->dentry, 0,
		error = do_truncate2(path->mnt, path->dentry, 0,
				    ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
				    filp);
	}
@@ -2620,7 +2651,7 @@ static int may_o_create(struct path *dir, struct dentry *dentry, umode_t mode)
	if (error)
		return error;

	error = inode_permission(dir->dentry->d_inode, MAY_WRITE | MAY_EXEC);
	error = inode_permission2(dir->mnt, dir->dentry->d_inode, MAY_WRITE | MAY_EXEC);
	if (error)
		return error;

@@ -2818,6 +2849,7 @@ static int lookup_open(struct nameidata *nd, struct path *path,
			bool got_write, int *opened)
{
	struct dentry *dir = nd->path.dentry;
	struct vfsmount *mnt = nd->path.mnt;
	struct inode *dir_inode = dir->d_inode;
	struct dentry *dentry;
	int error;
@@ -2865,7 +2897,7 @@ static int lookup_open(struct nameidata *nd, struct path *path,
		error = security_path_mknod(&nd->path, dentry, mode, 0);
		if (error)
			goto out_dput;
		error = vfs_create(dir->d_inode, dentry, mode,
		error = vfs_create2(mnt, dir->d_inode, dentry, mode,
				   nd->flags & LOOKUP_EXCL);
		if (error)
			goto out_dput;
@@ -3132,7 +3164,7 @@ static int do_tmpfile(int dfd, struct filename *pathname,
	if (unlikely(error))
		goto out;
	/* we want directory to be writable */
	error = inode_permission(nd->inode, MAY_WRITE | MAY_EXEC);
	error = inode_permission2(nd->path.mnt, nd->inode, MAY_WRITE | MAY_EXEC);
	if (error)
		goto out2;
	dentry = nd->path.dentry;
@@ -3379,9 +3411,9 @@ struct dentry *user_path_create(int dfd, const char __user *pathname,
}
EXPORT_SYMBOL(user_path_create);

int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
int vfs_mknod2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
{
	int error = may_create(dir, dentry);
	int error = may_create(mnt, dir, dentry);

	if (error)
		return error;
@@ -3405,6 +3437,12 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
		fsnotify_create(dir, dentry);
	return error;
}
EXPORT_SYMBOL(vfs_mknod2);

int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
{
	return vfs_mknod2(NULL, dir, dentry, mode, dev);
}
EXPORT_SYMBOL(vfs_mknod);

static int may_mknod(umode_t mode)
@@ -3447,10 +3485,10 @@ retry:
		goto out;
	switch (mode & S_IFMT) {
		case 0: case S_IFREG:
			error = vfs_create(path.dentry->d_inode,dentry,mode,true);
			error = vfs_create2(path.mnt, path.dentry->d_inode,dentry,mode,true);
			break;
		case S_IFCHR: case S_IFBLK:
			error = vfs_mknod(path.dentry->d_inode,dentry,mode,
			error = vfs_mknod2(path.mnt, path.dentry->d_inode,dentry,mode,
					new_decode_dev(dev));
			break;
		case S_IFIFO: case S_IFSOCK:
@@ -3471,9 +3509,9 @@ SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, d
	return sys_mknodat(AT_FDCWD, filename, mode, dev);
}

int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
int vfs_mkdir2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, umode_t mode)
{
	int error = may_create(dir, dentry);
	int error = may_create(mnt, dir, dentry);
	unsigned max_links = dir->i_sb->s_max_links;

	if (error)
@@ -3495,6 +3533,12 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
		fsnotify_mkdir(dir, dentry);
	return error;
}
EXPORT_SYMBOL(vfs_mkdir2);

int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
	return vfs_mkdir2(NULL, dir, dentry, mode);
}
EXPORT_SYMBOL(vfs_mkdir);

SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
@@ -3513,7 +3557,7 @@ retry:
		mode &= ~current_umask();
	error = security_path_mkdir(&path, dentry, mode);
	if (!error)
		error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
		error = vfs_mkdir2(path.mnt, path.dentry->d_inode, dentry, mode);
	done_path_create(&path, dentry);
	if (retry_estale(error, lookup_flags)) {
		lookup_flags |= LOOKUP_REVAL;
@@ -3552,9 +3596,9 @@ void dentry_unhash(struct dentry *dentry)
}
EXPORT_SYMBOL(dentry_unhash);

int vfs_rmdir(struct inode *dir, struct dentry *dentry)
int vfs_rmdir2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry)
{
	int error = may_delete(dir, dentry, 1);
	int error = may_delete(mnt, dir, dentry, 1);

	if (error)
		return error;
@@ -3589,6 +3633,10 @@ out:
		d_delete(dentry);
	return error;
}
int vfs_rmdir(struct inode *dir, struct dentry *dentry)
{
	return vfs_rmdir2(NULL, dir, dentry);
}
EXPORT_SYMBOL(vfs_rmdir);

static long do_rmdir(int dfd, const char __user *pathname)
@@ -3632,7 +3680,7 @@ retry:
	error = security_path_rmdir(&nd.path, dentry);
	if (error)
		goto exit3;
	error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
	error = vfs_rmdir2(nd.path.mnt, nd.path.dentry->d_inode, dentry);
exit3:
	dput(dentry);
exit2:
@@ -3671,10 +3719,10 @@ SYSCALL_DEFINE1(rmdir, const char __user *, pathname)
 * be appropriate for callers that expect the underlying filesystem not
 * to be NFS exported.
 */
int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegated_inode)
int vfs_unlink2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, struct inode **delegated_inode)
{
	struct inode *target = dentry->d_inode;
	int error = may_delete(dir, dentry, 0);
	int error = may_delete(mnt, dir, dentry, 0);

	if (error)
		return error;
@@ -3709,6 +3757,12 @@ out:

	return error;
}
EXPORT_SYMBOL(vfs_unlink2);

int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegated_inode)
{
	return vfs_unlink2(NULL, dir, dentry, delegated_inode);
}
EXPORT_SYMBOL(vfs_unlink);

/*
@@ -3754,7 +3808,7 @@ retry_deleg:
		error = security_path_unlink(&nd.path, dentry);
		if (error)
			goto exit2;
		error = vfs_unlink(nd.path.dentry->d_inode, dentry, &delegated_inode);
		error = vfs_unlink2(nd.path.mnt, nd.path.dentry->d_inode, dentry, &delegated_inode);
exit2:
		dput(dentry);
	}
@@ -3804,9 +3858,9 @@ SYSCALL_DEFINE1(unlink, const char __user *, pathname)
	return do_unlinkat(AT_FDCWD, pathname);
}

int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
int vfs_symlink2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, const char *oldname)
{
	int error = may_create(dir, dentry);
	int error = may_create(mnt, dir, dentry);

	if (error)
		return error;
@@ -3823,6 +3877,12 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
		fsnotify_create(dir, dentry);
	return error;
}
EXPORT_SYMBOL(vfs_symlink2);

int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
{
	return vfs_symlink2(NULL, dir, dentry, oldname);
}
EXPORT_SYMBOL(vfs_symlink);

SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
@@ -3845,7 +3905,7 @@ retry:

	error = security_path_symlink(&path, dentry, from->name);
	if (!error)
		error = vfs_symlink(path.dentry->d_inode, dentry, from->name);
		error = vfs_symlink2(path.mnt, path.dentry->d_inode, dentry, from->name);
	done_path_create(&path, dentry);
	if (retry_estale(error, lookup_flags)) {
		lookup_flags |= LOOKUP_REVAL;
@@ -3880,7 +3940,7 @@ SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newn
 * be appropriate for callers that expect the underlying filesystem not
 * to be NFS exported.
 */
int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry, struct inode **delegated_inode)
int vfs_link2(struct vfsmount *mnt, struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry, struct inode **delegated_inode)
{
	struct inode *inode = old_dentry->d_inode;
	unsigned max_links = dir->i_sb->s_max_links;
@@ -3889,7 +3949,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
	if (!inode)
		return -ENOENT;

	error = may_create(dir, new_dentry);
	error = may_create(mnt, dir, new_dentry);
	if (error)
		return error;

@@ -3932,6 +3992,12 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
		fsnotify_link(dir, inode, new_dentry);
	return error;
}
EXPORT_SYMBOL(vfs_link2);

int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry, struct inode **delegated_inode)
{
	return vfs_link2(NULL, old_dentry, dir, new_dentry, delegated_inode);
}
EXPORT_SYMBOL(vfs_link);

/*
@@ -3987,7 +4053,7 @@ retry:
	error = security_path_link(old_path.dentry, &new_path, new_dentry);
	if (error)
		goto out_dput;
	error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry, &delegated_inode);
	error = vfs_link2(old_path.mnt, old_path.dentry, new_path.dentry->d_inode, new_dentry, &delegated_inode);
out_dput:
	done_path_create(&new_path, new_dentry);
	if (delegated_inode) {
@@ -4062,7 +4128,8 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname
 *	   ->i_mutex on parents, which works but leads to some truly excessive
 *	   locking].
 */
int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
int vfs_rename2(struct vfsmount *mnt,
	       struct inode *old_dir, struct dentry *old_dentry,
	       struct inode *new_dir, struct dentry *new_dentry,
	       struct inode **delegated_inode, unsigned int flags)
{
@@ -4077,19 +4144,19 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
	if (source == target)
		return 0;

	error = may_delete(old_dir, old_dentry, is_dir);
	error = may_delete(mnt, old_dir, old_dentry, is_dir);
	if (error)
		return error;

	if (!target) {
		error = may_create(new_dir, new_dentry);
		error = may_create(mnt, new_dir, new_dentry);
	} else {
		new_is_dir = d_is_dir(new_dentry);

		if (!(flags & RENAME_EXCHANGE))
			error = may_delete(new_dir, new_dentry, is_dir);
			error = may_delete(mnt, new_dir, new_dentry, is_dir);
		else
			error = may_delete(new_dir, new_dentry, new_is_dir);
			error = may_delete(mnt, new_dir, new_dentry, new_is_dir);
	}
	if (error)
		return error;
@@ -4106,12 +4173,12 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
	 */
	if (new_dir != old_dir) {
		if (is_dir) {
			error = inode_permission(source, MAY_WRITE);
			error = inode_permission2(mnt, source, MAY_WRITE);
			if (error)
				return error;
		}
		if ((flags & RENAME_EXCHANGE) && new_is_dir) {
			error = inode_permission(target, MAY_WRITE);
			error = inode_permission2(mnt, target, MAY_WRITE);
			if (error)
				return error;
		}
@@ -4194,6 +4261,14 @@ out:

	return error;
}
EXPORT_SYMBOL(vfs_rename2);

int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
	       struct inode *new_dir, struct dentry *new_dentry,
	       struct inode **delegated_inode, unsigned int flags)
{
	return vfs_rename2(NULL, old_dir, old_dentry, new_dir, new_dentry, delegated_inode, flags);
}
EXPORT_SYMBOL(vfs_rename);

SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
@@ -4308,7 +4383,7 @@ retry_deleg:
				     &newnd.path, new_dentry, flags);
	if (error)
		goto exit5;
	error = vfs_rename(old_dir->d_inode, old_dentry,
	error = vfs_rename2(oldnd.path.mnt, old_dir->d_inode, old_dentry,
			   new_dir->d_inode, new_dentry,
			   &delegated_inode, flags);
exit5:
@@ -4353,7 +4428,7 @@ SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newna

int vfs_whiteout(struct inode *dir, struct dentry *dentry)
{
	int error = may_create(dir, dentry);
	int error = may_create(NULL, dir, dentry);
	if (error)
		return error;

+1 −1
Original line number Diff line number Diff line
@@ -475,7 +475,7 @@ static int fanotify_find_path(int dfd, const char __user *filename,
	}

	/* you can only watch an inode if you have read permissions on it */
	ret = inode_permission(path->dentry->d_inode, MAY_READ);
	ret = inode_permission2(path->mnt, path->dentry->d_inode, MAY_READ);
	if (ret)
		path_put(path);
out:
+1 −1
Original line number Diff line number Diff line
@@ -338,7 +338,7 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns
	if (error)
		return error;
	/* you can only watch an inode if you have read permissions on it */
	error = inode_permission(path->dentry->d_inode, MAY_READ);
	error = inode_permission2(path->mnt, path->dentry->d_inode, MAY_READ);
	if (error)
		path_put(path);
	return error;
+11 −5
Original line number Diff line number Diff line
@@ -66,9 +66,11 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
long vfs_truncate(struct path *path, loff_t length)
{
	struct inode *inode;
	struct vfsmount *mnt;
	long error;

	inode = path->dentry->d_inode;
	mnt = path->mnt;

	/* For directories it's -EISDIR, for other non-regulars - -EINVAL */
	if (S_ISDIR(inode->i_mode))
@@ -80,7 +82,7 @@ long vfs_truncate(struct path *path, loff_t length)
	if (error)
		goto out;

	error = inode_permission(inode, MAY_WRITE);
	error = inode_permission2(mnt, inode, MAY_WRITE);
	if (error)
		goto mnt_drop_write_and_out;

@@ -322,6 +324,7 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
	struct cred *override_cred;
	struct path path;
	struct inode *inode;
	struct vfsmount *mnt;
	int res;
	unsigned int lookup_flags = LOOKUP_FOLLOW;

@@ -352,6 +355,7 @@ retry:
		goto out;

	inode = path.dentry->d_inode;
	mnt = path.mnt;

	if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) {
		/*
@@ -363,7 +367,7 @@ retry:
			goto out_path_release;
	}

	res = inode_permission(inode, mode | MAY_ACCESS);
	res = inode_permission2(mnt, inode, mode | MAY_ACCESS);
	/* SuS v2 requires we report a read only fs too */
	if (res || !(mode & S_IWOTH) || special_file(inode->i_mode))
		goto out_path_release;
@@ -407,7 +411,7 @@ retry:
	if (error)
		goto out;

	error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
	error = inode_permission2(path.mnt, path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
	if (error)
		goto dput_and_out;

@@ -427,6 +431,7 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd)
{
	struct fd f = fdget_raw(fd);
	struct inode *inode;
	struct vfsmount *mnt;
	int error = -EBADF;

	error = -EBADF;
@@ -434,12 +439,13 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd)
		goto out;

	inode = file_inode(f.file);
	mnt = f.file->f_path.mnt;

	error = -ENOTDIR;
	if (!S_ISDIR(inode->i_mode))
		goto out_putf;

	error = inode_permission(inode, MAY_EXEC | MAY_CHDIR);
	error = inode_permission2(mnt, inode, MAY_EXEC | MAY_CHDIR);
	if (!error)
		set_fs_pwd(current->fs, &f.file->f_path);
out_putf:
@@ -458,7 +464,7 @@ retry:
	if (error)
		goto out;

	error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
	error = inode_permission2(path.mnt, path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
	if (error)
		goto dput_and_out;

Loading