Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: do_add_mount() should sanitize mnt_flags CIFS shouldn't make mountpoints shrinkable mnt_flags fixes in do_remount() attach_recursive_mnt() needs to hold vfsmount_lock over set_mnt_shared() may_umount() needs namespace_sem Fix configfs leak Fix the -ESTALE handling in do_filp_open() ecryptfs: Fix refcnt leak on ecryptfs_follow_link() error path Fix ACC_MODE() for real Unrot uml mconsole a bit hppfs: handle ->put_link() Kill 9p readlink() fix autofs/afs/etc. magic mountpoint breakage
This commit is contained in:
commit
7dc9c484a7
11 changed files with 73 additions and 117 deletions
|
@ -125,50 +125,36 @@ void mconsole_log(struct mc_request *req)
|
|||
void mconsole_proc(struct mc_request *req)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct file_system_type *proc;
|
||||
struct super_block *super;
|
||||
struct vfsmount *mnt = current->nsproxy->pid_ns->proc_mnt;
|
||||
struct file *file;
|
||||
int n, err;
|
||||
char *ptr = req->request.data, *buf;
|
||||
mm_segment_t old_fs = get_fs();
|
||||
|
||||
ptr += strlen("proc");
|
||||
ptr = skip_spaces(ptr);
|
||||
|
||||
proc = get_fs_type("proc");
|
||||
if (proc == NULL) {
|
||||
mconsole_reply(req, "procfs not registered", 1, 0);
|
||||
goto out;
|
||||
}
|
||||
|
||||
super = (*proc->get_sb)(proc, 0, NULL, NULL);
|
||||
put_filesystem(proc);
|
||||
if (super == NULL) {
|
||||
mconsole_reply(req, "Failed to get procfs superblock", 1, 0);
|
||||
goto out;
|
||||
}
|
||||
up_write(&super->s_umount);
|
||||
|
||||
nd.path.dentry = super->s_root;
|
||||
nd.path.mnt = NULL;
|
||||
nd.flags = O_RDONLY + 1;
|
||||
nd.last_type = LAST_ROOT;
|
||||
|
||||
/* START: it was experienced that the stability problems are closed
|
||||
* if commenting out these two calls + the below read cycle. To
|
||||
* make UML crash again, it was enough to readd either one.*/
|
||||
err = link_path_walk(ptr, &nd);
|
||||
err = vfs_path_lookup(mnt->mnt_root, mnt, ptr, LOOKUP_FOLLOW, &nd);
|
||||
if (err) {
|
||||
mconsole_reply(req, "Failed to look up file", 1, 0);
|
||||
goto out_kill;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = may_open(&nd.path, MAY_READ, FMODE_READ);
|
||||
if (result) {
|
||||
mconsole_reply(req, "Failed to open file", 1, 0);
|
||||
path_put(&nd.path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
file = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY,
|
||||
current_cred());
|
||||
err = PTR_ERR(file);
|
||||
if (IS_ERR(file)) {
|
||||
mconsole_reply(req, "Failed to open file", 1, 0);
|
||||
goto out_kill;
|
||||
path_put(&nd.path);
|
||||
goto out;
|
||||
}
|
||||
/*END*/
|
||||
|
||||
buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (buf == NULL) {
|
||||
|
@ -176,10 +162,13 @@ void mconsole_proc(struct mc_request *req)
|
|||
goto out_fput;
|
||||
}
|
||||
|
||||
if ((file->f_op != NULL) && (file->f_op->read != NULL)) {
|
||||
if (file->f_op->read) {
|
||||
do {
|
||||
n = (*file->f_op->read)(file, buf, PAGE_SIZE - 1,
|
||||
&file->f_pos);
|
||||
loff_t pos;
|
||||
set_fs(KERNEL_DS);
|
||||
n = vfs_read(file, buf, PAGE_SIZE - 1, &pos);
|
||||
file_pos_write(file, pos);
|
||||
set_fs(old_fs);
|
||||
if (n >= 0) {
|
||||
buf[n] = '\0';
|
||||
mconsole_reply(req, buf, 0, (n > 0));
|
||||
|
@ -197,8 +186,6 @@ void mconsole_proc(struct mc_request *req)
|
|||
kfree(buf);
|
||||
out_fput:
|
||||
fput(file);
|
||||
out_kill:
|
||||
deactivate_super(super);
|
||||
out: ;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1000,44 +1000,6 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
|
|||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* v9fs_vfs_readlink - read a symlink's location
|
||||
* @dentry: dentry for symlink
|
||||
* @buffer: buffer to load symlink location into
|
||||
* @buflen: length of buffer
|
||||
*
|
||||
*/
|
||||
|
||||
static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer,
|
||||
int buflen)
|
||||
{
|
||||
int retval;
|
||||
int ret;
|
||||
char *link = __getname();
|
||||
|
||||
if (unlikely(!link))
|
||||
return -ENOMEM;
|
||||
|
||||
if (buflen > PATH_MAX)
|
||||
buflen = PATH_MAX;
|
||||
|
||||
P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_name.name,
|
||||
dentry);
|
||||
|
||||
retval = v9fs_readlink(dentry, link, buflen);
|
||||
|
||||
if (retval > 0) {
|
||||
if ((ret = copy_to_user(buffer, link, retval)) != 0) {
|
||||
P9_DPRINTK(P9_DEBUG_ERROR,
|
||||
"problem copying to user: %d\n", ret);
|
||||
retval = ret;
|
||||
}
|
||||
}
|
||||
|
||||
__putname(link);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* v9fs_vfs_follow_link - follow a symlink path
|
||||
* @dentry: dentry for symlink
|
||||
|
@ -1230,7 +1192,6 @@ static const struct inode_operations v9fs_dir_inode_operations_ext = {
|
|||
.rmdir = v9fs_vfs_rmdir,
|
||||
.mknod = v9fs_vfs_mknod,
|
||||
.rename = v9fs_vfs_rename,
|
||||
.readlink = v9fs_vfs_readlink,
|
||||
.getattr = v9fs_vfs_getattr,
|
||||
.setattr = v9fs_vfs_setattr,
|
||||
};
|
||||
|
@ -1253,7 +1214,7 @@ static const struct inode_operations v9fs_file_inode_operations = {
|
|||
};
|
||||
|
||||
static const struct inode_operations v9fs_symlink_inode_operations = {
|
||||
.readlink = v9fs_vfs_readlink,
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = v9fs_vfs_follow_link,
|
||||
.put_link = v9fs_vfs_put_link,
|
||||
.getattr = v9fs_vfs_getattr,
|
||||
|
|
|
@ -269,7 +269,7 @@ static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd,
|
|||
int err;
|
||||
|
||||
mntget(newmnt);
|
||||
err = do_add_mount(newmnt, &nd->path, nd->path.mnt->mnt_flags, mntlist);
|
||||
err = do_add_mount(newmnt, &nd->path, nd->path.mnt->mnt_flags | MNT_SHRINKABLE, mntlist);
|
||||
switch (err) {
|
||||
case 0:
|
||||
path_put(&nd->path);
|
||||
|
@ -371,7 +371,6 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
|
|||
if (IS_ERR(mnt))
|
||||
goto out_err;
|
||||
|
||||
nd->path.mnt->mnt_flags |= MNT_SHRINKABLE;
|
||||
rc = add_mount_helper(mnt, nd, &cifs_dfs_automount_list);
|
||||
|
||||
out:
|
||||
|
|
|
@ -121,8 +121,10 @@ static int get_target(const char *symname, struct path *path,
|
|||
ret = -ENOENT;
|
||||
path_put(path);
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
ret = -EPERM;
|
||||
path_put(path);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -715,31 +715,31 @@ static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
|||
/* Released in ecryptfs_put_link(); only release here on error */
|
||||
buf = kmalloc(len, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
rc = -ENOMEM;
|
||||
buf = ERR_PTR(-ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
old_fs = get_fs();
|
||||
set_fs(get_ds());
|
||||
rc = dentry->d_inode->i_op->readlink(dentry, (char __user *)buf, len);
|
||||
set_fs(old_fs);
|
||||
if (rc < 0)
|
||||
goto out_free;
|
||||
else
|
||||
if (rc < 0) {
|
||||
kfree(buf);
|
||||
buf = ERR_PTR(rc);
|
||||
} else
|
||||
buf[rc] = '\0';
|
||||
rc = 0;
|
||||
nd_set_link(nd, buf);
|
||||
goto out;
|
||||
out_free:
|
||||
kfree(buf);
|
||||
out:
|
||||
return ERR_PTR(rc);
|
||||
nd_set_link(nd, buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
ecryptfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr)
|
||||
{
|
||||
/* Free the char* */
|
||||
kfree(nd_get_link(nd));
|
||||
char *buf = nd_get_link(nd);
|
||||
if (!IS_ERR(buf)) {
|
||||
/* Free the char* */
|
||||
kfree(buf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -646,22 +646,27 @@ static const struct super_operations hppfs_sbops = {
|
|||
static int hppfs_readlink(struct dentry *dentry, char __user *buffer,
|
||||
int buflen)
|
||||
{
|
||||
struct dentry *proc_dentry;
|
||||
|
||||
proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
|
||||
struct dentry *proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
|
||||
return proc_dentry->d_inode->i_op->readlink(proc_dentry, buffer,
|
||||
buflen);
|
||||
}
|
||||
|
||||
static void *hppfs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
struct dentry *proc_dentry;
|
||||
|
||||
proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
|
||||
struct dentry *proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
|
||||
|
||||
return proc_dentry->d_inode->i_op->follow_link(proc_dentry, nd);
|
||||
}
|
||||
|
||||
static void hppfs_put_link(struct dentry *dentry, struct nameidata *nd,
|
||||
void *cookie)
|
||||
{
|
||||
struct dentry *proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
|
||||
|
||||
if (proc_dentry->d_inode->i_op->put_link)
|
||||
proc_dentry->d_inode->i_op->put_link(proc_dentry, nd, cookie);
|
||||
}
|
||||
|
||||
static const struct inode_operations hppfs_dir_iops = {
|
||||
.lookup = hppfs_lookup,
|
||||
};
|
||||
|
@ -669,6 +674,7 @@ static const struct inode_operations hppfs_dir_iops = {
|
|||
static const struct inode_operations hppfs_link_iops = {
|
||||
.readlink = hppfs_readlink,
|
||||
.follow_link = hppfs_follow_link,
|
||||
.put_link = hppfs_put_link,
|
||||
};
|
||||
|
||||
static struct inode *get_inode(struct super_block *sb, struct dentry *dentry)
|
||||
|
|
23
fs/namei.c
23
fs/namei.c
|
@ -561,6 +561,7 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata
|
|||
dget(dentry);
|
||||
}
|
||||
mntget(path->mnt);
|
||||
nd->last_type = LAST_BIND;
|
||||
cookie = dentry->d_inode->i_op->follow_link(dentry, nd);
|
||||
error = PTR_ERR(cookie);
|
||||
if (!IS_ERR(cookie)) {
|
||||
|
@ -1603,11 +1604,12 @@ struct file *do_filp_open(int dfd, const char *pathname,
|
|||
struct file *filp;
|
||||
struct nameidata nd;
|
||||
int error;
|
||||
struct path path, save;
|
||||
struct path path;
|
||||
struct dentry *dir;
|
||||
int count = 0;
|
||||
int will_truncate;
|
||||
int flag = open_to_namei_flags(open_flag);
|
||||
int force_reval = 0;
|
||||
|
||||
/*
|
||||
* O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only
|
||||
|
@ -1619,7 +1621,7 @@ struct file *do_filp_open(int dfd, const char *pathname,
|
|||
open_flag |= O_DSYNC;
|
||||
|
||||
if (!acc_mode)
|
||||
acc_mode = MAY_OPEN | ACC_MODE(flag);
|
||||
acc_mode = MAY_OPEN | ACC_MODE(open_flag);
|
||||
|
||||
/* O_TRUNC implies we need access checks for write permissions */
|
||||
if (flag & O_TRUNC)
|
||||
|
@ -1659,9 +1661,12 @@ struct file *do_filp_open(int dfd, const char *pathname,
|
|||
/*
|
||||
* Create - we need to know the parent.
|
||||
*/
|
||||
reval:
|
||||
error = path_init(dfd, pathname, LOOKUP_PARENT, &nd);
|
||||
if (error)
|
||||
return ERR_PTR(error);
|
||||
if (force_reval)
|
||||
nd.flags |= LOOKUP_REVAL;
|
||||
error = path_walk(pathname, &nd);
|
||||
if (error) {
|
||||
if (nd.root.mnt)
|
||||
|
@ -1853,17 +1858,7 @@ struct file *do_filp_open(int dfd, const char *pathname,
|
|||
error = security_inode_follow_link(path.dentry, &nd);
|
||||
if (error)
|
||||
goto exit_dput;
|
||||
save = nd.path;
|
||||
path_get(&save);
|
||||
error = __do_follow_link(&path, &nd);
|
||||
if (error == -ESTALE) {
|
||||
/* nd.path had been dropped */
|
||||
nd.path = save;
|
||||
path_get(&nd.path);
|
||||
nd.flags |= LOOKUP_REVAL;
|
||||
error = __do_follow_link(&path, &nd);
|
||||
}
|
||||
path_put(&save);
|
||||
path_put(&path);
|
||||
if (error) {
|
||||
/* Does someone understand code flow here? Or it is only
|
||||
|
@ -1873,6 +1868,10 @@ struct file *do_filp_open(int dfd, const char *pathname,
|
|||
release_open_intent(&nd);
|
||||
if (nd.root.mnt)
|
||||
path_put(&nd.root);
|
||||
if (error == -ESTALE && !force_reval) {
|
||||
force_reval = 1;
|
||||
goto reval;
|
||||
}
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
nd.flags &= ~LOOKUP_PARENT;
|
||||
|
|
|
@ -965,10 +965,12 @@ EXPORT_SYMBOL(may_umount_tree);
|
|||
int may_umount(struct vfsmount *mnt)
|
||||
{
|
||||
int ret = 1;
|
||||
down_read(&namespace_sem);
|
||||
spin_lock(&vfsmount_lock);
|
||||
if (propagate_mount_busy(mnt, 2))
|
||||
ret = 0;
|
||||
spin_unlock(&vfsmount_lock);
|
||||
up_read(&namespace_sem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1352,12 +1354,12 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt,
|
|||
if (err)
|
||||
goto out_cleanup_ids;
|
||||
|
||||
spin_lock(&vfsmount_lock);
|
||||
|
||||
if (IS_MNT_SHARED(dest_mnt)) {
|
||||
for (p = source_mnt; p; p = next_mnt(p, source_mnt))
|
||||
set_mnt_shared(p);
|
||||
}
|
||||
|
||||
spin_lock(&vfsmount_lock);
|
||||
if (parent_path) {
|
||||
detach_mnt(source_mnt, parent_path);
|
||||
attach_mnt(source_mnt, path);
|
||||
|
@ -1534,8 +1536,12 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
|
|||
err = change_mount_flags(path->mnt, flags);
|
||||
else
|
||||
err = do_remount_sb(sb, flags, data, 0);
|
||||
if (!err)
|
||||
if (!err) {
|
||||
spin_lock(&vfsmount_lock);
|
||||
mnt_flags |= path->mnt->mnt_flags & MNT_PNODE_MASK;
|
||||
path->mnt->mnt_flags = mnt_flags;
|
||||
spin_unlock(&vfsmount_lock);
|
||||
}
|
||||
up_write(&sb->s_umount);
|
||||
if (!err) {
|
||||
security_sb_post_remount(path->mnt, flags, data);
|
||||
|
@ -1665,6 +1671,8 @@ int do_add_mount(struct vfsmount *newmnt, struct path *path,
|
|||
{
|
||||
int err;
|
||||
|
||||
mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD);
|
||||
|
||||
down_write(&namespace_sem);
|
||||
/* Something was mounted here while we slept */
|
||||
while (d_mountpoint(path->dentry) &&
|
||||
|
|
|
@ -1419,7 +1419,6 @@ static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
|
|||
goto out;
|
||||
|
||||
error = PROC_I(inode)->op.proc_get_link(inode, &nd->path);
|
||||
nd->last_type = LAST_BIND;
|
||||
out:
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
|
|
@ -2463,7 +2463,7 @@ int proc_nr_files(struct ctl_table *table, int write,
|
|||
|
||||
int __init get_filesystem_list(char *buf);
|
||||
|
||||
#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
|
||||
#define ACC_MODE(x) ("\004\002\006\006"[(x)&O_ACCMODE])
|
||||
#define OPEN_FMODE(flag) ((__force fmode_t)((flag + 1) & O_ACCMODE))
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
|
|
@ -80,9 +80,8 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
|
|||
return tomoyo_find_next_domain(bprm);
|
||||
/*
|
||||
* Read permission is checked against interpreters using next domain.
|
||||
* '1' is the result of open_to_namei_flags(O_RDONLY).
|
||||
*/
|
||||
return tomoyo_check_open_permission(domain, &bprm->file->f_path, 1);
|
||||
return tomoyo_check_open_permission(domain, &bprm->file->f_path, O_RDONLY);
|
||||
}
|
||||
|
||||
static int tomoyo_path_truncate(struct path *path, loff_t length,
|
||||
|
@ -184,10 +183,6 @@ static int tomoyo_file_fcntl(struct file *file, unsigned int cmd,
|
|||
static int tomoyo_dentry_open(struct file *f, const struct cred *cred)
|
||||
{
|
||||
int flags = f->f_flags;
|
||||
|
||||
if ((flags + 1) & O_ACCMODE)
|
||||
flags++;
|
||||
flags |= f->f_flags & (O_APPEND | O_TRUNC);
|
||||
/* Don't check read permission here if called from do_execve(). */
|
||||
if (current->in_execve)
|
||||
return 0;
|
||||
|
|
Loading…
Reference in a new issue