提交 7dc9c484 编写于 作者: L Linus Torvalds

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
...@@ -125,50 +125,36 @@ void mconsole_log(struct mc_request *req) ...@@ -125,50 +125,36 @@ void mconsole_log(struct mc_request *req)
void mconsole_proc(struct mc_request *req) void mconsole_proc(struct mc_request *req)
{ {
struct nameidata nd; struct nameidata nd;
struct file_system_type *proc; struct vfsmount *mnt = current->nsproxy->pid_ns->proc_mnt;
struct super_block *super;
struct file *file; struct file *file;
int n, err; int n, err;
char *ptr = req->request.data, *buf; char *ptr = req->request.data, *buf;
mm_segment_t old_fs = get_fs();
ptr += strlen("proc"); ptr += strlen("proc");
ptr = skip_spaces(ptr); ptr = skip_spaces(ptr);
proc = get_fs_type("proc"); err = vfs_path_lookup(mnt->mnt_root, mnt, ptr, LOOKUP_FOLLOW, &nd);
if (proc == NULL) { if (err) {
mconsole_reply(req, "procfs not registered", 1, 0); mconsole_reply(req, "Failed to look up file", 1, 0);
goto out; goto out;
} }
super = (*proc->get_sb)(proc, 0, NULL, NULL); err = may_open(&nd.path, MAY_READ, FMODE_READ);
put_filesystem(proc); if (result) {
if (super == NULL) { mconsole_reply(req, "Failed to open file", 1, 0);
mconsole_reply(req, "Failed to get procfs superblock", 1, 0); path_put(&nd.path);
goto out; 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);
if (err) {
mconsole_reply(req, "Failed to look up file", 1, 0);
goto out_kill;
}
file = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY, file = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY,
current_cred()); current_cred());
err = PTR_ERR(file);
if (IS_ERR(file)) { if (IS_ERR(file)) {
mconsole_reply(req, "Failed to open file", 1, 0); 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); buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (buf == NULL) { if (buf == NULL) {
...@@ -176,10 +162,13 @@ void mconsole_proc(struct mc_request *req) ...@@ -176,10 +162,13 @@ void mconsole_proc(struct mc_request *req)
goto out_fput; goto out_fput;
} }
if ((file->f_op != NULL) && (file->f_op->read != NULL)) { if (file->f_op->read) {
do { do {
n = (*file->f_op->read)(file, buf, PAGE_SIZE - 1, loff_t pos;
&file->f_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) { if (n >= 0) {
buf[n] = '\0'; buf[n] = '\0';
mconsole_reply(req, buf, 0, (n > 0)); mconsole_reply(req, buf, 0, (n > 0));
...@@ -197,8 +186,6 @@ void mconsole_proc(struct mc_request *req) ...@@ -197,8 +186,6 @@ void mconsole_proc(struct mc_request *req)
kfree(buf); kfree(buf);
out_fput: out_fput:
fput(file); fput(file);
out_kill:
deactivate_super(super);
out: ; out: ;
} }
#endif #endif
......
...@@ -1000,44 +1000,6 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) ...@@ -1000,44 +1000,6 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
return retval; 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 * v9fs_vfs_follow_link - follow a symlink path
* @dentry: dentry for symlink * @dentry: dentry for symlink
...@@ -1230,7 +1192,6 @@ static const struct inode_operations v9fs_dir_inode_operations_ext = { ...@@ -1230,7 +1192,6 @@ static const struct inode_operations v9fs_dir_inode_operations_ext = {
.rmdir = v9fs_vfs_rmdir, .rmdir = v9fs_vfs_rmdir,
.mknod = v9fs_vfs_mknod, .mknod = v9fs_vfs_mknod,
.rename = v9fs_vfs_rename, .rename = v9fs_vfs_rename,
.readlink = v9fs_vfs_readlink,
.getattr = v9fs_vfs_getattr, .getattr = v9fs_vfs_getattr,
.setattr = v9fs_vfs_setattr, .setattr = v9fs_vfs_setattr,
}; };
...@@ -1253,7 +1214,7 @@ static const struct inode_operations v9fs_file_inode_operations = { ...@@ -1253,7 +1214,7 @@ static const struct inode_operations v9fs_file_inode_operations = {
}; };
static const struct inode_operations v9fs_symlink_inode_operations = { static const struct inode_operations v9fs_symlink_inode_operations = {
.readlink = v9fs_vfs_readlink, .readlink = generic_readlink,
.follow_link = v9fs_vfs_follow_link, .follow_link = v9fs_vfs_follow_link,
.put_link = v9fs_vfs_put_link, .put_link = v9fs_vfs_put_link,
.getattr = v9fs_vfs_getattr, .getattr = v9fs_vfs_getattr,
......
...@@ -269,7 +269,7 @@ static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd, ...@@ -269,7 +269,7 @@ static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd,
int err; int err;
mntget(newmnt); 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) { switch (err) {
case 0: case 0:
path_put(&nd->path); path_put(&nd->path);
...@@ -371,7 +371,6 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) ...@@ -371,7 +371,6 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
if (IS_ERR(mnt)) if (IS_ERR(mnt))
goto out_err; goto out_err;
nd->path.mnt->mnt_flags |= MNT_SHRINKABLE;
rc = add_mount_helper(mnt, nd, &cifs_dfs_automount_list); rc = add_mount_helper(mnt, nd, &cifs_dfs_automount_list);
out: out:
......
...@@ -121,8 +121,10 @@ static int get_target(const char *symname, struct path *path, ...@@ -121,8 +121,10 @@ static int get_target(const char *symname, struct path *path,
ret = -ENOENT; ret = -ENOENT;
path_put(path); path_put(path);
} }
} else } else {
ret = -EPERM; ret = -EPERM;
path_put(path);
}
} }
return ret; return ret;
......
...@@ -715,31 +715,31 @@ static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd) ...@@ -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 */ /* Released in ecryptfs_put_link(); only release here on error */
buf = kmalloc(len, GFP_KERNEL); buf = kmalloc(len, GFP_KERNEL);
if (!buf) { if (!buf) {
rc = -ENOMEM; buf = ERR_PTR(-ENOMEM);
goto out; goto out;
} }
old_fs = get_fs(); old_fs = get_fs();
set_fs(get_ds()); set_fs(get_ds());
rc = dentry->d_inode->i_op->readlink(dentry, (char __user *)buf, len); rc = dentry->d_inode->i_op->readlink(dentry, (char __user *)buf, len);
set_fs(old_fs); set_fs(old_fs);
if (rc < 0) if (rc < 0) {
goto out_free;
else
buf[rc] = '\0';
rc = 0;
nd_set_link(nd, buf);
goto out;
out_free:
kfree(buf); kfree(buf);
buf = ERR_PTR(rc);
} else
buf[rc] = '\0';
out: out:
return ERR_PTR(rc); nd_set_link(nd, buf);
return NULL;
} }
static void static void
ecryptfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr) ecryptfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr)
{ {
char *buf = nd_get_link(nd);
if (!IS_ERR(buf)) {
/* Free the char* */ /* Free the char* */
kfree(nd_get_link(nd)); kfree(buf);
}
} }
/** /**
......
...@@ -646,22 +646,27 @@ static const struct super_operations hppfs_sbops = { ...@@ -646,22 +646,27 @@ static const struct super_operations hppfs_sbops = {
static int hppfs_readlink(struct dentry *dentry, char __user *buffer, static int hppfs_readlink(struct dentry *dentry, char __user *buffer,
int buflen) int buflen)
{ {
struct dentry *proc_dentry; struct dentry *proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
return proc_dentry->d_inode->i_op->readlink(proc_dentry, buffer, return proc_dentry->d_inode->i_op->readlink(proc_dentry, buffer,
buflen); buflen);
} }
static void *hppfs_follow_link(struct dentry *dentry, struct nameidata *nd) static void *hppfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{ {
struct dentry *proc_dentry; struct dentry *proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
return proc_dentry->d_inode->i_op->follow_link(proc_dentry, nd); 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 = { static const struct inode_operations hppfs_dir_iops = {
.lookup = hppfs_lookup, .lookup = hppfs_lookup,
}; };
...@@ -669,6 +674,7 @@ static const struct inode_operations hppfs_dir_iops = { ...@@ -669,6 +674,7 @@ static const struct inode_operations hppfs_dir_iops = {
static const struct inode_operations hppfs_link_iops = { static const struct inode_operations hppfs_link_iops = {
.readlink = hppfs_readlink, .readlink = hppfs_readlink,
.follow_link = hppfs_follow_link, .follow_link = hppfs_follow_link,
.put_link = hppfs_put_link,
}; };
static struct inode *get_inode(struct super_block *sb, struct dentry *dentry) static struct inode *get_inode(struct super_block *sb, struct dentry *dentry)
......
...@@ -561,6 +561,7 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata ...@@ -561,6 +561,7 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata
dget(dentry); dget(dentry);
} }
mntget(path->mnt); mntget(path->mnt);
nd->last_type = LAST_BIND;
cookie = dentry->d_inode->i_op->follow_link(dentry, nd); cookie = dentry->d_inode->i_op->follow_link(dentry, nd);
error = PTR_ERR(cookie); error = PTR_ERR(cookie);
if (!IS_ERR(cookie)) { if (!IS_ERR(cookie)) {
...@@ -1603,11 +1604,12 @@ struct file *do_filp_open(int dfd, const char *pathname, ...@@ -1603,11 +1604,12 @@ struct file *do_filp_open(int dfd, const char *pathname,
struct file *filp; struct file *filp;
struct nameidata nd; struct nameidata nd;
int error; int error;
struct path path, save; struct path path;
struct dentry *dir; struct dentry *dir;
int count = 0; int count = 0;
int will_truncate; int will_truncate;
int flag = open_to_namei_flags(open_flag); 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 * 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, ...@@ -1619,7 +1621,7 @@ struct file *do_filp_open(int dfd, const char *pathname,
open_flag |= O_DSYNC; open_flag |= O_DSYNC;
if (!acc_mode) 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 */ /* O_TRUNC implies we need access checks for write permissions */
if (flag & O_TRUNC) if (flag & O_TRUNC)
...@@ -1659,9 +1661,12 @@ struct file *do_filp_open(int dfd, const char *pathname, ...@@ -1659,9 +1661,12 @@ struct file *do_filp_open(int dfd, const char *pathname,
/* /*
* Create - we need to know the parent. * Create - we need to know the parent.
*/ */
reval:
error = path_init(dfd, pathname, LOOKUP_PARENT, &nd); error = path_init(dfd, pathname, LOOKUP_PARENT, &nd);
if (error) if (error)
return ERR_PTR(error); return ERR_PTR(error);
if (force_reval)
nd.flags |= LOOKUP_REVAL;
error = path_walk(pathname, &nd); error = path_walk(pathname, &nd);
if (error) { if (error) {
if (nd.root.mnt) if (nd.root.mnt)
...@@ -1853,17 +1858,7 @@ struct file *do_filp_open(int dfd, const char *pathname, ...@@ -1853,17 +1858,7 @@ struct file *do_filp_open(int dfd, const char *pathname,
error = security_inode_follow_link(path.dentry, &nd); error = security_inode_follow_link(path.dentry, &nd);
if (error) if (error)
goto exit_dput; 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); error = __do_follow_link(&path, &nd);
}
path_put(&save);
path_put(&path); path_put(&path);
if (error) { if (error) {
/* Does someone understand code flow here? Or it is only /* Does someone understand code flow here? Or it is only
...@@ -1873,6 +1868,10 @@ struct file *do_filp_open(int dfd, const char *pathname, ...@@ -1873,6 +1868,10 @@ struct file *do_filp_open(int dfd, const char *pathname,
release_open_intent(&nd); release_open_intent(&nd);
if (nd.root.mnt) if (nd.root.mnt)
path_put(&nd.root); path_put(&nd.root);
if (error == -ESTALE && !force_reval) {
force_reval = 1;
goto reval;
}
return ERR_PTR(error); return ERR_PTR(error);
} }
nd.flags &= ~LOOKUP_PARENT; nd.flags &= ~LOOKUP_PARENT;
......
...@@ -965,10 +965,12 @@ EXPORT_SYMBOL(may_umount_tree); ...@@ -965,10 +965,12 @@ EXPORT_SYMBOL(may_umount_tree);
int may_umount(struct vfsmount *mnt) int may_umount(struct vfsmount *mnt)
{ {
int ret = 1; int ret = 1;
down_read(&namespace_sem);
spin_lock(&vfsmount_lock); spin_lock(&vfsmount_lock);
if (propagate_mount_busy(mnt, 2)) if (propagate_mount_busy(mnt, 2))
ret = 0; ret = 0;
spin_unlock(&vfsmount_lock); spin_unlock(&vfsmount_lock);
up_read(&namespace_sem);
return ret; return ret;
} }
...@@ -1352,12 +1354,12 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt, ...@@ -1352,12 +1354,12 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt,
if (err) if (err)
goto out_cleanup_ids; goto out_cleanup_ids;
spin_lock(&vfsmount_lock);
if (IS_MNT_SHARED(dest_mnt)) { if (IS_MNT_SHARED(dest_mnt)) {
for (p = source_mnt; p; p = next_mnt(p, source_mnt)) for (p = source_mnt; p; p = next_mnt(p, source_mnt))
set_mnt_shared(p); set_mnt_shared(p);
} }
spin_lock(&vfsmount_lock);
if (parent_path) { if (parent_path) {
detach_mnt(source_mnt, parent_path); detach_mnt(source_mnt, parent_path);
attach_mnt(source_mnt, path); attach_mnt(source_mnt, path);
...@@ -1534,8 +1536,12 @@ static int do_remount(struct path *path, int flags, int mnt_flags, ...@@ -1534,8 +1536,12 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
err = change_mount_flags(path->mnt, flags); err = change_mount_flags(path->mnt, flags);
else else
err = do_remount_sb(sb, flags, data, 0); 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; path->mnt->mnt_flags = mnt_flags;
spin_unlock(&vfsmount_lock);
}
up_write(&sb->s_umount); up_write(&sb->s_umount);
if (!err) { if (!err) {
security_sb_post_remount(path->mnt, flags, data); security_sb_post_remount(path->mnt, flags, data);
...@@ -1665,6 +1671,8 @@ int do_add_mount(struct vfsmount *newmnt, struct path *path, ...@@ -1665,6 +1671,8 @@ int do_add_mount(struct vfsmount *newmnt, struct path *path,
{ {
int err; int err;
mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD);
down_write(&namespace_sem); down_write(&namespace_sem);
/* Something was mounted here while we slept */ /* Something was mounted here while we slept */
while (d_mountpoint(path->dentry) && while (d_mountpoint(path->dentry) &&
......
...@@ -1419,7 +1419,6 @@ static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) ...@@ -1419,7 +1419,6 @@ static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
goto out; goto out;
error = PROC_I(inode)->op.proc_get_link(inode, &nd->path); error = PROC_I(inode)->op.proc_get_link(inode, &nd->path);
nd->last_type = LAST_BIND;
out: out:
return ERR_PTR(error); return ERR_PTR(error);
} }
......
...@@ -2463,7 +2463,7 @@ int proc_nr_files(struct ctl_table *table, int write, ...@@ -2463,7 +2463,7 @@ int proc_nr_files(struct ctl_table *table, int write,
int __init get_filesystem_list(char *buf); 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)) #define OPEN_FMODE(flag) ((__force fmode_t)((flag + 1) & O_ACCMODE))
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
......
...@@ -80,9 +80,8 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) ...@@ -80,9 +80,8 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
return tomoyo_find_next_domain(bprm); return tomoyo_find_next_domain(bprm);
/* /*
* Read permission is checked against interpreters using next domain. * 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, 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, ...@@ -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) static int tomoyo_dentry_open(struct file *f, const struct cred *cred)
{ {
int flags = f->f_flags; 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(). */ /* Don't check read permission here if called from do_execve(). */
if (current->in_execve) if (current->in_execve)
return 0; return 0;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册