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 user namespace changes from Eric Biederman:
 "While small this set of changes is very significant with respect to
  containers in general and user namespaces in particular.  The user
  space interface is now complete.

  This set of changes adds support for unprivileged users to create user
  namespaces and as a user namespace root to create other namespaces.
  The tyranny of supporting suid root preventing unprivileged users from
  using cool new kernel features is broken.

  This set of changes completes the work on setns, adding support for
  the pid, user, mount namespaces.

  This set of changes includes a bunch of basic pid namespace
  cleanups/simplifications.  Of particular significance is the rework of
  the pid namespace cleanup so it no longer requires sending out
  tendrils into all kinds of unexpected cleanup paths for operation.  At
  least one case of broken error handling is fixed by this cleanup.

  The files under /proc/<pid>/ns/ have been converted from regular files
  to magic symlinks which prevents incorrect caching by the VFS,
  ensuring the files always refer to the namespace the process is
  currently using and ensuring that the ptrace_mayaccess permission
  checks are always applied.

  The files under /proc/<pid>/ns/ have been given stable inode numbers
  so it is now possible to see if different processes share the same
  namespaces.

  Through the David Miller's net tree are changes to relax many of the
  permission checks in the networking stack to allowing the user
  namespace root to usefully use the networking stack.  Similar changes
  for the mount namespace and the pid namespace are coming through my
  tree.

  Two small changes to add user namespace support were commited here adn
  in David Miller's -net tree so that I could complete the work on the
  /proc/<pid>/ns/ files in this tree.

  Work remains to make it safe to build user namespaces and 9p, afs,
  ceph, cifs, coda, gfs2, ncpfs, nfs, nfsd, ocfs2, and xfs so the
  Kconfig guard remains in place preventing that user namespaces from
  being built when any of those filesystems are enabled.

  Future design work remains to allow root users outside of the initial
  user namespace to mount more than just /proc and /sys."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: (38 commits)
  proc: Usable inode numbers for the namespace file descriptors.
  proc: Fix the namespace inode permission checks.
  proc: Generalize proc inode allocation
  userns: Allow unprivilged mounts of proc and sysfs
  userns: For /proc/self/{uid,gid}_map derive the lower userns from the struct file
  procfs: Print task uids and gids in the userns that opened the proc file
  userns: Implement unshare of the user namespace
  userns: Implent proc namespace operations
  userns: Kill task_user_ns
  userns: Make create_new_namespaces take a user_ns parameter
  userns: Allow unprivileged use of setns.
  userns: Allow unprivileged users to create new namespaces
  userns: Allow setting a userns mapping to your current uid.
  userns: Allow chown and setgid preservation
  userns: Allow unprivileged users to create user namespaces.
  userns: Ignore suid and sgid on binaries if the uid or gid can not be mapped
  userns: fix return value on mntns_install() failure
  vfs: Allow unprivileged manipulation of the mount namespace.
  vfs: Only support slave subtrees across different user namespaces
  vfs: Add a user namespace reference from struct mnt_namespace
  ...
  • Loading branch information
torvalds committed Dec 17, 2012
2 parents 9228ff9 + 98f842e commit 6a2b60b
Show file tree
Hide file tree
Showing 59 changed files with 996 additions and 451 deletions.
2 changes: 1 addition & 1 deletion arch/powerpc/platforms/cell/spufs/sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -1094,7 +1094,7 @@ static int show_spu_loadavg(struct seq_file *s, void *private)
LOAD_INT(c), LOAD_FRAC(c),
count_active_contexts(),
atomic_read(&nr_spu_contexts),
current->nsproxy->pid_ns->last_pid);
task_active_pid_ns(current)->last_pid);
return 0;
}

Expand Down
2 changes: 1 addition & 1 deletion arch/um/drivers/mconsole_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ void mconsole_log(struct mc_request *req)

void mconsole_proc(struct mc_request *req)
{
struct vfsmount *mnt = current->nsproxy->pid_ns->proc_mnt;
struct vfsmount *mnt = task_active_pid_ns(current)->proc_mnt;
char *buf;
int len;
struct file *file;
Expand Down
3 changes: 2 additions & 1 deletion drivers/staging/android/binder.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/pid_namespace.h>

#include "binder.h"
#include "binder_trace.h"
Expand Down Expand Up @@ -2320,7 +2321,7 @@ static int binder_thread_read(struct binder_proc *proc,
if (t->from) {
struct task_struct *sender = t->from->proc->tsk;
tr.sender_pid = task_tgid_nr_ns(sender,
current->nsproxy->pid_ns);
task_active_pid_ns(current));
} else {
tr.sender_pid = 0;
}
Expand Down
11 changes: 7 additions & 4 deletions fs/attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,15 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
/* Make sure a caller can chown. */
if ((ia_valid & ATTR_UID) &&
(!uid_eq(current_fsuid(), inode->i_uid) ||
!uid_eq(attr->ia_uid, inode->i_uid)) && !capable(CAP_CHOWN))
!uid_eq(attr->ia_uid, inode->i_uid)) &&
!inode_capable(inode, CAP_CHOWN))
return -EPERM;

/* Make sure caller can chgrp. */
if ((ia_valid & ATTR_GID) &&
(!uid_eq(current_fsuid(), inode->i_uid) ||
(!in_group_p(attr->ia_gid) && !gid_eq(attr->ia_gid, inode->i_gid))) &&
!capable(CAP_CHOWN))
!inode_capable(inode, CAP_CHOWN))
return -EPERM;

/* Make sure a caller can chmod. */
Expand All @@ -65,7 +66,8 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
return -EPERM;
/* Also check the setgid bit! */
if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
inode->i_gid) && !capable(CAP_FSETID))
inode->i_gid) &&
!inode_capable(inode, CAP_FSETID))
attr->ia_mode &= ~S_ISGID;
}

Expand Down Expand Up @@ -157,7 +159,8 @@ void setattr_copy(struct inode *inode, const struct iattr *attr)
if (ia_valid & ATTR_MODE) {
umode_t mode = attr->ia_mode;

if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
if (!in_group_p(inode->i_gid) &&
!inode_capable(inode, CAP_FSETID))
mode &= ~S_ISGID;
inode->i_mode = mode;
}
Expand Down
8 changes: 4 additions & 4 deletions fs/autofs4/autofs_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ struct autofs_info {
unsigned long last_used;
atomic_t count;

uid_t uid;
gid_t gid;
kuid_t uid;
kgid_t gid;
};

#define AUTOFS_INF_EXPIRING (1<<0) /* dentry is in the process of expiring */
Expand All @@ -89,8 +89,8 @@ struct autofs_wait_queue {
struct qstr name;
u32 dev;
u64 ino;
uid_t uid;
gid_t gid;
kuid_t uid;
kgid_t gid;
pid_t pid;
pid_t tgid;
/* This is for status reporting upon return */
Expand Down
4 changes: 2 additions & 2 deletions fs/autofs4/dev-ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -437,8 +437,8 @@ static int autofs_dev_ioctl_requester(struct file *fp,
err = 0;
autofs4_expire_wait(path.dentry);
spin_lock(&sbi->fs_lock);
param->requester.uid = ino->uid;
param->requester.gid = ino->gid;
param->requester.uid = from_kuid_munged(current_user_ns(), ino->uid);
param->requester.gid = from_kgid_munged(current_user_ns(), ino->gid);
spin_unlock(&sbi->fs_lock);
}
path_put(&path);
Expand Down
24 changes: 15 additions & 9 deletions fs/autofs4/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ struct autofs_info *autofs4_new_ino(struct autofs_sb_info *sbi)

void autofs4_clean_ino(struct autofs_info *ino)
{
ino->uid = 0;
ino->gid = 0;
ino->uid = GLOBAL_ROOT_UID;
ino->gid = GLOBAL_ROOT_GID;
ino->last_used = jiffies;
}

Expand Down Expand Up @@ -79,10 +79,12 @@ static int autofs4_show_options(struct seq_file *m, struct dentry *root)
return 0;

seq_printf(m, ",fd=%d", sbi->pipefd);
if (root_inode->i_uid != 0)
seq_printf(m, ",uid=%u", root_inode->i_uid);
if (root_inode->i_gid != 0)
seq_printf(m, ",gid=%u", root_inode->i_gid);
if (!uid_eq(root_inode->i_uid, GLOBAL_ROOT_UID))
seq_printf(m, ",uid=%u",
from_kuid_munged(&init_user_ns, root_inode->i_uid));
if (!gid_eq(root_inode->i_gid, GLOBAL_ROOT_GID))
seq_printf(m, ",gid=%u",
from_kgid_munged(&init_user_ns, root_inode->i_gid));
seq_printf(m, ",pgrp=%d", sbi->oz_pgrp);
seq_printf(m, ",timeout=%lu", sbi->exp_timeout/HZ);
seq_printf(m, ",minproto=%d", sbi->min_proto);
Expand Down Expand Up @@ -126,7 +128,7 @@ static const match_table_t tokens = {
{Opt_err, NULL}
};

static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
static int parse_options(char *options, int *pipefd, kuid_t *uid, kgid_t *gid,
pid_t *pgrp, unsigned int *type, int *minproto, int *maxproto)
{
char *p;
Expand Down Expand Up @@ -159,12 +161,16 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
case Opt_uid:
if (match_int(args, &option))
return 1;
*uid = option;
*uid = make_kuid(current_user_ns(), option);
if (!uid_valid(*uid))
return 1;
break;
case Opt_gid:
if (match_int(args, &option))
return 1;
*gid = option;
*gid = make_kgid(current_user_ns(), option);
if (!gid_valid(*gid))
return 1;
break;
case Opt_pgrp:
if (match_int(args, &option))
Expand Down
5 changes: 3 additions & 2 deletions fs/autofs4/waitq.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
case autofs_ptype_expire_direct:
{
struct autofs_v5_packet *packet = &pkt.v5_pkt.v5_packet;
struct user_namespace *user_ns = sbi->pipe->f_cred->user_ns;

pktsz = sizeof(*packet);

Expand All @@ -163,8 +164,8 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
packet->name[wq->name.len] = '\0';
packet->dev = wq->dev;
packet->ino = wq->ino;
packet->uid = wq->uid;
packet->gid = wq->gid;
packet->uid = from_kuid_munged(user_ns, wq->uid);
packet->gid = from_kgid_munged(user_ns, wq->gid);
packet->pid = wq->pid;
packet->tgid = wq->tgid;
break;
Expand Down
9 changes: 3 additions & 6 deletions fs/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -1266,14 +1266,13 @@ int prepare_binprm(struct linux_binprm *bprm)
bprm->cred->egid = current_egid();

if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) &&
!current->no_new_privs) {
!current->no_new_privs &&
kuid_has_mapping(bprm->cred->user_ns, inode->i_uid) &&
kgid_has_mapping(bprm->cred->user_ns, inode->i_gid)) {
/* Set-uid? */
if (mode & S_ISUID) {
if (!kuid_has_mapping(bprm->cred->user_ns, inode->i_uid))
return -EPERM;
bprm->per_clear |= PER_CLEAR_ON_SETID;
bprm->cred->euid = inode->i_uid;

}

/* Set-gid? */
Expand All @@ -1283,8 +1282,6 @@ int prepare_binprm(struct linux_binprm *bprm)
* executable.
*/
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
if (!kgid_has_mapping(bprm->cred->user_ns, inode->i_gid))
return -EPERM;
bprm->per_clear |= PER_CLEAR_ON_SETID;
bprm->cred->egid = inode->i_gid;
}
Expand Down
4 changes: 2 additions & 2 deletions fs/fuse/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ static void __fuse_put_request(struct fuse_req *req)

static void fuse_req_init_context(struct fuse_req *req)
{
req->in.h.uid = current_fsuid();
req->in.h.gid = current_fsgid();
req->in.h.uid = from_kuid_munged(&init_user_ns, current_fsuid());
req->in.h.gid = from_kgid_munged(&init_user_ns, current_fsgid());
req->in.h.pid = current->pid;
}

Expand Down
20 changes: 10 additions & 10 deletions fs/fuse/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -818,8 +818,8 @@ static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr,
stat->ino = attr->ino;
stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
stat->nlink = attr->nlink;
stat->uid = attr->uid;
stat->gid = attr->gid;
stat->uid = make_kuid(&init_user_ns, attr->uid);
stat->gid = make_kgid(&init_user_ns, attr->gid);
stat->rdev = inode->i_rdev;
stat->atime.tv_sec = attr->atime;
stat->atime.tv_nsec = attr->atimensec;
Expand Down Expand Up @@ -1007,12 +1007,12 @@ int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
rcu_read_lock();
ret = 0;
cred = __task_cred(task);
if (cred->euid == fc->user_id &&
cred->suid == fc->user_id &&
cred->uid == fc->user_id &&
cred->egid == fc->group_id &&
cred->sgid == fc->group_id &&
cred->gid == fc->group_id)
if (uid_eq(cred->euid, fc->user_id) &&
uid_eq(cred->suid, fc->user_id) &&
uid_eq(cred->uid, fc->user_id) &&
gid_eq(cred->egid, fc->group_id) &&
gid_eq(cred->sgid, fc->group_id) &&
gid_eq(cred->gid, fc->group_id))
ret = 1;
rcu_read_unlock();

Expand Down Expand Up @@ -1306,9 +1306,9 @@ static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
if (ivalid & ATTR_MODE)
arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode;
if (ivalid & ATTR_UID)
arg->valid |= FATTR_UID, arg->uid = iattr->ia_uid;
arg->valid |= FATTR_UID, arg->uid = from_kuid(&init_user_ns, iattr->ia_uid);
if (ivalid & ATTR_GID)
arg->valid |= FATTR_GID, arg->gid = iattr->ia_gid;
arg->valid |= FATTR_GID, arg->gid = from_kgid(&init_user_ns, iattr->ia_gid);
if (ivalid & ATTR_SIZE)
arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size;
if (ivalid & ATTR_ATIME) {
Expand Down
4 changes: 2 additions & 2 deletions fs/fuse/fuse_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -333,10 +333,10 @@ struct fuse_conn {
atomic_t count;

/** The user id for this mount */
uid_t user_id;
kuid_t user_id;

/** The group id for this mount */
gid_t group_id;
kgid_t group_id;

/** The fuse mount flags for this mount */
unsigned flags;
Expand Down
23 changes: 14 additions & 9 deletions fs/fuse/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ MODULE_PARM_DESC(max_user_congthresh,
struct fuse_mount_data {
int fd;
unsigned rootmode;
unsigned user_id;
unsigned group_id;
kuid_t user_id;
kgid_t group_id;
unsigned fd_present:1;
unsigned rootmode_present:1;
unsigned user_id_present:1;
Expand Down Expand Up @@ -164,8 +164,8 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
inode->i_ino = fuse_squash_ino(attr->ino);
inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
set_nlink(inode, attr->nlink);
inode->i_uid = attr->uid;
inode->i_gid = attr->gid;
inode->i_uid = make_kuid(&init_user_ns, attr->uid);
inode->i_gid = make_kgid(&init_user_ns, attr->gid);
inode->i_blocks = attr->blocks;
inode->i_atime.tv_sec = attr->atime;
inode->i_atime.tv_nsec = attr->atimensec;
Expand Down Expand Up @@ -492,14 +492,18 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev)
case OPT_USER_ID:
if (match_int(&args[0], &value))
return 0;
d->user_id = value;
d->user_id = make_kuid(current_user_ns(), value);
if (!uid_valid(d->user_id))
return 0;
d->user_id_present = 1;
break;

case OPT_GROUP_ID:
if (match_int(&args[0], &value))
return 0;
d->group_id = value;
d->group_id = make_kgid(current_user_ns(), value);
if (!gid_valid(d->group_id))
return 0;
d->group_id_present = 1;
break;

Expand Down Expand Up @@ -540,8 +544,8 @@ static int fuse_show_options(struct seq_file *m, struct dentry *root)
struct super_block *sb = root->d_sb;
struct fuse_conn *fc = get_fuse_conn_super(sb);

seq_printf(m, ",user_id=%u", fc->user_id);
seq_printf(m, ",group_id=%u", fc->group_id);
seq_printf(m, ",user_id=%u", from_kuid_munged(&init_user_ns, fc->user_id));
seq_printf(m, ",group_id=%u", from_kgid_munged(&init_user_ns, fc->group_id));
if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
seq_puts(m, ",default_permissions");
if (fc->flags & FUSE_ALLOW_OTHER)
Expand Down Expand Up @@ -989,7 +993,8 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
if (!file)
goto err;

if (file->f_op != &fuse_dev_operations)
if ((file->f_op != &fuse_dev_operations) ||
(file->f_cred->user_ns != &init_user_ns))
goto err_fput;

fc = kmalloc(sizeof(*fc), GFP_KERNEL);
Expand Down
2 changes: 1 addition & 1 deletion fs/hppfs/hppfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -710,7 +710,7 @@ static int hppfs_fill_super(struct super_block *sb, void *d, int silent)
struct vfsmount *proc_mnt;
int err = -ENOENT;

proc_mnt = mntget(current->nsproxy->pid_ns->proc_mnt);
proc_mnt = mntget(task_active_pid_ns(current)->proc_mnt);
if (IS_ERR(proc_mnt))
goto out;

Expand Down
3 changes: 3 additions & 0 deletions fs/mount.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@

struct mnt_namespace {
atomic_t count;
unsigned int proc_inum;
struct mount * root;
struct list_head list;
struct user_namespace *user_ns;
u64 seq; /* Sequence number to prevent loops */
wait_queue_head_t poll;
int event;
};
Expand Down
Loading

0 comments on commit 6a2b60b

Please sign in to comment.