{
umode_t mode = inode->i_mode;
- /* Prevent vservers from escaping chroot() barriers */
- if (IS_BARRIER(inode) && !vx_check(0, VX_ADMIN))
+ if (IS_BARRIER(inode) && !vx_check(0, VX_ADMIN|VX_WATCH))
return -EACCES;
if (mask & MAY_WRITE) {
return -EACCES;
}
-static inline int xid_permission(struct inode *inode, int mask, struct nameidata *nd)
+static inline int xid_permission(struct inode *inode)
{
if (inode->i_xid == 0)
return 0;
if (vx_check(inode->i_xid, VX_ADMIN|VX_WATCH|VX_IDENT))
return 0;
-/*
- printk("VSW: xid=%d denied access to %p[#%d,%lu] »%*s«.\n",
- vx_current_xid(), inode, inode->i_xid, inode->i_ino,
- nd->dentry->d_name.len, nd->dentry->d_name.name);
-*/
return -EACCES;
}
{
int retval;
int submask;
- umode_t mode = inode->i_mode;
/* Ordinary permission routines do not understand MAY_APPEND. */
submask = mask & ~MAY_APPEND;
- if (nd && (mask & MAY_WRITE) && MNT_IS_RDONLY(nd->mnt) &&
- (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
- return -EROFS;
-
- if ((retval = xid_permission(inode, mask, nd)))
+ if ((retval = xid_permission(inode)))
return retval;
if (inode->i_op && inode->i_op->permission)
retval = inode->i_op->permission(inode, submask, nd);
return permission(dir,MAY_WRITE | MAY_EXEC, nd);
}
-static inline int mnt_may_create(struct vfsmount *mnt, struct inode *dir, struct dentry *child) {
- if (child->d_inode)
- return -EEXIST;
- if (IS_DEADDIR(dir))
- return -ENOENT;
- if (mnt->mnt_flags & MNT_RDONLY)
- return -EROFS;
- return 0;
-}
-
-static inline int mnt_may_unlink(struct vfsmount *mnt, struct inode *dir, struct dentry *child) {
- if (!child->d_inode)
- return -ENOENT;
- if (mnt->mnt_flags & MNT_RDONLY)
- return -EROFS;
- return 0;
-}
-
/*
* Special case: O_CREAT|O_EXCL implies O_NOFOLLOW for security
* reasons.
return -EACCES;
flag &= ~O_TRUNC;
- } else if ((IS_RDONLY(inode) || (nd && MNT_IS_RDONLY(nd->mnt)))
- && (flag & FMODE_WRITE))
+ } else if (IS_RDONLY(inode) && (flag & FMODE_WRITE))
return -EROFS;
/*
* An append-only file must be opened in append mode for writing.
struct dentry *lookup_create(struct nameidata *nd, int is_dir)
{
struct dentry *dentry;
- int error;
down(&nd->dentry->d_inode->i_sem);
- error = -EEXIST;
+ dentry = ERR_PTR(-EEXIST);
if (nd->last_type != LAST_NORM)
- goto out;
+ goto fail;
nd->flags &= ~LOOKUP_PARENT;
dentry = lookup_hash(&nd->last, nd->dentry);
if (IS_ERR(dentry))
- goto ret;
- error = mnt_may_create(nd->mnt, nd->dentry->d_inode, dentry);
- if (error)
goto fail;
- error = -ENOENT;
if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)
- goto fail;
-ret:
+ goto enoent;
return dentry;
-fail:
+enoent:
dput(dentry);
-out:
- return ERR_PTR(error);
+ dentry = ERR_PTR(-ENOENT);
+fail:
+ return dentry;
}
int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
dentry = lookup_hash(&nd.last, nd.dentry);
error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
- error = mnt_may_unlink(nd.mnt, nd.dentry->d_inode, dentry);
- if (error)
- goto exit2;
error = vfs_rmdir(nd.dentry->d_inode, dentry);
- exit2:
dput(dentry);
}
up(&nd.dentry->d_inode->i_sem);
/* Why not before? Because we want correct error value */
if (nd.last.name[nd.last.len])
goto slashes;
- error = mnt_may_unlink(nd.mnt, nd.dentry->d_inode, dentry);
- if (error)
- goto exit2;
inode = dentry->d_inode;
if (inode)
atomic_inc(&inode->i_count);
error = path_lookup(to, LOOKUP_PARENT, &nd);
if (error)
goto out;
- /*
- * We allow hard-links to be created to a bind-mount as long
- * as the bind-mount is not read-only. Checking for cross-dev
- * links is subsumed by the superblock check in vfs_link().
- */
- error = -EROFS;
- if (MNT_IS_RDONLY(old_nd.mnt))
+ error = -EXDEV;
+ if (old_nd.mnt != nd.mnt)
goto out_release;
new_dentry = lookup_create(&nd, 0);
error = PTR_ERR(new_dentry);
error = -EINVAL;
if (old_dentry == trap)
goto exit4;
- error = -EROFS;
- if (MNT_IS_RDONLY(newnd.mnt))
- goto exit4;
new_dentry = lookup_hash(&newnd.last, new_dir);
error = PTR_ERR(new_dentry);
if (IS_ERR(new_dentry))