Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/ebiederm/user-namespace

Pull namespace updates from Eric Biederman:
 "This set of changes is a number of smaller things that have been
  overlooked in other development cycles focused on more fundamental
  change. The devpts changes are small things that were a distraction
  until we managed to kill off DEVPTS_MULTPLE_INSTANCES. There is an
  trivial regression fix to autofs for the unprivileged mount changes
  that went in last cycle. A pair of ioctls has been added by Andrey
  Vagin making it is possible to discover the relationships between
  namespaces when referring to them through file descriptors.

  The big user visible change is starting to add simple resource limits
  to catch programs that misbehave. With namespaces in general and user
  namespaces in particular allowing users to use more kinds of
  resources, it has become important to have something to limit errant
  programs. Because the purpose of these limits is to catch errant
  programs the code needs to be inexpensive to use as it always on, and
  the default limits need to be high enough that well behaved programs
  on well behaved systems don't encounter them.

  To this end, after some review I have implemented per user per user
  namespace limits, and use them to limit the number of namespaces. The
  limits being per user mean that one user can not exhause the limits of
  another user. The limits being per user namespace allow contexts where
  the limit is 0 and security conscious folks can remove from their
  threat anlysis the code used to manage namespaces (as they have
  historically done as it root only). At the same time the limits being
  per user namespace allow other parts of the system to use namespaces.

  Namespaces are increasingly being used in application sand boxing
  scenarios so an all or nothing disable for the entire system for the
  security conscious folks makes increasing use of these sandboxes
  impossible.

  There is also added a limit on the maximum number of mounts present in
  a single mount namespace. It is nontrivial to guess what a reasonable
  system wide limit on the number of mount structure in the kernel would
  be, especially as it various based on how a system is using
  containers. A limit on the number of mounts in a mount namespace
  however is much easier to understand and set. In most cases in
  practice only about 1000 mounts are used. Given that some autofs
  scenarious have the potential to be 30,000 to 50,000 mounts I have set
  the default limit for the number of mounts at 100,000 which is well
  above every known set of users but low enough that the mount hash
  tables don't degrade unreaonsably.

  These limits are a start. I expect this estabilishes a pattern that
  other limits for resources that namespaces use will follow. There has
  been interest in making inotify event limits per user per user
  namespace as well as interest expressed in making details about what
  is going on in the kernel more visible"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: (28 commits)
  autofs:  Fix automounts by using current_real_cred()->uid
  mnt: Add a per mount namespace limit on the number of mounts
  netns: move {inc,dec}_net_namespaces into #ifdef
  nsfs: Simplify __ns_get_path
  tools/testing: add a test to check nsfs ioctl-s
  nsfs: add ioctl to get a parent namespace
  nsfs: add ioctl to get an owning user namespace for ns file descriptor
  kernel: add a helper to get an owning user namespace for a namespace
  devpts: Change the owner of /dev/pts/ptmx to the mounter of /dev/pts
  devpts: Remove sync_filesystems
  devpts: Make devpts_kill_sb safe if fsi is NULL
  devpts: Simplify devpts_mount by using mount_nodev
  devpts: Move the creation of /dev/pts/ptmx into fill_super
  devpts: Move parse_mount_options into fill_super
  userns: When the per user per user namespace limit is reached return ENOSPC
  userns; Document per user per user namespace limits.
  mntns: Add a limit on the number of mount namespaces.
  netns: Add a limit on the number of net namespaces
  cgroupns: Add a limit on the number of cgroup namespaces
  ipcns: Add a  limit on the number of ipc namespaces
  ...
  • Loading branch information
torvalds committed Oct 6, 2016
2 parents 8d37059 + 069d5ac commit 14986a3
Show file tree
Hide file tree
Showing 35 changed files with 1,007 additions and 71 deletions.
1 change: 1 addition & 0 deletions Documentation/sysctl/README
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ proc/ <empty>
sunrpc/ SUN Remote Procedure Call (NFS)
vm/ memory management tuning
buffer and cache management
user/ Per user per user namespace limits

These are the subdirs I have on my system. There might be more
or other subdirs in another setup. If you see another dir, I'd
Expand Down
7 changes: 7 additions & 0 deletions Documentation/sysctl/fs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,13 @@ aio-nr can grow to.

==============================================================

mount-max:

This denotes the maximum number of mounts that may exist
in a mount namespace.

==============================================================


2. /proc/sys/fs/binfmt_misc
----------------------------------------------------------
Expand Down
66 changes: 66 additions & 0 deletions Documentation/sysctl/user.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
Documentation for /proc/sys/user/* kernel version 4.9.0
(c) 2016 Eric Biederman <ebiederm@xmission.com>

==============================================================

This file contains the documetation for the sysctl files in
/proc/sys/user.

The files in this directory can be used to override the default
limits on the number of namespaces and other objects that have
per user per user namespace limits.

The primary purpose of these limits is to stop programs that
malfunction and attempt to create a ridiculous number of objects,
before the malfunction becomes a system wide problem. It is the
intention that the defaults of these limits are set high enough that
no program in normal operation should run into these limits.

The creation of per user per user namespace objects are charged to
the user in the user namespace who created the object and
verified to be below the per user limit in that user namespace.

The creation of objects is also charged to all of the users
who created user namespaces the creation of the object happens
in (user namespaces can be nested) and verified to be below the per user
limits in the user namespaces of those users.

This recursive counting of created objects ensures that creating a
user namespace does not allow a user to escape their current limits.

Currently, these files are in /proc/sys/user:

- max_cgroup_namespaces

The maximum number of cgroup namespaces that any user in the current
user namespace may create.

- max_ipc_namespaces

The maximum number of ipc namespaces that any user in the current
user namespace may create.

- max_mnt_namespaces

The maximum number of mount namespaces that any user in the current
user namespace may create.

- max_net_namespaces

The maximum number of network namespaces that any user in the
current user namespace may create.

- max_pid_namespaces

The maximum number of pid namespaces that any user in the current
user namespace may create.

- max_user_namespaces

The maximum number of user namespaces that any user in the current
user namespace may create.

- max_uts_namespaces

The maximum number of user namespaces that any user in the current
user namespace may create.
4 changes: 2 additions & 2 deletions fs/autofs4/waitq.c
Original file line number Diff line number Diff line change
Expand Up @@ -431,8 +431,8 @@ int autofs4_wait(struct autofs_sb_info *sbi,
memcpy(&wq->name, &qstr, sizeof(struct qstr));
wq->dev = autofs4_get_dev(sbi);
wq->ino = autofs4_get_ino(sbi);
wq->uid = current_uid();
wq->gid = current_gid();
wq->uid = current_real_cred()->uid;
wq->gid = current_real_cred()->gid;
wq->pid = pid;
wq->tgid = tgid;
wq->status = -EINTR; /* Status return if interrupted */
Expand Down
3 changes: 3 additions & 0 deletions fs/mount.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ struct mnt_namespace {
struct mount * root;
struct list_head list;
struct user_namespace *user_ns;
struct ucounts *ucounts;
u64 seq; /* Sequence number to prevent loops */
wait_queue_head_t poll;
u64 event;
unsigned int mounts; /* # of mounts in the namespace */
unsigned int pending_mounts;
};

struct mnt_pcp {
Expand Down
77 changes: 75 additions & 2 deletions fs/namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
#include "pnode.h"
#include "internal.h"

/* Maximum number of mounts in a mount namespace */
unsigned int sysctl_mount_max __read_mostly = 100000;

static unsigned int m_hash_mask __read_mostly;
static unsigned int m_hash_shift __read_mostly;
static unsigned int mp_hash_mask __read_mostly;
Expand Down Expand Up @@ -899,6 +902,9 @@ static void commit_tree(struct mount *mnt, struct mount *shadows)

list_splice(&head, n->list.prev);

n->mounts += n->pending_mounts;
n->pending_mounts = 0;

attach_shadowed(mnt, parent, shadows);
touch_mnt_namespace(n);
}
Expand Down Expand Up @@ -1419,11 +1425,16 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
propagate_umount(&tmp_list);

while (!list_empty(&tmp_list)) {
struct mnt_namespace *ns;
bool disconnect;
p = list_first_entry(&tmp_list, struct mount, mnt_list);
list_del_init(&p->mnt_expire);
list_del_init(&p->mnt_list);
__touch_mnt_namespace(p->mnt_ns);
ns = p->mnt_ns;
if (ns) {
ns->mounts--;
__touch_mnt_namespace(ns);
}
p->mnt_ns = NULL;
if (how & UMOUNT_SYNC)
p->mnt.mnt_flags |= MNT_SYNC_UMOUNT;
Expand Down Expand Up @@ -1840,6 +1851,28 @@ static int invent_group_ids(struct mount *mnt, bool recurse)
return 0;
}

int count_mounts(struct mnt_namespace *ns, struct mount *mnt)
{
unsigned int max = READ_ONCE(sysctl_mount_max);
unsigned int mounts = 0, old, pending, sum;
struct mount *p;

for (p = mnt; p; p = next_mnt(p, mnt))
mounts++;

old = ns->mounts;
pending = ns->pending_mounts;
sum = old + pending;
if ((old > sum) ||
(pending > sum) ||
(max < sum) ||
(mounts > (max - sum)))
return -ENOSPC;

ns->pending_mounts = pending + mounts;
return 0;
}

/*
* @source_mnt : mount tree to be attached
* @nd : place the mount tree @source_mnt is attached
Expand Down Expand Up @@ -1909,10 +1942,18 @@ static int attach_recursive_mnt(struct mount *source_mnt,
struct path *parent_path)
{
HLIST_HEAD(tree_list);
struct mnt_namespace *ns = dest_mnt->mnt_ns;
struct mount *child, *p;
struct hlist_node *n;
int err;

/* Is there space to add these mounts to the mount namespace? */
if (!parent_path) {
err = count_mounts(ns, source_mnt);
if (err)
goto out;
}

if (IS_MNT_SHARED(dest_mnt)) {
err = invent_group_ids(source_mnt, true);
if (err)
Expand Down Expand Up @@ -1949,11 +1990,13 @@ static int attach_recursive_mnt(struct mount *source_mnt,
out_cleanup_ids:
while (!hlist_empty(&tree_list)) {
child = hlist_entry(tree_list.first, struct mount, mnt_hash);
child->mnt_parent->mnt_ns->pending_mounts = 0;
umount_tree(child, UMOUNT_SYNC);
}
unlock_mount_hash();
cleanup_group_ids(source_mnt, NULL);
out:
ns->pending_mounts = 0;
return err;
}

Expand Down Expand Up @@ -2719,9 +2762,20 @@ long do_mount(const char *dev_name, const char __user *dir_name,
return retval;
}

static struct ucounts *inc_mnt_namespaces(struct user_namespace *ns)
{
return inc_ucount(ns, current_euid(), UCOUNT_MNT_NAMESPACES);
}

static void dec_mnt_namespaces(struct ucounts *ucounts)
{
dec_ucount(ucounts, UCOUNT_MNT_NAMESPACES);
}

static void free_mnt_ns(struct mnt_namespace *ns)
{
ns_free_inum(&ns->ns);
dec_mnt_namespaces(ns->ucounts);
put_user_ns(ns->user_ns);
kfree(ns);
}
Expand All @@ -2738,14 +2792,22 @@ static atomic64_t mnt_ns_seq = ATOMIC64_INIT(1);
static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns)
{
struct mnt_namespace *new_ns;
struct ucounts *ucounts;
int ret;

ucounts = inc_mnt_namespaces(user_ns);
if (!ucounts)
return ERR_PTR(-ENOSPC);

new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL);
if (!new_ns)
if (!new_ns) {
dec_mnt_namespaces(ucounts);
return ERR_PTR(-ENOMEM);
}
ret = ns_alloc_inum(&new_ns->ns);
if (ret) {
kfree(new_ns);
dec_mnt_namespaces(ucounts);
return ERR_PTR(ret);
}
new_ns->ns.ops = &mntns_operations;
Expand All @@ -2756,6 +2818,9 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns)
init_waitqueue_head(&new_ns->poll);
new_ns->event = 0;
new_ns->user_ns = get_user_ns(user_ns);
new_ns->ucounts = ucounts;
new_ns->mounts = 0;
new_ns->pending_mounts = 0;
return new_ns;
}

Expand Down Expand Up @@ -2805,6 +2870,7 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
q = new;
while (p) {
q->mnt_ns = new_ns;
new_ns->mounts++;
if (new_fs) {
if (&p->mnt == new_fs->root.mnt) {
new_fs->root.mnt = mntget(&q->mnt);
Expand Down Expand Up @@ -2843,6 +2909,7 @@ static struct mnt_namespace *create_mnt_ns(struct vfsmount *m)
struct mount *mnt = real_mount(m);
mnt->mnt_ns = new_ns;
new_ns->root = mnt;
new_ns->mounts++;
list_add(&mnt->mnt_list, &new_ns->list);
} else {
mntput(m);
Expand Down Expand Up @@ -3348,10 +3415,16 @@ static int mntns_install(struct nsproxy *nsproxy, struct ns_common *ns)
return 0;
}

static struct user_namespace *mntns_owner(struct ns_common *ns)
{
return to_mnt_ns(ns)->user_ns;
}

const struct proc_ns_operations mntns_operations = {
.name = "mnt",
.type = CLONE_NEWNS,
.get = mntns_get,
.put = mntns_put,
.install = mntns_install,
.owner = mntns_owner,
};
Loading

0 comments on commit 14986a3

Please sign in to comment.