#include <linux/security.h>
#include <linux/mount.h>
#include <linux/audit.h>
+#include <linux/vs_base.h>
+
#include <asm/namei.h>
#include <asm/uaccess.h>
return -EACCES;
}
+static inline int xid_permission(struct inode *inode, int mask, struct nameidata *nd)
+{
+ 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 permission(struct inode * inode,int mask, struct nameidata *nd)
{
int retval;
/* Ordinary permission routines do not understand MAY_APPEND. */
submask = mask & ~MAY_APPEND;
+ if ((retval = xid_permission(inode, mask, nd)))
+ return retval;
if (inode->i_op && inode->i_op->permission)
retval = inode->i_op->permission(inode, submask, nd);
else
{
struct path next;
struct inode *inode;
- int err;
+ int err, atomic;
unsigned int lookup_flags = nd->flags;
-
+
+ atomic = (lookup_flags & LOOKUP_ATOMIC);
+
while (*name=='/')
name++;
if (!*name)
if (err < 0)
break;
}
+ err = -EWOULDBLOCKIO;
+ if (atomic)
+ break;
nd->flags |= LOOKUP_CONTINUE;
/* This does the actual lookups.. */
err = do_lookup(nd, &this, &next);
if (err < 0)
break;
}
+ err = -EWOULDBLOCKIO;
+ if (atomic)
+ break;
err = do_lookup(nd, &this, &next);
if (err)
break;
return 0; /* something went wrong... */
if (!nd->dentry->d_inode || S_ISDIR(nd->dentry->d_inode->i_mode)) {
- struct nameidata nd_root;
+ struct dentry *old_dentry = nd->dentry;
+ struct vfsmount *old_mnt = nd->mnt;
+ struct qstr last = nd->last;
+ int last_type = nd->last_type;
/*
* NAME was not found in alternate root or it's a directory. Try to find
* it in the normal root:
*/
- nd_root.last_type = LAST_ROOT;
- nd_root.flags = nd->flags;
- nd_root.depth = 0;
- memcpy(&nd_root.intent, &nd->intent, sizeof(nd_root.intent));
+ nd->last_type = LAST_ROOT;
read_lock(¤t->fs->lock);
- nd_root.mnt = mntget(current->fs->rootmnt);
- nd_root.dentry = dget(current->fs->root);
+ nd->mnt = mntget(current->fs->rootmnt);
+ nd->dentry = dget(current->fs->root);
read_unlock(¤t->fs->lock);
- if (path_walk(name, &nd_root))
- return 1;
- if (nd_root.dentry->d_inode) {
+ if (path_walk(name, nd) == 0) {
+ if (nd->dentry->d_inode) {
+ dput(old_dentry);
+ mntput(old_mnt);
+ return 1;
+ }
path_release(nd);
- nd->dentry = nd_root.dentry;
- nd->mnt = nd_root.mnt;
- nd->last = nd_root.last;
- return 1;
}
- path_release(&nd_root);
+ nd->dentry = old_dentry;
+ nd->mnt = old_mnt;
+ nd->last = last;
+ nd->last_type = last_type;
}
return 1;
}
}
nd->mnt = mntget(current->fs->rootmnt);
nd->dentry = dget(current->fs->root);
- }
- else{
+ } else {
nd->mnt = mntget(current->fs->pwdmnt);
nd->dentry = dget(current->fs->pwd);
}
static inline int may_delete(struct inode *dir,struct dentry *victim,int isdir)
{
int error;
- if (!victim->d_inode || victim->d_parent->d_inode != dir)
+ if (!victim->d_inode)
return -ENOENT;
+ if (victim->d_parent->d_inode != dir)
+ BUG();
+
error = permission(dir,MAY_WRITE | MAY_EXEC, NULL);
if (error)
return error;
if (IS_APPEND(dir))
return -EPERM;
if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)||
- IS_IMMUTABLE(victim->d_inode))
+ IS_IXORUNLINK(victim->d_inode))
return -EPERM;
if (isdir) {
if (!S_ISDIR(victim->d_inode->i_mode))
if (f & O_DIRECTORY)
retval |= LOOKUP_DIRECTORY;
+ if (f & O_ATOMICLOOKUP)
+ retval |= LOOKUP_ATOMIC;
return retval;
}
/*
* A link to an append-only or immutable file cannot be created.
*/
- if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+ if (IS_APPEND(inode) || IS_IXORUNLINK(inode))
return -EPERM;
if (!dir->i_op || !dir->i_op->link)
return -EPERM;
int page_follow_link_light(struct dentry *dentry, struct nameidata *nd)
{
struct page *page;
- char *s = page_getlink(dentry, &page);
- if (!IS_ERR(s)) {
- nd_set_link(nd, s);
- s = NULL;
- }
- return PTR_ERR(s);
+ nd_set_link(nd, page_getlink(dentry, &page));
+ return 0;
}
void page_put_link(struct dentry *dentry, struct nameidata *nd)