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 and namespace infrastructure changes from Eric W Biederman:
 "This set of changes starts with a few small enhnacements to the user
  namespace.  reboot support, allowing more arbitrary mappings, and
  support for mounting devpts, ramfs, tmpfs, and mqueuefs as just the
  user namespace root.

  I do my best to document that if you care about limiting your
  unprivileged users that when you have the user namespace support
  enabled you will need to enable memory control groups.

  There is a minor bug fix to prevent overflowing the stack if someone
  creates way too many user namespaces.

  The bulk of the changes are a continuation of the kuid/kgid push down
  work through the filesystems.  These changes make using uids and gids
  typesafe which ensures that these filesystems are safe to use when
  multiple user namespaces are in use.  The filesystems converted for
  3.9 are ceph, 9p, afs, ocfs2, gfs2, ncpfs, nfs, nfsd, and cifs.  The
  changes for these filesystems were a little more involved so I split
  the changes into smaller hopefully obviously correct changes.

  XFS is the only filesystem that remains.  I was hoping I could get
  that in this release so that user namespace support would be enabled
  with an allyesconfig or an allmodconfig but it looks like the xfs
  changes need another couple of days before it they are ready."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: (93 commits)
  cifs: Enable building with user namespaces enabled.
  cifs: Convert struct cifs_ses to use a kuid_t and a kgid_t
  cifs: Convert struct cifs_sb_info to use kuids and kgids
  cifs: Modify struct smb_vol to use kuids and kgids
  cifs: Convert struct cifsFileInfo to use a kuid
  cifs: Convert struct cifs_fattr to use kuid and kgids
  cifs: Convert struct tcon_link to use a kuid.
  cifs: Modify struct cifs_unix_set_info_args to hold a kuid_t and a kgid_t
  cifs: Convert from a kuid before printing current_fsuid
  cifs: Use kuids and kgids SID to uid/gid mapping
  cifs: Pass GLOBAL_ROOT_UID and GLOBAL_ROOT_GID to keyring_alloc
  cifs: Use BUILD_BUG_ON to validate uids and gids are the same size
  cifs: Override unmappable incoming uids and gids
  nfsd: Enable building with user namespaces enabled.
  nfsd: Properly compare and initialize kuids and kgids
  nfsd: Store ex_anon_uid and ex_anon_gid as kuids and kgids
  nfsd: Modify nfsd4_cb_sec to use kuids and kgids
  nfsd: Handle kuids and kgids in the nfs4acl to posix_acl conversion
  nfsd: Convert nfsxdr to use kuids and kgids
  nfsd: Convert nfs3xdr to use kuids and kgids
  ...
  • Loading branch information
torvalds committed Feb 26, 2013
2 parents 8d168f7 + 139321c commit 94f2f14
Show file tree
Hide file tree
Showing 101 changed files with 1,058 additions and 656 deletions.
14 changes: 14 additions & 0 deletions Documentation/namespaces/resource-control.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
There are a lot of kinds of objects in the kernel that don't have
individual limits or that have limits that are ineffective when a set
of processes is allowed to switch user ids. With user namespaces
enabled in a kernel for people who don't trust their users or their
users programs to play nice this problems becomes more acute.

Therefore it is recommended that memory control groups be enabled in
kernels that enable user namespaces, and it is further recommended
that userspace configure memory control groups to limit how much
memory user's they don't trust to play nice can use.

Memory control groups can be configured by installing the libcgroup
package present on most distros editing /etc/cgrules.conf,
/etc/cgconfig.conf and setting up libpam-cgroup.
17 changes: 9 additions & 8 deletions fs/9p/fid.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,20 @@ int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid)
*
*/

static struct p9_fid *v9fs_fid_find(struct dentry *dentry, u32 uid, int any)
static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any)
{
struct v9fs_dentry *dent;
struct p9_fid *fid, *ret;

p9_debug(P9_DEBUG_VFS, " dentry: %s (%p) uid %d any %d\n",
dentry->d_name.name, dentry, uid, any);
dentry->d_name.name, dentry, from_kuid(&init_user_ns, uid),
any);
dent = (struct v9fs_dentry *) dentry->d_fsdata;
ret = NULL;
if (dent) {
spin_lock(&dent->lock);
list_for_each_entry(fid, &dent->fidlist, dlist) {
if (any || fid->uid == uid) {
if (any || uid_eq(fid->uid, uid)) {
ret = fid;
break;
}
Expand Down Expand Up @@ -126,7 +127,7 @@ static int build_path_from_dentry(struct v9fs_session_info *v9ses,
}

static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry,
uid_t uid, int any)
kuid_t uid, int any)
{
struct dentry *ds;
char **wnames, *uname;
Expand Down Expand Up @@ -233,7 +234,7 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry,

struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
{
uid_t uid;
kuid_t uid;
int any, access;
struct v9fs_session_info *v9ses;

Expand All @@ -253,7 +254,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
break;

default:
uid = ~0;
uid = INVALID_UID;
any = 0;
break;
}
Expand All @@ -272,7 +273,7 @@ struct p9_fid *v9fs_fid_clone(struct dentry *dentry)
return ret;
}

static struct p9_fid *v9fs_fid_clone_with_uid(struct dentry *dentry, uid_t uid)
static struct p9_fid *v9fs_fid_clone_with_uid(struct dentry *dentry, kuid_t uid)
{
struct p9_fid *fid, *ret;

Expand All @@ -289,7 +290,7 @@ struct p9_fid *v9fs_writeback_fid(struct dentry *dentry)
int err;
struct p9_fid *fid;

fid = v9fs_fid_clone_with_uid(dentry, 0);
fid = v9fs_fid_clone_with_uid(dentry, GLOBAL_ROOT_UID);
if (IS_ERR(fid))
goto error_out;
/*
Expand Down
34 changes: 27 additions & 7 deletions fs/9p/v9fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,13 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
ret = r;
continue;
}
v9ses->dfltuid = option;
v9ses->dfltuid = make_kuid(current_user_ns(), option);
if (!uid_valid(v9ses->dfltuid)) {
p9_debug(P9_DEBUG_ERROR,
"uid field, but not a uid?\n");
ret = -EINVAL;
continue;
}
break;
case Opt_dfltgid:
r = match_int(&args[0], &option);
Expand All @@ -171,7 +177,13 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
ret = r;
continue;
}
v9ses->dfltgid = option;
v9ses->dfltgid = make_kgid(current_user_ns(), option);
if (!gid_valid(v9ses->dfltgid)) {
p9_debug(P9_DEBUG_ERROR,
"gid field, but not a gid?\n");
ret = -EINVAL;
continue;
}
break;
case Opt_afid:
r = match_int(&args[0], &option);
Expand Down Expand Up @@ -248,15 +260,23 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
else if (strcmp(s, "client") == 0) {
v9ses->flags |= V9FS_ACCESS_CLIENT;
} else {
uid_t uid;
v9ses->flags |= V9FS_ACCESS_SINGLE;
v9ses->uid = simple_strtoul(s, &e, 10);
uid = simple_strtoul(s, &e, 10);
if (*e != '\0') {
ret = -EINVAL;
pr_info("Unknown access argument %s\n",
s);
kfree(s);
goto free_and_return;
}
v9ses->uid = make_kuid(current_user_ns(), uid);
if (!uid_valid(v9ses->uid)) {
ret = -EINVAL;
pr_info("Uknown uid %s\n", s);
kfree(s);
goto free_and_return;
}
}

kfree(s);
Expand Down Expand Up @@ -319,7 +339,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
list_add(&v9ses->slist, &v9fs_sessionlist);
spin_unlock(&v9fs_sessionlist_lock);

v9ses->uid = ~0;
v9ses->uid = INVALID_UID;
v9ses->dfltuid = V9FS_DEFUID;
v9ses->dfltgid = V9FS_DEFGID;

Expand Down Expand Up @@ -364,7 +384,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,

v9ses->flags &= ~V9FS_ACCESS_MASK;
v9ses->flags |= V9FS_ACCESS_ANY;
v9ses->uid = ~0;
v9ses->uid = INVALID_UID;
}
if (!v9fs_proto_dotl(v9ses) ||
!((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)) {
Expand All @@ -375,7 +395,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
v9ses->flags &= ~V9FS_ACL_MASK;
}

fid = p9_client_attach(v9ses->clnt, NULL, v9ses->uname, ~0,
fid = p9_client_attach(v9ses->clnt, NULL, v9ses->uname, INVALID_UID,
v9ses->aname);
if (IS_ERR(fid)) {
retval = PTR_ERR(fid);
Expand All @@ -387,7 +407,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
if ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_SINGLE)
fid->uid = v9ses->uid;
else
fid->uid = ~0;
fid->uid = INVALID_UID;

#ifdef CONFIG_9P_FSCACHE
/* register the session for caching */
Expand Down
10 changes: 5 additions & 5 deletions fs/9p/v9fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ struct v9fs_session_info {
char *uname; /* user name to mount as */
char *aname; /* name of remote hierarchy being mounted */
unsigned int maxdata; /* max data for client interface */
unsigned int dfltuid; /* default uid/muid for legacy support */
unsigned int dfltgid; /* default gid for legacy support */
u32 uid; /* if ACCESS_SINGLE, the uid that has access */
kuid_t dfltuid; /* default uid/muid for legacy support */
kgid_t dfltgid; /* default gid for legacy support */
kuid_t uid; /* if ACCESS_SINGLE, the uid that has access */
struct p9_client *clnt; /* 9p client */
struct list_head slist; /* list of sessions registered with v9fs */
struct backing_dev_info bdi;
Expand Down Expand Up @@ -165,8 +165,8 @@ extern struct inode *v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses,
#define V9FS_PORT 564
#define V9FS_DEFUSER "nobody"
#define V9FS_DEFANAME ""
#define V9FS_DEFUID (-2)
#define V9FS_DEFGID (-2)
#define V9FS_DEFUID KUIDT_INIT(-2)
#define V9FS_DEFGID KGIDT_INIT(-2)

static inline struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode)
{
Expand Down
6 changes: 3 additions & 3 deletions fs/9p/vfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,9 +225,9 @@ v9fs_blank_wstat(struct p9_wstat *wstat)
wstat->uid = NULL;
wstat->gid = NULL;
wstat->muid = NULL;
wstat->n_uid = ~0;
wstat->n_gid = ~0;
wstat->n_muid = ~0;
wstat->n_uid = INVALID_UID;
wstat->n_gid = INVALID_GID;
wstat->n_muid = INVALID_UID;
wstat->extension = NULL;
}

Expand Down
10 changes: 5 additions & 5 deletions fs/9p/vfs_inode_dotl.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
* group of the new file system object.
*/

static gid_t v9fs_get_fsgid_for_create(struct inode *dir_inode)
static kgid_t v9fs_get_fsgid_for_create(struct inode *dir_inode)
{
BUG_ON(dir_inode == NULL);

Expand Down Expand Up @@ -245,7 +245,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
int *opened)
{
int err = 0;
gid_t gid;
kgid_t gid;
umode_t mode;
char *name = NULL;
struct p9_qid qid;
Expand Down Expand Up @@ -396,7 +396,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
int err;
struct v9fs_session_info *v9ses;
struct p9_fid *fid = NULL, *dfid = NULL;
gid_t gid;
kgid_t gid;
char *name;
umode_t mode;
struct inode *inode;
Expand Down Expand Up @@ -697,7 +697,7 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
const char *symname)
{
int err;
gid_t gid;
kgid_t gid;
char *name;
struct p9_qid qid;
struct inode *inode;
Expand Down Expand Up @@ -837,7 +837,7 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
dev_t rdev)
{
int err;
gid_t gid;
kgid_t gid;
char *name;
umode_t mode;
struct v9fs_session_info *v9ses;
Expand Down
11 changes: 2 additions & 9 deletions fs/afs/afs.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ struct afs_file_status {
u64 size; /* file size */
afs_dataversion_t data_version; /* current data version */
u32 author; /* author ID */
u32 owner; /* owner ID */
u32 group; /* group ID */
kuid_t owner; /* owner ID */
kgid_t group; /* group ID */
afs_access_t caller_access; /* access rights for authenticated caller */
afs_access_t anon_access; /* access rights for unauthenticated caller */
umode_t mode; /* UNIX mode */
Expand All @@ -133,13 +133,6 @@ struct afs_file_status {
/*
* AFS file status change request
*/
struct afs_store_status {
u32 mask; /* which bits of the struct are set */
u32 mtime_client; /* last time client changed data */
u32 owner; /* owner ID */
u32 group; /* group ID */
umode_t mode; /* UNIX mode */
};

#define AFS_SET_MTIME 0x01 /* set the mtime */
#define AFS_SET_OWNER 0x02 /* set the owner ID */
Expand Down
14 changes: 10 additions & 4 deletions fs/afs/fsclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
umode_t mode;
u64 data_version, size;
u32 changed = 0; /* becomes non-zero if ctime-type changes seen */
kuid_t owner;
kgid_t group;

#define EXTRACT(DST) \
do { \
Expand All @@ -56,7 +58,9 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
size = ntohl(*bp++);
data_version = ntohl(*bp++);
EXTRACT(status->author);
EXTRACT(status->owner);
owner = make_kuid(&init_user_ns, ntohl(*bp++));
changed |= !uid_eq(owner, status->owner);
status->owner = owner;
EXTRACT(status->caller_access); /* call ticket dependent */
EXTRACT(status->anon_access);
EXTRACT(status->mode);
Expand All @@ -65,7 +69,9 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
bp++; /* seg size */
status->mtime_client = ntohl(*bp++);
status->mtime_server = ntohl(*bp++);
EXTRACT(status->group);
group = make_kgid(&init_user_ns, ntohl(*bp++));
changed |= !gid_eq(group, status->group);
status->group = group;
bp++; /* sync counter */
data_version |= (u64) ntohl(*bp++) << 32;
EXTRACT(status->lock_count);
Expand Down Expand Up @@ -181,12 +187,12 @@ static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)

if (attr->ia_valid & ATTR_UID) {
mask |= AFS_SET_OWNER;
owner = attr->ia_uid;
owner = from_kuid(&init_user_ns, attr->ia_uid);
}

if (attr->ia_valid & ATTR_GID) {
mask |= AFS_SET_GROUP;
group = attr->ia_gid;
group = from_kgid(&init_user_ns, attr->ia_gid);
}

if (attr->ia_valid & ATTR_MODE) {
Expand Down
6 changes: 3 additions & 3 deletions fs/afs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)

set_nlink(inode, vnode->status.nlink);
inode->i_uid = vnode->status.owner;
inode->i_gid = 0;
inode->i_gid = GLOBAL_ROOT_GID;
inode->i_size = vnode->status.size;
inode->i_ctime.tv_sec = vnode->status.mtime_server;
inode->i_ctime.tv_nsec = 0;
Expand Down Expand Up @@ -175,8 +175,8 @@ struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name,
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
inode->i_op = &afs_autocell_inode_operations;
set_nlink(inode, 2);
inode->i_uid = 0;
inode->i_gid = 0;
inode->i_uid = GLOBAL_ROOT_UID;
inode->i_gid = GLOBAL_ROOT_GID;
inode->i_ctime.tv_sec = get_seconds();
inode->i_ctime.tv_nsec = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime;
Expand Down
6 changes: 6 additions & 0 deletions fs/afs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#include <linux/parser.h>
#include <linux/statfs.h>
#include <linux/sched.h>
#include <linux/nsproxy.h>
#include <net/net_namespace.h>
#include "internal.h"

#define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */
Expand Down Expand Up @@ -363,6 +365,10 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,

memset(&params, 0, sizeof(params));

ret = -EINVAL;
if (current->nsproxy->net_ns != &init_net)
goto error;

/* parse the options and device name */
if (options) {
ret = afs_parse_options(&params, options, &dev_name);
Expand Down
Loading

0 comments on commit 94f2f14

Please sign in to comment.