Commit 603ba7e4 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull vfs pile #2 from Al Viro:
 "Next pile (and there'll be one or two more).

  The large piece in this one is getting rid of /proc/*/ns/* weirdness;
  among other things, it allows to (finally) make nameidata completely
  opaque outside of fs/namei.c, making for easier further cleanups in
  there"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  coda_venus_readdir(): use file_inode()
  fs/namei.c: fold link_path_walk() call into path_init()
  path_init(): don't bother with LOOKUP_PARENT in argument
  fs/namei.c: new helper (path_cleanup())
  path_init(): store the "base" pointer to file in nameidata itself
  make default ->i_fop have ->open() fail with ENXIO
  make nameidata completely opaque outside of fs/namei.c
  kill proc_ns completely
  take the targets of /proc/*/ns/* symlinks to separate fs
  bury struct proc_ns in fs/proc
  copy address of proc_ns_ops into ns_common
  new helpers: ns_alloc_inum/ns_free_inum
  make proc_ns_operations work with struct ns_common * instead of void *
  switch the rest of proc_ns_operations to working with &...->ns
  netns: switch ->get()/->put()/->install()/->inum() to working with &net->ns
  make mntns ->get()/->put()/->install()/->inum() work with &mnt_ns->ns
  common object embedded into various struct ....ns
parents 31f48fc8 93fe74b2
...@@ -2145,22 +2145,12 @@ pfm_close(struct inode *inode, struct file *filp) ...@@ -2145,22 +2145,12 @@ pfm_close(struct inode *inode, struct file *filp)
return 0; return 0;
} }
static int
pfm_no_open(struct inode *irrelevant, struct file *dontcare)
{
DPRINT(("pfm_no_open called\n"));
return -ENXIO;
}
static const struct file_operations pfm_file_ops = { static const struct file_operations pfm_file_ops = {
.llseek = no_llseek, .llseek = no_llseek,
.read = pfm_read, .read = pfm_read,
.write = pfm_write, .write = pfm_write,
.poll = pfm_poll, .poll = pfm_poll,
.unlocked_ioctl = pfm_ioctl, .unlocked_ioctl = pfm_ioctl,
.open = pfm_no_open, /* special open code to disallow open via /proc */
.fasync = pfm_fasync, .fasync = pfm_fasync,
.release = pfm_close, .release = pfm_close,
.flush = pfm_flush .flush = pfm_flush
......
...@@ -11,7 +11,7 @@ obj-y := open.o read_write.o file_table.o super.o \ ...@@ -11,7 +11,7 @@ obj-y := open.o read_write.o file_table.o super.o \
attr.o bad_inode.o file.o filesystems.o namespace.o \ attr.o bad_inode.o file.o filesystems.o namespace.o \
seq_file.o xattr.o libfs.o fs-writeback.o \ seq_file.o xattr.o libfs.o fs-writeback.o \
pnode.o splice.o sync.o utimes.o \ pnode.o splice.o sync.o utimes.o \
stack.o fs_struct.o statfs.o fs_pin.o stack.o fs_struct.o statfs.o fs_pin.o nsfs.o
ifeq ($(CONFIG_BLOCK),y) ifeq ($(CONFIG_BLOCK),y)
obj-y += buffer.o block_dev.o direct-io.o mpage.o obj-y += buffer.o block_dev.o direct-io.o mpage.o
......
...@@ -426,7 +426,6 @@ static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx) ...@@ -426,7 +426,6 @@ static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx)
struct coda_file_info *cfi; struct coda_file_info *cfi;
struct coda_inode_info *cii; struct coda_inode_info *cii;
struct file *host_file; struct file *host_file;
struct dentry *de;
struct venus_dirent *vdir; struct venus_dirent *vdir;
unsigned long vdir_size = offsetof(struct venus_dirent, d_name); unsigned long vdir_size = offsetof(struct venus_dirent, d_name);
unsigned int type; unsigned int type;
...@@ -438,8 +437,7 @@ static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx) ...@@ -438,8 +437,7 @@ static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx)
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
host_file = cfi->cfi_container; host_file = cfi->cfi_container;
de = coda_file->f_path.dentry; cii = ITOC(file_inode(coda_file));
cii = ITOC(de->d_inode);
vdir = kmalloc(sizeof(*vdir), GFP_KERNEL); vdir = kmalloc(sizeof(*vdir), GFP_KERNEL);
if (!vdir) return -ENOMEM; if (!vdir) return -ENOMEM;
......
...@@ -114,6 +114,11 @@ int proc_nr_inodes(struct ctl_table *table, int write, ...@@ -114,6 +114,11 @@ int proc_nr_inodes(struct ctl_table *table, int write,
} }
#endif #endif
static int no_open(struct inode *inode, struct file *file)
{
return -ENXIO;
}
/** /**
* inode_init_always - perform inode structure intialisation * inode_init_always - perform inode structure intialisation
* @sb: superblock inode belongs to * @sb: superblock inode belongs to
...@@ -125,7 +130,7 @@ int proc_nr_inodes(struct ctl_table *table, int write, ...@@ -125,7 +130,7 @@ int proc_nr_inodes(struct ctl_table *table, int write,
int inode_init_always(struct super_block *sb, struct inode *inode) int inode_init_always(struct super_block *sb, struct inode *inode)
{ {
static const struct inode_operations empty_iops; static const struct inode_operations empty_iops;
static const struct file_operations empty_fops; static const struct file_operations no_open_fops = {.open = no_open};
struct address_space *const mapping = &inode->i_data; struct address_space *const mapping = &inode->i_data;
inode->i_sb = sb; inode->i_sb = sb;
...@@ -133,7 +138,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode) ...@@ -133,7 +138,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
inode->i_flags = 0; inode->i_flags = 0;
atomic_set(&inode->i_count, 1); atomic_set(&inode->i_count, 1);
inode->i_op = &empty_iops; inode->i_op = &empty_iops;
inode->i_fop = &empty_fops; inode->i_fop = &no_open_fops;
inode->__i_nlink = 1; inode->__i_nlink = 1;
inode->i_opflags = 0; inode->i_opflags = 0;
i_uid_write(inode, 0); i_uid_write(inode, 0);
...@@ -1798,7 +1803,7 @@ void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev) ...@@ -1798,7 +1803,7 @@ void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
} else if (S_ISFIFO(mode)) } else if (S_ISFIFO(mode))
inode->i_fop = &pipefifo_fops; inode->i_fop = &pipefifo_fops;
else if (S_ISSOCK(mode)) else if (S_ISSOCK(mode))
inode->i_fop = &bad_sock_fops; ; /* leave it no_open_fops */
else else
printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for" printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for"
" inode %s:%lu\n", mode, inode->i_sb->s_id, " inode %s:%lu\n", mode, inode->i_sb->s_id,
......
...@@ -147,3 +147,8 @@ extern const struct file_operations pipefifo_fops; ...@@ -147,3 +147,8 @@ extern const struct file_operations pipefifo_fops;
*/ */
extern void sb_pin_kill(struct super_block *sb); extern void sb_pin_kill(struct super_block *sb);
extern void mnt_pin_kill(struct mount *m); extern void mnt_pin_kill(struct mount *m);
/*
* fs/nsfs.c
*/
extern struct dentry_operations ns_dentry_operations;
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/ns_common.h>
struct mnt_namespace { struct mnt_namespace {
atomic_t count; atomic_t count;
unsigned int proc_inum; struct ns_common ns;
struct mount * root; struct mount * root;
struct list_head list; struct list_head list;
struct user_namespace *user_ns; struct user_namespace *user_ns;
......
...@@ -487,6 +487,19 @@ void path_put(const struct path *path) ...@@ -487,6 +487,19 @@ void path_put(const struct path *path)
} }
EXPORT_SYMBOL(path_put); EXPORT_SYMBOL(path_put);
struct nameidata {
struct path path;
struct qstr last;
struct path root;
struct inode *inode; /* path.dentry.d_inode */
unsigned int flags;
unsigned seq, m_seq;
int last_type;
unsigned depth;
struct file *base;
char *saved_names[MAX_NESTED_LINKS + 1];
};
/* /*
* Path walking has 2 modes, rcu-walk and ref-walk (see * Path walking has 2 modes, rcu-walk and ref-walk (see
* Documentation/filesystems/path-lookup.txt). In situations when we can't * Documentation/filesystems/path-lookup.txt). In situations when we can't
...@@ -695,6 +708,18 @@ void nd_jump_link(struct nameidata *nd, struct path *path) ...@@ -695,6 +708,18 @@ void nd_jump_link(struct nameidata *nd, struct path *path)
nd->flags |= LOOKUP_JUMPED; nd->flags |= LOOKUP_JUMPED;
} }
void nd_set_link(struct nameidata *nd, char *path)
{
nd->saved_names[nd->depth] = path;
}
EXPORT_SYMBOL(nd_set_link);
char *nd_get_link(struct nameidata *nd)
{
return nd->saved_names[nd->depth];
}
EXPORT_SYMBOL(nd_get_link);
static inline void put_link(struct nameidata *nd, struct path *link, void *cookie) static inline void put_link(struct nameidata *nd, struct path *link, void *cookie)
{ {
struct inode *inode = link->dentry->d_inode; struct inode *inode = link->dentry->d_inode;
...@@ -1821,13 +1846,14 @@ static int link_path_walk(const char *name, struct nameidata *nd) ...@@ -1821,13 +1846,14 @@ static int link_path_walk(const char *name, struct nameidata *nd)
} }
static int path_init(int dfd, const char *name, unsigned int flags, static int path_init(int dfd, const char *name, unsigned int flags,
struct nameidata *nd, struct file **fp) struct nameidata *nd)
{ {
int retval = 0; int retval = 0;
nd->last_type = LAST_ROOT; /* if there are only slashes... */ nd->last_type = LAST_ROOT; /* if there are only slashes... */
nd->flags = flags | LOOKUP_JUMPED; nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT;
nd->depth = 0; nd->depth = 0;
nd->base = NULL;
if (flags & LOOKUP_ROOT) { if (flags & LOOKUP_ROOT) {
struct dentry *root = nd->root.dentry; struct dentry *root = nd->root.dentry;
struct inode *inode = root->d_inode; struct inode *inode = root->d_inode;
...@@ -1847,7 +1873,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, ...@@ -1847,7 +1873,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
} else { } else {
path_get(&nd->path); path_get(&nd->path);
} }
return 0; goto done;
} }
nd->root.mnt = NULL; nd->root.mnt = NULL;
...@@ -1897,7 +1923,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, ...@@ -1897,7 +1923,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
nd->path = f.file->f_path; nd->path = f.file->f_path;
if (flags & LOOKUP_RCU) { if (flags & LOOKUP_RCU) {
if (f.flags & FDPUT_FPUT) if (f.flags & FDPUT_FPUT)
*fp = f.file; nd->base = f.file;
nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
rcu_read_lock(); rcu_read_lock();
} else { } else {
...@@ -1908,13 +1934,26 @@ static int path_init(int dfd, const char *name, unsigned int flags, ...@@ -1908,13 +1934,26 @@ static int path_init(int dfd, const char *name, unsigned int flags,
nd->inode = nd->path.dentry->d_inode; nd->inode = nd->path.dentry->d_inode;
if (!(flags & LOOKUP_RCU)) if (!(flags & LOOKUP_RCU))
return 0; goto done;
if (likely(!read_seqcount_retry(&nd->path.dentry->d_seq, nd->seq))) if (likely(!read_seqcount_retry(&nd->path.dentry->d_seq, nd->seq)))
return 0; goto done;
if (!(nd->flags & LOOKUP_ROOT)) if (!(nd->flags & LOOKUP_ROOT))
nd->root.mnt = NULL; nd->root.mnt = NULL;
rcu_read_unlock(); rcu_read_unlock();
return -ECHILD; return -ECHILD;
done:
current->total_link_count = 0;
return link_path_walk(name, nd);
}
static void path_cleanup(struct nameidata *nd)
{
if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) {
path_put(&nd->root);
nd->root.mnt = NULL;
}
if (unlikely(nd->base))
fput(nd->base);
} }
static inline int lookup_last(struct nameidata *nd, struct path *path) static inline int lookup_last(struct nameidata *nd, struct path *path)
...@@ -1930,7 +1969,6 @@ static inline int lookup_last(struct nameidata *nd, struct path *path) ...@@ -1930,7 +1969,6 @@ static inline int lookup_last(struct nameidata *nd, struct path *path)
static int path_lookupat(int dfd, const char *name, static int path_lookupat(int dfd, const char *name,
unsigned int flags, struct nameidata *nd) unsigned int flags, struct nameidata *nd)
{ {
struct file *base = NULL;
struct path path; struct path path;
int err; int err;
...@@ -1948,14 +1986,7 @@ static int path_lookupat(int dfd, const char *name, ...@@ -1948,14 +1986,7 @@ static int path_lookupat(int dfd, const char *name,
* be handled by restarting a traditional ref-walk (which will always * be handled by restarting a traditional ref-walk (which will always
* be able to complete). * be able to complete).
*/ */
err = path_init(dfd, name, flags | LOOKUP_PARENT, nd, &base); err = path_init(dfd, name, flags, nd);
if (unlikely(err))
goto out;
current->total_link_count = 0;
err = link_path_walk(name, nd);
if (!err && !(flags & LOOKUP_PARENT)) { if (!err && !(flags & LOOKUP_PARENT)) {
err = lookup_last(nd, &path); err = lookup_last(nd, &path);
while (err > 0) { while (err > 0) {
...@@ -1983,14 +2014,7 @@ static int path_lookupat(int dfd, const char *name, ...@@ -1983,14 +2014,7 @@ static int path_lookupat(int dfd, const char *name,
} }
} }
out: path_cleanup(nd);
if (base)
fput(base);
if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) {
path_put(&nd->root);
nd->root.mnt = NULL;
}
return err; return err;
} }
...@@ -2297,19 +2321,13 @@ mountpoint_last(struct nameidata *nd, struct path *path) ...@@ -2297,19 +2321,13 @@ mountpoint_last(struct nameidata *nd, struct path *path)
static int static int
path_mountpoint(int dfd, const char *name, struct path *path, unsigned int flags) path_mountpoint(int dfd, const char *name, struct path *path, unsigned int flags)
{ {
struct file *base = NULL;
struct nameidata nd; struct nameidata nd;
int err; int err;
err = path_init(dfd, name, flags | LOOKUP_PARENT, &nd, &base); err = path_init(dfd, name, flags, &nd);
if (unlikely(err)) if (unlikely(err))
goto out; goto out;
current->total_link_count = 0;
err = link_path_walk(name, &nd);
if (err)
goto out;
err = mountpoint_last(&nd, path); err = mountpoint_last(&nd, path);
while (err > 0) { while (err > 0) {
void *cookie; void *cookie;
...@@ -2325,12 +2343,7 @@ path_mountpoint(int dfd, const char *name, struct path *path, unsigned int flags ...@@ -2325,12 +2343,7 @@ path_mountpoint(int dfd, const char *name, struct path *path, unsigned int flags
put_link(&nd, &link, cookie); put_link(&nd, &link, cookie);
} }
out: out:
if (base) path_cleanup(&nd);
fput(base);
if (nd.root.mnt && !(nd.flags & LOOKUP_ROOT))
path_put(&nd.root);
return err; return err;
} }
...@@ -3181,7 +3194,6 @@ static int do_tmpfile(int dfd, struct filename *pathname, ...@@ -3181,7 +3194,6 @@ static int do_tmpfile(int dfd, struct filename *pathname,
static struct file *path_openat(int dfd, struct filename *pathname, static struct file *path_openat(int dfd, struct filename *pathname,
struct nameidata *nd, const struct open_flags *op, int flags) struct nameidata *nd, const struct open_flags *op, int flags)
{ {
struct file *base = NULL;
struct file *file; struct file *file;
struct path path; struct path path;
int opened = 0; int opened = 0;
...@@ -3198,12 +3210,7 @@ static struct file *path_openat(int dfd, struct filename *pathname, ...@@ -3198,12 +3210,7 @@ static struct file *path_openat(int dfd, struct filename *pathname,
goto out; goto out;
} }
error = path_init(dfd, pathname->name, flags | LOOKUP_PARENT, nd, &base); error = path_init(dfd, pathname->name, flags, nd);
if (unlikely(error))
goto out;
current->total_link_count = 0;
error = link_path_walk(pathname->name, nd);
if (unlikely(error)) if (unlikely(error))
goto out; goto out;
...@@ -3229,10 +3236,7 @@ static struct file *path_openat(int dfd, struct filename *pathname, ...@@ -3229,10 +3236,7 @@ static struct file *path_openat(int dfd, struct filename *pathname,
put_link(nd, &link, cookie); put_link(nd, &link, cookie);
} }
out: out:
if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) path_cleanup(nd);
path_put(&nd->root);
if (base)
fput(base);
if (!(opened & FILE_OPENED)) { if (!(opened & FILE_OPENED)) {
BUG_ON(!error); BUG_ON(!error);
put_filp(file); put_filp(file);
......
...@@ -1569,17 +1569,13 @@ SYSCALL_DEFINE1(oldumount, char __user *, name) ...@@ -1569,17 +1569,13 @@ SYSCALL_DEFINE1(oldumount, char __user *, name)
static bool is_mnt_ns_file(struct dentry *dentry) static bool is_mnt_ns_file(struct dentry *dentry)
{ {
/* Is this a proxy for a mount namespace? */ /* Is this a proxy for a mount namespace? */
struct inode *inode = dentry->d_inode; return dentry->d_op == &ns_dentry_operations &&
struct proc_ns *ei; dentry->d_fsdata == &mntns_operations;
}
if (!proc_ns_inode(inode))
return false;
ei = get_proc_ns(inode);
if (ei->ns_ops != &mntns_operations)
return false;
return true; struct mnt_namespace *to_mnt_ns(struct ns_common *ns)
{
return container_of(ns, struct mnt_namespace, ns);
} }
static bool mnt_ns_loop(struct dentry *dentry) static bool mnt_ns_loop(struct dentry *dentry)
...@@ -1591,7 +1587,7 @@ static bool mnt_ns_loop(struct dentry *dentry) ...@@ -1591,7 +1587,7 @@ static bool mnt_ns_loop(struct dentry *dentry)
if (!is_mnt_ns_file(dentry)) if (!is_mnt_ns_file(dentry))
return false; return false;
mnt_ns = get_proc_ns(dentry->d_inode)->ns; mnt_ns = to_mnt_ns(get_proc_ns(dentry->d_inode));
return current->nsproxy->mnt_ns->seq >= mnt_ns->seq; return current->nsproxy->mnt_ns->seq >= mnt_ns->seq;
} }
...@@ -2020,7 +2016,10 @@ static int do_loopback(struct path *path, const char *old_name, ...@@ -2020,7 +2016,10 @@ static int do_loopback(struct path *path, const char *old_name,
if (IS_MNT_UNBINDABLE(old)) if (IS_MNT_UNBINDABLE(old))
goto out2; goto out2;
if (!check_mnt(parent) || !check_mnt(old)) if (!check_mnt(parent))
goto out2;
if (!check_mnt(old) && old_path.dentry->d_op != &ns_dentry_operations)
goto out2; goto out2;
if (!recurse && has_locked_children(old, old_path.dentry)) if (!recurse && has_locked_children(old, old_path.dentry))
...@@ -2640,7 +2639,7 @@ long do_mount(const char *dev_name, const char __user *dir_name, ...@@ -2640,7 +2639,7 @@ long do_mount(const char *dev_name, const char __user *dir_name,
static void free_mnt_ns(struct mnt_namespace *ns) static void free_mnt_ns(struct mnt_namespace *ns)
{ {
proc_free_inum(ns->proc_inum); ns_free_inum(&ns->ns);
put_user_ns(ns->user_ns); put_user_ns(ns->user_ns);
kfree(ns); kfree(ns);
} }
...@@ -2662,11 +2661,12 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns) ...@@ -2662,11 +2661,12 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns)
new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL);
if (!new_ns) if (!new_ns)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
ret = proc_alloc_inum(&new_ns->proc_inum); ret = ns_alloc_inum(&new_ns->ns);
if (ret) { if (ret) {
kfree(new_ns); kfree(new_ns);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
new_ns->ns.ops = &mntns_operations;
new_ns->seq = atomic64_add_return(1, &mnt_ns_seq); new_ns->seq = atomic64_add_return(1, &mnt_ns_seq);
atomic_set(&new_ns->count, 1); atomic_set(&new_ns->count, 1);
new_ns->root = NULL; new_ns->root = NULL;
...@@ -3144,31 +3144,31 @@ bool fs_fully_visible(struct file_system_type *type) ...@@ -3144,31 +3144,31 @@ bool fs_fully_visible(struct file_system_type *type)
return visible; return visible;
} }
static void *mntns_get(struct task_struct *task) static struct ns_common *mntns_get(struct task_struct *task)
{ {
struct mnt_namespace *ns = NULL; struct ns_common *ns = NULL;
struct nsproxy *nsproxy; struct nsproxy *nsproxy;
task_lock(task); task_lock(task);
nsproxy = task->nsproxy; nsproxy = task->nsproxy;
if (nsproxy) { if (nsproxy) {
ns = nsproxy->mnt_ns; ns = &nsproxy->mnt_ns->ns;
get_mnt_ns(ns); get_mnt_ns(to_mnt_ns(ns));
} }
task_unlock(task); task_unlock(task);
return ns; return ns;
} }
static void mntns_put(void *ns) static void mntns_put(struct ns_common *ns)
{ {
put_mnt_ns(ns); put_mnt_ns(to_mnt_ns(ns));
} }
static int mntns_install(struct nsproxy *nsproxy, void *ns) static int mntns_install(struct nsproxy *nsproxy, struct ns_common *ns)
{ {
struct fs_struct *fs = current->fs; struct fs_struct *fs = current->fs;
struct mnt_namespace *mnt_ns = ns; struct mnt_namespace *mnt_ns = to_mnt_ns(ns);
struct path root; struct path root;
if (!ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN) || if (!ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN) ||
...@@ -3198,17 +3198,10 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns) ...@@ -3198,17 +3198,10 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns)
return 0; return 0;
} }
static unsigned int mntns_inum(void *ns)
{
struct mnt_namespace *mnt_ns = ns;
return mnt_ns->proc_inum;
}
const struct proc_ns_operations mntns_operations = { const struct proc_ns_operations mntns_operations = {
.name = "mnt", .name = "mnt",
.type = CLONE_NEWNS, .type = CLONE_NEWNS,
.get = mntns_get, .get = mntns_get,
.put = mntns_put, .put = mntns_put,
.install = mntns_install, .install = mntns_install,
.inum = mntns_inum,
}; };
#include <linux/mount.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/proc_ns.h>
#include <linux/magic.h>
#include <linux/ktime.h>
static struct vfsmount *nsfs_mnt;
static const struct file_operations ns_file_operations = {
.llseek = no_llseek,
};
static char *ns_dname(struct dentry *dentry, char *buffer, int buflen)
{
struct inode *inode = dentry->d_inode;
const struct proc_ns_operations *ns_ops = dentry->d_fsdata;
return dynamic_dname(dentry, buffer, buflen, "%s:[%lu]",
ns_ops->name, inode->i_ino);
}
static void ns_prune_dentry(struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
if (inode) {
struct ns_common *ns = inode->i_private;
atomic_long_set(&ns->stashed, 0);
}
}
const struct dentry_operations ns_dentry_operations =
{
.d_prune = ns_prune_dentry,
.d_delete = always_delete_dentry,
.d_dname = ns_dname,
};
static void nsfs_evict(struct inode *inode)
{
struct ns_common *ns = inode->i_private;
clear_inode(inode);
ns->ops->put(ns);
}
void *ns_get_path(struct path *path, struct task_struct *task,
const struct proc_ns_operations *ns_ops)
{
struct vfsmount *mnt = mntget(nsfs_mnt);
struct qstr qname = { .name = "", };
struct dentry *dentry;
struct inode *inode;
struct ns_common *ns;
unsigned long d;
again:
ns = ns_ops->get(task);
if (!ns) {
mntput(mnt);
return ERR_PTR(-ENOENT);
}
rcu_read_lock();
d = atomic_long_read(&ns->stashed);
if (!d)
goto slow;
dentry = (struct dentry *)d;
if (!lockref_get_not_dead(&dentry->d_lockref))
goto slow;
rcu_read_unlock();
ns_ops->put(ns);
got_it:
path->mnt = mnt;
path->dentry = dentry;
return NULL;
slow:
rcu_read_unlock();
inode = new_inode_pseudo(mnt->mnt_sb);
if (!inode) {
ns_ops->put(ns);
mntput(mnt);
return ERR_PTR(-ENOMEM);
}
inode->i_ino = ns->inum;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_flags |= S_IMMUTABLE;
inode->i_mode = S_IFREG | S_IRUGO;
inode->i_fop = &ns_file_operations;
inode->i_private = ns;
dentry = d_alloc_pseudo(mnt->mnt_sb, &qname);
if (!dentry) {
iput(inode);
mntput(mnt);
return ERR_PTR(-ENOMEM);
}
d_instantiate(dentry, inode);
dentry->d_fsdata = (void *)ns_ops;
d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry);
if (d) {
d_delete(dentry); /* make sure ->d_prune() does nothing */
dput(dentry);
cpu_relax();
goto again;
}
goto got_it;
}
int ns_get_name(char *buf, size_t size, struct task_struct *task,
const struct proc_ns_operations *ns_ops)
{
struct ns_common *ns;
int res = -ENOENT;
ns = ns_ops->get(task);
if (ns) {
res = snprintf(buf, size, "%s:[%u]", ns_ops->name, ns->inum);
ns_ops->put(ns);
}
return res;
}
struct file *proc_ns_fget(int fd)
{
struct file *file;
file = fget(fd);
if (!file)
return ERR_PTR(-EBADF);
if (file->f_op != &ns_file_operations)
goto out_invalid;
return file;
out_invalid:
fput(file);
return ERR_PTR(-EINVAL);
}
static const struct super_operations nsfs_ops = {
.statfs = simple_statfs,
.evict_inode = nsfs_evict,
};
static struct dentry *nsfs_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
return mount_pseudo(fs_type, "nsfs:", &nsfs_ops,
&ns_dentry_operations, NSFS_MAGIC);
}
static struct file_system_type nsfs = {
.name = "nsfs",
.mount = nsfs_mount,
.kill_sb = kill_anon_super,
};
void __init nsfs_init(void)
{
nsfs_mnt = kern_mount(&nsfs);
if (IS_ERR(nsfs_mnt))
panic("can't set nsfs up\n");
nsfs_mnt->mnt_sb->s_flags &= ~MS_NOUSER;
}
...@@ -32,8 +32,6 @@ static void proc_evict_inode(struct inode *inode) ...@@ -32,8 +32,6 @@ static void proc_evict_inode(struct inode *inode)
{ {
struct proc_dir_entry *de; struct proc_dir_entry *de;
struct ctl_table_header *head; struct ctl_table_header *head;
const struct proc_ns_operations *ns_ops;
void *ns;
truncate_inode_pages_final(&inode->i_data); truncate_inode_pages_final(&inode->i_data);
clear_inode(inode); clear_inode(inode);
...@@ -50,11 +48,6 @@ static void proc_evict_inode(struct inode *inode) ...@@ -50,11 +48,6 @@ static void proc_evict_inode(struct inode *inode)
RCU_INIT_POINTER(PROC_I(inode)->sysctl, NULL); RCU_INIT_POINTER(PROC_I(inode)->sysctl, NULL);
sysctl_head_put(head); sysctl_head_put(head);
} }
/* Release any associated namespace */
ns_ops = PROC_I(inode)->ns.ns_ops;
ns = PROC_I(inode)->ns.ns;
if (ns_ops && ns)
ns_ops->put(ns);
} }
static struct kmem_cache * proc_inode_cachep; static struct kmem_cache * proc_inode_cachep;
...@@ -73,8 +66,7 @@ static struct inode *proc_alloc_inode(struct super_block *sb) ...@@ -73,8 +66,7 @@ static struct inode *proc_alloc_inode(struct super_block *sb)
ei->pde = NULL; ei->pde = NULL;
ei->sysctl = NULL; ei->sysctl = NULL;
ei->sysctl_entry = NULL; ei->sysctl_entry = NULL;
ei->ns.ns = NULL; ei->ns_ops = NULL;
ei->ns.ns_ops = NULL;
inode = &ei->vfs_inode; inode = &ei->vfs_inode;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
return inode; return inode;
......
...@@ -65,7 +65,7 @@ struct proc_inode { ...@@ -65,7 +65,7 @@ struct proc_inode {
struct proc_dir_entry *pde; struct proc_dir_entry *pde;
struct ctl_table_header *sysctl; struct ctl_table_header *sysctl;
struct ctl_table *sysctl_entry; struct ctl_table *sysctl_entry;
struct proc_ns ns; const struct proc_ns_operations *ns_ops;
struct inode vfs_inode; struct inode vfs_inode;
}; };
......
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/nsproxy.h> #include <linux/nsproxy.h>
#include <linux/sched.h>
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/fs_struct.h>
#include <linux/mount.h>
#include <linux/path.h>
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/utsname.h> #include <linux/utsname.h>
...@@ -34,138 +30,45 @@ static const struct proc_ns_operations *ns_entries[] = { ...@@ -34,138 +30,45 @@ static const struct proc_ns_operations *ns_entries[] = {
&mntns_operations, &mntns_operations,
}; };
static const struct file_operations ns_file_operations = {
.llseek = no_llseek,
};
static const struct inode_operations ns_inode_operations = {
.setattr = proc_setattr,
};
static char *ns_dname(struct dentry *dentry, char *buffer, int buflen)
{
struct inode *inode = dentry->d_inode;
const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns.ns_ops;
return dynamic_dname(dentry, buffer, buflen, "%s:[%lu]",
ns_ops->name, inode->i_ino);
}
const struct dentry_operations ns_dentry_operations =
{
.d_delete = always_delete_dentry,
.d_dname = ns_dname,
};
static struct dentry *proc_ns_get_dentry(struct super_block *sb,
struct task_struct *task, const struct proc_ns_operations *ns_ops)
{
struct dentry *dentry, *result;
struct inode *inode;
struct proc_inode *ei;
struct qstr qname = { .name = "", };
void *ns;
ns = ns_ops->get(task);
if (!ns)
return ERR_PTR(-ENOENT);
dentry = d_alloc_pseudo(sb, &qname);
if (!dentry) {
ns_ops->put(ns);
return ERR_PTR(-ENOMEM);
}
inode = iget_locked(sb, ns_ops->inum(ns));
if (!inode) {
dput(dentry);
ns_ops->put(ns);
return ERR_PTR(-ENOMEM);
}
ei = PROC_I(inode);
if (inode->i_state & I_NEW) {
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_op = &ns_inode_operations;
inode->i_mode = S_IFREG | S_IRUGO;
inode->i_fop = &ns_file_operations;
ei->ns.ns_ops = ns_ops;
ei->ns.ns = ns;
unlock_new_inode(inode);
} else {
ns_ops->put(ns);
}
d_set_d_op(dentry, &ns_dentry_operations);
result = d_instantiate_unique(dentry, inode);
if (result) {
dput(dentry);
dentry = result;
}
return dentry;
}
static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd) static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd)
{ {
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
struct super_block *sb = inode->i_sb; const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops;
struct proc_inode *ei = PROC_I(inode);
struct task_struct *task; struct task_struct *task;
struct path ns_path; struct path ns_path;
void *error = ERR_PTR(-EACCES); void *error = ERR_PTR(-EACCES);
task = get_proc_task(inode); task = get_proc_task(inode);
if (!task) if (!task)
goto out; return error;
if (!ptrace_may_access(task, PTRACE_MODE_READ)) if (ptrace_may_access(task, PTRACE_MODE_READ)) {
goto out_put_task; error = ns_get_path(&ns_path, task, ns_ops);
if (!error)
ns_path.dentry = proc_ns_get_dentry(sb, task, ei->ns.ns_ops); nd_jump_link(nd, &ns_path);
if (IS_ERR(ns_path.dentry)) {
error = ERR_CAST(ns_path.dentry);
goto out_put_task;
} }
ns_path.mnt = mntget(nd->path.mnt);
nd_jump_link(nd, &ns_path);
error = NULL;
out_put_task:
put_task_struct(task); put_task_struct(task);
out:
return error; return error;
} }
static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int buflen) static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int buflen)
{ {
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
struct proc_inode *ei = PROC_I(inode); const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops;
const struct proc_ns_operations *ns_ops = ei->ns.ns_ops;
struct task_struct *task; struct task_struct *task;
void *ns;
char name[50]; char name[50];
int res = -EACCES; int res = -EACCES;
task = get_proc_task(inode); task = get_proc_task(inode);
if (!task) if (!task)
goto out; return res;
if (!ptrace_may_access(task, PTRACE_MODE_READ))
goto out_put_task;
res = -ENOENT; if (ptrace_may_access(task, PTRACE_MODE_READ)) {
ns = ns_ops->get(task); res = ns_get_name(name, sizeof(name), task, ns_ops);
if (!ns) if (res >= 0)
goto out_put_task; res = readlink_copy(buffer, buflen, name);
}
snprintf(name, sizeof(name), "%s:[%u]", ns_ops->name, ns_ops->inum(ns));
res = readlink_copy(buffer, buflen, name);
ns_ops->put(ns);
out_put_task:
put_task_struct(task); put_task_struct(task);
out:
return res; return res;
} }
...@@ -189,7 +92,7 @@ static int proc_ns_instantiate(struct inode *dir, ...@@ -189,7 +92,7 @@ static int proc_ns_instantiate(struct inode *dir,
ei = PROC_I(inode); ei = PROC_I(inode);
inode->i_mode = S_IFLNK|S_IRWXUGO; inode->i_mode = S_IFLNK|S_IRWXUGO;
inode->i_op = &proc_ns_link_inode_operations; inode->i_op = &proc_ns_link_inode_operations;
ei->ns.ns_ops = ns_ops; ei->ns_ops = ns_ops;
d_set_d_op(dentry, &pid_dentry_operations); d_set_d_op(dentry, &pid_dentry_operations);
d_add(dentry, inode); d_add(dentry, inode);
...@@ -267,31 +170,3 @@ const struct inode_operations proc_ns_dir_inode_operations = { ...@@ -267,31 +170,3 @@ const struct inode_operations proc_ns_dir_inode_operations = {
.getattr = pid_getattr, .getattr = pid_getattr,
.setattr = proc_setattr, .setattr = proc_setattr,
}; };
struct file *proc_ns_fget(int fd)
{
struct file *file;
file = fget(fd);
if (!file)
return ERR_PTR(-EBADF);
if (file->f_op != &ns_file_operations)
goto out_invalid;
return file;
out_invalid:
fput(file);
return ERR_PTR(-EINVAL);
}
struct proc_ns *get_proc_ns(struct inode *inode)
{
return &PROC_I(inode)->ns;
}
bool proc_ns_inode(struct inode *inode)
{
return inode->i_fop == &ns_file_operations;
}
...@@ -2176,7 +2176,6 @@ static inline int sb_is_blkdev_sb(struct super_block *sb) ...@@ -2176,7 +2176,6 @@ static inline int sb_is_blkdev_sb(struct super_block *sb)
extern int sync_filesystem(struct super_block *); extern int sync_filesystem(struct super_block *);
extern const struct file_operations def_blk_fops; extern const struct file_operations def_blk_fops;
extern const struct file_operations def_chr_fops; extern const struct file_operations def_chr_fops;
extern const struct file_operations bad_sock_fops;
#ifdef CONFIG_BLOCK #ifdef CONFIG_BLOCK
extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long); extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
extern int blkdev_ioctl(struct block_device *, fmode_t, unsigned, unsigned long); extern int blkdev_ioctl(struct block_device *, fmode_t, unsigned, unsigned long);
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/nsproxy.h> #include <linux/nsproxy.h>
#include <linux/ns_common.h>
struct user_namespace; struct user_namespace;
...@@ -58,7 +59,7 @@ struct ipc_namespace { ...@@ -58,7 +59,7 @@ struct ipc_namespace {
/* user_ns which owns the ipc ns */ /* user_ns which owns the ipc ns */
struct user_namespace *user_ns; struct user_namespace *user_ns;
unsigned int proc_inum; struct ns_common ns;
}; };
extern struct ipc_namespace init_ipc_ns; extern struct ipc_namespace init_ipc_ns;
......
...@@ -7,21 +7,10 @@ ...@@ -7,21 +7,10 @@
#include <linux/path.h> #include <linux/path.h>
struct vfsmount; struct vfsmount;
struct nameidata;
enum { MAX_NESTED_LINKS = 8 }; enum { MAX_NESTED_LINKS = 8 };
struct nameidata {
struct path path;
struct qstr last;
struct path root;
struct inode *inode; /* path.dentry.d_inode */
unsigned int flags;
unsigned seq, m_seq;
int last_type;
unsigned depth;
char *saved_names[MAX_NESTED_LINKS + 1];
};
/* /*
* Type of the last component on LOOKUP_PARENT * Type of the last component on LOOKUP_PARENT
*/ */
...@@ -82,16 +71,8 @@ extern struct dentry *lock_rename(struct dentry *, struct dentry *); ...@@ -82,16 +71,8 @@ extern struct dentry *lock_rename(struct dentry *, struct dentry *);
extern void unlock_rename(struct dentry *, struct dentry *); extern void unlock_rename(struct dentry *, struct dentry *);
extern void nd_jump_link(struct nameidata *nd, struct path *path); extern void nd_jump_link(struct nameidata *nd, struct path *path);
extern void nd_set_link(struct nameidata *nd, char *path);
static inline void nd_set_link(struct nameidata *nd, char *path) extern char *nd_get_link(struct nameidata *nd);
{
nd->saved_names[nd->depth] = path;
}
static inline char *nd_get_link(struct nameidata *nd)
{
return nd->saved_names[nd->depth];
}
static inline void nd_terminate_link(void *name, size_t len, size_t maxlen) static inline void nd_terminate_link(void *name, size_t len, size_t maxlen)
{ {
......
#ifndef _LINUX_NS_COMMON_H
#define _LINUX_NS_COMMON_H
struct proc_ns_operations;
struct ns_common {
atomic_long_t stashed;
const struct proc_ns_operations *ops;
unsigned int inum;
};
#endif
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/threads.h> #include <linux/threads.h>
#include <linux/nsproxy.h> #include <linux/nsproxy.h>
#include <linux/kref.h> #include <linux/kref.h>
#include <linux/ns_common.h>
struct pidmap { struct pidmap {
atomic_t nr_free; atomic_t nr_free;
...@@ -43,7 +44,7 @@ struct pid_namespace { ...@@ -43,7 +44,7 @@ struct pid_namespace {
kgid_t pid_gid; kgid_t pid_gid;
int hide_pid; int hide_pid;
int reboot; /* group exit code if this pidns was rebooted */ int reboot; /* group exit code if this pidns was rebooted */
unsigned int proc_inum; struct ns_common ns;
}; };
extern struct pid_namespace init_pid_ns; extern struct pid_namespace init_pid_ns;
......
...@@ -4,21 +4,18 @@ ...@@ -4,21 +4,18 @@
#ifndef _LINUX_PROC_NS_H #ifndef _LINUX_PROC_NS_H
#define _LINUX_PROC_NS_H #define _LINUX_PROC_NS_H
#include <linux/ns_common.h>
struct pid_namespace; struct pid_namespace;
struct nsproxy; struct nsproxy;
struct path;
struct proc_ns_operations { struct proc_ns_operations {
const char *name; const char *name;
int type; int type;
void *(*get)(struct task_struct *task); struct ns_common *(*get)(struct task_struct *task);
void (*put)(void *ns); void (*put)(struct ns_common *ns);
int (*install)(struct nsproxy *nsproxy, void *ns); int (*install)(struct nsproxy *nsproxy, struct ns_common *ns);
unsigned int (*inum)(void *ns);
};
struct proc_ns {
void *ns;
const struct proc_ns_operations *ns_ops;
}; };
extern const struct proc_ns_operations netns_operations; extern const struct proc_ns_operations netns_operations;
...@@ -43,32 +40,38 @@ enum { ...@@ -43,32 +40,38 @@ enum {
extern int pid_ns_prepare_proc(struct pid_namespace *ns); extern int pid_ns_prepare_proc(struct pid_namespace *ns);
extern void pid_ns_release_proc(struct pid_namespace *ns); extern void pid_ns_release_proc(struct pid_namespace *ns);
extern struct file *proc_ns_fget(int fd);
extern struct proc_ns *get_proc_ns(struct inode *);
extern int proc_alloc_inum(unsigned int *pino); extern int proc_alloc_inum(unsigned int *pino);
extern void proc_free_inum(unsigned int inum); extern void proc_free_inum(unsigned int inum);
extern bool proc_ns_inode(struct inode *inode);
#else /* CONFIG_PROC_FS */ #else /* CONFIG_PROC_FS */
static inline int pid_ns_prepare_proc(struct pid_namespace *ns) { return 0; } static inline int pid_ns_prepare_proc(struct pid_namespace *ns) { return 0; }
static inline void pid_ns_release_proc(struct pid_namespace *ns) {} static inline void pid_ns_release_proc(struct pid_namespace *ns) {}
static inline struct file *proc_ns_fget(int fd)
{
return ERR_PTR(-EINVAL);
}
static inline struct proc_ns *get_proc_ns(struct inode *inode) { return NULL; }
static inline int proc_alloc_inum(unsigned int *inum) static inline int proc_alloc_inum(unsigned int *inum)
{ {
*inum = 1; *inum = 1;
return 0; return 0;
} }
static inline void proc_free_inum(unsigned int inum) {} static inline void proc_free_inum(unsigned int inum) {}
static inline bool proc_ns_inode(struct inode *inode) { return false; }
#endif /* CONFIG_PROC_FS */ #endif /* CONFIG_PROC_FS */
static inline int ns_alloc_inum(struct ns_common *ns)
{
atomic_long_set(&ns->stashed, 0);
return proc_alloc_inum(&ns->inum);
}
#define ns_free_inum(ns) proc_free_inum((ns)->inum)
extern struct file *proc_ns_fget(int fd);
#define get_proc_ns(inode) ((struct ns_common *)(inode)->i_private)
extern void *ns_get_path(struct path *path, struct task_struct *task,
const struct proc_ns_operations *ns_ops);
extern int ns_get_name(char *buf, size_t size, struct task_struct *task,
const struct proc_ns_operations *ns_ops);
extern void nsfs_init(void);
#endif /* _LINUX_PROC_NS_H */ #endif /* _LINUX_PROC_NS_H */
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <linux/kref.h> #include <linux/kref.h>
#include <linux/nsproxy.h> #include <linux/nsproxy.h>
#include <linux/ns_common.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/err.h> #include <linux/err.h>
...@@ -26,7 +27,7 @@ struct user_namespace { ...@@ -26,7 +27,7 @@ struct user_namespace {
int level; int level;
kuid_t owner; kuid_t owner;
kgid_t group; kgid_t group;
unsigned int proc_inum; struct ns_common ns;
/* Register of per-UID persistent keyrings for this namespace */ /* Register of per-UID persistent keyrings for this namespace */
#ifdef CONFIG_PERSISTENT_KEYRINGS #ifdef CONFIG_PERSISTENT_KEYRINGS
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/kref.h> #include <linux/kref.h>
#include <linux/nsproxy.h> #include <linux/nsproxy.h>
#include <linux/ns_common.h>
#include <linux/err.h> #include <linux/err.h>
#include <uapi/linux/utsname.h> #include <uapi/linux/utsname.h>
...@@ -23,7 +24,7 @@ struct uts_namespace { ...@@ -23,7 +24,7 @@ struct uts_namespace {
struct kref kref; struct kref kref;
struct new_utsname name; struct new_utsname name;
struct user_namespace *user_ns; struct user_namespace *user_ns;
unsigned int proc_inum; struct ns_common ns;
}; };
extern struct uts_namespace init_uts_ns; extern struct uts_namespace init_uts_ns;
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#endif #endif
#include <net/netns/nftables.h> #include <net/netns/nftables.h>
#include <net/netns/xfrm.h> #include <net/netns/xfrm.h>
#include <linux/ns_common.h>
struct user_namespace; struct user_namespace;
struct proc_dir_entry; struct proc_dir_entry;
...@@ -60,7 +61,7 @@ struct net { ...@@ -60,7 +61,7 @@ struct net {
struct user_namespace *user_ns; /* Owning user namespace */ struct user_namespace *user_ns; /* Owning user namespace */
unsigned int proc_inum; struct ns_common ns;
struct proc_dir_entry *proc_net; struct proc_dir_entry *proc_net;
struct proc_dir_entry *proc_net_stat; struct proc_dir_entry *proc_net_stat;
......
...@@ -72,5 +72,6 @@ ...@@ -72,5 +72,6 @@
#define MTD_INODE_FS_MAGIC 0x11307854 #define MTD_INODE_FS_MAGIC 0x11307854
#define ANON_INODE_FS_MAGIC 0x09041934 #define ANON_INODE_FS_MAGIC 0x09041934
#define BTRFS_TEST_MAGIC 0x73727279 #define BTRFS_TEST_MAGIC 0x73727279
#define NSFS_MAGIC 0x6e736673
#endif /* __LINUX_MAGIC_H__ */ #endif /* __LINUX_MAGIC_H__ */
...@@ -79,6 +79,7 @@ ...@@ -79,6 +79,7 @@
#include <linux/random.h> #include <linux/random.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/integrity.h> #include <linux/integrity.h>
#include <linux/proc_ns.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/bugs.h> #include <asm/bugs.h>
...@@ -665,6 +666,7 @@ asmlinkage __visible void __init start_kernel(void) ...@@ -665,6 +666,7 @@ asmlinkage __visible void __init start_kernel(void)
/* rootfs populating might need page-writeback */ /* rootfs populating might need page-writeback */
page_writeback_init(); page_writeback_init();
proc_root_init(); proc_root_init();
nsfs_init();
cgroup_init(); cgroup_init();
cpuset_init(); cpuset_init();
taskstats_init_early(); taskstats_init_early();
......
...@@ -35,7 +35,10 @@ struct uts_namespace init_uts_ns = { ...@@ -35,7 +35,10 @@ struct uts_namespace init_uts_ns = {
.domainname = UTS_DOMAINNAME, .domainname = UTS_DOMAINNAME,
}, },
.user_ns = &init_user_ns, .user_ns = &init_user_ns,
.proc_inum = PROC_UTS_INIT_INO, .ns.inum = PROC_UTS_INIT_INO,
#ifdef CONFIG_UTS_NS
.ns.ops = &utsns_operations,
#endif
}; };
EXPORT_SYMBOL_GPL(init_uts_ns); EXPORT_SYMBOL_GPL(init_uts_ns);
......
...@@ -31,7 +31,10 @@ DEFINE_SPINLOCK(mq_lock); ...@@ -31,7 +31,10 @@ DEFINE_SPINLOCK(mq_lock);
struct ipc_namespace init_ipc_ns = { struct ipc_namespace init_ipc_ns = {
.count = ATOMIC_INIT(1), .count = ATOMIC_INIT(1),
.user_ns = &init_user_ns, .user_ns = &init_user_ns,
.proc_inum = PROC_IPC_INIT_INO, .ns.inum = PROC_IPC_INIT_INO,
#ifdef CONFIG_IPC_NS
.ns.ops = &ipcns_operations,
#endif
}; };
atomic_t nr_ipc_ns = ATOMIC_INIT(1); atomic_t nr_ipc_ns = ATOMIC_INIT(1);
......
...@@ -26,16 +26,17 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns, ...@@ -26,16 +26,17 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
if (ns == NULL) if (ns == NULL)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
err = proc_alloc_inum(&ns->proc_inum); err = ns_alloc_inum(&ns->ns);
if (err) { if (err) {
kfree(ns); kfree(ns);
return ERR_PTR(err); return ERR_PTR(err);
} }
ns->ns.ops = &ipcns_operations;
atomic_set(&ns->count, 1); atomic_set(&ns->count, 1);
err = mq_init_ns(ns); err = mq_init_ns(ns);
if (err) { if (err) {
proc_free_inum(ns->proc_inum); ns_free_inum(&ns->ns);
kfree(ns); kfree(ns);
return ERR_PTR(err); return ERR_PTR(err);
} }
...@@ -97,7 +98,7 @@ static void free_ipc_ns(struct ipc_namespace *ns) ...@@ -97,7 +98,7 @@ static void free_ipc_ns(struct ipc_namespace *ns)
atomic_dec(&nr_ipc_ns); atomic_dec(&nr_ipc_ns);
put_user_ns(ns->user_ns); put_user_ns(ns->user_ns);
proc_free_inum(ns->proc_inum); ns_free_inum(&ns->ns);
kfree(ns); kfree(ns);
} }
...@@ -127,7 +128,12 @@ void put_ipc_ns(struct ipc_namespace *ns) ...@@ -127,7 +128,12 @@ void put_ipc_ns(struct ipc_namespace *ns)
} }
} }
static void *ipcns_get(struct task_struct *task) static inline struct ipc_namespace *to_ipc_ns(struct ns_common *ns)
{
return container_of(ns, struct ipc_namespace, ns);
}
static struct ns_common *ipcns_get(struct task_struct *task)
{ {
struct ipc_namespace *ns = NULL; struct ipc_namespace *ns = NULL;
struct nsproxy *nsproxy; struct nsproxy *nsproxy;
...@@ -138,17 +144,17 @@ static void *ipcns_get(struct task_struct *task) ...@@ -138,17 +144,17 @@ static void *ipcns_get(struct task_struct *task)
ns = get_ipc_ns(nsproxy->ipc_ns); ns = get_ipc_ns(nsproxy->ipc_ns);
task_unlock(task); task_unlock(task);
return ns; return ns ? &ns->ns : NULL;
} }
static void ipcns_put(void *ns) static void ipcns_put(struct ns_common *ns)
{ {
return put_ipc_ns(ns); return put_ipc_ns(to_ipc_ns(ns));
} }
static int ipcns_install(struct nsproxy *nsproxy, void *new) static int ipcns_install(struct nsproxy *nsproxy, struct ns_common *new)
{ {
struct ipc_namespace *ns = new; struct ipc_namespace *ns = to_ipc_ns(new);
if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) || if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) ||
!ns_capable(current_user_ns(), CAP_SYS_ADMIN)) !ns_capable(current_user_ns(), CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
...@@ -160,18 +166,10 @@ static int ipcns_install(struct nsproxy *nsproxy, void *new) ...@@ -160,18 +166,10 @@ static int ipcns_install(struct nsproxy *nsproxy, void *new)
return 0; return 0;
} }
static unsigned int ipcns_inum(void *vp)
{
struct ipc_namespace *ns = vp;
return ns->proc_inum;
}
const struct proc_ns_operations ipcns_operations = { const struct proc_ns_operations ipcns_operations = {
.name = "ipc", .name = "ipc",
.type = CLONE_NEWIPC, .type = CLONE_NEWIPC,
.get = ipcns_get, .get = ipcns_get,
.put = ipcns_put, .put = ipcns_put,
.install = ipcns_install, .install = ipcns_install,
.inum = ipcns_inum,
}; };
...@@ -220,11 +220,10 @@ void exit_task_namespaces(struct task_struct *p) ...@@ -220,11 +220,10 @@ void exit_task_namespaces(struct task_struct *p)
SYSCALL_DEFINE2(setns, int, fd, int, nstype) SYSCALL_DEFINE2(setns, int, fd, int, nstype)
{ {
const struct proc_ns_operations *ops;
struct task_struct *tsk = current; struct task_struct *tsk = current;
struct nsproxy *new_nsproxy; struct nsproxy *new_nsproxy;
struct proc_ns *ei;
struct file *file; struct file *file;
struct ns_common *ns;
int err; int err;
file = proc_ns_fget(fd); file = proc_ns_fget(fd);
...@@ -232,9 +231,8 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype) ...@@ -232,9 +231,8 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype)
return PTR_ERR(file); return PTR_ERR(file);
err = -EINVAL; err = -EINVAL;
ei = get_proc_ns(file_inode(file)); ns = get_proc_ns(file_inode(file));
ops = ei->ns_ops; if (nstype && (ns->ops->type != nstype))
if (nstype && (ops->type != nstype))
goto out; goto out;
new_nsproxy = create_new_namespaces(0, tsk, current_user_ns(), tsk->fs); new_nsproxy = create_new_namespaces(0, tsk, current_user_ns(), tsk->fs);
...@@ -243,7 +241,7 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype) ...@@ -243,7 +241,7 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype)
goto out; goto out;
} }
err = ops->install(new_nsproxy, ei->ns); err = ns->ops->install(new_nsproxy, ns);
if (err) { if (err) {
free_nsproxy(new_nsproxy); free_nsproxy(new_nsproxy);
goto out; goto out;
......
...@@ -79,7 +79,10 @@ struct pid_namespace init_pid_ns = { ...@@ -79,7 +79,10 @@ struct pid_namespace init_pid_ns = {
.level = 0, .level = 0,
.child_reaper = &init_task, .child_reaper = &init_task,
.user_ns = &init_user_ns, .user_ns = &init_user_ns,
.proc_inum = PROC_PID_INIT_INO, .ns.inum = PROC_PID_INIT_INO,
#ifdef CONFIG_PID_NS
.ns.ops = &pidns_operations,
#endif
}; };
EXPORT_SYMBOL_GPL(init_pid_ns); EXPORT_SYMBOL_GPL(init_pid_ns);
......
...@@ -105,9 +105,10 @@ static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns ...@@ -105,9 +105,10 @@ static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns
if (ns->pid_cachep == NULL) if (ns->pid_cachep == NULL)
goto out_free_map; goto out_free_map;
err = proc_alloc_inum(&ns->proc_inum); err = ns_alloc_inum(&ns->ns);
if (err) if (err)
goto out_free_map; goto out_free_map;
ns->ns.ops = &pidns_operations;
kref_init(&ns->kref); kref_init(&ns->kref);
ns->level = level; ns->level = level;
...@@ -142,7 +143,7 @@ static void destroy_pid_namespace(struct pid_namespace *ns) ...@@ -142,7 +143,7 @@ static void destroy_pid_namespace(struct pid_namespace *ns)
{ {
int i; int i;
proc_free_inum(ns->proc_inum); ns_free_inum(&ns->ns);
for (i = 0; i < PIDMAP_ENTRIES; i++) for (i = 0; i < PIDMAP_ENTRIES; i++)
kfree(ns->pidmap[i].page); kfree(ns->pidmap[i].page);
put_user_ns(ns->user_ns); put_user_ns(ns->user_ns);
...@@ -333,7 +334,12 @@ int reboot_pid_ns(struct pid_namespace *pid_ns, int cmd) ...@@ -333,7 +334,12 @@ int reboot_pid_ns(struct pid_namespace *pid_ns, int cmd)
return 0; return 0;
} }
static void *pidns_get(struct task_struct *task) static inline struct pid_namespace *to_pid_ns(struct ns_common *ns)
{
return container_of(ns, struct pid_namespace, ns);
}
static struct ns_common *pidns_get(struct task_struct *task)
{ {
struct pid_namespace *ns; struct pid_namespace *ns;
...@@ -343,18 +349,18 @@ static void *pidns_get(struct task_struct *task) ...@@ -343,18 +349,18 @@ static void *pidns_get(struct task_struct *task)
get_pid_ns(ns); get_pid_ns(ns);
rcu_read_unlock(); rcu_read_unlock();
return ns; return ns ? &ns->ns : NULL;
} }
static void pidns_put(void *ns) static void pidns_put(struct ns_common *ns)
{ {
put_pid_ns(ns); put_pid_ns(to_pid_ns(ns));
} }
static int pidns_install(struct nsproxy *nsproxy, void *ns) static int pidns_install(struct nsproxy *nsproxy, struct ns_common *ns)
{ {
struct pid_namespace *active = task_active_pid_ns(current); struct pid_namespace *active = task_active_pid_ns(current);
struct pid_namespace *ancestor, *new = ns; struct pid_namespace *ancestor, *new = to_pid_ns(ns);
if (!ns_capable(new->user_ns, CAP_SYS_ADMIN) || if (!ns_capable(new->user_ns, CAP_SYS_ADMIN) ||
!ns_capable(current_user_ns(), CAP_SYS_ADMIN)) !ns_capable(current_user_ns(), CAP_SYS_ADMIN))
...@@ -382,19 +388,12 @@ static int pidns_install(struct nsproxy *nsproxy, void *ns) ...@@ -382,19 +388,12 @@ static int pidns_install(struct nsproxy *nsproxy, void *ns)
return 0; return 0;
} }
static unsigned int pidns_inum(void *ns)
{
struct pid_namespace *pid_ns = ns;
return pid_ns->proc_inum;
}
const struct proc_ns_operations pidns_operations = { const struct proc_ns_operations pidns_operations = {
.name = "pid", .name = "pid",
.type = CLONE_NEWPID, .type = CLONE_NEWPID,
.get = pidns_get, .get = pidns_get,
.put = pidns_put, .put = pidns_put,
.install = pidns_install, .install = pidns_install,
.inum = pidns_inum,
}; };
static __init int pid_namespaces_init(void) static __init int pid_namespaces_init(void)
......
...@@ -50,7 +50,10 @@ struct user_namespace init_user_ns = { ...@@ -50,7 +50,10 @@ struct user_namespace init_user_ns = {
.count = ATOMIC_INIT(3), .count = ATOMIC_INIT(3),
.owner = GLOBAL_ROOT_UID, .owner = GLOBAL_ROOT_UID,
.group = GLOBAL_ROOT_GID, .group = GLOBAL_ROOT_GID,
.proc_inum = PROC_USER_INIT_INO, .ns.inum = PROC_USER_INIT_INO,
#ifdef CONFIG_USER_NS
.ns.ops = &userns_operations,
#endif
#ifdef CONFIG_PERSISTENT_KEYRINGS #ifdef CONFIG_PERSISTENT_KEYRINGS
.persistent_keyring_register_sem = .persistent_keyring_register_sem =
__RWSEM_INITIALIZER(init_user_ns.persistent_keyring_register_sem), __RWSEM_INITIALIZER(init_user_ns.persistent_keyring_register_sem),
......
...@@ -86,11 +86,12 @@ int create_user_ns(struct cred *new) ...@@ -86,11 +86,12 @@ int create_user_ns(struct cred *new)
if (!ns) if (!ns)
return -ENOMEM; return -ENOMEM;
ret = proc_alloc_inum(&ns->proc_inum); ret = ns_alloc_inum(&ns->ns);
if (ret) { if (ret) {
kmem_cache_free(user_ns_cachep, ns); kmem_cache_free(user_ns_cachep, ns);
return ret; return ret;
} }
ns->ns.ops = &userns_operations;
atomic_set(&ns->count, 1); atomic_set(&ns->count, 1);
/* Leave the new->user_ns reference with the new user namespace. */ /* Leave the new->user_ns reference with the new user namespace. */
...@@ -136,7 +137,7 @@ void free_user_ns(struct user_namespace *ns) ...@@ -136,7 +137,7 @@ void free_user_ns(struct user_namespace *ns)
#ifdef CONFIG_PERSISTENT_KEYRINGS #ifdef CONFIG_PERSISTENT_KEYRINGS
key_put(ns->persistent_keyring_register); key_put(ns->persistent_keyring_register);
#endif #endif
proc_free_inum(ns->proc_inum); ns_free_inum(&ns->ns);
kmem_cache_free(user_ns_cachep, ns); kmem_cache_free(user_ns_cachep, ns);
ns = parent; ns = parent;
} while (atomic_dec_and_test(&parent->count)); } while (atomic_dec_and_test(&parent->count));
...@@ -841,7 +842,12 @@ static bool new_idmap_permitted(const struct file *file, ...@@ -841,7 +842,12 @@ static bool new_idmap_permitted(const struct file *file,
return false; return false;
} }
static void *userns_get(struct task_struct *task) static inline struct user_namespace *to_user_ns(struct ns_common *ns)
{
return container_of(ns, struct user_namespace, ns);
}
static struct ns_common *userns_get(struct task_struct *task)
{ {
struct user_namespace *user_ns; struct user_namespace *user_ns;
...@@ -849,17 +855,17 @@ static void *userns_get(struct task_struct *task) ...@@ -849,17 +855,17 @@ static void *userns_get(struct task_struct *task)
user_ns = get_user_ns(__task_cred(task)->user_ns); user_ns = get_user_ns(__task_cred(task)->user_ns);
rcu_read_unlock(); rcu_read_unlock();
return user_ns; return user_ns ? &user_ns->ns : NULL;
} }
static void userns_put(void *ns) static void userns_put(struct ns_common *ns)
{ {
put_user_ns(ns); put_user_ns(to_user_ns(ns));
} }
static int userns_install(struct nsproxy *nsproxy, void *ns) static int userns_install(struct nsproxy *nsproxy, struct ns_common *ns)
{ {
struct user_namespace *user_ns = ns; struct user_namespace *user_ns = to_user_ns(ns);
struct cred *cred; struct cred *cred;
/* Don't allow gaining capabilities by reentering /* Don't allow gaining capabilities by reentering
...@@ -888,19 +894,12 @@ static int userns_install(struct nsproxy *nsproxy, void *ns) ...@@ -888,19 +894,12 @@ static int userns_install(struct nsproxy *nsproxy, void *ns)
return commit_creds(cred); return commit_creds(cred);
} }
static unsigned int userns_inum(void *ns)
{
struct user_namespace *user_ns = ns;
return user_ns->proc_inum;
}
const struct proc_ns_operations userns_operations = { const struct proc_ns_operations userns_operations = {
.name = "user", .name = "user",
.type = CLONE_NEWUSER, .type = CLONE_NEWUSER,
.get = userns_get, .get = userns_get,
.put = userns_put, .put = userns_put,
.install = userns_install, .install = userns_install,
.inum = userns_inum,
}; };
static __init int user_namespaces_init(void) static __init int user_namespaces_init(void)
......
...@@ -42,12 +42,14 @@ static struct uts_namespace *clone_uts_ns(struct user_namespace *user_ns, ...@@ -42,12 +42,14 @@ static struct uts_namespace *clone_uts_ns(struct user_namespace *user_ns,
if (!ns) if (!ns)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
err = proc_alloc_inum(&ns->proc_inum); err = ns_alloc_inum(&ns->ns);
if (err) { if (err) {
kfree(ns); kfree(ns);
return ERR_PTR(err); return ERR_PTR(err);
} }
ns->ns.ops = &utsns_operations;
down_read(&uts_sem); down_read(&uts_sem);
memcpy(&ns->name, &old_ns->name, sizeof(ns->name)); memcpy(&ns->name, &old_ns->name, sizeof(ns->name));
ns->user_ns = get_user_ns(user_ns); ns->user_ns = get_user_ns(user_ns);
...@@ -84,11 +86,16 @@ void free_uts_ns(struct kref *kref) ...@@ -84,11 +86,16 @@ void free_uts_ns(struct kref *kref)
ns = container_of(kref, struct uts_namespace, kref); ns = container_of(kref, struct uts_namespace, kref);
put_user_ns(ns->user_ns); put_user_ns(ns->user_ns);
proc_free_inum(ns->proc_inum); ns_free_inum(&ns->ns);
kfree(ns); kfree(ns);
} }
static void *utsns_get(struct task_struct *task) static inline struct uts_namespace *to_uts_ns(struct ns_common *ns)
{
return container_of(ns, struct uts_namespace, ns);
}
static struct ns_common *utsns_get(struct task_struct *task)
{ {
struct uts_namespace *ns = NULL; struct uts_namespace *ns = NULL;
struct nsproxy *nsproxy; struct nsproxy *nsproxy;
...@@ -101,17 +108,17 @@ static void *utsns_get(struct task_struct *task) ...@@ -101,17 +108,17 @@ static void *utsns_get(struct task_struct *task)
} }
task_unlock(task); task_unlock(task);
return ns; return ns ? &ns->ns : NULL;
} }
static void utsns_put(void *ns) static void utsns_put(struct ns_common *ns)
{ {
put_uts_ns(ns); put_uts_ns(to_uts_ns(ns));
} }
static int utsns_install(struct nsproxy *nsproxy, void *new) static int utsns_install(struct nsproxy *nsproxy, struct ns_common *new)
{ {
struct uts_namespace *ns = new; struct uts_namespace *ns = to_uts_ns(new);
if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) || if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) ||
!ns_capable(current_user_ns(), CAP_SYS_ADMIN)) !ns_capable(current_user_ns(), CAP_SYS_ADMIN))
...@@ -123,18 +130,10 @@ static int utsns_install(struct nsproxy *nsproxy, void *new) ...@@ -123,18 +130,10 @@ static int utsns_install(struct nsproxy *nsproxy, void *new)
return 0; return 0;
} }
static unsigned int utsns_inum(void *vp)
{
struct uts_namespace *ns = vp;
return ns->proc_inum;
}
const struct proc_ns_operations utsns_operations = { const struct proc_ns_operations utsns_operations = {
.name = "uts", .name = "uts",
.type = CLONE_NEWUTS, .type = CLONE_NEWUTS,
.get = utsns_get, .get = utsns_get,
.put = utsns_put, .put = utsns_put,
.install = utsns_install, .install = utsns_install,
.inum = utsns_inum,
}; };
...@@ -5,8 +5,6 @@ ...@@ -5,8 +5,6 @@
# Rewritten to use lists instead of if-statements. # Rewritten to use lists instead of if-statements.
# #
obj-y := nonet.o
obj-$(CONFIG_NET) := socket.o core/ obj-$(CONFIG_NET) := socket.o core/
tmp-$(CONFIG_COMPAT) := compat.o tmp-$(CONFIG_COMPAT) := compat.o
......
...@@ -337,17 +337,17 @@ EXPORT_SYMBOL_GPL(__put_net); ...@@ -337,17 +337,17 @@ EXPORT_SYMBOL_GPL(__put_net);
struct net *get_net_ns_by_fd(int fd) struct net *get_net_ns_by_fd(int fd)
{ {
struct proc_ns *ei;
struct file *file; struct file *file;
struct ns_common *ns;
struct net *net; struct net *net;
file = proc_ns_fget(fd); file = proc_ns_fget(fd);
if (IS_ERR(file)) if (IS_ERR(file))
return ERR_CAST(file); return ERR_CAST(file);
ei = get_proc_ns(file_inode(file)); ns = get_proc_ns(file_inode(file));
if (ei->ns_ops == &netns_operations) if (ns->ops == &netns_operations)
net = get_net(ei->ns); net = get_net(container_of(ns, struct net, ns));
else else
net = ERR_PTR(-EINVAL); net = ERR_PTR(-EINVAL);
...@@ -386,12 +386,15 @@ EXPORT_SYMBOL_GPL(get_net_ns_by_pid); ...@@ -386,12 +386,15 @@ EXPORT_SYMBOL_GPL(get_net_ns_by_pid);
static __net_init int net_ns_net_init(struct net *net) static __net_init int net_ns_net_init(struct net *net)
{ {
return proc_alloc_inum(&net->proc_inum); #ifdef CONFIG_NET_NS
net->ns.ops = &netns_operations;
#endif
return ns_alloc_inum(&net->ns);
} }
static __net_exit void net_ns_net_exit(struct net *net) static __net_exit void net_ns_net_exit(struct net *net)
{ {
proc_free_inum(net->proc_inum); ns_free_inum(&net->ns);
} }
static struct pernet_operations __net_initdata net_ns_ops = { static struct pernet_operations __net_initdata net_ns_ops = {
...@@ -629,7 +632,7 @@ void unregister_pernet_device(struct pernet_operations *ops) ...@@ -629,7 +632,7 @@ void unregister_pernet_device(struct pernet_operations *ops)
EXPORT_SYMBOL_GPL(unregister_pernet_device); EXPORT_SYMBOL_GPL(unregister_pernet_device);
#ifdef CONFIG_NET_NS #ifdef CONFIG_NET_NS
static void *netns_get(struct task_struct *task) static struct ns_common *netns_get(struct task_struct *task)
{ {
struct net *net = NULL; struct net *net = NULL;
struct nsproxy *nsproxy; struct nsproxy *nsproxy;
...@@ -640,17 +643,22 @@ static void *netns_get(struct task_struct *task) ...@@ -640,17 +643,22 @@ static void *netns_get(struct task_struct *task)
net = get_net(nsproxy->net_ns); net = get_net(nsproxy->net_ns);
task_unlock(task); task_unlock(task);
return net; return net ? &net->ns : NULL;
} }
static void netns_put(void *ns) static inline struct net *to_net_ns(struct ns_common *ns)
{ {
put_net(ns); return container_of(ns, struct net, ns);
} }
static int netns_install(struct nsproxy *nsproxy, void *ns) static void netns_put(struct ns_common *ns)
{ {
struct net *net = ns; put_net(to_net_ns(ns));
}
static int netns_install(struct nsproxy *nsproxy, struct ns_common *ns)
{
struct net *net = to_net_ns(ns);
if (!ns_capable(net->user_ns, CAP_SYS_ADMIN) || if (!ns_capable(net->user_ns, CAP_SYS_ADMIN) ||
!ns_capable(current_user_ns(), CAP_SYS_ADMIN)) !ns_capable(current_user_ns(), CAP_SYS_ADMIN))
...@@ -661,18 +669,11 @@ static int netns_install(struct nsproxy *nsproxy, void *ns) ...@@ -661,18 +669,11 @@ static int netns_install(struct nsproxy *nsproxy, void *ns)
return 0; return 0;
} }
static unsigned int netns_inum(void *ns)
{
struct net *net = ns;
return net->proc_inum;
}
const struct proc_ns_operations netns_operations = { const struct proc_ns_operations netns_operations = {
.name = "net", .name = "net",
.type = CLONE_NEWNET, .type = CLONE_NEWNET,
.get = netns_get, .get = netns_get,
.put = netns_put, .put = netns_put,
.install = netns_install, .install = netns_install,
.inum = netns_inum,
}; };
#endif #endif
/*
* net/nonet.c
*
* Dummy functions to allow us to configure network support entirely
* out of the kernel.
*
* Distributed under the terms of the GNU GPL version 2.
* Copyright (c) Matthew Wilcox 2003
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
static int sock_no_open(struct inode *irrelevant, struct file *dontcare)
{
return -ENXIO;
}
const struct file_operations bad_sock_fops = {
.owner = THIS_MODULE,
.open = sock_no_open,
.llseek = noop_llseek,
};
...@@ -113,7 +113,6 @@ unsigned int sysctl_net_busy_read __read_mostly; ...@@ -113,7 +113,6 @@ unsigned int sysctl_net_busy_read __read_mostly;
unsigned int sysctl_net_busy_poll __read_mostly; unsigned int sysctl_net_busy_poll __read_mostly;
#endif #endif
static int sock_no_open(struct inode *irrelevant, struct file *dontcare);
static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos); unsigned long nr_segs, loff_t pos);
static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov,
...@@ -151,7 +150,6 @@ static const struct file_operations socket_file_ops = { ...@@ -151,7 +150,6 @@ static const struct file_operations socket_file_ops = {
.compat_ioctl = compat_sock_ioctl, .compat_ioctl = compat_sock_ioctl,
#endif #endif
.mmap = sock_mmap, .mmap = sock_mmap,
.open = sock_no_open, /* special open code to disallow open via /proc */
.release = sock_close, .release = sock_close,
.fasync = sock_fasync, .fasync = sock_fasync,
.sendpage = sock_sendpage, .sendpage = sock_sendpage,
...@@ -559,23 +557,6 @@ static struct socket *sock_alloc(void) ...@@ -559,23 +557,6 @@ static struct socket *sock_alloc(void)
return sock; return sock;
} }
/*
* In theory you can't get an open on this inode, but /proc provides
* a back door. Remember to keep it shut otherwise you'll let the
* creepy crawlies in.
*/
static int sock_no_open(struct inode *irrelevant, struct file *dontcare)
{
return -ENXIO;
}
const struct file_operations bad_sock_fops = {
.owner = THIS_MODULE,
.open = sock_no_open,
.llseek = noop_llseek,
};
/** /**
* sock_release - close a socket * sock_release - close a socket
* @sock: socket to close * @sock: socket to close
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment