Skip to content

Commit 644473e

Browse files
committed
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace
Pull user namespace enhancements from Eric Biederman: "This is a course correction for the user namespace, so that we can reach an inexpensive, maintainable, and reasonably complete implementation. Highlights: - Config guards make it impossible to enable the user namespace and code that has not been converted to be user namespace safe. - Use of the new kuid_t type ensures the if you somehow get past the config guards the kernel will encounter type errors if you enable user namespaces and attempt to compile in code whose permission checks have not been updated to be user namespace safe. - All uids from child user namespaces are mapped into the initial user namespace before they are processed. Removing the need to add an additional check to see if the user namespace of the compared uids remains the same. - With the user namespaces compiled out the performance is as good or better than it is today. - For most operations absolutely nothing changes performance or operationally with the user namespace enabled. - The worst case performance I could come up with was timing 1 billion cache cold stat operations with the user namespace code enabled. This went from 156s to 164s on my laptop (or 156ns to 164ns per stat operation). - (uid_t)-1 and (gid_t)-1 are reserved as an internal error value. Most uid/gid setting system calls treat these value specially anyway so attempting to use -1 as a uid would likely cause entertaining failures in userspace. - If setuid is called with a uid that can not be mapped setuid fails. I have looked at sendmail, login, ssh and every other program I could think of that would call setuid and they all check for and handle the case where setuid fails. - If stat or a similar system call is called from a context in which we can not map a uid we lie and return overflowuid. The LFS experience suggests not lying and returning an error code might be better, but the historical precedent with uids is different and I can not think of anything that would break by lying about a uid we can't map. - Capabilities are localized to the current user namespace making it safe to give the initial user in a user namespace all capabilities. My git tree covers all of the modifications needed to convert the core kernel and enough changes to make a system bootable to runlevel 1." Fix up trivial conflicts due to nearby independent changes in fs/stat.c * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: (46 commits) userns: Silence silly gcc warning. cred: use correct cred accessor with regards to rcu read lock userns: Convert the move_pages, and migrate_pages permission checks to use uid_eq userns: Convert cgroup permission checks to use uid_eq userns: Convert tmpfs to use kuid and kgid where appropriate userns: Convert sysfs to use kgid/kuid where appropriate userns: Convert sysctl permission checks to use kuid and kgids. userns: Convert proc to use kuid/kgid where appropriate userns: Convert ext4 to user kuid/kgid where appropriate userns: Convert ext3 to use kuid/kgid where appropriate userns: Convert ext2 to use kuid/kgid where appropriate. userns: Convert devpts to use kuid/kgid where appropriate userns: Convert binary formats to use kuid/kgid where appropriate userns: Add negative depends on entries to avoid building code that is userns unsafe userns: signal remove unnecessary map_cred_ns userns: Teach inode_capable to understand inodes whose uids map to other namespaces. userns: Fail exec for suid and sgid binaries with ids outside our user namespace. userns: Convert stat to return values mapped from kuids and kgids userns: Convert user specfied uids and gids in chown into kuids and kgid userns: Use uid_eq gid_eq helpers when comparing kuids and kgids in the vfs ...
2 parents fb827ec + 4b06a81 commit 644473e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+1787
-605
lines changed

arch/arm/kernel/sys_oabi-compat.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,8 @@ static long cp_oldabi_stat64(struct kstat *stat,
124124
tmp.__st_ino = stat->ino;
125125
tmp.st_mode = stat->mode;
126126
tmp.st_nlink = stat->nlink;
127-
tmp.st_uid = stat->uid;
128-
tmp.st_gid = stat->gid;
127+
tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid);
128+
tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid);
129129
tmp.st_rdev = huge_encode_dev(stat->rdev);
130130
tmp.st_size = stat->size;
131131
tmp.st_blocks = stat->blocks;

arch/parisc/hpux/fs.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,8 @@ static int cp_hpux_stat(struct kstat *stat, struct hpux_stat64 __user *statbuf)
159159
tmp.st_ino = stat->ino;
160160
tmp.st_mode = stat->mode;
161161
tmp.st_nlink = stat->nlink;
162-
tmp.st_uid = stat->uid;
163-
tmp.st_gid = stat->gid;
162+
tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid);
163+
tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid);
164164
tmp.st_rdev = new_encode_dev(stat->rdev);
165165
tmp.st_size = stat->size;
166166
tmp.st_atime = stat->atime.tv_sec;

arch/s390/kernel/compat_linux.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,14 @@ asmlinkage long sys32_setfsgid16(u16 gid)
173173

174174
static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info)
175175
{
176+
struct user_namespace *user_ns = current_user_ns();
176177
int i;
177178
u16 group;
179+
kgid_t kgid;
178180

179181
for (i = 0; i < group_info->ngroups; i++) {
180-
group = (u16)GROUP_AT(group_info, i);
182+
kgid = GROUP_AT(group_info, i);
183+
group = (u16)from_kgid_munged(user_ns, kgid);
181184
if (put_user(group, grouplist+i))
182185
return -EFAULT;
183186
}
@@ -187,13 +190,20 @@ static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info
187190

188191
static int groups16_from_user(struct group_info *group_info, u16 __user *grouplist)
189192
{
193+
struct user_namespace *user_ns = current_user_ns();
190194
int i;
191195
u16 group;
196+
kgid_t kgid;
192197

193198
for (i = 0; i < group_info->ngroups; i++) {
194199
if (get_user(group, grouplist+i))
195200
return -EFAULT;
196-
GROUP_AT(group_info, i) = (gid_t)group;
201+
202+
kgid = make_kgid(user_ns, (gid_t)group);
203+
if (!gid_valid(kgid))
204+
return -EINVAL;
205+
206+
GROUP_AT(group_info, i) = kgid;
197207
}
198208

199209
return 0;
@@ -537,8 +547,8 @@ static int cp_stat64(struct stat64_emu31 __user *ubuf, struct kstat *stat)
537547
tmp.__st_ino = (u32)stat->ino;
538548
tmp.st_mode = stat->mode;
539549
tmp.st_nlink = (unsigned int)stat->nlink;
540-
tmp.st_uid = stat->uid;
541-
tmp.st_gid = stat->gid;
550+
tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid);
551+
tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid);
542552
tmp.st_rdev = huge_encode_dev(stat->rdev);
543553
tmp.st_size = stat->size;
544554
tmp.st_blksize = (u32)stat->blksize;

arch/sparc/kernel/sys_sparc32.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,8 @@ static int cp_compat_stat64(struct kstat *stat,
139139
err |= put_user(stat->ino, &statbuf->st_ino);
140140
err |= put_user(stat->mode, &statbuf->st_mode);
141141
err |= put_user(stat->nlink, &statbuf->st_nlink);
142-
err |= put_user(stat->uid, &statbuf->st_uid);
143-
err |= put_user(stat->gid, &statbuf->st_gid);
142+
err |= put_user(from_kuid_munged(current_user_ns(), stat->uid), &statbuf->st_uid);
143+
err |= put_user(from_kgid_munged(current_user_ns(), stat->gid), &statbuf->st_gid);
144144
err |= put_user(huge_encode_dev(stat->rdev), &statbuf->st_rdev);
145145
err |= put_user(0, (unsigned long __user *) &statbuf->__pad3[0]);
146146
err |= put_user(stat->size, &statbuf->st_size);

arch/x86/ia32/sys_ia32.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ static int cp_stat64(struct stat64 __user *ubuf, struct kstat *stat)
7171
{
7272
typeof(ubuf->st_uid) uid = 0;
7373
typeof(ubuf->st_gid) gid = 0;
74-
SET_UID(uid, stat->uid);
75-
SET_GID(gid, stat->gid);
74+
SET_UID(uid, from_kuid_munged(current_user_ns(), stat->uid));
75+
SET_GID(gid, from_kgid_munged(current_user_ns(), stat->gid));
7676
if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct stat64)) ||
7777
__put_user(huge_encode_dev(stat->dev), &ubuf->st_dev) ||
7878
__put_user(stat->ino, &ubuf->__st_ino) ||

arch/x86/mm/fault.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,7 @@ show_fault_oops(struct pt_regs *regs, unsigned long error_code,
582582
pte_t *pte = lookup_address(address, &level);
583583

584584
if (pte && pte_present(*pte) && !pte_exec(*pte))
585-
printk(nx_warning, current_uid());
585+
printk(nx_warning, from_kuid(&init_user_ns, current_uid()));
586586
}
587587

588588
printk(KERN_ALERT "BUG: unable to handle kernel ");

fs/attr.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,14 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
4747

4848
/* Make sure a caller can chown. */
4949
if ((ia_valid & ATTR_UID) &&
50-
(current_fsuid() != inode->i_uid ||
51-
attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN))
50+
(!uid_eq(current_fsuid(), inode->i_uid) ||
51+
!uid_eq(attr->ia_uid, inode->i_uid)) && !capable(CAP_CHOWN))
5252
return -EPERM;
5353

5454
/* Make sure caller can chgrp. */
5555
if ((ia_valid & ATTR_GID) &&
56-
(current_fsuid() != inode->i_uid ||
57-
(!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) &&
56+
(!uid_eq(current_fsuid(), inode->i_uid) ||
57+
(!in_group_p(attr->ia_gid) && !gid_eq(attr->ia_gid, inode->i_gid))) &&
5858
!capable(CAP_CHOWN))
5959
return -EPERM;
6060

fs/binfmt_elf.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -226,10 +226,10 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
226226
NEW_AUX_ENT(AT_BASE, interp_load_addr);
227227
NEW_AUX_ENT(AT_FLAGS, 0);
228228
NEW_AUX_ENT(AT_ENTRY, exec->e_entry);
229-
NEW_AUX_ENT(AT_UID, cred->uid);
230-
NEW_AUX_ENT(AT_EUID, cred->euid);
231-
NEW_AUX_ENT(AT_GID, cred->gid);
232-
NEW_AUX_ENT(AT_EGID, cred->egid);
229+
NEW_AUX_ENT(AT_UID, from_kuid_munged(cred->user_ns, cred->uid));
230+
NEW_AUX_ENT(AT_EUID, from_kuid_munged(cred->user_ns, cred->euid));
231+
NEW_AUX_ENT(AT_GID, from_kgid_munged(cred->user_ns, cred->gid));
232+
NEW_AUX_ENT(AT_EGID, from_kgid_munged(cred->user_ns, cred->egid));
233233
NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm));
234234
NEW_AUX_ENT(AT_RANDOM, (elf_addr_t)(unsigned long)u_rand_bytes);
235235
NEW_AUX_ENT(AT_EXECFN, bprm->exec);
@@ -1356,8 +1356,8 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
13561356
psinfo->pr_flag = p->flags;
13571357
rcu_read_lock();
13581358
cred = __task_cred(p);
1359-
SET_UID(psinfo->pr_uid, cred->uid);
1360-
SET_GID(psinfo->pr_gid, cred->gid);
1359+
SET_UID(psinfo->pr_uid, from_kuid_munged(cred->user_ns, cred->uid));
1360+
SET_GID(psinfo->pr_gid, from_kgid_munged(cred->user_ns, cred->gid));
13611361
rcu_read_unlock();
13621362
strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));
13631363

fs/binfmt_elf_fdpic.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -627,10 +627,10 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
627627
NEW_AUX_ENT(AT_BASE, interp_params->elfhdr_addr);
628628
NEW_AUX_ENT(AT_FLAGS, 0);
629629
NEW_AUX_ENT(AT_ENTRY, exec_params->entry_addr);
630-
NEW_AUX_ENT(AT_UID, (elf_addr_t) cred->uid);
631-
NEW_AUX_ENT(AT_EUID, (elf_addr_t) cred->euid);
632-
NEW_AUX_ENT(AT_GID, (elf_addr_t) cred->gid);
633-
NEW_AUX_ENT(AT_EGID, (elf_addr_t) cred->egid);
630+
NEW_AUX_ENT(AT_UID, (elf_addr_t) from_kuid_munged(cred->user_ns, cred->uid));
631+
NEW_AUX_ENT(AT_EUID, (elf_addr_t) from_kuid_munged(cred->user_ns, cred->euid));
632+
NEW_AUX_ENT(AT_GID, (elf_addr_t) from_kgid_munged(cred->user_ns, cred->gid));
633+
NEW_AUX_ENT(AT_EGID, (elf_addr_t) from_kgid_munged(cred->user_ns, cred->egid));
634634
NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm));
635635
NEW_AUX_ENT(AT_EXECFN, bprm->exec);
636636

@@ -1421,8 +1421,8 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
14211421
psinfo->pr_flag = p->flags;
14221422
rcu_read_lock();
14231423
cred = __task_cred(p);
1424-
SET_UID(psinfo->pr_uid, cred->uid);
1425-
SET_GID(psinfo->pr_gid, cred->gid);
1424+
SET_UID(psinfo->pr_uid, from_kuid_munged(cred->user_ns, cred->uid));
1425+
SET_GID(psinfo->pr_gid, from_kgid_munged(cred->user_ns, cred->gid));
14261426
rcu_read_unlock();
14271427
strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));
14281428

fs/compat.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,8 @@ static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
144144
tmp.st_nlink = stat->nlink;
145145
if (tmp.st_nlink != stat->nlink)
146146
return -EOVERFLOW;
147-
SET_UID(tmp.st_uid, stat->uid);
148-
SET_GID(tmp.st_gid, stat->gid);
147+
SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid));
148+
SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid));
149149
tmp.st_rdev = old_encode_dev(stat->rdev);
150150
if ((u64) stat->size > MAX_NON_LFS)
151151
return -EOVERFLOW;

0 commit comments

Comments
 (0)