From: Herbert Pƶtzl <herbert@13thfloor.at>
Previously, vfs_* functions do not regard the vfs context that the
inodes came from for their checks.
In order to honour per-vfsmount permission options, VFS functions must
be passed the nameidata structure, similar to the existing
vfs_create().
This allows for proper checks in may_create(), may_delete() and
permission().
Acked-by: Sam Vilain <sam.vilain@catalyst.net.nz>
--- fs/namei.c | 59 ++++++++++++++++++++++++++++++--------------------- fs/nfsd/vfs.c | 16 ++++++++------ fs/reiserfs/xattr.c | 3 ++- include/linux/fs.h | 12 +++++----- ipc/mqueue.c | 2 +- net/unix/af_unix.c | 2 +- 6 files changed, 54 insertions(+), 40 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index e28de84..89cccf5 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1345,7 +1345,8 @@ static inline int check_sticky(struct in * 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,int isdir) +static int may_delete(struct inode *dir, struct dentry *victim, + int isdir, struct nameidata *nd) { int error; @@ -1354,7 +1355,7 @@ static int may_delete(struct inode *dir, BUG_ON(victim->d_parent->d_inode != dir); - error = permission(dir,MAY_WRITE | MAY_EXEC, NULL); + error = permission(dir,MAY_WRITE | MAY_EXEC, nd); if (error) return error; if (IS_APPEND(dir)) @@ -1773,9 +1774,10 @@ fail: } EXPORT_SYMBOL_GPL(lookup_create); -int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +int vfs_mknod(struct inode *dir, struct dentry *dentry, + int mode, dev_t dev, struct nameidata *nd) { - int error = may_create(dir, dentry, NULL); + int error = may_create(dir, dentry, nd); if (error) return error; @@ -1825,11 +1827,12 @@ asmlinkage long sys_mknodat(int dfd, con error = vfs_create(nd.dentry->d_inode,dentry,mode,&nd); break; case S_IFCHR: case S_IFBLK: - error = vfs_mknod(nd.dentry->d_inode,dentry,mode, - new_decode_dev(dev)); + error = vfs_mknod(nd.dentry->d_inode, dentry, mode, + new_decode_dev(dev), &nd); break; case S_IFIFO: case S_IFSOCK: - error = vfs_mknod(nd.dentry->d_inode,dentry,mode,0); + error = vfs_mknod(nd.dentry->d_inode, dentry, mode, + 0, &nd); break; case S_IFDIR: error = -EPERM; @@ -1852,9 +1855,10 @@ asmlinkage long sys_mknod(const char __u return sys_mknodat(AT_FDCWD, filename, mode, dev); } -int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +int vfs_mkdir(struct inode *dir, struct dentry *dentry, + int mode, struct nameidata *nd) { - int error = may_create(dir, dentry, NULL); + int error = may_create(dir, dentry, nd); if (error) return error; @@ -1893,7 +1897,8 @@ asmlinkage long sys_mkdirat(int dfd, con if (!IS_ERR(dentry)) { if (!IS_POSIXACL(nd.dentry->d_inode)) mode &= ~current->fs->umask; - error = vfs_mkdir(nd.dentry->d_inode, dentry, mode); + error = vfs_mkdir(nd.dentry->d_inode, dentry, + mode, &nd); dput(dentry); } mutex_unlock(&nd.dentry->d_inode->i_mutex); @@ -1938,9 +1943,10 @@ void dentry_unhash(struct dentry *dentry spin_unlock(&dcache_lock); } -int vfs_rmdir(struct inode *dir, struct dentry *dentry) +int vfs_rmdir(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) { - int error = may_delete(dir, dentry, 1); + int error = may_delete(dir, dentry, 1, nd); if (error) return error; @@ -2001,7 +2007,7 @@ static long do_rmdir(int dfd, const char dentry = lookup_hash(&nd); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { - error = vfs_rmdir(nd.dentry->d_inode, dentry); + error = vfs_rmdir(nd.dentry->d_inode, dentry, &nd); dput(dentry); } mutex_unlock(&nd.dentry->d_inode->i_mutex); @@ -2017,9 +2023,10 @@ asmlinkage long sys_rmdir(const char __u return do_rmdir(AT_FDCWD, pathname); } -int vfs_unlink(struct inode *dir, struct dentry *dentry) +int vfs_unlink(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) { - int error = may_delete(dir, dentry, 0); + int error = may_delete(dir, dentry, 0, nd); if (error) return error; @@ -2081,7 +2088,7 @@ static long do_unlinkat(int dfd, const c inode = dentry->d_inode; if (inode) atomic_inc(&inode->i_count); - error = vfs_unlink(nd.dentry->d_inode, dentry); + error = vfs_unlink(nd.dentry->d_inode, dentry, &nd); exit2: dput(dentry); } @@ -2116,9 +2123,10 @@ asmlinkage long sys_unlink(const char __ return do_unlinkat(AT_FDCWD, pathname); } -int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, int mode) +int vfs_symlink(struct inode *dir, struct dentry *dentry, + const char *oldname, int mode, struct nameidata *nd) { - int error = may_create(dir, dentry, NULL); + int error = may_create(dir, dentry, nd); if (error) return error; @@ -2159,7 +2167,8 @@ asmlinkage long sys_symlinkat(const char dentry = lookup_create(&nd, 0); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { - error = vfs_symlink(nd.dentry->d_inode, dentry, from, S_IALLUGO); + error = vfs_symlink(nd.dentry->d_inode, dentry, + from, S_IALLUGO, &nd); dput(dentry); } mutex_unlock(&nd.dentry->d_inode->i_mutex); @@ -2176,7 +2185,8 @@ asmlinkage long sys_symlink(const char _ return sys_symlinkat(oldname, AT_FDCWD, newname); } -int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) +int vfs_link(struct dentry *old_dentry, struct inode *dir, + struct dentry *new_dentry, struct nameidata *nd) { struct inode *inode = old_dentry->d_inode; int error; @@ -2184,7 +2194,7 @@ int vfs_link(struct dentry *old_dentry, if (!inode) return -ENOENT; - error = may_create(dir, new_dentry, NULL); + error = may_create(dir, new_dentry, nd); if (error) return error; @@ -2247,7 +2257,8 @@ asmlinkage long sys_linkat(int olddfd, c new_dentry = lookup_create(&nd, 0); error = PTR_ERR(new_dentry); if (!IS_ERR(new_dentry)) { - error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry); + error = vfs_link(old_nd.dentry, nd.dentry->d_inode, + new_dentry, &nd); dput(new_dentry); } mutex_unlock(&nd.dentry->d_inode->i_mutex); @@ -2379,14 +2390,14 @@ int vfs_rename(struct inode *old_dir, st if (old_dentry->d_inode == new_dentry->d_inode) return 0; - error = may_delete(old_dir, old_dentry, is_dir); + error = may_delete(old_dir, old_dentry, is_dir, NULL); if (error) return error; if (!new_dentry->d_inode) error = may_create(new_dir, new_dentry, NULL); else - error = may_delete(new_dir, new_dentry, is_dir); + error = may_delete(new_dir, new_dentry, is_dir, NULL); if (error) return error; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 5320e5a..6fe2491 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1160,13 +1160,13 @@ nfsd_create(struct svc_rqst *rqstp, stru err = vfs_create(dirp, dchild, iap->ia_mode, NULL); break; case S_IFDIR: - err = vfs_mkdir(dirp, dchild, iap->ia_mode); + err = vfs_mkdir(dirp, dchild, iap->ia_mode, NULL); break; case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK: - err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev); + err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev, NULL); break; default: printk("nfsd: bad file type %o in nfsd_create\n", type); @@ -1446,11 +1446,13 @@ nfsd_symlink(struct svc_rqst *rqstp, str else { strncpy(path_alloced, path, plen); path_alloced[plen] = 0; - err = vfs_symlink(dentry->d_inode, dnew, path_alloced, mode); + err = vfs_symlink(dentry->d_inode, dnew, + path_alloced, mode, NULL); kfree(path_alloced); } } else - err = vfs_symlink(dentry->d_inode, dnew, path, mode); + err = vfs_symlink(dentry->d_inode, dnew, + path, mode, NULL); if (!err) if (EX_ISSYNC(fhp->fh_export)) @@ -1508,7 +1510,7 @@ nfsd_link(struct svc_rqst *rqstp, struct dold = tfhp->fh_dentry; dest = dold->d_inode; - err = vfs_link(dold, dirp, dnew); + err = vfs_link(dold, dirp, dnew, NULL); if (!err) { if (EX_ISSYNC(ffhp->fh_export)) { err = nfserrno(nfsd_sync_dir(ddir)); @@ -1670,9 +1672,9 @@ nfsd_unlink(struct svc_rqst *rqstp, stru err = -EPERM; } else #endif - err = vfs_unlink(dirp, rdentry); + err = vfs_unlink(dirp, rdentry, NULL); } else { /* It's RMDIR */ - err = vfs_rmdir(dirp, rdentry); + err = vfs_rmdir(dirp, rdentry, NULL); } dput(rdentry); diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index ffb79c4..b99819a 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -35,6 +35,7 @@ #include <linux/namei.h> #include <linux/errno.h> #include <linux/fs.h> +#include <linux/mount.h> #include <linux/file.h> #include <linux/pagemap.h> #include <linux/xattr.h> @@ -824,7 +825,7 @@ int reiserfs_delete_xattrs(struct inode if (dir->d_inode->i_nlink <= 2) { root = get_xa_root(inode->i_sb); reiserfs_write_lock_xattrs(inode->i_sb); - err = vfs_rmdir(root->d_inode, dir); + err = vfs_rmdir(root->d_inode, dir, NULL); reiserfs_write_unlock_xattrs(inode->i_sb); dput(root); } else { diff --git a/include/linux/fs.h b/include/linux/fs.h index 2a0866a..3000655 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -903,12 +903,12 @@ static inline void unlock_super(struct s */ extern int vfs_permission(struct nameidata *, int); extern int vfs_create(struct inode *, struct dentry *, int, struct nameidata *); -extern int vfs_mkdir(struct inode *, struct dentry *, int); -extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t); -extern int vfs_symlink(struct inode *, struct dentry *, const char *, int); -extern int vfs_link(struct dentry *, struct inode *, struct dentry *); -extern int vfs_rmdir(struct inode *, struct dentry *); -extern int vfs_unlink(struct inode *, struct dentry *); +extern int vfs_mkdir(struct inode *, struct dentry *, int, struct nameidata *); +extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t, struct nameidata *); +extern int vfs_symlink(struct inode *, struct dentry *, const char *, int, struct nameidata *); +extern int vfs_link(struct dentry *, struct inode *, struct dentry *, struct nameidata *); +extern int vfs_rmdir(struct inode *, struct dentry *, struct nameidata *); +extern int vfs_unlink(struct inode *, struct dentry *, struct nameidata *); extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); /* diff --git a/ipc/mqueue.c b/ipc/mqueue.c index fd2e26b..57391b7 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -738,7 +738,7 @@ asmlinkage long sys_mq_unlink(const char if (inode) atomic_inc(&inode->i_count); - err = vfs_unlink(dentry->d_parent->d_inode, dentry); + err = vfs_unlink(dentry->d_parent->d_inode, dentry, NULL); out_err: dput(dentry); diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 1b5989b..10b3375 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -781,7 +781,7 @@ static int unix_bind(struct socket *sock */ mode = S_IFSOCK | (SOCK_INODE(sock)->i_mode & ~current->fs->umask); - err = vfs_mknod(nd.dentry->d_inode, dentry, mode, 0); + err = vfs_mknod(nd.dentry->d_inode, dentry, mode, 0, NULL); if (err) goto out_mknod_dput; mutex_unlock(&nd.dentry->d_inode->i_mutex); _______________________________________________ Vserver mailing list Vserver@list.linux-vserver.org http://list.linux-vserver.org/mailman/listinfo/vserverReceived on Mon Feb 27 05:41:10 2006