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/vserver
Received on Mon Feb 27 05:41:10 2006