Skip to content

Commit c7c4591

Browse files
committed
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace
Pull namespace changes from Eric Biederman: "This is an assorted mishmash of small cleanups, enhancements and bug fixes. The major theme is user namespace mount restrictions. nsown_capable is killed as it encourages not thinking about details that need to be considered. A very hard to hit pid namespace exiting bug was finally tracked and fixed. A couple of cleanups to the basic namespace infrastructure. Finally there is an enhancement that makes per user namespace capabilities usable as capabilities, and an enhancement that allows the per userns root to nice other processes in the user namespace" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: userns: Kill nsown_capable it makes the wrong thing easy capabilities: allow nice if we are privileged pidns: Don't have unshare(CLONE_NEWPID) imply CLONE_THREAD userns: Allow PR_CAPBSET_DROP in a user namespace. namespaces: Simplify copy_namespaces so it is clear what is going on. pidns: Fix hang in zap_pid_ns_processes by sending a potentially extra wakeup sysfs: Restrict mounting sysfs userns: Better restrictions on when proc and sysfs can be mounted vfs: Don't copy mount bind mounts of /proc/<pid>/ns/mnt between namespaces kernel/nsproxy.c: Improving a snippet of code. proc: Restrict mounting the proc filesystem vfs: Lock in place mounts from more privileged users
2 parents 11c7b03 + c7b96ac commit c7c4591

27 files changed

Lines changed: 177 additions & 104 deletions

fs/namespace.c

Lines changed: 95 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,10 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
831831
if ((flag & CL_UNPRIVILEGED) && (mnt->mnt.mnt_flags & MNT_READONLY))
832832
mnt->mnt.mnt_flags |= MNT_LOCK_READONLY;
833833

834+
/* Don't allow unprivileged users to reveal what is under a mount */
835+
if ((flag & CL_UNPRIVILEGED) && list_empty(&old->mnt_expire))
836+
mnt->mnt.mnt_flags |= MNT_LOCKED;
837+
834838
atomic_inc(&sb->s_active);
835839
mnt->mnt.mnt_sb = sb;
836840
mnt->mnt.mnt_root = dget(root);
@@ -1327,6 +1331,8 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags)
13271331
goto dput_and_out;
13281332
if (!check_mnt(mnt))
13291333
goto dput_and_out;
1334+
if (mnt->mnt.mnt_flags & MNT_LOCKED)
1335+
goto dput_and_out;
13301336

13311337
retval = do_umount(mnt, flags);
13321338
dput_and_out:
@@ -1349,14 +1355,11 @@ SYSCALL_DEFINE1(oldumount, char __user *, name)
13491355

13501356
#endif
13511357

1352-
static bool mnt_ns_loop(struct path *path)
1358+
static bool is_mnt_ns_file(struct dentry *dentry)
13531359
{
1354-
/* Could bind mounting the mount namespace inode cause a
1355-
* mount namespace loop?
1356-
*/
1357-
struct inode *inode = path->dentry->d_inode;
1360+
/* Is this a proxy for a mount namespace? */
1361+
struct inode *inode = dentry->d_inode;
13581362
struct proc_ns *ei;
1359-
struct mnt_namespace *mnt_ns;
13601363

13611364
if (!proc_ns_inode(inode))
13621365
return false;
@@ -1365,7 +1368,19 @@ static bool mnt_ns_loop(struct path *path)
13651368
if (ei->ns_ops != &mntns_operations)
13661369
return false;
13671370

1368-
mnt_ns = ei->ns;
1371+
return true;
1372+
}
1373+
1374+
static bool mnt_ns_loop(struct dentry *dentry)
1375+
{
1376+
/* Could bind mounting the mount namespace inode cause a
1377+
* mount namespace loop?
1378+
*/
1379+
struct mnt_namespace *mnt_ns;
1380+
if (!is_mnt_ns_file(dentry))
1381+
return false;
1382+
1383+
mnt_ns = get_proc_ns(dentry->d_inode)->ns;
13691384
return current->nsproxy->mnt_ns->seq >= mnt_ns->seq;
13701385
}
13711386

@@ -1374,13 +1389,17 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
13741389
{
13751390
struct mount *res, *p, *q, *r, *parent;
13761391

1377-
if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(mnt))
1392+
if (!(flag & CL_COPY_UNBINDABLE) && IS_MNT_UNBINDABLE(mnt))
1393+
return ERR_PTR(-EINVAL);
1394+
1395+
if (!(flag & CL_COPY_MNT_NS_FILE) && is_mnt_ns_file(dentry))
13781396
return ERR_PTR(-EINVAL);
13791397

13801398
res = q = clone_mnt(mnt, dentry, flag);
13811399
if (IS_ERR(q))
13821400
return q;
13831401

1402+
q->mnt.mnt_flags &= ~MNT_LOCKED;
13841403
q->mnt_mountpoint = mnt->mnt_mountpoint;
13851404

13861405
p = mnt;
@@ -1390,7 +1409,13 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
13901409
continue;
13911410

13921411
for (s = r; s; s = next_mnt(s, r)) {
1393-
if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(s)) {
1412+
if (!(flag & CL_COPY_UNBINDABLE) &&
1413+
IS_MNT_UNBINDABLE(s)) {
1414+
s = skip_mnt_tree(s);
1415+
continue;
1416+
}
1417+
if (!(flag & CL_COPY_MNT_NS_FILE) &&
1418+
is_mnt_ns_file(s->mnt.mnt_root)) {
13941419
s = skip_mnt_tree(s);
13951420
continue;
13961421
}
@@ -1696,6 +1721,19 @@ static int do_change_type(struct path *path, int flag)
16961721
return err;
16971722
}
16981723

1724+
static bool has_locked_children(struct mount *mnt, struct dentry *dentry)
1725+
{
1726+
struct mount *child;
1727+
list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) {
1728+
if (!is_subdir(child->mnt_mountpoint, dentry))
1729+
continue;
1730+
1731+
if (child->mnt.mnt_flags & MNT_LOCKED)
1732+
return true;
1733+
}
1734+
return false;
1735+
}
1736+
16991737
/*
17001738
* do loopback mount.
17011739
*/
@@ -1713,7 +1751,7 @@ static int do_loopback(struct path *path, const char *old_name,
17131751
return err;
17141752

17151753
err = -EINVAL;
1716-
if (mnt_ns_loop(&old_path))
1754+
if (mnt_ns_loop(old_path.dentry))
17171755
goto out;
17181756

17191757
mp = lock_mount(path);
@@ -1731,8 +1769,11 @@ static int do_loopback(struct path *path, const char *old_name,
17311769
if (!check_mnt(parent) || !check_mnt(old))
17321770
goto out2;
17331771

1772+
if (!recurse && has_locked_children(old, old_path.dentry))
1773+
goto out2;
1774+
17341775
if (recurse)
1735-
mnt = copy_tree(old, old_path.dentry, 0);
1776+
mnt = copy_tree(old, old_path.dentry, CL_COPY_MNT_NS_FILE);
17361777
else
17371778
mnt = clone_mnt(old, old_path.dentry, 0);
17381779

@@ -1741,6 +1782,8 @@ static int do_loopback(struct path *path, const char *old_name,
17411782
goto out2;
17421783
}
17431784

1785+
mnt->mnt.mnt_flags &= ~MNT_LOCKED;
1786+
17441787
err = graft_tree(mnt, parent, mp);
17451788
if (err) {
17461789
br_write_lock(&vfsmount_lock);
@@ -1853,6 +1896,9 @@ static int do_move_mount(struct path *path, const char *old_name)
18531896
if (!check_mnt(p) || !check_mnt(old))
18541897
goto out1;
18551898

1899+
if (old->mnt.mnt_flags & MNT_LOCKED)
1900+
goto out1;
1901+
18561902
err = -EINVAL;
18571903
if (old_path.dentry != old_path.mnt->mnt_root)
18581904
goto out1;
@@ -2389,7 +2435,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
23892435

23902436
namespace_lock();
23912437
/* First pass: copy the tree topology */
2392-
copy_flags = CL_COPY_ALL | CL_EXPIRE;
2438+
copy_flags = CL_COPY_UNBINDABLE | CL_EXPIRE;
23932439
if (user_ns != mnt_ns->user_ns)
23942440
copy_flags |= CL_SHARED_TO_SLAVE | CL_UNPRIVILEGED;
23952441
new = copy_tree(old, old->mnt.mnt_root, copy_flags);
@@ -2424,6 +2470,10 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
24242470
}
24252471
p = next_mnt(p, old);
24262472
q = next_mnt(q, new);
2473+
if (!q)
2474+
break;
2475+
while (p->mnt.mnt_root != q->mnt.mnt_root)
2476+
p = next_mnt(p, old);
24272477
}
24282478
namespace_unlock();
24292479

@@ -2630,6 +2680,8 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
26302680
goto out4;
26312681
if (!check_mnt(root_mnt) || !check_mnt(new_mnt))
26322682
goto out4;
2683+
if (new_mnt->mnt.mnt_flags & MNT_LOCKED)
2684+
goto out4;
26332685
error = -ENOENT;
26342686
if (d_unlinked(new.dentry))
26352687
goto out4;
@@ -2653,6 +2705,10 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
26532705
br_write_lock(&vfsmount_lock);
26542706
detach_mnt(new_mnt, &parent_path);
26552707
detach_mnt(root_mnt, &root_parent);
2708+
if (root_mnt->mnt.mnt_flags & MNT_LOCKED) {
2709+
new_mnt->mnt.mnt_flags |= MNT_LOCKED;
2710+
root_mnt->mnt.mnt_flags &= ~MNT_LOCKED;
2711+
}
26562712
/* mount old root on put_old */
26572713
attach_mnt(root_mnt, old_mnt, old_mp);
26582714
/* mount new_root on / */
@@ -2811,25 +2867,38 @@ bool current_chrooted(void)
28112867
return chrooted;
28122868
}
28132869

2814-
void update_mnt_policy(struct user_namespace *userns)
2870+
bool fs_fully_visible(struct file_system_type *type)
28152871
{
28162872
struct mnt_namespace *ns = current->nsproxy->mnt_ns;
28172873
struct mount *mnt;
2874+
bool visible = false;
28182875

2819-
down_read(&namespace_sem);
2876+
if (unlikely(!ns))
2877+
return false;
2878+
2879+
namespace_lock();
28202880
list_for_each_entry(mnt, &ns->list, mnt_list) {
2821-
switch (mnt->mnt.mnt_sb->s_magic) {
2822-
case SYSFS_MAGIC:
2823-
userns->may_mount_sysfs = true;
2824-
break;
2825-
case PROC_SUPER_MAGIC:
2826-
userns->may_mount_proc = true;
2827-
break;
2881+
struct mount *child;
2882+
if (mnt->mnt.mnt_sb->s_type != type)
2883+
continue;
2884+
2885+
/* This mount is not fully visible if there are any child mounts
2886+
* that cover anything except for empty directories.
2887+
*/
2888+
list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) {
2889+
struct inode *inode = child->mnt_mountpoint->d_inode;
2890+
if (!S_ISDIR(inode->i_mode))
2891+
goto next;
2892+
if (inode->i_nlink != 2)
2893+
goto next;
28282894
}
2829-
if (userns->may_mount_sysfs && userns->may_mount_proc)
2830-
break;
2895+
visible = true;
2896+
goto found;
2897+
next: ;
28312898
}
2832-
up_read(&namespace_sem);
2899+
found:
2900+
namespace_unlock();
2901+
return visible;
28332902
}
28342903

28352904
static void *mntns_get(struct task_struct *task)
@@ -2860,8 +2929,8 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns)
28602929
struct path root;
28612930

28622931
if (!ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN) ||
2863-
!nsown_capable(CAP_SYS_CHROOT) ||
2864-
!nsown_capable(CAP_SYS_ADMIN))
2932+
!ns_capable(current_user_ns(), CAP_SYS_CHROOT) ||
2933+
!ns_capable(current_user_ns(), CAP_SYS_ADMIN))
28652934
return -EPERM;
28662935

28672936
if (fs->users != 1)

fs/open.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
443443
goto dput_and_out;
444444

445445
error = -EPERM;
446-
if (!nsown_capable(CAP_SYS_CHROOT))
446+
if (!ns_capable(current_user_ns(), CAP_SYS_CHROOT))
447447
goto dput_and_out;
448448
error = security_path_chroot(&path);
449449
if (error)

fs/pnode.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,14 @@
1919

2020
#define CL_EXPIRE 0x01
2121
#define CL_SLAVE 0x02
22-
#define CL_COPY_ALL 0x04
22+
#define CL_COPY_UNBINDABLE 0x04
2323
#define CL_MAKE_SHARED 0x08
2424
#define CL_PRIVATE 0x10
2525
#define CL_SHARED_TO_SLAVE 0x20
2626
#define CL_UNPRIVILEGED 0x40
27+
#define CL_COPY_MNT_NS_FILE 0x80
28+
29+
#define CL_COPY_ALL (CL_COPY_UNBINDABLE | CL_COPY_MNT_NS_FILE)
2730

2831
static inline void set_mnt_shared(struct mount *mnt)
2932
{

fs/proc/root.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,11 @@ static struct dentry *proc_mount(struct file_system_type *fs_type,
110110
ns = task_active_pid_ns(current);
111111
options = data;
112112

113-
if (!current_user_ns()->may_mount_proc)
113+
if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type))
114+
return ERR_PTR(-EPERM);
115+
116+
/* Does the mounter have privilege over the pid namespace? */
117+
if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
114118
return ERR_PTR(-EPERM);
115119
}
116120

fs/sysfs/mount.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,15 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
112112
struct super_block *sb;
113113
int error;
114114

115-
if (!(flags & MS_KERNMOUNT) && !current_user_ns()->may_mount_sysfs)
116-
return ERR_PTR(-EPERM);
115+
if (!(flags & MS_KERNMOUNT)) {
116+
if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type))
117+
return ERR_PTR(-EPERM);
118+
119+
for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) {
120+
if (!kobj_ns_current_may_mount(type))
121+
return ERR_PTR(-EPERM);
122+
}
123+
}
117124

118125
info = kzalloc(sizeof(*info), GFP_KERNEL);
119126
if (!info)

include/linux/capability.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,6 @@ extern bool has_ns_capability_noaudit(struct task_struct *t,
210210
struct user_namespace *ns, int cap);
211211
extern bool capable(int cap);
212212
extern bool ns_capable(struct user_namespace *ns, int cap);
213-
extern bool nsown_capable(int cap);
214213
extern bool inode_capable(const struct inode *inode, int cap);
215214
extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap);
216215

include/linux/fs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,6 +1900,7 @@ extern int vfs_ustat(dev_t, struct kstatfs *);
19001900
extern int freeze_super(struct super_block *super);
19011901
extern int thaw_super(struct super_block *super);
19021902
extern bool our_mnt(struct vfsmount *mnt);
1903+
extern bool fs_fully_visible(struct file_system_type *);
19031904

19041905
extern int current_umask(void);
19051906

include/linux/kobject_ns.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ enum kobj_ns_type {
3939
*/
4040
struct kobj_ns_type_operations {
4141
enum kobj_ns_type type;
42+
bool (*current_may_mount)(void);
4243
void *(*grab_current_ns)(void);
4344
const void *(*netlink_ns)(struct sock *sk);
4445
const void *(*initial_ns)(void);
@@ -50,6 +51,7 @@ int kobj_ns_type_registered(enum kobj_ns_type type);
5051
const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent);
5152
const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj);
5253

54+
bool kobj_ns_current_may_mount(enum kobj_ns_type type);
5355
void *kobj_ns_grab_current(enum kobj_ns_type type);
5456
const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk);
5557
const void *kobj_ns_initial(enum kobj_ns_type type);

include/linux/mount.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ struct mnt_namespace;
4848
#define MNT_INTERNAL 0x4000
4949

5050
#define MNT_LOCK_READONLY 0x400000
51+
#define MNT_LOCKED 0x800000
5152

5253
struct vfsmount {
5354
struct dentry *mnt_root; /* root of the mounted tree */

include/linux/user_namespace.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ struct user_namespace {
2727
kuid_t owner;
2828
kgid_t group;
2929
unsigned int proc_inum;
30-
bool may_mount_sysfs;
31-
bool may_mount_proc;
3230
};
3331

3432
extern struct user_namespace init_user_ns;
@@ -85,6 +83,4 @@ static inline void put_user_ns(struct user_namespace *ns)
8583

8684
#endif
8785

88-
void update_mnt_policy(struct user_namespace *userns);
89-
9086
#endif /* _LINUX_USER_H */

0 commit comments

Comments
 (0)