diff options
85 files changed, 1787 insertions, 605 deletions
diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c index af0aaebf4de6..3e94811690ce 100644 --- a/arch/arm/kernel/sys_oabi-compat.c +++ b/arch/arm/kernel/sys_oabi-compat.c | |||
| @@ -124,8 +124,8 @@ static long cp_oldabi_stat64(struct kstat *stat, | |||
| 124 | tmp.__st_ino = stat->ino; | 124 | tmp.__st_ino = stat->ino; |
| 125 | tmp.st_mode = stat->mode; | 125 | tmp.st_mode = stat->mode; |
| 126 | tmp.st_nlink = stat->nlink; | 126 | tmp.st_nlink = stat->nlink; |
| 127 | tmp.st_uid = stat->uid; | 127 | tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid); |
| 128 | tmp.st_gid = stat->gid; | 128 | tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid); |
| 129 | tmp.st_rdev = huge_encode_dev(stat->rdev); | 129 | tmp.st_rdev = huge_encode_dev(stat->rdev); |
| 130 | tmp.st_size = stat->size; | 130 | tmp.st_size = stat->size; |
| 131 | tmp.st_blocks = stat->blocks; | 131 | tmp.st_blocks = stat->blocks; |
diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c index 0dc8543acb4f..c71eb6c79897 100644 --- a/arch/parisc/hpux/fs.c +++ b/arch/parisc/hpux/fs.c | |||
| @@ -159,8 +159,8 @@ static int cp_hpux_stat(struct kstat *stat, struct hpux_stat64 __user *statbuf) | |||
| 159 | tmp.st_ino = stat->ino; | 159 | tmp.st_ino = stat->ino; |
| 160 | tmp.st_mode = stat->mode; | 160 | tmp.st_mode = stat->mode; |
| 161 | tmp.st_nlink = stat->nlink; | 161 | tmp.st_nlink = stat->nlink; |
| 162 | tmp.st_uid = stat->uid; | 162 | tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid); |
| 163 | tmp.st_gid = stat->gid; | 163 | tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid); |
| 164 | tmp.st_rdev = new_encode_dev(stat->rdev); | 164 | tmp.st_rdev = new_encode_dev(stat->rdev); |
| 165 | tmp.st_size = stat->size; | 165 | tmp.st_size = stat->size; |
| 166 | tmp.st_atime = stat->atime.tv_sec; | 166 | tmp.st_atime = stat->atime.tv_sec; |
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index ab64bdbab2ae..65426525d9f2 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c | |||
| @@ -173,11 +173,14 @@ asmlinkage long sys32_setfsgid16(u16 gid) | |||
| 173 | 173 | ||
| 174 | static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info) | 174 | static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info) |
| 175 | { | 175 | { |
| 176 | struct user_namespace *user_ns = current_user_ns(); | ||
| 176 | int i; | 177 | int i; |
| 177 | u16 group; | 178 | u16 group; |
| 179 | kgid_t kgid; | ||
| 178 | 180 | ||
| 179 | for (i = 0; i < group_info->ngroups; i++) { | 181 | 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); | ||
| 181 | if (put_user(group, grouplist+i)) | 184 | if (put_user(group, grouplist+i)) |
| 182 | return -EFAULT; | 185 | return -EFAULT; |
| 183 | } | 186 | } |
| @@ -187,13 +190,20 @@ static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info | |||
| 187 | 190 | ||
| 188 | static int groups16_from_user(struct group_info *group_info, u16 __user *grouplist) | 191 | static int groups16_from_user(struct group_info *group_info, u16 __user *grouplist) |
| 189 | { | 192 | { |
| 193 | struct user_namespace *user_ns = current_user_ns(); | ||
| 190 | int i; | 194 | int i; |
| 191 | u16 group; | 195 | u16 group; |
| 196 | kgid_t kgid; | ||
| 192 | 197 | ||
| 193 | for (i = 0; i < group_info->ngroups; i++) { | 198 | for (i = 0; i < group_info->ngroups; i++) { |
| 194 | if (get_user(group, grouplist+i)) | 199 | if (get_user(group, grouplist+i)) |
| 195 | return -EFAULT; | 200 | 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; | ||
| 197 | } | 207 | } |
| 198 | 208 | ||
| 199 | return 0; | 209 | return 0; |
| @@ -537,8 +547,8 @@ static int cp_stat64(struct stat64_emu31 __user *ubuf, struct kstat *stat) | |||
| 537 | tmp.__st_ino = (u32)stat->ino; | 547 | tmp.__st_ino = (u32)stat->ino; |
| 538 | tmp.st_mode = stat->mode; | 548 | tmp.st_mode = stat->mode; |
| 539 | tmp.st_nlink = (unsigned int)stat->nlink; | 549 | tmp.st_nlink = (unsigned int)stat->nlink; |
| 540 | tmp.st_uid = stat->uid; | 550 | tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid); |
| 541 | tmp.st_gid = stat->gid; | 551 | tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid); |
| 542 | tmp.st_rdev = huge_encode_dev(stat->rdev); | 552 | tmp.st_rdev = huge_encode_dev(stat->rdev); |
| 543 | tmp.st_size = stat->size; | 553 | tmp.st_size = stat->size; |
| 544 | tmp.st_blksize = (u32)stat->blksize; | 554 | tmp.st_blksize = (u32)stat->blksize; |
diff --git a/arch/sparc/kernel/sys_sparc32.c b/arch/sparc/kernel/sys_sparc32.c index 29c478ffed91..f7392336961f 100644 --- a/arch/sparc/kernel/sys_sparc32.c +++ b/arch/sparc/kernel/sys_sparc32.c | |||
| @@ -139,8 +139,8 @@ static int cp_compat_stat64(struct kstat *stat, | |||
| 139 | err |= put_user(stat->ino, &statbuf->st_ino); | 139 | err |= put_user(stat->ino, &statbuf->st_ino); |
| 140 | err |= put_user(stat->mode, &statbuf->st_mode); | 140 | err |= put_user(stat->mode, &statbuf->st_mode); |
| 141 | err |= put_user(stat->nlink, &statbuf->st_nlink); | 141 | err |= put_user(stat->nlink, &statbuf->st_nlink); |
| 142 | err |= put_user(stat->uid, &statbuf->st_uid); | 142 | err |= put_user(from_kuid_munged(current_user_ns(), stat->uid), &statbuf->st_uid); |
| 143 | err |= put_user(stat->gid, &statbuf->st_gid); | 143 | err |= put_user(from_kgid_munged(current_user_ns(), stat->gid), &statbuf->st_gid); |
| 144 | err |= put_user(huge_encode_dev(stat->rdev), &statbuf->st_rdev); | 144 | err |= put_user(huge_encode_dev(stat->rdev), &statbuf->st_rdev); |
| 145 | err |= put_user(0, (unsigned long __user *) &statbuf->__pad3[0]); | 145 | err |= put_user(0, (unsigned long __user *) &statbuf->__pad3[0]); |
| 146 | err |= put_user(stat->size, &statbuf->st_size); | 146 | err |= put_user(stat->size, &statbuf->st_size); |
diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c index edca9c0a79cc..4540bece0946 100644 --- a/arch/x86/ia32/sys_ia32.c +++ b/arch/x86/ia32/sys_ia32.c | |||
| @@ -71,8 +71,8 @@ static int cp_stat64(struct stat64 __user *ubuf, struct kstat *stat) | |||
| 71 | { | 71 | { |
| 72 | typeof(ubuf->st_uid) uid = 0; | 72 | typeof(ubuf->st_uid) uid = 0; |
| 73 | typeof(ubuf->st_gid) gid = 0; | 73 | typeof(ubuf->st_gid) gid = 0; |
| 74 | SET_UID(uid, stat->uid); | 74 | SET_UID(uid, from_kuid_munged(current_user_ns(), stat->uid)); |
| 75 | SET_GID(gid, stat->gid); | 75 | SET_GID(gid, from_kgid_munged(current_user_ns(), stat->gid)); |
| 76 | if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct stat64)) || | 76 | if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct stat64)) || |
| 77 | __put_user(huge_encode_dev(stat->dev), &ubuf->st_dev) || | 77 | __put_user(huge_encode_dev(stat->dev), &ubuf->st_dev) || |
| 78 | __put_user(stat->ino, &ubuf->__st_ino) || | 78 | __put_user(stat->ino, &ubuf->__st_ino) || |
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 3ecfd1aaf214..76dcd9d8e0bc 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c | |||
| @@ -582,7 +582,7 @@ show_fault_oops(struct pt_regs *regs, unsigned long error_code, | |||
| 582 | pte_t *pte = lookup_address(address, &level); | 582 | pte_t *pte = lookup_address(address, &level); |
| 583 | 583 | ||
| 584 | if (pte && pte_present(*pte) && !pte_exec(*pte)) | 584 | 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())); |
| 586 | } | 586 | } |
| 587 | 587 | ||
| 588 | printk(KERN_ALERT "BUG: unable to handle kernel "); | 588 | printk(KERN_ALERT "BUG: unable to handle kernel "); |
| @@ -47,14 +47,14 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr) | |||
| 47 | 47 | ||
| 48 | /* Make sure a caller can chown. */ | 48 | /* Make sure a caller can chown. */ |
| 49 | if ((ia_valid & ATTR_UID) && | 49 | if ((ia_valid & ATTR_UID) && |
| 50 | (current_fsuid() != inode->i_uid || | 50 | (!uid_eq(current_fsuid(), inode->i_uid) || |
| 51 | attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN)) | 51 | !uid_eq(attr->ia_uid, inode->i_uid)) && !capable(CAP_CHOWN)) |
| 52 | return -EPERM; | 52 | return -EPERM; |
| 53 | 53 | ||
| 54 | /* Make sure caller can chgrp. */ | 54 | /* Make sure caller can chgrp. */ |
| 55 | if ((ia_valid & ATTR_GID) && | 55 | if ((ia_valid & ATTR_GID) && |
| 56 | (current_fsuid() != inode->i_uid || | 56 | (!uid_eq(current_fsuid(), inode->i_uid) || |
| 57 | (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) && | 57 | (!in_group_p(attr->ia_gid) && !gid_eq(attr->ia_gid, inode->i_gid))) && |
| 58 | !capable(CAP_CHOWN)) | 58 | !capable(CAP_CHOWN)) |
| 59 | return -EPERM; | 59 | return -EPERM; |
| 60 | 60 | ||
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 16f735417072..e658dd134b95 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
| @@ -226,10 +226,10 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, | |||
| 226 | NEW_AUX_ENT(AT_BASE, interp_load_addr); | 226 | NEW_AUX_ENT(AT_BASE, interp_load_addr); |
| 227 | NEW_AUX_ENT(AT_FLAGS, 0); | 227 | NEW_AUX_ENT(AT_FLAGS, 0); |
| 228 | NEW_AUX_ENT(AT_ENTRY, exec->e_entry); | 228 | NEW_AUX_ENT(AT_ENTRY, exec->e_entry); |
| 229 | NEW_AUX_ENT(AT_UID, cred->uid); | 229 | NEW_AUX_ENT(AT_UID, from_kuid_munged(cred->user_ns, cred->uid)); |
| 230 | NEW_AUX_ENT(AT_EUID, cred->euid); | 230 | NEW_AUX_ENT(AT_EUID, from_kuid_munged(cred->user_ns, cred->euid)); |
| 231 | NEW_AUX_ENT(AT_GID, cred->gid); | 231 | NEW_AUX_ENT(AT_GID, from_kgid_munged(cred->user_ns, cred->gid)); |
| 232 | NEW_AUX_ENT(AT_EGID, cred->egid); | 232 | NEW_AUX_ENT(AT_EGID, from_kgid_munged(cred->user_ns, cred->egid)); |
| 233 | NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm)); | 233 | NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm)); |
| 234 | NEW_AUX_ENT(AT_RANDOM, (elf_addr_t)(unsigned long)u_rand_bytes); | 234 | NEW_AUX_ENT(AT_RANDOM, (elf_addr_t)(unsigned long)u_rand_bytes); |
| 235 | NEW_AUX_ENT(AT_EXECFN, bprm->exec); | 235 | NEW_AUX_ENT(AT_EXECFN, bprm->exec); |
| @@ -1356,8 +1356,8 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, | |||
| 1356 | psinfo->pr_flag = p->flags; | 1356 | psinfo->pr_flag = p->flags; |
| 1357 | rcu_read_lock(); | 1357 | rcu_read_lock(); |
| 1358 | cred = __task_cred(p); | 1358 | cred = __task_cred(p); |
| 1359 | SET_UID(psinfo->pr_uid, cred->uid); | 1359 | SET_UID(psinfo->pr_uid, from_kuid_munged(cred->user_ns, cred->uid)); |
| 1360 | SET_GID(psinfo->pr_gid, cred->gid); | 1360 | SET_GID(psinfo->pr_gid, from_kgid_munged(cred->user_ns, cred->gid)); |
| 1361 | rcu_read_unlock(); | 1361 | rcu_read_unlock(); |
| 1362 | strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname)); | 1362 | strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname)); |
| 1363 | 1363 | ||
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index d390a0fffc65..3d77cf81ba3c 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c | |||
| @@ -627,10 +627,10 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm, | |||
| 627 | NEW_AUX_ENT(AT_BASE, interp_params->elfhdr_addr); | 627 | NEW_AUX_ENT(AT_BASE, interp_params->elfhdr_addr); |
| 628 | NEW_AUX_ENT(AT_FLAGS, 0); | 628 | NEW_AUX_ENT(AT_FLAGS, 0); |
| 629 | NEW_AUX_ENT(AT_ENTRY, exec_params->entry_addr); | 629 | NEW_AUX_ENT(AT_ENTRY, exec_params->entry_addr); |
| 630 | NEW_AUX_ENT(AT_UID, (elf_addr_t) cred->uid); | 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) cred->euid); | 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) cred->gid); | 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) cred->egid); | 633 | NEW_AUX_ENT(AT_EGID, (elf_addr_t) from_kgid_munged(cred->user_ns, cred->egid)); |
| 634 | NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm)); | 634 | NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm)); |
| 635 | NEW_AUX_ENT(AT_EXECFN, bprm->exec); | 635 | NEW_AUX_ENT(AT_EXECFN, bprm->exec); |
| 636 | 636 | ||
| @@ -1421,8 +1421,8 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, | |||
| 1421 | psinfo->pr_flag = p->flags; | 1421 | psinfo->pr_flag = p->flags; |
| 1422 | rcu_read_lock(); | 1422 | rcu_read_lock(); |
| 1423 | cred = __task_cred(p); | 1423 | cred = __task_cred(p); |
| 1424 | SET_UID(psinfo->pr_uid, cred->uid); | 1424 | SET_UID(psinfo->pr_uid, from_kuid_munged(cred->user_ns, cred->uid)); |
| 1425 | SET_GID(psinfo->pr_gid, cred->gid); | 1425 | SET_GID(psinfo->pr_gid, from_kgid_munged(cred->user_ns, cred->gid)); |
| 1426 | rcu_read_unlock(); | 1426 | rcu_read_unlock(); |
| 1427 | strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname)); | 1427 | strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname)); |
| 1428 | 1428 | ||
diff --git a/fs/compat.c b/fs/compat.c index f2944ace7a7b..0781e619a62a 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
| @@ -144,8 +144,8 @@ static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf) | |||
| 144 | tmp.st_nlink = stat->nlink; | 144 | tmp.st_nlink = stat->nlink; |
| 145 | if (tmp.st_nlink != stat->nlink) | 145 | if (tmp.st_nlink != stat->nlink) |
| 146 | return -EOVERFLOW; | 146 | return -EOVERFLOW; |
| 147 | SET_UID(tmp.st_uid, stat->uid); | 147 | SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid)); |
| 148 | SET_GID(tmp.st_gid, stat->gid); | 148 | SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid)); |
| 149 | tmp.st_rdev = old_encode_dev(stat->rdev); | 149 | tmp.st_rdev = old_encode_dev(stat->rdev); |
| 150 | if ((u64) stat->size > MAX_NON_LFS) | 150 | if ((u64) stat->size > MAX_NON_LFS) |
| 151 | return -EOVERFLOW; | 151 | return -EOVERFLOW; |
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 10f5e0b484db..979c1e309c73 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c | |||
| @@ -98,8 +98,8 @@ static struct vfsmount *devpts_mnt; | |||
| 98 | struct pts_mount_opts { | 98 | struct pts_mount_opts { |
| 99 | int setuid; | 99 | int setuid; |
| 100 | int setgid; | 100 | int setgid; |
| 101 | uid_t uid; | 101 | kuid_t uid; |
| 102 | gid_t gid; | 102 | kgid_t gid; |
| 103 | umode_t mode; | 103 | umode_t mode; |
| 104 | umode_t ptmxmode; | 104 | umode_t ptmxmode; |
| 105 | int newinstance; | 105 | int newinstance; |
| @@ -158,11 +158,13 @@ static inline struct super_block *pts_sb_from_inode(struct inode *inode) | |||
| 158 | static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts) | 158 | static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts) |
| 159 | { | 159 | { |
| 160 | char *p; | 160 | char *p; |
| 161 | kuid_t uid; | ||
| 162 | kgid_t gid; | ||
| 161 | 163 | ||
| 162 | opts->setuid = 0; | 164 | opts->setuid = 0; |
| 163 | opts->setgid = 0; | 165 | opts->setgid = 0; |
| 164 | opts->uid = 0; | 166 | opts->uid = GLOBAL_ROOT_UID; |
| 165 | opts->gid = 0; | 167 | opts->gid = GLOBAL_ROOT_GID; |
| 166 | opts->mode = DEVPTS_DEFAULT_MODE; | 168 | opts->mode = DEVPTS_DEFAULT_MODE; |
| 167 | opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE; | 169 | opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE; |
| 168 | opts->max = NR_UNIX98_PTY_MAX; | 170 | opts->max = NR_UNIX98_PTY_MAX; |
| @@ -184,13 +186,19 @@ static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts) | |||
| 184 | case Opt_uid: | 186 | case Opt_uid: |
| 185 | if (match_int(&args[0], &option)) | 187 | if (match_int(&args[0], &option)) |
| 186 | return -EINVAL; | 188 | return -EINVAL; |
| 187 | opts->uid = option; | 189 | uid = make_kuid(current_user_ns(), option); |
| 190 | if (!uid_valid(uid)) | ||
| 191 | return -EINVAL; | ||
| 192 | opts->uid = uid; | ||
| 188 | opts->setuid = 1; | 193 | opts->setuid = 1; |
| 189 | break; | 194 | break; |
| 190 | case Opt_gid: | 195 | case Opt_gid: |
| 191 | if (match_int(&args[0], &option)) | 196 | if (match_int(&args[0], &option)) |
| 192 | return -EINVAL; | 197 | return -EINVAL; |
| 193 | opts->gid = option; | 198 | gid = make_kgid(current_user_ns(), option); |
| 199 | if (!gid_valid(gid)) | ||
| 200 | return -EINVAL; | ||
| 201 | opts->gid = gid; | ||
| 194 | opts->setgid = 1; | 202 | opts->setgid = 1; |
| 195 | break; | 203 | break; |
| 196 | case Opt_mode: | 204 | case Opt_mode: |
| @@ -315,9 +323,9 @@ static int devpts_show_options(struct seq_file *seq, struct dentry *root) | |||
| 315 | struct pts_mount_opts *opts = &fsi->mount_opts; | 323 | struct pts_mount_opts *opts = &fsi->mount_opts; |
| 316 | 324 | ||
| 317 | if (opts->setuid) | 325 | if (opts->setuid) |
| 318 | seq_printf(seq, ",uid=%u", opts->uid); | 326 | seq_printf(seq, ",uid=%u", from_kuid_munged(&init_user_ns, opts->uid)); |
| 319 | if (opts->setgid) | 327 | if (opts->setgid) |
| 320 | seq_printf(seq, ",gid=%u", opts->gid); | 328 | seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, opts->gid)); |
| 321 | seq_printf(seq, ",mode=%03o", opts->mode); | 329 | seq_printf(seq, ",mode=%03o", opts->mode); |
| 322 | #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES | 330 | #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES |
| 323 | seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode); | 331 | seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode); |
diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c index ab2248090515..a750f957b145 100644 --- a/fs/ecryptfs/messaging.c +++ b/fs/ecryptfs/messaging.c | |||
| @@ -303,7 +303,7 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid, | |||
| 303 | mutex_unlock(&ecryptfs_daemon_hash_mux); | 303 | mutex_unlock(&ecryptfs_daemon_hash_mux); |
| 304 | goto wake_up; | 304 | goto wake_up; |
| 305 | } | 305 | } |
| 306 | tsk_user_ns = __task_cred(msg_ctx->task)->user->user_ns; | 306 | tsk_user_ns = __task_cred(msg_ctx->task)->user_ns; |
| 307 | ctx_euid = task_euid(msg_ctx->task); | 307 | ctx_euid = task_euid(msg_ctx->task); |
| 308 | rc = ecryptfs_find_daemon_by_euid(&daemon, ctx_euid, tsk_user_ns); | 308 | rc = ecryptfs_find_daemon_by_euid(&daemon, ctx_euid, tsk_user_ns); |
| 309 | rcu_read_unlock(); | 309 | rcu_read_unlock(); |
| @@ -1139,7 +1139,7 @@ void setup_new_exec(struct linux_binprm * bprm) | |||
| 1139 | /* This is the point of no return */ | 1139 | /* This is the point of no return */ |
| 1140 | current->sas_ss_sp = current->sas_ss_size = 0; | 1140 | current->sas_ss_sp = current->sas_ss_size = 0; |
| 1141 | 1141 | ||
| 1142 | if (current_euid() == current_uid() && current_egid() == current_gid()) | 1142 | if (uid_eq(current_euid(), current_uid()) && gid_eq(current_egid(), current_gid())) |
| 1143 | set_dumpable(current->mm, 1); | 1143 | set_dumpable(current->mm, 1); |
| 1144 | else | 1144 | else |
| 1145 | set_dumpable(current->mm, suid_dumpable); | 1145 | set_dumpable(current->mm, suid_dumpable); |
| @@ -1153,8 +1153,8 @@ void setup_new_exec(struct linux_binprm * bprm) | |||
| 1153 | current->mm->task_size = TASK_SIZE; | 1153 | current->mm->task_size = TASK_SIZE; |
| 1154 | 1154 | ||
| 1155 | /* install the new credentials */ | 1155 | /* install the new credentials */ |
| 1156 | if (bprm->cred->uid != current_euid() || | 1156 | if (!uid_eq(bprm->cred->uid, current_euid()) || |
| 1157 | bprm->cred->gid != current_egid()) { | 1157 | !gid_eq(bprm->cred->gid, current_egid())) { |
| 1158 | current->pdeath_signal = 0; | 1158 | current->pdeath_signal = 0; |
| 1159 | } else { | 1159 | } else { |
| 1160 | would_dump(bprm, bprm->file); | 1160 | would_dump(bprm, bprm->file); |
| @@ -1299,8 +1299,11 @@ int prepare_binprm(struct linux_binprm *bprm) | |||
| 1299 | !current->no_new_privs) { | 1299 | !current->no_new_privs) { |
| 1300 | /* Set-uid? */ | 1300 | /* Set-uid? */ |
| 1301 | if (mode & S_ISUID) { | 1301 | if (mode & S_ISUID) { |
| 1302 | if (!kuid_has_mapping(bprm->cred->user_ns, inode->i_uid)) | ||
| 1303 | return -EPERM; | ||
| 1302 | bprm->per_clear |= PER_CLEAR_ON_SETID; | 1304 | bprm->per_clear |= PER_CLEAR_ON_SETID; |
| 1303 | bprm->cred->euid = inode->i_uid; | 1305 | bprm->cred->euid = inode->i_uid; |
| 1306 | |||
| 1304 | } | 1307 | } |
| 1305 | 1308 | ||
| 1306 | /* Set-gid? */ | 1309 | /* Set-gid? */ |
| @@ -1310,6 +1313,8 @@ int prepare_binprm(struct linux_binprm *bprm) | |||
| 1310 | * executable. | 1313 | * executable. |
| 1311 | */ | 1314 | */ |
| 1312 | if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { | 1315 | if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { |
| 1316 | if (!kgid_has_mapping(bprm->cred->user_ns, inode->i_gid)) | ||
| 1317 | return -EPERM; | ||
| 1313 | bprm->per_clear |= PER_CLEAR_ON_SETID; | 1318 | bprm->per_clear |= PER_CLEAR_ON_SETID; |
| 1314 | bprm->cred->egid = inode->i_gid; | 1319 | bprm->cred->egid = inode->i_gid; |
| 1315 | } | 1320 | } |
| @@ -2142,7 +2147,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
| 2142 | if (__get_dumpable(cprm.mm_flags) == 2) { | 2147 | if (__get_dumpable(cprm.mm_flags) == 2) { |
| 2143 | /* Setuid core dump mode */ | 2148 | /* Setuid core dump mode */ |
| 2144 | flag = O_EXCL; /* Stop rewrite attacks */ | 2149 | flag = O_EXCL; /* Stop rewrite attacks */ |
| 2145 | cred->fsuid = 0; /* Dump root private */ | 2150 | cred->fsuid = GLOBAL_ROOT_UID; /* Dump root private */ |
| 2146 | } | 2151 | } |
| 2147 | 2152 | ||
| 2148 | retval = coredump_wait(exit_code, &core_state); | 2153 | retval = coredump_wait(exit_code, &core_state); |
| @@ -2243,7 +2248,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
| 2243 | * Dont allow local users get cute and trick others to coredump | 2248 | * Dont allow local users get cute and trick others to coredump |
| 2244 | * into their pre-created files. | 2249 | * into their pre-created files. |
| 2245 | */ | 2250 | */ |
| 2246 | if (inode->i_uid != current_fsuid()) | 2251 | if (!uid_eq(inode->i_uid, current_fsuid())) |
| 2247 | goto close_fail; | 2252 | goto close_fail; |
| 2248 | if (!cprm.file->f_op || !cprm.file->f_op->write) | 2253 | if (!cprm.file->f_op || !cprm.file->f_op->write) |
| 2249 | goto close_fail; | 2254 | goto close_fail; |
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index a8cbe1bc6ad4..030c6d277e14 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c | |||
| @@ -1193,8 +1193,9 @@ static int ext2_has_free_blocks(struct ext2_sb_info *sbi) | |||
| 1193 | free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); | 1193 | free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); |
| 1194 | root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count); | 1194 | root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count); |
| 1195 | if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) && | 1195 | if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) && |
| 1196 | sbi->s_resuid != current_fsuid() && | 1196 | !uid_eq(sbi->s_resuid, current_fsuid()) && |
| 1197 | (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) { | 1197 | (gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) || |
| 1198 | !in_group_p (sbi->s_resgid))) { | ||
| 1198 | return 0; | 1199 | return 0; |
| 1199 | } | 1200 | } |
| 1200 | return 1; | 1201 | return 1; |
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 0b2b4db5bdcd..d9a17d0b124d 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h | |||
| @@ -82,8 +82,8 @@ struct ext2_sb_info { | |||
| 82 | struct buffer_head ** s_group_desc; | 82 | struct buffer_head ** s_group_desc; |
| 83 | unsigned long s_mount_opt; | 83 | unsigned long s_mount_opt; |
| 84 | unsigned long s_sb_block; | 84 | unsigned long s_sb_block; |
| 85 | uid_t s_resuid; | 85 | kuid_t s_resuid; |
| 86 | gid_t s_resgid; | 86 | kgid_t s_resgid; |
| 87 | unsigned short s_mount_state; | 87 | unsigned short s_mount_state; |
| 88 | unsigned short s_pad; | 88 | unsigned short s_pad; |
| 89 | int s_addr_per_block_bits; | 89 | int s_addr_per_block_bits; |
| @@ -637,8 +637,8 @@ static inline void verify_offsets(void) | |||
| 637 | */ | 637 | */ |
| 638 | struct ext2_mount_options { | 638 | struct ext2_mount_options { |
| 639 | unsigned long s_mount_opt; | 639 | unsigned long s_mount_opt; |
| 640 | uid_t s_resuid; | 640 | kuid_t s_resuid; |
| 641 | gid_t s_resgid; | 641 | kgid_t s_resgid; |
| 642 | }; | 642 | }; |
| 643 | 643 | ||
| 644 | /* | 644 | /* |
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 740cad8dcd8d..f9fa95f8443d 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c | |||
| @@ -1293,6 +1293,8 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino) | |||
| 1293 | struct inode *inode; | 1293 | struct inode *inode; |
| 1294 | long ret = -EIO; | 1294 | long ret = -EIO; |
| 1295 | int n; | 1295 | int n; |
| 1296 | uid_t i_uid; | ||
| 1297 | gid_t i_gid; | ||
| 1296 | 1298 | ||
| 1297 | inode = iget_locked(sb, ino); | 1299 | inode = iget_locked(sb, ino); |
| 1298 | if (!inode) | 1300 | if (!inode) |
| @@ -1310,12 +1312,14 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino) | |||
| 1310 | } | 1312 | } |
| 1311 | 1313 | ||
| 1312 | inode->i_mode = le16_to_cpu(raw_inode->i_mode); | 1314 | inode->i_mode = le16_to_cpu(raw_inode->i_mode); |
| 1313 | inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); | 1315 | i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); |
| 1314 | inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); | 1316 | i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); |
| 1315 | if (!(test_opt (inode->i_sb, NO_UID32))) { | 1317 | if (!(test_opt (inode->i_sb, NO_UID32))) { |
| 1316 | inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; | 1318 | i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; |
| 1317 | inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; | 1319 | i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; |
| 1318 | } | 1320 | } |
| 1321 | i_uid_write(inode, i_uid); | ||
| 1322 | i_gid_write(inode, i_gid); | ||
| 1319 | set_nlink(inode, le16_to_cpu(raw_inode->i_links_count)); | 1323 | set_nlink(inode, le16_to_cpu(raw_inode->i_links_count)); |
| 1320 | inode->i_size = le32_to_cpu(raw_inode->i_size); | 1324 | inode->i_size = le32_to_cpu(raw_inode->i_size); |
| 1321 | inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime); | 1325 | inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime); |
| @@ -1413,8 +1417,8 @@ static int __ext2_write_inode(struct inode *inode, int do_sync) | |||
| 1413 | struct ext2_inode_info *ei = EXT2_I(inode); | 1417 | struct ext2_inode_info *ei = EXT2_I(inode); |
| 1414 | struct super_block *sb = inode->i_sb; | 1418 | struct super_block *sb = inode->i_sb; |
| 1415 | ino_t ino = inode->i_ino; | 1419 | ino_t ino = inode->i_ino; |
| 1416 | uid_t uid = inode->i_uid; | 1420 | uid_t uid = i_uid_read(inode); |
| 1417 | gid_t gid = inode->i_gid; | 1421 | gid_t gid = i_gid_read(inode); |
| 1418 | struct buffer_head * bh; | 1422 | struct buffer_head * bh; |
| 1419 | struct ext2_inode * raw_inode = ext2_get_inode(sb, ino, &bh); | 1423 | struct ext2_inode * raw_inode = ext2_get_inode(sb, ino, &bh); |
| 1420 | int n; | 1424 | int n; |
| @@ -1529,8 +1533,8 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr) | |||
| 1529 | 1533 | ||
| 1530 | if (is_quota_modification(inode, iattr)) | 1534 | if (is_quota_modification(inode, iattr)) |
| 1531 | dquot_initialize(inode); | 1535 | dquot_initialize(inode); |
| 1532 | if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) || | 1536 | if ((iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) || |
| 1533 | (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) { | 1537 | (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))) { |
| 1534 | error = dquot_transfer(inode, iattr); | 1538 | error = dquot_transfer(inode, iattr); |
| 1535 | if (error) | 1539 | if (error) |
| 1536 | return error; | 1540 | return error; |
diff --git a/fs/ext2/super.c b/fs/ext2/super.c index e1025c7a437a..38f816071ddb 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c | |||
| @@ -228,13 +228,15 @@ static int ext2_show_options(struct seq_file *seq, struct dentry *root) | |||
| 228 | seq_puts(seq, ",grpid"); | 228 | seq_puts(seq, ",grpid"); |
| 229 | if (!test_opt(sb, GRPID) && (def_mount_opts & EXT2_DEFM_BSDGROUPS)) | 229 | if (!test_opt(sb, GRPID) && (def_mount_opts & EXT2_DEFM_BSDGROUPS)) |
| 230 | seq_puts(seq, ",nogrpid"); | 230 | seq_puts(seq, ",nogrpid"); |
| 231 | if (sbi->s_resuid != EXT2_DEF_RESUID || | 231 | if (!uid_eq(sbi->s_resuid, make_kuid(&init_user_ns, EXT2_DEF_RESUID)) || |
| 232 | le16_to_cpu(es->s_def_resuid) != EXT2_DEF_RESUID) { | 232 | le16_to_cpu(es->s_def_resuid) != EXT2_DEF_RESUID) { |
| 233 | seq_printf(seq, ",resuid=%u", sbi->s_resuid); | 233 | seq_printf(seq, ",resuid=%u", |
| 234 | from_kuid_munged(&init_user_ns, sbi->s_resuid)); | ||
| 234 | } | 235 | } |
| 235 | if (sbi->s_resgid != EXT2_DEF_RESGID || | 236 | if (!gid_eq(sbi->s_resgid, make_kgid(&init_user_ns, EXT2_DEF_RESGID)) || |
| 236 | le16_to_cpu(es->s_def_resgid) != EXT2_DEF_RESGID) { | 237 | le16_to_cpu(es->s_def_resgid) != EXT2_DEF_RESGID) { |
| 237 | seq_printf(seq, ",resgid=%u", sbi->s_resgid); | 238 | seq_printf(seq, ",resgid=%u", |
| 239 | from_kgid_munged(&init_user_ns, sbi->s_resgid)); | ||
| 238 | } | 240 | } |
| 239 | if (test_opt(sb, ERRORS_RO)) { | 241 | if (test_opt(sb, ERRORS_RO)) { |
| 240 | int def_errors = le16_to_cpu(es->s_errors); | 242 | int def_errors = le16_to_cpu(es->s_errors); |
| @@ -436,6 +438,8 @@ static int parse_options(char *options, struct super_block *sb) | |||
| 436 | struct ext2_sb_info *sbi = EXT2_SB(sb); | 438 | struct ext2_sb_info *sbi = EXT2_SB(sb); |
| 437 | substring_t args[MAX_OPT_ARGS]; | 439 | substring_t args[MAX_OPT_ARGS]; |
| 438 | int option; | 440 | int option; |
| 441 | kuid_t uid; | ||
| 442 | kgid_t gid; | ||
| 439 | 443 | ||
| 440 | if (!options) | 444 | if (!options) |
| 441 | return 1; | 445 | return 1; |
| @@ -462,12 +466,23 @@ static int parse_options(char *options, struct super_block *sb) | |||
| 462 | case Opt_resuid: | 466 | case Opt_resuid: |
| 463 | if (match_int(&args[0], &option)) | 467 | if (match_int(&args[0], &option)) |
| 464 | return 0; | 468 | return 0; |
| 465 | sbi->s_resuid = option; | 469 | uid = make_kuid(current_user_ns(), option); |
| 470 | if (!uid_valid(uid)) { | ||
| 471 | ext2_msg(sb, KERN_ERR, "Invalid uid value %d", option); | ||
| 472 | return -1; | ||
| 473 | |||
| 474 | } | ||
| 475 | sbi->s_resuid = uid; | ||
| 466 | break; | 476 | break; |
| 467 | case Opt_resgid: | 477 | case Opt_resgid: |
| 468 | if (match_int(&args[0], &option)) | 478 | if (match_int(&args[0], &option)) |
| 469 | return 0; | 479 | return 0; |
| 470 | sbi->s_resgid = option; | 480 | gid = make_kgid(current_user_ns(), option); |
| 481 | if (!gid_valid(gid)) { | ||
| 482 | ext2_msg(sb, KERN_ERR, "Invalid gid value %d", option); | ||
| 483 | return -1; | ||
| 484 | } | ||
| 485 | sbi->s_resgid = gid; | ||
| 471 | break; | 486 | break; |
| 472 | case Opt_sb: | 487 | case Opt_sb: |
| 473 | /* handled by get_sb_block() instead of here */ | 488 | /* handled by get_sb_block() instead of here */ |
| @@ -841,8 +856,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) | |||
| 841 | else | 856 | else |
| 842 | set_opt(sbi->s_mount_opt, ERRORS_RO); | 857 | set_opt(sbi->s_mount_opt, ERRORS_RO); |
| 843 | 858 | ||
| 844 | sbi->s_resuid = le16_to_cpu(es->s_def_resuid); | 859 | sbi->s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid)); |
| 845 | sbi->s_resgid = le16_to_cpu(es->s_def_resgid); | 860 | sbi->s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid)); |
| 846 | 861 | ||
| 847 | set_opt(sbi->s_mount_opt, RESERVATION); | 862 | set_opt(sbi->s_mount_opt, RESERVATION); |
| 848 | 863 | ||
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index baac1b129fba..25cd60892116 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c | |||
| @@ -1439,8 +1439,9 @@ static int ext3_has_free_blocks(struct ext3_sb_info *sbi, int use_reservation) | |||
| 1439 | free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); | 1439 | free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); |
| 1440 | root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count); | 1440 | root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count); |
| 1441 | if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) && | 1441 | if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) && |
| 1442 | !use_reservation && sbi->s_resuid != current_fsuid() && | 1442 | !use_reservation && !uid_eq(sbi->s_resuid, current_fsuid()) && |
| 1443 | (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) { | 1443 | (gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) || |
| 1444 | !in_group_p (sbi->s_resgid))) { | ||
| 1444 | return 0; | 1445 | return 0; |
| 1445 | } | 1446 | } |
| 1446 | return 1; | 1447 | return 1; |
diff --git a/fs/ext3/ext3.h b/fs/ext3/ext3.h index b6515fd7e56c..7977973a24f0 100644 --- a/fs/ext3/ext3.h +++ b/fs/ext3/ext3.h | |||
| @@ -243,8 +243,8 @@ struct ext3_new_group_data { | |||
| 243 | */ | 243 | */ |
| 244 | struct ext3_mount_options { | 244 | struct ext3_mount_options { |
| 245 | unsigned long s_mount_opt; | 245 | unsigned long s_mount_opt; |
| 246 | uid_t s_resuid; | 246 | kuid_t s_resuid; |
| 247 | gid_t s_resgid; | 247 | kgid_t s_resgid; |
| 248 | unsigned long s_commit_interval; | 248 | unsigned long s_commit_interval; |
| 249 | #ifdef CONFIG_QUOTA | 249 | #ifdef CONFIG_QUOTA |
| 250 | int s_jquota_fmt; | 250 | int s_jquota_fmt; |
| @@ -637,8 +637,8 @@ struct ext3_sb_info { | |||
| 637 | struct buffer_head ** s_group_desc; | 637 | struct buffer_head ** s_group_desc; |
| 638 | unsigned long s_mount_opt; | 638 | unsigned long s_mount_opt; |
| 639 | ext3_fsblk_t s_sb_block; | 639 | ext3_fsblk_t s_sb_block; |
| 640 | uid_t s_resuid; | 640 | kuid_t s_resuid; |
| 641 | gid_t s_resgid; | 641 | kgid_t s_resgid; |
| 642 | unsigned short s_mount_state; | 642 | unsigned short s_mount_state; |
| 643 | unsigned short s_pad; | 643 | unsigned short s_pad; |
| 644 | int s_addr_per_block_bits; | 644 | int s_addr_per_block_bits; |
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 10d7812f6021..a09790a412b1 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
| @@ -2891,6 +2891,8 @@ struct inode *ext3_iget(struct super_block *sb, unsigned long ino) | |||
| 2891 | transaction_t *transaction; | 2891 | transaction_t *transaction; |
| 2892 | long ret; | 2892 | long ret; |
| 2893 | int block; | 2893 | int block; |
| 2894 | uid_t i_uid; | ||
| 2895 | gid_t i_gid; | ||
| 2894 | 2896 | ||
| 2895 | inode = iget_locked(sb, ino); | 2897 | inode = iget_locked(sb, ino); |
| 2896 | if (!inode) | 2898 | if (!inode) |
| @@ -2907,12 +2909,14 @@ struct inode *ext3_iget(struct super_block *sb, unsigned long ino) | |||
| 2907 | bh = iloc.bh; | 2909 | bh = iloc.bh; |
| 2908 | raw_inode = ext3_raw_inode(&iloc); | 2910 | raw_inode = ext3_raw_inode(&iloc); |
| 2909 | inode->i_mode = le16_to_cpu(raw_inode->i_mode); | 2911 | inode->i_mode = le16_to_cpu(raw_inode->i_mode); |
| 2910 | inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); | 2912 | i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); |
| 2911 | inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); | 2913 | i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); |
| 2912 | if(!(test_opt (inode->i_sb, NO_UID32))) { | 2914 | if(!(test_opt (inode->i_sb, NO_UID32))) { |
| 2913 | inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; | 2915 | i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; |
| 2914 | inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; | 2916 | i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; |
| 2915 | } | 2917 | } |
| 2918 | i_uid_write(inode, i_uid); | ||
| 2919 | i_gid_write(inode, i_gid); | ||
| 2916 | set_nlink(inode, le16_to_cpu(raw_inode->i_links_count)); | 2920 | set_nlink(inode, le16_to_cpu(raw_inode->i_links_count)); |
| 2917 | inode->i_size = le32_to_cpu(raw_inode->i_size); | 2921 | inode->i_size = le32_to_cpu(raw_inode->i_size); |
| 2918 | inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime); | 2922 | inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime); |
| @@ -3068,6 +3072,8 @@ static int ext3_do_update_inode(handle_t *handle, | |||
| 3068 | struct ext3_inode_info *ei = EXT3_I(inode); | 3072 | struct ext3_inode_info *ei = EXT3_I(inode); |
| 3069 | struct buffer_head *bh = iloc->bh; | 3073 | struct buffer_head *bh = iloc->bh; |
| 3070 | int err = 0, rc, block; | 3074 | int err = 0, rc, block; |
| 3075 | uid_t i_uid; | ||
| 3076 | gid_t i_gid; | ||
| 3071 | 3077 | ||
| 3072 | again: | 3078 | again: |
| 3073 | /* we can't allow multiple procs in here at once, its a bit racey */ | 3079 | /* we can't allow multiple procs in here at once, its a bit racey */ |
| @@ -3080,27 +3086,29 @@ again: | |||
| 3080 | 3086 | ||
| 3081 | ext3_get_inode_flags(ei); | 3087 | ext3_get_inode_flags(ei); |
| 3082 | raw_inode->i_mode = cpu_to_le16(inode->i_mode); | 3088 | raw_inode->i_mode = cpu_to_le16(inode->i_mode); |
| 3089 | i_uid = i_uid_read(inode); | ||
| 3090 | i_gid = i_gid_read(inode); | ||
| 3083 | if(!(test_opt(inode->i_sb, NO_UID32))) { | 3091 | if(!(test_opt(inode->i_sb, NO_UID32))) { |
| 3084 | raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid)); | 3092 | raw_inode->i_uid_low = cpu_to_le16(low_16_bits(i_uid)); |
| 3085 | raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid)); | 3093 | raw_inode->i_gid_low = cpu_to_le16(low_16_bits(i_gid)); |
| 3086 | /* | 3094 | /* |
| 3087 | * Fix up interoperability with old kernels. Otherwise, old inodes get | 3095 | * Fix up interoperability with old kernels. Otherwise, old inodes get |
| 3088 | * re-used with the upper 16 bits of the uid/gid intact | 3096 | * re-used with the upper 16 bits of the uid/gid intact |
| 3089 | */ | 3097 | */ |
| 3090 | if(!ei->i_dtime) { | 3098 | if(!ei->i_dtime) { |
| 3091 | raw_inode->i_uid_high = | 3099 | raw_inode->i_uid_high = |
| 3092 | cpu_to_le16(high_16_bits(inode->i_uid)); | 3100 | cpu_to_le16(high_16_bits(i_uid)); |
| 3093 | raw_inode->i_gid_high = | 3101 | raw_inode->i_gid_high = |
| 3094 | cpu_to_le16(high_16_bits(inode->i_gid)); | 3102 | cpu_to_le16(high_16_bits(i_gid)); |
| 3095 | } else { | 3103 | } else { |
| 3096 | raw_inode->i_uid_high = 0; | 3104 | raw_inode->i_uid_high = 0; |
| 3097 | raw_inode->i_gid_high = 0; | 3105 | raw_inode->i_gid_high = 0; |
| 3098 | } | 3106 | } |
| 3099 | } else { | 3107 | } else { |
| 3100 | raw_inode->i_uid_low = | 3108 | raw_inode->i_uid_low = |
| 3101 | cpu_to_le16(fs_high2lowuid(inode->i_uid)); | 3109 | cpu_to_le16(fs_high2lowuid(i_uid)); |
| 3102 | raw_inode->i_gid_low = | 3110 | raw_inode->i_gid_low = |
| 3103 | cpu_to_le16(fs_high2lowgid(inode->i_gid)); | 3111 | cpu_to_le16(fs_high2lowgid(i_gid)); |
| 3104 | raw_inode->i_uid_high = 0; | 3112 | raw_inode->i_uid_high = 0; |
| 3105 | raw_inode->i_gid_high = 0; | 3113 | raw_inode->i_gid_high = 0; |
| 3106 | } | 3114 | } |
| @@ -3262,8 +3270,8 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 3262 | 3270 | ||
| 3263 | if (is_quota_modification(inode, attr)) | 3271 | if (is_quota_modification(inode, attr)) |
| 3264 | dquot_initialize(inode); | 3272 | dquot_initialize(inode); |
| 3265 | if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || | 3273 | if ((ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, inode->i_uid)) || |
| 3266 | (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { | 3274 | (ia_valid & ATTR_GID && !gid_eq(attr->ia_gid, inode->i_gid))) { |
| 3267 | handle_t *handle; | 3275 | handle_t *handle; |
| 3268 | 3276 | ||
| 3269 | /* (user+group)*(old+new) structure, inode write (sb, | 3277 | /* (user+group)*(old+new) structure, inode write (sb, |
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index cf0b5921cf0f..94ef7e616129 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
| @@ -617,13 +617,15 @@ static int ext3_show_options(struct seq_file *seq, struct dentry *root) | |||
| 617 | seq_puts(seq, ",grpid"); | 617 | seq_puts(seq, ",grpid"); |
| 618 | if (!test_opt(sb, GRPID) && (def_mount_opts & EXT3_DEFM_BSDGROUPS)) | 618 | if (!test_opt(sb, GRPID) && (def_mount_opts & EXT3_DEFM_BSDGROUPS)) |
| 619 | seq_puts(seq, ",nogrpid"); | 619 | seq_puts(seq, ",nogrpid"); |
| 620 | if (sbi->s_resuid != EXT3_DEF_RESUID || | 620 | if (!uid_eq(sbi->s_resuid, make_kuid(&init_user_ns, EXT3_DEF_RESUID)) || |
| 621 | le16_to_cpu(es->s_def_resuid) != EXT3_DEF_RESUID) { | 621 | le16_to_cpu(es->s_def_resuid) != EXT3_DEF_RESUID) { |
| 622 | seq_printf(seq, ",resuid=%u", sbi->s_resuid); | 622 | seq_printf(seq, ",resuid=%u", |
| 623 | from_kuid_munged(&init_user_ns, sbi->s_resuid)); | ||
| 623 | } | 624 | } |
| 624 | if (sbi->s_resgid != EXT3_DEF_RESGID || | 625 | if (!gid_eq(sbi->s_resgid, make_kgid(&init_user_ns, EXT3_DEF_RESGID)) || |
| 625 | le16_to_cpu(es->s_def_resgid) != EXT3_DEF_RESGID) { | 626 | le16_to_cpu(es->s_def_resgid) != EXT3_DEF_RESGID) { |
| 626 | seq_printf(seq, ",resgid=%u", sbi->s_resgid); | 627 | seq_printf(seq, ",resgid=%u", |
| 628 | from_kgid_munged(&init_user_ns, sbi->s_resgid)); | ||
| 627 | } | 629 | } |
| 628 | if (test_opt(sb, ERRORS_RO)) { | 630 | if (test_opt(sb, ERRORS_RO)) { |
| 629 | int def_errors = le16_to_cpu(es->s_errors); | 631 | int def_errors = le16_to_cpu(es->s_errors); |
| @@ -967,6 +969,8 @@ static int parse_options (char *options, struct super_block *sb, | |||
| 967 | substring_t args[MAX_OPT_ARGS]; | 969 | substring_t args[MAX_OPT_ARGS]; |
| 968 | int data_opt = 0; | 970 | int data_opt = 0; |
| 969 | int option; | 971 | int option; |
| 972 | kuid_t uid; | ||
| 973 | kgid_t gid; | ||
| 970 | #ifdef CONFIG_QUOTA | 974 | #ifdef CONFIG_QUOTA |
| 971 | int qfmt; | 975 | int qfmt; |
| 972 | #endif | 976 | #endif |
| @@ -1000,12 +1004,23 @@ static int parse_options (char *options, struct super_block *sb, | |||
| 1000 | case Opt_resuid: | 1004 | case Opt_resuid: |
| 1001 | if (match_int(&args[0], &option)) | 1005 | if (match_int(&args[0], &option)) |
| 1002 | return 0; | 1006 | return 0; |
| 1003 | sbi->s_resuid = option; | 1007 | uid = make_kuid(current_user_ns(), option); |
| 1008 | if (!uid_valid(uid)) { | ||
| 1009 | ext3_msg(sb, KERN_ERR, "Invalid uid value %d", option); | ||
| 1010 | return -1; | ||
| 1011 | |||
| 1012 | } | ||
| 1013 | sbi->s_resuid = uid; | ||
| 1004 | break; | 1014 | break; |
| 1005 | case Opt_resgid: | 1015 | case Opt_resgid: |
| 1006 | if (match_int(&args[0], &option)) | 1016 | if (match_int(&args[0], &option)) |
| 1007 | return 0; | 1017 | return 0; |
| 1008 | sbi->s_resgid = option; | 1018 | gid = make_kgid(current_user_ns(), option); |
| 1019 | if (!gid_valid(gid)) { | ||
| 1020 | ext3_msg(sb, KERN_ERR, "Invalid gid value %d", option); | ||
| 1021 | return -1; | ||
| 1022 | } | ||
| 1023 | sbi->s_resgid = gid; | ||
| 1009 | break; | 1024 | break; |
| 1010 | case Opt_sb: | 1025 | case Opt_sb: |
| 1011 | /* handled by get_sb_block() instead of here */ | 1026 | /* handled by get_sb_block() instead of here */ |
| @@ -1651,8 +1666,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) | |||
| 1651 | } | 1666 | } |
| 1652 | sb->s_fs_info = sbi; | 1667 | sb->s_fs_info = sbi; |
| 1653 | sbi->s_mount_opt = 0; | 1668 | sbi->s_mount_opt = 0; |
| 1654 | sbi->s_resuid = EXT3_DEF_RESUID; | 1669 | sbi->s_resuid = make_kuid(&init_user_ns, EXT3_DEF_RESUID); |
| 1655 | sbi->s_resgid = EXT3_DEF_RESGID; | 1670 | sbi->s_resgid = make_kgid(&init_user_ns, EXT3_DEF_RESGID); |
| 1656 | sbi->s_sb_block = sb_block; | 1671 | sbi->s_sb_block = sb_block; |
| 1657 | 1672 | ||
| 1658 | blocksize = sb_min_blocksize(sb, EXT3_MIN_BLOCK_SIZE); | 1673 | blocksize = sb_min_blocksize(sb, EXT3_MIN_BLOCK_SIZE); |
| @@ -1716,8 +1731,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) | |||
| 1716 | else | 1731 | else |
| 1717 | set_opt(sbi->s_mount_opt, ERRORS_RO); | 1732 | set_opt(sbi->s_mount_opt, ERRORS_RO); |
| 1718 | 1733 | ||
| 1719 | sbi->s_resuid = le16_to_cpu(es->s_def_resuid); | 1734 | sbi->s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid)); |
| 1720 | sbi->s_resgid = le16_to_cpu(es->s_def_resgid); | 1735 | sbi->s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid)); |
| 1721 | 1736 | ||
| 1722 | /* enable barriers by default */ | 1737 | /* enable barriers by default */ |
| 1723 | set_opt(sbi->s_mount_opt, BARRIER); | 1738 | set_opt(sbi->s_mount_opt, BARRIER); |
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 4bbd07a6fa18..c45c41129a35 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
| @@ -461,8 +461,8 @@ static int ext4_has_free_clusters(struct ext4_sb_info *sbi, | |||
| 461 | return 1; | 461 | return 1; |
| 462 | 462 | ||
| 463 | /* Hm, nope. Are (enough) root reserved clusters available? */ | 463 | /* Hm, nope. Are (enough) root reserved clusters available? */ |
| 464 | if (sbi->s_resuid == current_fsuid() || | 464 | if (uid_eq(sbi->s_resuid, current_fsuid()) || |
| 465 | ((sbi->s_resgid != 0) && in_group_p(sbi->s_resgid)) || | 465 | (!gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) && in_group_p(sbi->s_resgid)) || |
| 466 | capable(CAP_SYS_RESOURCE) || | 466 | capable(CAP_SYS_RESOURCE) || |
| 467 | (flags & EXT4_MB_USE_ROOT_BLOCKS)) { | 467 | (flags & EXT4_MB_USE_ROOT_BLOCKS)) { |
| 468 | 468 | ||
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 0e01e90add8b..c21b1de51afb 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
| @@ -1153,8 +1153,8 @@ struct ext4_sb_info { | |||
| 1153 | unsigned int s_mount_flags; | 1153 | unsigned int s_mount_flags; |
| 1154 | unsigned int s_def_mount_opt; | 1154 | unsigned int s_def_mount_opt; |
| 1155 | ext4_fsblk_t s_sb_block; | 1155 | ext4_fsblk_t s_sb_block; |
| 1156 | uid_t s_resuid; | 1156 | kuid_t s_resuid; |
| 1157 | gid_t s_resgid; | 1157 | kgid_t s_resgid; |
| 1158 | unsigned short s_mount_state; | 1158 | unsigned short s_mount_state; |
| 1159 | unsigned short s_pad; | 1159 | unsigned short s_pad; |
| 1160 | int s_addr_per_block_bits; | 1160 | int s_addr_per_block_bits; |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 409c2ee7750a..9f9acac6c43f 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
| @@ -808,8 +808,8 @@ got: | |||
| 808 | } | 808 | } |
| 809 | if (owner) { | 809 | if (owner) { |
| 810 | inode->i_mode = mode; | 810 | inode->i_mode = mode; |
| 811 | inode->i_uid = owner[0]; | 811 | i_uid_write(inode, owner[0]); |
| 812 | inode->i_gid = owner[1]; | 812 | i_gid_write(inode, owner[1]); |
| 813 | } else if (test_opt(sb, GRPID)) { | 813 | } else if (test_opt(sb, GRPID)) { |
| 814 | inode->i_mode = mode; | 814 | inode->i_mode = mode; |
| 815 | inode->i_uid = current_fsuid(); | 815 | inode->i_uid = current_fsuid(); |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index c77b0bd2c711..07eaf565fdcb 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
| @@ -3630,6 +3630,8 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
| 3630 | journal_t *journal = EXT4_SB(sb)->s_journal; | 3630 | journal_t *journal = EXT4_SB(sb)->s_journal; |
| 3631 | long ret; | 3631 | long ret; |
| 3632 | int block; | 3632 | int block; |
| 3633 | uid_t i_uid; | ||
| 3634 | gid_t i_gid; | ||
| 3633 | 3635 | ||
| 3634 | inode = iget_locked(sb, ino); | 3636 | inode = iget_locked(sb, ino); |
| 3635 | if (!inode) | 3637 | if (!inode) |
| @@ -3645,12 +3647,14 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
| 3645 | goto bad_inode; | 3647 | goto bad_inode; |
| 3646 | raw_inode = ext4_raw_inode(&iloc); | 3648 | raw_inode = ext4_raw_inode(&iloc); |
| 3647 | inode->i_mode = le16_to_cpu(raw_inode->i_mode); | 3649 | inode->i_mode = le16_to_cpu(raw_inode->i_mode); |
| 3648 | inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); | 3650 | i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); |
| 3649 | inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); | 3651 | i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); |
| 3650 | if (!(test_opt(inode->i_sb, NO_UID32))) { | 3652 | if (!(test_opt(inode->i_sb, NO_UID32))) { |
| 3651 | inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; | 3653 | i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; |
| 3652 | inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; | 3654 | i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; |
| 3653 | } | 3655 | } |
| 3656 | i_uid_write(inode, i_uid); | ||
| 3657 | i_gid_write(inode, i_gid); | ||
| 3654 | set_nlink(inode, le16_to_cpu(raw_inode->i_links_count)); | 3658 | set_nlink(inode, le16_to_cpu(raw_inode->i_links_count)); |
| 3655 | 3659 | ||
| 3656 | ext4_clear_state_flags(ei); /* Only relevant on 32-bit archs */ | 3660 | ext4_clear_state_flags(ei); /* Only relevant on 32-bit archs */ |
| @@ -3870,6 +3874,8 @@ static int ext4_do_update_inode(handle_t *handle, | |||
| 3870 | struct ext4_inode_info *ei = EXT4_I(inode); | 3874 | struct ext4_inode_info *ei = EXT4_I(inode); |
| 3871 | struct buffer_head *bh = iloc->bh; | 3875 | struct buffer_head *bh = iloc->bh; |
| 3872 | int err = 0, rc, block; | 3876 | int err = 0, rc, block; |
| 3877 | uid_t i_uid; | ||
| 3878 | gid_t i_gid; | ||
| 3873 | 3879 | ||
| 3874 | /* For fields not not tracking in the in-memory inode, | 3880 | /* For fields not not tracking in the in-memory inode, |
| 3875 | * initialise them to zero for new inodes. */ | 3881 | * initialise them to zero for new inodes. */ |
| @@ -3878,27 +3884,27 @@ static int ext4_do_update_inode(handle_t *handle, | |||
| 3878 | 3884 | ||
| 3879 | ext4_get_inode_flags(ei); | 3885 | ext4_get_inode_flags(ei); |
| 3880 | raw_inode->i_mode = cpu_to_le16(inode->i_mode); | 3886 | raw_inode->i_mode = cpu_to_le16(inode->i_mode); |
| 3887 | i_uid = i_uid_read(inode); | ||
| 3888 | i_gid = i_gid_read(inode); | ||
| 3881 | if (!(test_opt(inode->i_sb, NO_UID32))) { | 3889 | if (!(test_opt(inode->i_sb, NO_UID32))) { |
| 3882 | raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid)); | 3890 | raw_inode->i_uid_low = cpu_to_le16(low_16_bits(i_uid)); |
| 3883 | raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid)); | 3891 | raw_inode->i_gid_low = cpu_to_le16(low_16_bits(i_gid)); |
| 3884 | /* | 3892 | /* |
| 3885 | * Fix up interoperability with old kernels. Otherwise, old inodes get | 3893 | * Fix up interoperability with old kernels. Otherwise, old inodes get |
| 3886 | * re-used with the upper 16 bits of the uid/gid intact | 3894 | * re-used with the upper 16 bits of the uid/gid intact |
| 3887 | */ | 3895 | */ |
| 3888 | if (!ei->i_dtime) { | 3896 | if (!ei->i_dtime) { |
| 3889 | raw_inode->i_uid_high = | 3897 | raw_inode->i_uid_high = |
| 3890 | cpu_to_le16(high_16_bits(inode->i_uid)); | 3898 | cpu_to_le16(high_16_bits(i_uid)); |
| 3891 | raw_inode->i_gid_high = | 3899 | raw_inode->i_gid_high = |
| 3892 | cpu_to_le16(high_16_bits(inode->i_gid)); | 3900 | cpu_to_le16(high_16_bits(i_gid)); |
| 3893 | } else { | 3901 | } else { |
| 3894 | raw_inode->i_uid_high = 0; | 3902 | raw_inode->i_uid_high = 0; |
| 3895 | raw_inode->i_gid_high = 0; | 3903 | raw_inode->i_gid_high = 0; |
| 3896 | } | 3904 | } |
| 3897 | } else { | 3905 | } else { |
| 3898 | raw_inode->i_uid_low = | 3906 | raw_inode->i_uid_low = cpu_to_le16(fs_high2lowuid(i_uid)); |
| 3899 | cpu_to_le16(fs_high2lowuid(inode->i_uid)); | 3907 | raw_inode->i_gid_low = cpu_to_le16(fs_high2lowgid(i_gid)); |
| 3900 | raw_inode->i_gid_low = | ||
| 3901 | cpu_to_le16(fs_high2lowgid(inode->i_gid)); | ||
| 3902 | raw_inode->i_uid_high = 0; | 3908 | raw_inode->i_uid_high = 0; |
| 3903 | raw_inode->i_gid_high = 0; | 3909 | raw_inode->i_gid_high = 0; |
| 3904 | } | 3910 | } |
| @@ -4084,8 +4090,8 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 4084 | 4090 | ||
| 4085 | if (is_quota_modification(inode, attr)) | 4091 | if (is_quota_modification(inode, attr)) |
| 4086 | dquot_initialize(inode); | 4092 | dquot_initialize(inode); |
| 4087 | if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || | 4093 | if ((ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, inode->i_uid)) || |
| 4088 | (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { | 4094 | (ia_valid & ATTR_GID && !gid_eq(attr->ia_gid, inode->i_gid))) { |
| 4089 | handle_t *handle; | 4095 | handle_t *handle; |
| 4090 | 4096 | ||
| 4091 | /* (user+group)*(old+new) structure, inode write (sb, | 4097 | /* (user+group)*(old+new) structure, inode write (sb, |
diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c index f39f80f8f2c5..f1bb32ec0169 100644 --- a/fs/ext4/migrate.c +++ b/fs/ext4/migrate.c | |||
| @@ -466,8 +466,8 @@ int ext4_ext_migrate(struct inode *inode) | |||
| 466 | } | 466 | } |
| 467 | goal = (((inode->i_ino - 1) / EXT4_INODES_PER_GROUP(inode->i_sb)) * | 467 | goal = (((inode->i_ino - 1) / EXT4_INODES_PER_GROUP(inode->i_sb)) * |
| 468 | EXT4_INODES_PER_GROUP(inode->i_sb)) + 1; | 468 | EXT4_INODES_PER_GROUP(inode->i_sb)) + 1; |
| 469 | owner[0] = inode->i_uid; | 469 | owner[0] = i_uid_read(inode); |
| 470 | owner[1] = inode->i_gid; | 470 | owner[1] = i_gid_read(inode); |
| 471 | tmp_inode = ext4_new_inode(handle, inode->i_sb->s_root->d_inode, | 471 | tmp_inode = ext4_new_inode(handle, inode->i_sb->s_root->d_inode, |
| 472 | S_IFREG, NULL, goal, owner); | 472 | S_IFREG, NULL, goal, owner); |
| 473 | if (IS_ERR(tmp_inode)) { | 473 | if (IS_ERR(tmp_inode)) { |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index e1fb1d5de58e..436b4223df66 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
| @@ -1448,6 +1448,8 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token, | |||
| 1448 | { | 1448 | { |
| 1449 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 1449 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
| 1450 | const struct mount_opts *m; | 1450 | const struct mount_opts *m; |
| 1451 | kuid_t uid; | ||
| 1452 | kgid_t gid; | ||
| 1451 | int arg = 0; | 1453 | int arg = 0; |
| 1452 | 1454 | ||
| 1453 | #ifdef CONFIG_QUOTA | 1455 | #ifdef CONFIG_QUOTA |
| @@ -1474,10 +1476,20 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token, | |||
| 1474 | "Ignoring removed %s option", opt); | 1476 | "Ignoring removed %s option", opt); |
| 1475 | return 1; | 1477 | return 1; |
| 1476 | case Opt_resuid: | 1478 | case Opt_resuid: |
| 1477 | sbi->s_resuid = arg; | 1479 | uid = make_kuid(current_user_ns(), arg); |
| 1480 | if (!uid_valid(uid)) { | ||
| 1481 | ext4_msg(sb, KERN_ERR, "Invalid uid value %d", arg); | ||
| 1482 | return -1; | ||
| 1483 | } | ||
| 1484 | sbi->s_resuid = uid; | ||
| 1478 | return 1; | 1485 | return 1; |
| 1479 | case Opt_resgid: | 1486 | case Opt_resgid: |
| 1480 | sbi->s_resgid = arg; | 1487 | gid = make_kgid(current_user_ns(), arg); |
| 1488 | if (!gid_valid(gid)) { | ||
| 1489 | ext4_msg(sb, KERN_ERR, "Invalid gid value %d", arg); | ||
| 1490 | return -1; | ||
| 1491 | } | ||
| 1492 | sbi->s_resgid = gid; | ||
| 1481 | return 1; | 1493 | return 1; |
| 1482 | case Opt_abort: | 1494 | case Opt_abort: |
| 1483 | sbi->s_mount_flags |= EXT4_MF_FS_ABORTED; | 1495 | sbi->s_mount_flags |= EXT4_MF_FS_ABORTED; |
| @@ -1732,12 +1744,14 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb, | |||
| 1732 | SEQ_OPTS_PRINT("%s", token2str(m->token)); | 1744 | SEQ_OPTS_PRINT("%s", token2str(m->token)); |
| 1733 | } | 1745 | } |
| 1734 | 1746 | ||
| 1735 | if (nodefs || sbi->s_resuid != EXT4_DEF_RESUID || | 1747 | if (nodefs || !uid_eq(sbi->s_resuid, make_kuid(&init_user_ns, EXT4_DEF_RESUID)) || |
| 1736 | le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID) | 1748 | le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID) |
| 1737 | SEQ_OPTS_PRINT("resuid=%u", sbi->s_resuid); | 1749 | SEQ_OPTS_PRINT("resuid=%u", |
| 1738 | if (nodefs || sbi->s_resgid != EXT4_DEF_RESGID || | 1750 | from_kuid_munged(&init_user_ns, sbi->s_resuid)); |
| 1751 | if (nodefs || !gid_eq(sbi->s_resgid, make_kgid(&init_user_ns, EXT4_DEF_RESGID)) || | ||
| 1739 | le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID) | 1752 | le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID) |
| 1740 | SEQ_OPTS_PRINT("resgid=%u", sbi->s_resgid); | 1753 | SEQ_OPTS_PRINT("resgid=%u", |
| 1754 | from_kgid_munged(&init_user_ns, sbi->s_resgid)); | ||
| 1741 | def_errors = nodefs ? -1 : le16_to_cpu(es->s_errors); | 1755 | def_errors = nodefs ? -1 : le16_to_cpu(es->s_errors); |
| 1742 | if (test_opt(sb, ERRORS_RO) && def_errors != EXT4_ERRORS_RO) | 1756 | if (test_opt(sb, ERRORS_RO) && def_errors != EXT4_ERRORS_RO) |
| 1743 | SEQ_OPTS_PUTS("errors=remount-ro"); | 1757 | SEQ_OPTS_PUTS("errors=remount-ro"); |
| @@ -2980,8 +2994,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
| 2980 | } | 2994 | } |
| 2981 | sb->s_fs_info = sbi; | 2995 | sb->s_fs_info = sbi; |
| 2982 | sbi->s_mount_opt = 0; | 2996 | sbi->s_mount_opt = 0; |
| 2983 | sbi->s_resuid = EXT4_DEF_RESUID; | 2997 | sbi->s_resuid = make_kuid(&init_user_ns, EXT4_DEF_RESUID); |
| 2984 | sbi->s_resgid = EXT4_DEF_RESGID; | 2998 | sbi->s_resgid = make_kgid(&init_user_ns, EXT4_DEF_RESGID); |
| 2985 | sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS; | 2999 | sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS; |
| 2986 | sbi->s_sb_block = sb_block; | 3000 | sbi->s_sb_block = sb_block; |
| 2987 | if (sb->s_bdev->bd_part) | 3001 | if (sb->s_bdev->bd_part) |
| @@ -3060,8 +3074,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
| 3060 | if (def_mount_opts & EXT4_DEFM_DISCARD) | 3074 | if (def_mount_opts & EXT4_DEFM_DISCARD) |
| 3061 | set_opt(sb, DISCARD); | 3075 | set_opt(sb, DISCARD); |
| 3062 | 3076 | ||
| 3063 | sbi->s_resuid = le16_to_cpu(es->s_def_resuid); | 3077 | sbi->s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid)); |
| 3064 | sbi->s_resgid = le16_to_cpu(es->s_def_resgid); | 3078 | sbi->s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid)); |
| 3065 | sbi->s_commit_interval = JBD2_DEFAULT_MAX_COMMIT_AGE * HZ; | 3079 | sbi->s_commit_interval = JBD2_DEFAULT_MAX_COMMIT_AGE * HZ; |
| 3066 | sbi->s_min_batch_time = EXT4_DEF_MIN_BATCH_TIME; | 3080 | sbi->s_min_batch_time = EXT4_DEF_MIN_BATCH_TIME; |
| 3067 | sbi->s_max_batch_time = EXT4_DEF_MAX_BATCH_TIME; | 3081 | sbi->s_max_batch_time = EXT4_DEF_MAX_BATCH_TIME; |
| @@ -4213,8 +4227,8 @@ static int ext4_unfreeze(struct super_block *sb) | |||
| 4213 | struct ext4_mount_options { | 4227 | struct ext4_mount_options { |
| 4214 | unsigned long s_mount_opt; | 4228 | unsigned long s_mount_opt; |
| 4215 | unsigned long s_mount_opt2; | 4229 | unsigned long s_mount_opt2; |
| 4216 | uid_t s_resuid; | 4230 | kuid_t s_resuid; |
| 4217 | gid_t s_resgid; | 4231 | kgid_t s_resgid; |
| 4218 | unsigned long s_commit_interval; | 4232 | unsigned long s_commit_interval; |
| 4219 | u32 s_min_batch_time, s_max_batch_time; | 4233 | u32 s_min_batch_time, s_max_batch_time; |
| 4220 | #ifdef CONFIG_QUOTA | 4234 | #ifdef CONFIG_QUOTA |
diff --git a/fs/fcntl.c b/fs/fcntl.c index 75e7c1f3a080..d078b75572a7 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
| @@ -532,9 +532,9 @@ static inline int sigio_perm(struct task_struct *p, | |||
| 532 | 532 | ||
| 533 | rcu_read_lock(); | 533 | rcu_read_lock(); |
| 534 | cred = __task_cred(p); | 534 | cred = __task_cred(p); |
| 535 | ret = ((fown->euid == 0 || | 535 | ret = ((uid_eq(fown->euid, GLOBAL_ROOT_UID) || |
| 536 | fown->euid == cred->suid || fown->euid == cred->uid || | 536 | uid_eq(fown->euid, cred->suid) || uid_eq(fown->euid, cred->uid) || |
| 537 | fown->uid == cred->suid || fown->uid == cred->uid) && | 537 | uid_eq(fown->uid, cred->suid) || uid_eq(fown->uid, cred->uid)) && |
| 538 | !security_file_send_sigiotask(p, fown, sig)); | 538 | !security_file_send_sigiotask(p, fown, sig)); |
| 539 | rcu_read_unlock(); | 539 | rcu_read_unlock(); |
| 540 | return ret; | 540 | return ret; |
diff --git a/fs/inode.c b/fs/inode.c index 9f4f5fecc096..deb72f6c2b4f 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
| @@ -135,8 +135,8 @@ int inode_init_always(struct super_block *sb, struct inode *inode) | |||
| 135 | inode->i_fop = &empty_fops; | 135 | inode->i_fop = &empty_fops; |
| 136 | inode->__i_nlink = 1; | 136 | inode->__i_nlink = 1; |
| 137 | inode->i_opflags = 0; | 137 | inode->i_opflags = 0; |
| 138 | inode->i_uid = 0; | 138 | i_uid_write(inode, 0); |
| 139 | inode->i_gid = 0; | 139 | i_gid_write(inode, 0); |
| 140 | atomic_set(&inode->i_writecount, 0); | 140 | atomic_set(&inode->i_writecount, 0); |
| 141 | inode->i_size = 0; | 141 | inode->i_size = 0; |
| 142 | inode->i_blocks = 0; | 142 | inode->i_blocks = 0; |
| @@ -1732,11 +1732,9 @@ EXPORT_SYMBOL(inode_init_owner); | |||
| 1732 | */ | 1732 | */ |
| 1733 | bool inode_owner_or_capable(const struct inode *inode) | 1733 | bool inode_owner_or_capable(const struct inode *inode) |
| 1734 | { | 1734 | { |
| 1735 | struct user_namespace *ns = inode_userns(inode); | 1735 | if (uid_eq(current_fsuid(), inode->i_uid)) |
| 1736 | |||
| 1737 | if (current_user_ns() == ns && current_fsuid() == inode->i_uid) | ||
| 1738 | return true; | 1736 | return true; |
| 1739 | if (ns_capable(ns, CAP_FOWNER)) | 1737 | if (inode_capable(inode, CAP_FOWNER)) |
| 1740 | return true; | 1738 | return true; |
| 1741 | return false; | 1739 | return false; |
| 1742 | } | 1740 | } |
diff --git a/fs/ioprio.c b/fs/ioprio.c index 0f1b9515213b..5e6dbe8958fc 100644 --- a/fs/ioprio.c +++ b/fs/ioprio.c | |||
| @@ -37,8 +37,8 @@ int set_task_ioprio(struct task_struct *task, int ioprio) | |||
| 37 | 37 | ||
| 38 | rcu_read_lock(); | 38 | rcu_read_lock(); |
| 39 | tcred = __task_cred(task); | 39 | tcred = __task_cred(task); |
| 40 | if (tcred->uid != cred->euid && | 40 | if (!uid_eq(tcred->uid, cred->euid) && |
| 41 | tcred->uid != cred->uid && !capable(CAP_SYS_NICE)) { | 41 | !uid_eq(tcred->uid, cred->uid) && !capable(CAP_SYS_NICE)) { |
| 42 | rcu_read_unlock(); | 42 | rcu_read_unlock(); |
| 43 | return -EPERM; | 43 | return -EPERM; |
| 44 | } | 44 | } |
| @@ -65,6 +65,7 @@ SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio) | |||
| 65 | struct task_struct *p, *g; | 65 | struct task_struct *p, *g; |
| 66 | struct user_struct *user; | 66 | struct user_struct *user; |
| 67 | struct pid *pgrp; | 67 | struct pid *pgrp; |
| 68 | kuid_t uid; | ||
| 68 | int ret; | 69 | int ret; |
| 69 | 70 | ||
| 70 | switch (class) { | 71 | switch (class) { |
| @@ -110,16 +111,19 @@ SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio) | |||
| 110 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); | 111 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); |
| 111 | break; | 112 | break; |
| 112 | case IOPRIO_WHO_USER: | 113 | case IOPRIO_WHO_USER: |
| 114 | uid = make_kuid(current_user_ns(), who); | ||
| 115 | if (!uid_valid(uid)) | ||
| 116 | break; | ||
| 113 | if (!who) | 117 | if (!who) |
| 114 | user = current_user(); | 118 | user = current_user(); |
| 115 | else | 119 | else |
| 116 | user = find_user(who); | 120 | user = find_user(uid); |
| 117 | 121 | ||
| 118 | if (!user) | 122 | if (!user) |
| 119 | break; | 123 | break; |
| 120 | 124 | ||
| 121 | do_each_thread(g, p) { | 125 | do_each_thread(g, p) { |
| 122 | if (__task_cred(p)->uid != who) | 126 | if (!uid_eq(task_uid(p), uid)) |
| 123 | continue; | 127 | continue; |
| 124 | ret = set_task_ioprio(p, ioprio); | 128 | ret = set_task_ioprio(p, ioprio); |
| 125 | if (ret) | 129 | if (ret) |
| @@ -174,6 +178,7 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who) | |||
| 174 | struct task_struct *g, *p; | 178 | struct task_struct *g, *p; |
| 175 | struct user_struct *user; | 179 | struct user_struct *user; |
| 176 | struct pid *pgrp; | 180 | struct pid *pgrp; |
| 181 | kuid_t uid; | ||
| 177 | int ret = -ESRCH; | 182 | int ret = -ESRCH; |
| 178 | int tmpio; | 183 | int tmpio; |
| 179 | 184 | ||
| @@ -203,16 +208,17 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who) | |||
| 203 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); | 208 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); |
| 204 | break; | 209 | break; |
| 205 | case IOPRIO_WHO_USER: | 210 | case IOPRIO_WHO_USER: |
| 211 | uid = make_kuid(current_user_ns(), who); | ||
| 206 | if (!who) | 212 | if (!who) |
| 207 | user = current_user(); | 213 | user = current_user(); |
| 208 | else | 214 | else |
| 209 | user = find_user(who); | 215 | user = find_user(uid); |
| 210 | 216 | ||
| 211 | if (!user) | 217 | if (!user) |
| 212 | break; | 218 | break; |
| 213 | 219 | ||
| 214 | do_each_thread(g, p) { | 220 | do_each_thread(g, p) { |
| 215 | if (__task_cred(p)->uid != user->uid) | 221 | if (!uid_eq(task_uid(p), user->uid)) |
| 216 | continue; | 222 | continue; |
| 217 | tmpio = get_task_ioprio(p); | 223 | tmpio = get_task_ioprio(p); |
| 218 | if (tmpio < 0) | 224 | if (tmpio < 0) |
diff --git a/fs/locks.c b/fs/locks.c index 0d68f1f81799..4f441e46cef4 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
| @@ -1446,7 +1446,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
| 1446 | struct inode *inode = dentry->d_inode; | 1446 | struct inode *inode = dentry->d_inode; |
| 1447 | int error; | 1447 | int error; |
| 1448 | 1448 | ||
| 1449 | if ((current_fsuid() != inode->i_uid) && !capable(CAP_LEASE)) | 1449 | if ((!uid_eq(current_fsuid(), inode->i_uid)) && !capable(CAP_LEASE)) |
| 1450 | return -EACCES; | 1450 | return -EACCES; |
| 1451 | if (!S_ISREG(inode->i_mode)) | 1451 | if (!S_ISREG(inode->i_mode)) |
| 1452 | return -EINVAL; | 1452 | return -EINVAL; |
diff --git a/fs/namei.c b/fs/namei.c index f9e883c1b856..e70ebab9624b 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -218,10 +218,7 @@ static int acl_permission_check(struct inode *inode, int mask) | |||
| 218 | { | 218 | { |
| 219 | unsigned int mode = inode->i_mode; | 219 | unsigned int mode = inode->i_mode; |
| 220 | 220 | ||
| 221 | if (current_user_ns() != inode_userns(inode)) | 221 | if (likely(uid_eq(current_fsuid(), inode->i_uid))) |
| 222 | goto other_perms; | ||
| 223 | |||
| 224 | if (likely(current_fsuid() == inode->i_uid)) | ||
| 225 | mode >>= 6; | 222 | mode >>= 6; |
| 226 | else { | 223 | else { |
| 227 | if (IS_POSIXACL(inode) && (mode & S_IRWXG)) { | 224 | if (IS_POSIXACL(inode) && (mode & S_IRWXG)) { |
| @@ -234,7 +231,6 @@ static int acl_permission_check(struct inode *inode, int mask) | |||
| 234 | mode >>= 3; | 231 | mode >>= 3; |
| 235 | } | 232 | } |
| 236 | 233 | ||
| 237 | other_perms: | ||
| 238 | /* | 234 | /* |
| 239 | * If the DACs are ok we don't need any capability check. | 235 | * If the DACs are ok we don't need any capability check. |
| 240 | */ | 236 | */ |
| @@ -270,10 +266,10 @@ int generic_permission(struct inode *inode, int mask) | |||
| 270 | 266 | ||
| 271 | if (S_ISDIR(inode->i_mode)) { | 267 | if (S_ISDIR(inode->i_mode)) { |
| 272 | /* DACs are overridable for directories */ | 268 | /* DACs are overridable for directories */ |
| 273 | if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE)) | 269 | if (inode_capable(inode, CAP_DAC_OVERRIDE)) |
| 274 | return 0; | 270 | return 0; |
| 275 | if (!(mask & MAY_WRITE)) | 271 | if (!(mask & MAY_WRITE)) |
| 276 | if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH)) | 272 | if (inode_capable(inode, CAP_DAC_READ_SEARCH)) |
| 277 | return 0; | 273 | return 0; |
| 278 | return -EACCES; | 274 | return -EACCES; |
| 279 | } | 275 | } |
| @@ -283,7 +279,7 @@ int generic_permission(struct inode *inode, int mask) | |||
| 283 | * at least one exec bit set. | 279 | * at least one exec bit set. |
| 284 | */ | 280 | */ |
| 285 | if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO)) | 281 | if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO)) |
| 286 | if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE)) | 282 | if (inode_capable(inode, CAP_DAC_OVERRIDE)) |
| 287 | return 0; | 283 | return 0; |
| 288 | 284 | ||
| 289 | /* | 285 | /* |
| @@ -291,7 +287,7 @@ int generic_permission(struct inode *inode, int mask) | |||
| 291 | */ | 287 | */ |
| 292 | mask &= MAY_READ | MAY_WRITE | MAY_EXEC; | 288 | mask &= MAY_READ | MAY_WRITE | MAY_EXEC; |
| 293 | if (mask == MAY_READ) | 289 | if (mask == MAY_READ) |
| 294 | if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH)) | 290 | if (inode_capable(inode, CAP_DAC_READ_SEARCH)) |
| 295 | return 0; | 291 | return 0; |
| 296 | 292 | ||
| 297 | return -EACCES; | 293 | return -EACCES; |
| @@ -1934,19 +1930,15 @@ static int user_path_parent(int dfd, const char __user *path, | |||
| 1934 | */ | 1930 | */ |
| 1935 | static inline int check_sticky(struct inode *dir, struct inode *inode) | 1931 | static inline int check_sticky(struct inode *dir, struct inode *inode) |
| 1936 | { | 1932 | { |
| 1937 | uid_t fsuid = current_fsuid(); | 1933 | kuid_t fsuid = current_fsuid(); |
| 1938 | 1934 | ||
| 1939 | if (!(dir->i_mode & S_ISVTX)) | 1935 | if (!(dir->i_mode & S_ISVTX)) |
| 1940 | return 0; | 1936 | return 0; |
| 1941 | if (current_user_ns() != inode_userns(inode)) | 1937 | if (uid_eq(inode->i_uid, fsuid)) |
| 1942 | goto other_userns; | ||
| 1943 | if (inode->i_uid == fsuid) | ||
| 1944 | return 0; | 1938 | return 0; |
| 1945 | if (dir->i_uid == fsuid) | 1939 | if (uid_eq(dir->i_uid, fsuid)) |
| 1946 | return 0; | 1940 | return 0; |
| 1947 | 1941 | return !inode_capable(inode, CAP_FOWNER); | |
| 1948 | other_userns: | ||
| 1949 | return !ns_capable(inode_userns(inode), CAP_FOWNER); | ||
| 1950 | } | 1942 | } |
| 1951 | 1943 | ||
| 1952 | /* | 1944 | /* |
| @@ -2534,8 +2526,7 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) | |||
| 2534 | if (error) | 2526 | if (error) |
| 2535 | return error; | 2527 | return error; |
| 2536 | 2528 | ||
| 2537 | if ((S_ISCHR(mode) || S_ISBLK(mode)) && | 2529 | if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD)) |
| 2538 | !ns_capable(inode_userns(dir), CAP_MKNOD)) | ||
| 2539 | return -EPERM; | 2530 | return -EPERM; |
| 2540 | 2531 | ||
| 2541 | if (!dir->i_op->mknod) | 2532 | if (!dir->i_op->mknod) |
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index 79717a40daba..204438cc914e 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | /* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> */ | 1 | /* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> */ |
| 2 | 2 | ||
| 3 | #include <linux/sched.h> | 3 | #include <linux/sched.h> |
| 4 | #include <linux/user_namespace.h> | ||
| 4 | #include "nfsd.h" | 5 | #include "nfsd.h" |
| 5 | #include "auth.h" | 6 | #include "auth.h" |
| 6 | 7 | ||
| @@ -56,8 +57,8 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) | |||
| 56 | goto oom; | 57 | goto oom; |
| 57 | 58 | ||
| 58 | for (i = 0; i < rqgi->ngroups; i++) { | 59 | for (i = 0; i < rqgi->ngroups; i++) { |
| 59 | if (!GROUP_AT(rqgi, i)) | 60 | if (gid_eq(GLOBAL_ROOT_GID, GROUP_AT(rqgi, i))) |
| 60 | GROUP_AT(gi, i) = exp->ex_anon_gid; | 61 | GROUP_AT(gi, i) = make_kgid(&init_user_ns, exp->ex_anon_gid); |
| 61 | else | 62 | else |
| 62 | GROUP_AT(gi, i) = GROUP_AT(rqgi, i); | 63 | GROUP_AT(gi, i) = GROUP_AT(rqgi, i); |
| 63 | } | 64 | } |
| @@ -316,7 +316,8 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) | |||
| 316 | 316 | ||
| 317 | if (!issecure(SECURE_NO_SETUID_FIXUP)) { | 317 | if (!issecure(SECURE_NO_SETUID_FIXUP)) { |
| 318 | /* Clear the capabilities if we switch to a non-root user */ | 318 | /* Clear the capabilities if we switch to a non-root user */ |
| 319 | if (override_cred->uid) | 319 | kuid_t root_uid = make_kuid(override_cred->user_ns, 0); |
| 320 | if (!uid_eq(override_cred->uid, root_uid)) | ||
| 320 | cap_clear(override_cred->cap_effective); | 321 | cap_clear(override_cred->cap_effective); |
| 321 | else | 322 | else |
| 322 | override_cred->cap_effective = | 323 | override_cred->cap_effective = |
| @@ -505,15 +506,24 @@ static int chown_common(struct path *path, uid_t user, gid_t group) | |||
| 505 | struct inode *inode = path->dentry->d_inode; | 506 | struct inode *inode = path->dentry->d_inode; |
| 506 | int error; | 507 | int error; |
| 507 | struct iattr newattrs; | 508 | struct iattr newattrs; |
| 509 | kuid_t uid; | ||
| 510 | kgid_t gid; | ||
| 511 | |||
| 512 | uid = make_kuid(current_user_ns(), user); | ||
| 513 | gid = make_kgid(current_user_ns(), group); | ||
| 508 | 514 | ||
| 509 | newattrs.ia_valid = ATTR_CTIME; | 515 | newattrs.ia_valid = ATTR_CTIME; |
| 510 | if (user != (uid_t) -1) { | 516 | if (user != (uid_t) -1) { |
| 517 | if (!uid_valid(uid)) | ||
| 518 | return -EINVAL; | ||
| 511 | newattrs.ia_valid |= ATTR_UID; | 519 | newattrs.ia_valid |= ATTR_UID; |
| 512 | newattrs.ia_uid = user; | 520 | newattrs.ia_uid = uid; |
| 513 | } | 521 | } |
| 514 | if (group != (gid_t) -1) { | 522 | if (group != (gid_t) -1) { |
| 523 | if (!gid_valid(gid)) | ||
| 524 | return -EINVAL; | ||
| 515 | newattrs.ia_valid |= ATTR_GID; | 525 | newattrs.ia_valid |= ATTR_GID; |
| 516 | newattrs.ia_gid = group; | 526 | newattrs.ia_gid = gid; |
| 517 | } | 527 | } |
| 518 | if (!S_ISDIR(inode->i_mode)) | 528 | if (!S_ISDIR(inode->i_mode)) |
| 519 | newattrs.ia_valid |= | 529 | newattrs.ia_valid |= |
diff --git a/fs/proc/array.c b/fs/proc/array.c index f9bd395b3473..dc4c5a7b9ece 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
| @@ -81,6 +81,7 @@ | |||
| 81 | #include <linux/pid_namespace.h> | 81 | #include <linux/pid_namespace.h> |
| 82 | #include <linux/ptrace.h> | 82 | #include <linux/ptrace.h> |
| 83 | #include <linux/tracehook.h> | 83 | #include <linux/tracehook.h> |
| 84 | #include <linux/user_namespace.h> | ||
| 84 | 85 | ||
| 85 | #include <asm/pgtable.h> | 86 | #include <asm/pgtable.h> |
| 86 | #include <asm/processor.h> | 87 | #include <asm/processor.h> |
| @@ -161,6 +162,7 @@ static inline const char *get_task_state(struct task_struct *tsk) | |||
| 161 | static inline void task_state(struct seq_file *m, struct pid_namespace *ns, | 162 | static inline void task_state(struct seq_file *m, struct pid_namespace *ns, |
| 162 | struct pid *pid, struct task_struct *p) | 163 | struct pid *pid, struct task_struct *p) |
| 163 | { | 164 | { |
| 165 | struct user_namespace *user_ns = current_user_ns(); | ||
| 164 | struct group_info *group_info; | 166 | struct group_info *group_info; |
| 165 | int g; | 167 | int g; |
| 166 | struct fdtable *fdt = NULL; | 168 | struct fdtable *fdt = NULL; |
| @@ -189,8 +191,14 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, | |||
| 189 | task_tgid_nr_ns(p, ns), | 191 | task_tgid_nr_ns(p, ns), |
| 190 | pid_nr_ns(pid, ns), | 192 | pid_nr_ns(pid, ns), |
| 191 | ppid, tpid, | 193 | ppid, tpid, |
| 192 | cred->uid, cred->euid, cred->suid, cred->fsuid, | 194 | from_kuid_munged(user_ns, cred->uid), |
| 193 | cred->gid, cred->egid, cred->sgid, cred->fsgid); | 195 | from_kuid_munged(user_ns, cred->euid), |
| 196 | from_kuid_munged(user_ns, cred->suid), | ||
| 197 | from_kuid_munged(user_ns, cred->fsuid), | ||
| 198 | from_kgid_munged(user_ns, cred->gid), | ||
| 199 | from_kgid_munged(user_ns, cred->egid), | ||
| 200 | from_kgid_munged(user_ns, cred->sgid), | ||
| 201 | from_kgid_munged(user_ns, cred->fsgid)); | ||
| 194 | 202 | ||
| 195 | task_lock(p); | 203 | task_lock(p); |
| 196 | if (p->files) | 204 | if (p->files) |
| @@ -205,7 +213,8 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, | |||
| 205 | task_unlock(p); | 213 | task_unlock(p); |
| 206 | 214 | ||
| 207 | for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++) | 215 | for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++) |
| 208 | seq_printf(m, "%d ", GROUP_AT(group_info, g)); | 216 | seq_printf(m, "%d ", |
| 217 | from_kgid_munged(user_ns, GROUP_AT(group_info, g))); | ||
| 209 | put_cred(cred); | 218 | put_cred(cred); |
| 210 | 219 | ||
| 211 | seq_putc(m, '\n'); | 220 | seq_putc(m, '\n'); |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 57b8159f26f3..d2d3108a611c 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
| @@ -81,6 +81,7 @@ | |||
| 81 | #include <linux/oom.h> | 81 | #include <linux/oom.h> |
| 82 | #include <linux/elf.h> | 82 | #include <linux/elf.h> |
| 83 | #include <linux/pid_namespace.h> | 83 | #include <linux/pid_namespace.h> |
| 84 | #include <linux/user_namespace.h> | ||
| 84 | #include <linux/fs_struct.h> | 85 | #include <linux/fs_struct.h> |
| 85 | #include <linux/slab.h> | 86 | #include <linux/slab.h> |
| 86 | #include <linux/flex_array.h> | 87 | #include <linux/flex_array.h> |
| @@ -1561,8 +1562,8 @@ int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
| 1561 | generic_fillattr(inode, stat); | 1562 | generic_fillattr(inode, stat); |
| 1562 | 1563 | ||
| 1563 | rcu_read_lock(); | 1564 | rcu_read_lock(); |
| 1564 | stat->uid = 0; | 1565 | stat->uid = GLOBAL_ROOT_UID; |
| 1565 | stat->gid = 0; | 1566 | stat->gid = GLOBAL_ROOT_GID; |
| 1566 | task = pid_task(proc_pid(inode), PIDTYPE_PID); | 1567 | task = pid_task(proc_pid(inode), PIDTYPE_PID); |
| 1567 | if (task) { | 1568 | if (task) { |
| 1568 | if (!has_pid_permissions(pid, task, 2)) { | 1569 | if (!has_pid_permissions(pid, task, 2)) { |
| @@ -1622,8 +1623,8 @@ int pid_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
| 1622 | inode->i_gid = cred->egid; | 1623 | inode->i_gid = cred->egid; |
| 1623 | rcu_read_unlock(); | 1624 | rcu_read_unlock(); |
| 1624 | } else { | 1625 | } else { |
| 1625 | inode->i_uid = 0; | 1626 | inode->i_uid = GLOBAL_ROOT_UID; |
| 1626 | inode->i_gid = 0; | 1627 | inode->i_gid = GLOBAL_ROOT_GID; |
| 1627 | } | 1628 | } |
| 1628 | inode->i_mode &= ~(S_ISUID | S_ISGID); | 1629 | inode->i_mode &= ~(S_ISUID | S_ISGID); |
| 1629 | security_task_to_inode(task, inode); | 1630 | security_task_to_inode(task, inode); |
| @@ -1815,8 +1816,8 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
| 1815 | inode->i_gid = cred->egid; | 1816 | inode->i_gid = cred->egid; |
| 1816 | rcu_read_unlock(); | 1817 | rcu_read_unlock(); |
| 1817 | } else { | 1818 | } else { |
| 1818 | inode->i_uid = 0; | 1819 | inode->i_uid = GLOBAL_ROOT_UID; |
| 1819 | inode->i_gid = 0; | 1820 | inode->i_gid = GLOBAL_ROOT_GID; |
| 1820 | } | 1821 | } |
| 1821 | 1822 | ||
| 1822 | i_mode = S_IFLNK; | 1823 | i_mode = S_IFLNK; |
| @@ -2045,8 +2046,8 @@ static int map_files_d_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
| 2045 | inode->i_gid = cred->egid; | 2046 | inode->i_gid = cred->egid; |
| 2046 | rcu_read_unlock(); | 2047 | rcu_read_unlock(); |
| 2047 | } else { | 2048 | } else { |
| 2048 | inode->i_uid = 0; | 2049 | inode->i_uid = GLOBAL_ROOT_UID; |
| 2049 | inode->i_gid = 0; | 2050 | inode->i_gid = GLOBAL_ROOT_GID; |
| 2050 | } | 2051 | } |
| 2051 | security_task_to_inode(task, inode); | 2052 | security_task_to_inode(task, inode); |
| 2052 | status = 1; | 2053 | status = 1; |
| @@ -2924,6 +2925,74 @@ static int proc_tgid_io_accounting(struct task_struct *task, char *buffer) | |||
| 2924 | } | 2925 | } |
| 2925 | #endif /* CONFIG_TASK_IO_ACCOUNTING */ | 2926 | #endif /* CONFIG_TASK_IO_ACCOUNTING */ |
| 2926 | 2927 | ||
| 2928 | #ifdef CONFIG_USER_NS | ||
| 2929 | static int proc_id_map_open(struct inode *inode, struct file *file, | ||
| 2930 | struct seq_operations *seq_ops) | ||
| 2931 | { | ||
| 2932 | struct user_namespace *ns = NULL; | ||
| 2933 | struct task_struct *task; | ||
| 2934 | struct seq_file *seq; | ||
| 2935 | int ret = -EINVAL; | ||
| 2936 | |||
| 2937 | task = get_proc_task(inode); | ||
| 2938 | if (task) { | ||
| 2939 | rcu_read_lock(); | ||
| 2940 | ns = get_user_ns(task_cred_xxx(task, user_ns)); | ||
| 2941 | rcu_read_unlock(); | ||
| 2942 | put_task_struct(task); | ||
| 2943 | } | ||
| 2944 | if (!ns) | ||
| 2945 | goto err; | ||
| 2946 | |||
| 2947 | ret = seq_open(file, seq_ops); | ||
| 2948 | if (ret) | ||
| 2949 | goto err_put_ns; | ||
| 2950 | |||
| 2951 | seq = file->private_data; | ||
| 2952 | seq->private = ns; | ||
| 2953 | |||
| 2954 | return 0; | ||
| 2955 | err_put_ns: | ||
| 2956 | put_user_ns(ns); | ||
| 2957 | err: | ||
| 2958 | return ret; | ||
| 2959 | } | ||
| 2960 | |||
| 2961 | static int proc_id_map_release(struct inode *inode, struct file *file) | ||
| 2962 | { | ||
| 2963 | struct seq_file *seq = file->private_data; | ||
| 2964 | struct user_namespace *ns = seq->private; | ||
| 2965 | put_user_ns(ns); | ||
| 2966 | return seq_release(inode, file); | ||
| 2967 | } | ||
| 2968 | |||
| 2969 | static int proc_uid_map_open(struct inode *inode, struct file *file) | ||
| 2970 | { | ||
| 2971 | return proc_id_map_open(inode, file, &proc_uid_seq_operations); | ||
| 2972 | } | ||
| 2973 | |||
| 2974 | static int proc_gid_map_open(struct inode *inode, struct file *file) | ||
| 2975 | { | ||
| 2976 | return proc_id_map_open(inode, file, &proc_gid_seq_operations); | ||
| 2977 | } | ||
| 2978 | |||
| 2979 | static const struct file_operations proc_uid_map_operations = { | ||
| 2980 | .open = proc_uid_map_open, | ||
| 2981 | .write = proc_uid_map_write, | ||
| 2982 | .read = seq_read, | ||
| 2983 | .llseek = seq_lseek, | ||
| 2984 | .release = proc_id_map_release, | ||
| 2985 | }; | ||
| 2986 | |||
| 2987 | static const struct file_operations proc_gid_map_operations = { | ||
| 2988 | .open = proc_gid_map_open, | ||
| 2989 | .write = proc_gid_map_write, | ||
| 2990 | .read = seq_read, | ||
| 2991 | .llseek = seq_lseek, | ||
| 2992 | .release = proc_id_map_release, | ||
| 2993 | }; | ||
| 2994 | #endif /* CONFIG_USER_NS */ | ||
| 2995 | |||
| 2927 | static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns, | 2996 | static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns, |
| 2928 | struct pid *pid, struct task_struct *task) | 2997 | struct pid *pid, struct task_struct *task) |
| 2929 | { | 2998 | { |
| @@ -3026,6 +3095,10 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
| 3026 | #ifdef CONFIG_HARDWALL | 3095 | #ifdef CONFIG_HARDWALL |
| 3027 | INF("hardwall", S_IRUGO, proc_pid_hardwall), | 3096 | INF("hardwall", S_IRUGO, proc_pid_hardwall), |
| 3028 | #endif | 3097 | #endif |
| 3098 | #ifdef CONFIG_USER_NS | ||
| 3099 | REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations), | ||
| 3100 | REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations), | ||
| 3101 | #endif | ||
| 3029 | }; | 3102 | }; |
| 3030 | 3103 | ||
| 3031 | static int proc_tgid_base_readdir(struct file * filp, | 3104 | static int proc_tgid_base_readdir(struct file * filp, |
| @@ -3381,6 +3454,10 @@ static const struct pid_entry tid_base_stuff[] = { | |||
| 3381 | #ifdef CONFIG_HARDWALL | 3454 | #ifdef CONFIG_HARDWALL |
| 3382 | INF("hardwall", S_IRUGO, proc_pid_hardwall), | 3455 | INF("hardwall", S_IRUGO, proc_pid_hardwall), |
| 3383 | #endif | 3456 | #endif |
| 3457 | #ifdef CONFIG_USER_NS | ||
| 3458 | REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations), | ||
| 3459 | REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations), | ||
| 3460 | #endif | ||
| 3384 | }; | 3461 | }; |
| 3385 | 3462 | ||
| 3386 | static int proc_tid_base_readdir(struct file * filp, | 3463 | static int proc_tid_base_readdir(struct file * filp, |
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 205c92280838..554ecc54799f 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
| @@ -108,8 +108,8 @@ static int proc_show_options(struct seq_file *seq, struct dentry *root) | |||
| 108 | struct super_block *sb = root->d_sb; | 108 | struct super_block *sb = root->d_sb; |
| 109 | struct pid_namespace *pid = sb->s_fs_info; | 109 | struct pid_namespace *pid = sb->s_fs_info; |
| 110 | 110 | ||
| 111 | if (pid->pid_gid) | 111 | if (!gid_eq(pid->pid_gid, GLOBAL_ROOT_GID)) |
| 112 | seq_printf(seq, ",gid=%lu", (unsigned long)pid->pid_gid); | 112 | seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, pid->pid_gid)); |
| 113 | if (pid->hide_pid != 0) | 113 | if (pid->hide_pid != 0) |
| 114 | seq_printf(seq, ",hidepid=%u", pid->hide_pid); | 114 | seq_printf(seq, ",hidepid=%u", pid->hide_pid); |
| 115 | 115 | ||
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 21d836f40292..3476bca8f7af 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
| @@ -371,9 +371,9 @@ void register_sysctl_root(struct ctl_table_root *root) | |||
| 371 | 371 | ||
| 372 | static int test_perm(int mode, int op) | 372 | static int test_perm(int mode, int op) |
| 373 | { | 373 | { |
| 374 | if (!current_euid()) | 374 | if (uid_eq(current_euid(), GLOBAL_ROOT_UID)) |
| 375 | mode >>= 6; | 375 | mode >>= 6; |
| 376 | else if (in_egroup_p(0)) | 376 | else if (in_egroup_p(GLOBAL_ROOT_GID)) |
| 377 | mode >>= 3; | 377 | mode >>= 3; |
| 378 | if ((op & ~mode & (MAY_READ|MAY_WRITE|MAY_EXEC)) == 0) | 378 | if ((op & ~mode & (MAY_READ|MAY_WRITE|MAY_EXEC)) == 0) |
| 379 | return 0; | 379 | return 0; |
diff --git a/fs/proc/root.c b/fs/proc/root.c index eed44bfc85db..7c30fce037c0 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c | |||
| @@ -67,7 +67,7 @@ static int proc_parse_options(char *options, struct pid_namespace *pid) | |||
| 67 | case Opt_gid: | 67 | case Opt_gid: |
| 68 | if (match_int(&args[0], &option)) | 68 | if (match_int(&args[0], &option)) |
| 69 | return 0; | 69 | return 0; |
| 70 | pid->pid_gid = option; | 70 | pid->pid_gid = make_kgid(current_user_ns(), option); |
| 71 | break; | 71 | break; |
| 72 | case Opt_hidepid: | 72 | case Opt_hidepid: |
| 73 | if (match_int(&args[0], &option)) | 73 | if (match_int(&args[0], &option)) |
| @@ -138,8 +138,8 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta | |||
| 138 | tmp.st_nlink = stat->nlink; | 138 | tmp.st_nlink = stat->nlink; |
| 139 | if (tmp.st_nlink != stat->nlink) | 139 | if (tmp.st_nlink != stat->nlink) |
| 140 | return -EOVERFLOW; | 140 | return -EOVERFLOW; |
| 141 | SET_UID(tmp.st_uid, stat->uid); | 141 | SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid)); |
| 142 | SET_GID(tmp.st_gid, stat->gid); | 142 | SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid)); |
| 143 | tmp.st_rdev = old_encode_dev(stat->rdev); | 143 | tmp.st_rdev = old_encode_dev(stat->rdev); |
| 144 | #if BITS_PER_LONG == 32 | 144 | #if BITS_PER_LONG == 32 |
| 145 | if (stat->size > MAX_NON_LFS) | 145 | if (stat->size > MAX_NON_LFS) |
| @@ -224,8 +224,8 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf) | |||
| 224 | tmp.st_nlink = stat->nlink; | 224 | tmp.st_nlink = stat->nlink; |
| 225 | if (tmp.st_nlink != stat->nlink) | 225 | if (tmp.st_nlink != stat->nlink) |
| 226 | return -EOVERFLOW; | 226 | return -EOVERFLOW; |
| 227 | SET_UID(tmp.st_uid, stat->uid); | 227 | SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid)); |
| 228 | SET_GID(tmp.st_gid, stat->gid); | 228 | SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid)); |
| 229 | tmp.st_rdev = encode_dev(stat->rdev); | 229 | tmp.st_rdev = encode_dev(stat->rdev); |
| 230 | tmp.st_size = stat->size; | 230 | tmp.st_size = stat->size; |
| 231 | tmp.st_atime = stat->atime.tv_sec; | 231 | tmp.st_atime = stat->atime.tv_sec; |
| @@ -355,8 +355,8 @@ static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf) | |||
| 355 | #endif | 355 | #endif |
| 356 | tmp.st_mode = stat->mode; | 356 | tmp.st_mode = stat->mode; |
| 357 | tmp.st_nlink = stat->nlink; | 357 | tmp.st_nlink = stat->nlink; |
| 358 | tmp.st_uid = stat->uid; | 358 | tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid); |
| 359 | tmp.st_gid = stat->gid; | 359 | tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid); |
| 360 | tmp.st_atime = stat->atime.tv_sec; | 360 | tmp.st_atime = stat->atime.tv_sec; |
| 361 | tmp.st_atime_nsec = stat->atime.tv_nsec; | 361 | tmp.st_atime_nsec = stat->atime.tv_nsec; |
| 362 | tmp.st_mtime = stat->mtime.tv_sec; | 362 | tmp.st_mtime = stat->mtime.tv_sec; |
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index feb2d69396cf..907c2b3af758 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
| @@ -62,8 +62,8 @@ static struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) | |||
| 62 | 62 | ||
| 63 | /* assign default attributes */ | 63 | /* assign default attributes */ |
| 64 | iattrs->ia_mode = sd->s_mode; | 64 | iattrs->ia_mode = sd->s_mode; |
| 65 | iattrs->ia_uid = 0; | 65 | iattrs->ia_uid = GLOBAL_ROOT_UID; |
| 66 | iattrs->ia_gid = 0; | 66 | iattrs->ia_gid = GLOBAL_ROOT_GID; |
| 67 | iattrs->ia_atime = iattrs->ia_mtime = iattrs->ia_ctime = CURRENT_TIME; | 67 | iattrs->ia_atime = iattrs->ia_mtime = iattrs->ia_ctime = CURRENT_TIME; |
| 68 | 68 | ||
| 69 | return attrs; | 69 | return attrs; |
diff --git a/include/linux/capability.h b/include/linux/capability.h index c398cff3dab7..68d56effc328 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h | |||
| @@ -377,6 +377,7 @@ struct cpu_vfs_cap_data { | |||
| 377 | 377 | ||
| 378 | #ifdef __KERNEL__ | 378 | #ifdef __KERNEL__ |
| 379 | 379 | ||
| 380 | struct inode; | ||
| 380 | struct dentry; | 381 | struct dentry; |
| 381 | struct user_namespace; | 382 | struct user_namespace; |
| 382 | 383 | ||
| @@ -551,6 +552,7 @@ extern bool has_ns_capability_noaudit(struct task_struct *t, | |||
| 551 | extern bool capable(int cap); | 552 | extern bool capable(int cap); |
| 552 | extern bool ns_capable(struct user_namespace *ns, int cap); | 553 | extern bool ns_capable(struct user_namespace *ns, int cap); |
| 553 | extern bool nsown_capable(int cap); | 554 | extern bool nsown_capable(int cap); |
| 555 | extern bool inode_capable(const struct inode *inode, int cap); | ||
| 554 | 556 | ||
| 555 | /* audit system wants to get cap info from files as well */ | 557 | /* audit system wants to get cap info from files as well */ |
| 556 | extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps); | 558 | extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps); |
diff --git a/include/linux/cred.h b/include/linux/cred.h index adadf71a7327..917dc5aeb1d4 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/key.h> | 17 | #include <linux/key.h> |
| 18 | #include <linux/selinux.h> | 18 | #include <linux/selinux.h> |
| 19 | #include <linux/atomic.h> | 19 | #include <linux/atomic.h> |
| 20 | #include <linux/uidgid.h> | ||
| 20 | 21 | ||
| 21 | struct user_struct; | 22 | struct user_struct; |
| 22 | struct cred; | 23 | struct cred; |
| @@ -26,14 +27,14 @@ struct inode; | |||
| 26 | * COW Supplementary groups list | 27 | * COW Supplementary groups list |
| 27 | */ | 28 | */ |
| 28 | #define NGROUPS_SMALL 32 | 29 | #define NGROUPS_SMALL 32 |
| 29 | #define NGROUPS_PER_BLOCK ((unsigned int)(PAGE_SIZE / sizeof(gid_t))) | 30 | #define NGROUPS_PER_BLOCK ((unsigned int)(PAGE_SIZE / sizeof(kgid_t))) |
| 30 | 31 | ||
| 31 | struct group_info { | 32 | struct group_info { |
| 32 | atomic_t usage; | 33 | atomic_t usage; |
| 33 | int ngroups; | 34 | int ngroups; |
| 34 | int nblocks; | 35 | int nblocks; |
| 35 | gid_t small_block[NGROUPS_SMALL]; | 36 | kgid_t small_block[NGROUPS_SMALL]; |
| 36 | gid_t *blocks[0]; | 37 | kgid_t *blocks[0]; |
| 37 | }; | 38 | }; |
| 38 | 39 | ||
| 39 | /** | 40 | /** |
| @@ -66,14 +67,14 @@ extern struct group_info init_groups; | |||
| 66 | extern void groups_free(struct group_info *); | 67 | extern void groups_free(struct group_info *); |
| 67 | extern int set_current_groups(struct group_info *); | 68 | extern int set_current_groups(struct group_info *); |
| 68 | extern int set_groups(struct cred *, struct group_info *); | 69 | extern int set_groups(struct cred *, struct group_info *); |
| 69 | extern int groups_search(const struct group_info *, gid_t); | 70 | extern int groups_search(const struct group_info *, kgid_t); |
| 70 | 71 | ||
| 71 | /* access the groups "array" with this macro */ | 72 | /* access the groups "array" with this macro */ |
| 72 | #define GROUP_AT(gi, i) \ | 73 | #define GROUP_AT(gi, i) \ |
| 73 | ((gi)->blocks[(i) / NGROUPS_PER_BLOCK][(i) % NGROUPS_PER_BLOCK]) | 74 | ((gi)->blocks[(i) / NGROUPS_PER_BLOCK][(i) % NGROUPS_PER_BLOCK]) |
| 74 | 75 | ||
| 75 | extern int in_group_p(gid_t); | 76 | extern int in_group_p(kgid_t); |
| 76 | extern int in_egroup_p(gid_t); | 77 | extern int in_egroup_p(kgid_t); |
| 77 | 78 | ||
| 78 | /* | 79 | /* |
| 79 | * The common credentials for a thread group | 80 | * The common credentials for a thread group |
| @@ -122,14 +123,14 @@ struct cred { | |||
| 122 | #define CRED_MAGIC 0x43736564 | 123 | #define CRED_MAGIC 0x43736564 |
| 123 | #define CRED_MAGIC_DEAD 0x44656144 | 124 | #define CRED_MAGIC_DEAD 0x44656144 |
| 124 | #endif | 125 | #endif |
| 125 | uid_t uid; /* real UID of the task */ | 126 | kuid_t uid; /* real UID of the task */ |
| 126 | gid_t gid; /* real GID of the task */ | 127 | kgid_t gid; /* real GID of the task */ |
| 127 | uid_t suid; /* saved UID of the task */ | 128 | kuid_t suid; /* saved UID of the task */ |
| 128 | gid_t sgid; /* saved GID of the task */ | 129 | kgid_t sgid; /* saved GID of the task */ |
| 129 | uid_t euid; /* effective UID of the task */ | 130 | kuid_t euid; /* effective UID of the task */ |
| 130 | gid_t egid; /* effective GID of the task */ | 131 | kgid_t egid; /* effective GID of the task */ |
| 131 | uid_t fsuid; /* UID for VFS ops */ | 132 | kuid_t fsuid; /* UID for VFS ops */ |
| 132 | gid_t fsgid; /* GID for VFS ops */ | 133 | kgid_t fsgid; /* GID for VFS ops */ |
| 133 | unsigned securebits; /* SUID-less security management */ | 134 | unsigned securebits; /* SUID-less security management */ |
| 134 | kernel_cap_t cap_inheritable; /* caps our children can inherit */ | 135 | kernel_cap_t cap_inheritable; /* caps our children can inherit */ |
| 135 | kernel_cap_t cap_permitted; /* caps we're permitted */ | 136 | kernel_cap_t cap_permitted; /* caps we're permitted */ |
| @@ -146,7 +147,7 @@ struct cred { | |||
| 146 | void *security; /* subjective LSM security */ | 147 | void *security; /* subjective LSM security */ |
| 147 | #endif | 148 | #endif |
| 148 | struct user_struct *user; /* real user ID subscription */ | 149 | struct user_struct *user; /* real user ID subscription */ |
| 149 | struct user_namespace *user_ns; /* cached user->user_ns */ | 150 | struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */ |
| 150 | struct group_info *group_info; /* supplementary groups for euid/fsgid */ | 151 | struct group_info *group_info; /* supplementary groups for euid/fsgid */ |
| 151 | struct rcu_head rcu; /* RCU deletion hook */ | 152 | struct rcu_head rcu; /* RCU deletion hook */ |
| 152 | }; | 153 | }; |
| @@ -357,11 +358,11 @@ static inline void put_cred(const struct cred *_cred) | |||
| 357 | #define current_user() (current_cred_xxx(user)) | 358 | #define current_user() (current_cred_xxx(user)) |
| 358 | #define current_security() (current_cred_xxx(security)) | 359 | #define current_security() (current_cred_xxx(security)) |
| 359 | 360 | ||
| 361 | extern struct user_namespace init_user_ns; | ||
| 360 | #ifdef CONFIG_USER_NS | 362 | #ifdef CONFIG_USER_NS |
| 361 | #define current_user_ns() (current_cred_xxx(user_ns)) | 363 | #define current_user_ns() (current_cred_xxx(user_ns)) |
| 362 | #define task_user_ns(task) (task_cred_xxx((task), user_ns)) | 364 | #define task_user_ns(task) (task_cred_xxx((task), user_ns)) |
| 363 | #else | 365 | #else |
| 364 | extern struct user_namespace init_user_ns; | ||
| 365 | #define current_user_ns() (&init_user_ns) | 366 | #define current_user_ns() (&init_user_ns) |
| 366 | #define task_user_ns(task) (&init_user_ns) | 367 | #define task_user_ns(task) (&init_user_ns) |
| 367 | #endif | 368 | #endif |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 25c40b9f848a..c0e53372b082 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -402,6 +402,7 @@ struct inodes_stat_t { | |||
| 402 | #include <linux/atomic.h> | 402 | #include <linux/atomic.h> |
| 403 | #include <linux/shrinker.h> | 403 | #include <linux/shrinker.h> |
| 404 | #include <linux/migrate_mode.h> | 404 | #include <linux/migrate_mode.h> |
| 405 | #include <linux/uidgid.h> | ||
| 405 | 406 | ||
| 406 | #include <asm/byteorder.h> | 407 | #include <asm/byteorder.h> |
| 407 | 408 | ||
| @@ -469,8 +470,8 @@ typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset, | |||
| 469 | struct iattr { | 470 | struct iattr { |
| 470 | unsigned int ia_valid; | 471 | unsigned int ia_valid; |
| 471 | umode_t ia_mode; | 472 | umode_t ia_mode; |
| 472 | uid_t ia_uid; | 473 | kuid_t ia_uid; |
| 473 | gid_t ia_gid; | 474 | kgid_t ia_gid; |
| 474 | loff_t ia_size; | 475 | loff_t ia_size; |
| 475 | struct timespec ia_atime; | 476 | struct timespec ia_atime; |
| 476 | struct timespec ia_mtime; | 477 | struct timespec ia_mtime; |
| @@ -761,8 +762,8 @@ struct posix_acl; | |||
| 761 | struct inode { | 762 | struct inode { |
| 762 | umode_t i_mode; | 763 | umode_t i_mode; |
| 763 | unsigned short i_opflags; | 764 | unsigned short i_opflags; |
| 764 | uid_t i_uid; | 765 | kuid_t i_uid; |
| 765 | gid_t i_gid; | 766 | kgid_t i_gid; |
| 766 | unsigned int i_flags; | 767 | unsigned int i_flags; |
| 767 | 768 | ||
| 768 | #ifdef CONFIG_FS_POSIX_ACL | 769 | #ifdef CONFIG_FS_POSIX_ACL |
| @@ -927,6 +928,31 @@ static inline void i_size_write(struct inode *inode, loff_t i_size) | |||
| 927 | #endif | 928 | #endif |
| 928 | } | 929 | } |
| 929 | 930 | ||
| 931 | /* Helper functions so that in most cases filesystems will | ||
| 932 | * not need to deal directly with kuid_t and kgid_t and can | ||
| 933 | * instead deal with the raw numeric values that are stored | ||
| 934 | * in the filesystem. | ||
| 935 | */ | ||
| 936 | static inline uid_t i_uid_read(const struct inode *inode) | ||
| 937 | { | ||
| 938 | return from_kuid(&init_user_ns, inode->i_uid); | ||
| 939 | } | ||
| 940 | |||
| 941 | static inline gid_t i_gid_read(const struct inode *inode) | ||
| 942 | { | ||
| 943 | return from_kgid(&init_user_ns, inode->i_gid); | ||
| 944 | } | ||
| 945 | |||
| 946 | static inline void i_uid_write(struct inode *inode, uid_t uid) | ||
| 947 | { | ||
| 948 | inode->i_uid = make_kuid(&init_user_ns, uid); | ||
| 949 | } | ||
| 950 | |||
| 951 | static inline void i_gid_write(struct inode *inode, gid_t gid) | ||
| 952 | { | ||
| 953 | inode->i_gid = make_kgid(&init_user_ns, gid); | ||
| 954 | } | ||
| 955 | |||
| 930 | static inline unsigned iminor(const struct inode *inode) | 956 | static inline unsigned iminor(const struct inode *inode) |
| 931 | { | 957 | { |
| 932 | return MINOR(inode->i_rdev); | 958 | return MINOR(inode->i_rdev); |
| @@ -943,7 +969,7 @@ struct fown_struct { | |||
| 943 | rwlock_t lock; /* protects pid, uid, euid fields */ | 969 | rwlock_t lock; /* protects pid, uid, euid fields */ |
| 944 | struct pid *pid; /* pid or -pgrp where SIGIO should be sent */ | 970 | struct pid *pid; /* pid or -pgrp where SIGIO should be sent */ |
| 945 | enum pid_type pid_type; /* Kind of process group SIGIO should be sent to */ | 971 | enum pid_type pid_type; /* Kind of process group SIGIO should be sent to */ |
| 946 | uid_t uid, euid; /* uid/euid of process setting the owner */ | 972 | kuid_t uid, euid; /* uid/euid of process setting the owner */ |
| 947 | int signum; /* posix.1b rt signal to be delivered on IO */ | 973 | int signum; /* posix.1b rt signal to be delivered on IO */ |
| 948 | }; | 974 | }; |
| 949 | 975 | ||
| @@ -1527,12 +1553,6 @@ enum { | |||
| 1527 | #define vfs_check_frozen(sb, level) \ | 1553 | #define vfs_check_frozen(sb, level) \ |
| 1528 | wait_event((sb)->s_wait_unfrozen, ((sb)->s_frozen < (level))) | 1554 | wait_event((sb)->s_wait_unfrozen, ((sb)->s_frozen < (level))) |
| 1529 | 1555 | ||
| 1530 | /* | ||
| 1531 | * until VFS tracks user namespaces for inodes, just make all files | ||
| 1532 | * belong to init_user_ns | ||
| 1533 | */ | ||
| 1534 | extern struct user_namespace init_user_ns; | ||
| 1535 | #define inode_userns(inode) (&init_user_ns) | ||
| 1536 | extern bool inode_owner_or_capable(const struct inode *inode); | 1556 | extern bool inode_owner_or_capable(const struct inode *inode); |
| 1537 | 1557 | ||
| 1538 | /* not quite ready to be deprecated, but... */ | 1558 | /* not quite ready to be deprecated, but... */ |
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h index b067bd8c49d0..00474b047145 100644 --- a/include/linux/pid_namespace.h +++ b/include/linux/pid_namespace.h | |||
| @@ -31,7 +31,7 @@ struct pid_namespace { | |||
| 31 | #ifdef CONFIG_BSD_PROCESS_ACCT | 31 | #ifdef CONFIG_BSD_PROCESS_ACCT |
| 32 | struct bsd_acct_struct *bacct; | 32 | struct bsd_acct_struct *bacct; |
| 33 | #endif | 33 | #endif |
| 34 | gid_t pid_gid; | 34 | kgid_t pid_gid; |
| 35 | int hide_pid; | 35 | int hide_pid; |
| 36 | int reboot; /* group exit code if this pidns was rebooted */ | 36 | int reboot; /* group exit code if this pidns was rebooted */ |
| 37 | }; | 37 | }; |
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 85c507306239..3fd2e871ff1b 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h | |||
| @@ -52,8 +52,8 @@ struct proc_dir_entry { | |||
| 52 | unsigned int low_ino; | 52 | unsigned int low_ino; |
| 53 | umode_t mode; | 53 | umode_t mode; |
| 54 | nlink_t nlink; | 54 | nlink_t nlink; |
| 55 | uid_t uid; | 55 | kuid_t uid; |
| 56 | gid_t gid; | 56 | kgid_t gid; |
| 57 | loff_t size; | 57 | loff_t size; |
| 58 | const struct inode_operations *proc_iops; | 58 | const struct inode_operations *proc_iops; |
| 59 | /* | 59 | /* |
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h index d93f95e6177c..17b977304a09 100644 --- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h | |||
| @@ -22,8 +22,8 @@ static inline struct quota_info *sb_dqopt(struct super_block *sb) | |||
| 22 | static inline bool is_quota_modification(struct inode *inode, struct iattr *ia) | 22 | static inline bool is_quota_modification(struct inode *inode, struct iattr *ia) |
| 23 | { | 23 | { |
| 24 | return (ia->ia_valid & ATTR_SIZE && ia->ia_size != inode->i_size) || | 24 | return (ia->ia_valid & ATTR_SIZE && ia->ia_size != inode->i_size) || |
| 25 | (ia->ia_valid & ATTR_UID && ia->ia_uid != inode->i_uid) || | 25 | (ia->ia_valid & ATTR_UID && !uid_eq(ia->ia_uid, inode->i_uid)) || |
| 26 | (ia->ia_valid & ATTR_GID && ia->ia_gid != inode->i_gid); | 26 | (ia->ia_valid & ATTR_GID && !gid_eq(ia->ia_gid, inode->i_gid)); |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | #if defined(CONFIG_QUOTA) | 29 | #if defined(CONFIG_QUOTA) |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 28fa9d02fd59..5ea8baea9387 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
| @@ -90,6 +90,7 @@ struct sched_param { | |||
| 90 | #include <linux/latencytop.h> | 90 | #include <linux/latencytop.h> |
| 91 | #include <linux/cred.h> | 91 | #include <linux/cred.h> |
| 92 | #include <linux/llist.h> | 92 | #include <linux/llist.h> |
| 93 | #include <linux/uidgid.h> | ||
| 93 | 94 | ||
| 94 | #include <asm/processor.h> | 95 | #include <asm/processor.h> |
| 95 | 96 | ||
| @@ -728,8 +729,7 @@ struct user_struct { | |||
| 728 | 729 | ||
| 729 | /* Hash table maintenance information */ | 730 | /* Hash table maintenance information */ |
| 730 | struct hlist_node uidhash_node; | 731 | struct hlist_node uidhash_node; |
| 731 | uid_t uid; | 732 | kuid_t uid; |
| 732 | struct user_namespace *user_ns; | ||
| 733 | 733 | ||
| 734 | #ifdef CONFIG_PERF_EVENTS | 734 | #ifdef CONFIG_PERF_EVENTS |
| 735 | atomic_long_t locked_vm; | 735 | atomic_long_t locked_vm; |
| @@ -738,7 +738,7 @@ struct user_struct { | |||
| 738 | 738 | ||
| 739 | extern int uids_sysfs_init(void); | 739 | extern int uids_sysfs_init(void); |
| 740 | 740 | ||
| 741 | extern struct user_struct *find_user(uid_t); | 741 | extern struct user_struct *find_user(kuid_t); |
| 742 | 742 | ||
| 743 | extern struct user_struct root_user; | 743 | extern struct user_struct root_user; |
| 744 | #define INIT_USER (&root_user) | 744 | #define INIT_USER (&root_user) |
| @@ -2142,14 +2142,13 @@ extern struct task_struct *find_task_by_pid_ns(pid_t nr, | |||
| 2142 | extern void __set_special_pids(struct pid *pid); | 2142 | extern void __set_special_pids(struct pid *pid); |
| 2143 | 2143 | ||
| 2144 | /* per-UID process charging. */ | 2144 | /* per-UID process charging. */ |
| 2145 | extern struct user_struct * alloc_uid(struct user_namespace *, uid_t); | 2145 | extern struct user_struct * alloc_uid(kuid_t); |
| 2146 | static inline struct user_struct *get_uid(struct user_struct *u) | 2146 | static inline struct user_struct *get_uid(struct user_struct *u) |
| 2147 | { | 2147 | { |
| 2148 | atomic_inc(&u->__count); | 2148 | atomic_inc(&u->__count); |
| 2149 | return u; | 2149 | return u; |
| 2150 | } | 2150 | } |
| 2151 | extern void free_uid(struct user_struct *); | 2151 | extern void free_uid(struct user_struct *); |
| 2152 | extern void release_uids(struct user_namespace *ns); | ||
| 2153 | 2152 | ||
| 2154 | #include <asm/current.h> | 2153 | #include <asm/current.h> |
| 2155 | 2154 | ||
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h index 79ab2555b3b0..bef2cf00b3be 100644 --- a/include/linux/shmem_fs.h +++ b/include/linux/shmem_fs.h | |||
| @@ -28,8 +28,8 @@ struct shmem_sb_info { | |||
| 28 | unsigned long max_inodes; /* How many inodes are allowed */ | 28 | unsigned long max_inodes; /* How many inodes are allowed */ |
| 29 | unsigned long free_inodes; /* How many are left for allocation */ | 29 | unsigned long free_inodes; /* How many are left for allocation */ |
| 30 | spinlock_t stat_lock; /* Serialize shmem_sb_info changes */ | 30 | spinlock_t stat_lock; /* Serialize shmem_sb_info changes */ |
| 31 | uid_t uid; /* Mount uid for root directory */ | 31 | kuid_t uid; /* Mount uid for root directory */ |
| 32 | gid_t gid; /* Mount gid for root directory */ | 32 | kgid_t gid; /* Mount gid for root directory */ |
| 33 | umode_t mode; /* Mount mode for root directory */ | 33 | umode_t mode; /* Mount mode for root directory */ |
| 34 | struct mempolicy *mpol; /* default memory policy for mappings */ | 34 | struct mempolicy *mpol; /* default memory policy for mappings */ |
| 35 | }; | 35 | }; |
diff --git a/include/linux/stat.h b/include/linux/stat.h index 611c398dab72..46132409a3f7 100644 --- a/include/linux/stat.h +++ b/include/linux/stat.h | |||
| @@ -58,14 +58,15 @@ | |||
| 58 | 58 | ||
| 59 | #include <linux/types.h> | 59 | #include <linux/types.h> |
| 60 | #include <linux/time.h> | 60 | #include <linux/time.h> |
| 61 | #include <linux/uidgid.h> | ||
| 61 | 62 | ||
| 62 | struct kstat { | 63 | struct kstat { |
| 63 | u64 ino; | 64 | u64 ino; |
| 64 | dev_t dev; | 65 | dev_t dev; |
| 65 | umode_t mode; | 66 | umode_t mode; |
| 66 | unsigned int nlink; | 67 | unsigned int nlink; |
| 67 | uid_t uid; | 68 | kuid_t uid; |
| 68 | gid_t gid; | 69 | kgid_t gid; |
| 69 | dev_t rdev; | 70 | dev_t rdev; |
| 70 | loff_t size; | 71 | loff_t size; |
| 71 | struct timespec atime; | 72 | struct timespec atime; |
diff --git a/include/linux/uidgid.h b/include/linux/uidgid.h new file mode 100644 index 000000000000..8e522cbcef29 --- /dev/null +++ b/include/linux/uidgid.h | |||
| @@ -0,0 +1,200 @@ | |||
| 1 | #ifndef _LINUX_UIDGID_H | ||
| 2 | #define _LINUX_UIDGID_H | ||
| 3 | |||
| 4 | /* | ||
| 5 | * A set of types for the internal kernel types representing uids and gids. | ||
| 6 | * | ||
| 7 | * The types defined in this header allow distinguishing which uids and gids in | ||
| 8 | * the kernel are values used by userspace and which uid and gid values are | ||
| 9 | * the internal kernel values. With the addition of user namespaces the values | ||
| 10 | * can be different. Using the type system makes it possible for the compiler | ||
| 11 | * to detect when we overlook these differences. | ||
| 12 | * | ||
| 13 | */ | ||
| 14 | #include <linux/types.h> | ||
| 15 | #include <linux/highuid.h> | ||
| 16 | |||
| 17 | struct user_namespace; | ||
| 18 | extern struct user_namespace init_user_ns; | ||
| 19 | |||
| 20 | #ifdef CONFIG_UIDGID_STRICT_TYPE_CHECKS | ||
| 21 | |||
| 22 | typedef struct { | ||
| 23 | uid_t val; | ||
| 24 | } kuid_t; | ||
| 25 | |||
| 26 | |||
| 27 | typedef struct { | ||
| 28 | gid_t val; | ||
| 29 | } kgid_t; | ||
| 30 | |||
| 31 | #define KUIDT_INIT(value) (kuid_t){ value } | ||
| 32 | #define KGIDT_INIT(value) (kgid_t){ value } | ||
| 33 | |||
| 34 | static inline uid_t __kuid_val(kuid_t uid) | ||
| 35 | { | ||
| 36 | return uid.val; | ||
| 37 | } | ||
| 38 | |||
| 39 | static inline gid_t __kgid_val(kgid_t gid) | ||
| 40 | { | ||
| 41 | return gid.val; | ||
| 42 | } | ||
| 43 | |||
| 44 | #else | ||
| 45 | |||
| 46 | typedef uid_t kuid_t; | ||
| 47 | typedef gid_t kgid_t; | ||
| 48 | |||
| 49 | static inline uid_t __kuid_val(kuid_t uid) | ||
| 50 | { | ||
| 51 | return uid; | ||
| 52 | } | ||
| 53 | |||
| 54 | static inline gid_t __kgid_val(kgid_t gid) | ||
| 55 | { | ||
| 56 | return gid; | ||
| 57 | } | ||
| 58 | |||
| 59 | #define KUIDT_INIT(value) ((kuid_t) value ) | ||
| 60 | #define KGIDT_INIT(value) ((kgid_t) value ) | ||
| 61 | |||
| 62 | #endif | ||
| 63 | |||
| 64 | #define GLOBAL_ROOT_UID KUIDT_INIT(0) | ||
| 65 | #define GLOBAL_ROOT_GID KGIDT_INIT(0) | ||
| 66 | |||
| 67 | #define INVALID_UID KUIDT_INIT(-1) | ||
| 68 | #define INVALID_GID KGIDT_INIT(-1) | ||
| 69 | |||
| 70 | static inline bool uid_eq(kuid_t left, kuid_t right) | ||
| 71 | { | ||
| 72 | return __kuid_val(left) == __kuid_val(right); | ||
| 73 | } | ||
| 74 | |||
| 75 | static inline bool gid_eq(kgid_t left, kgid_t right) | ||
| 76 | { | ||
| 77 | return __kgid_val(left) == __kgid_val(right); | ||
| 78 | } | ||
| 79 | |||
| 80 | static inline bool uid_gt(kuid_t left, kuid_t right) | ||
| 81 | { | ||
| 82 | return __kuid_val(left) > __kuid_val(right); | ||
| 83 | } | ||
| 84 | |||
| 85 | static inline bool gid_gt(kgid_t left, kgid_t right) | ||
| 86 | { | ||
| 87 | return __kgid_val(left) > __kgid_val(right); | ||
| 88 | } | ||
| 89 | |||
| 90 | static inline bool uid_gte(kuid_t left, kuid_t right) | ||
| 91 | { | ||
| 92 | return __kuid_val(left) >= __kuid_val(right); | ||
| 93 | } | ||
| 94 | |||
| 95 | static inline bool gid_gte(kgid_t left, kgid_t right) | ||
| 96 | { | ||
| 97 | return __kgid_val(left) >= __kgid_val(right); | ||
| 98 | } | ||
| 99 | |||
| 100 | static inline bool uid_lt(kuid_t left, kuid_t right) | ||
| 101 | { | ||
| 102 | return __kuid_val(left) < __kuid_val(right); | ||
| 103 | } | ||
| 104 | |||
| 105 | static inline bool gid_lt(kgid_t left, kgid_t right) | ||
| 106 | { | ||
| 107 | return __kgid_val(left) < __kgid_val(right); | ||
| 108 | } | ||
| 109 | |||
| 110 | static inline bool uid_lte(kuid_t left, kuid_t right) | ||
| 111 | { | ||
| 112 | return __kuid_val(left) <= __kuid_val(right); | ||
| 113 | } | ||
| 114 | |||
| 115 | static inline bool gid_lte(kgid_t left, kgid_t right) | ||
| 116 | { | ||
| 117 | return __kgid_val(left) <= __kgid_val(right); | ||
| 118 | } | ||
| 119 | |||
| 120 | static inline bool uid_valid(kuid_t uid) | ||
| 121 | { | ||
| 122 | return !uid_eq(uid, INVALID_UID); | ||
| 123 | } | ||
| 124 | |||
| 125 | static inline bool gid_valid(kgid_t gid) | ||
| 126 | { | ||
| 127 | return !gid_eq(gid, INVALID_GID); | ||
| 128 | } | ||
| 129 | |||
| 130 | #ifdef CONFIG_USER_NS | ||
| 131 | |||
| 132 | extern kuid_t make_kuid(struct user_namespace *from, uid_t uid); | ||
| 133 | extern kgid_t make_kgid(struct user_namespace *from, gid_t gid); | ||
| 134 | |||
| 135 | extern uid_t from_kuid(struct user_namespace *to, kuid_t uid); | ||
| 136 | extern gid_t from_kgid(struct user_namespace *to, kgid_t gid); | ||
| 137 | extern uid_t from_kuid_munged(struct user_namespace *to, kuid_t uid); | ||
| 138 | extern gid_t from_kgid_munged(struct user_namespace *to, kgid_t gid); | ||
| 139 | |||
| 140 | static inline bool kuid_has_mapping(struct user_namespace *ns, kuid_t uid) | ||
| 141 | { | ||
| 142 | return from_kuid(ns, uid) != (uid_t) -1; | ||
| 143 | } | ||
| 144 | |||
| 145 | static inline bool kgid_has_mapping(struct user_namespace *ns, kgid_t gid) | ||
| 146 | { | ||
| 147 | return from_kgid(ns, gid) != (gid_t) -1; | ||
| 148 | } | ||
| 149 | |||
| 150 | #else | ||
| 151 | |||
| 152 | static inline kuid_t make_kuid(struct user_namespace *from, uid_t uid) | ||
| 153 | { | ||
| 154 | return KUIDT_INIT(uid); | ||
| 155 | } | ||
| 156 | |||
| 157 | static inline kgid_t make_kgid(struct user_namespace *from, gid_t gid) | ||
| 158 | { | ||
| 159 | return KGIDT_INIT(gid); | ||
| 160 | } | ||
| 161 | |||
| 162 | static inline uid_t from_kuid(struct user_namespace *to, kuid_t kuid) | ||
| 163 | { | ||
| 164 | return __kuid_val(kuid); | ||
| 165 | } | ||
| 166 | |||
| 167 | static inline gid_t from_kgid(struct user_namespace *to, kgid_t kgid) | ||
| 168 | { | ||
| 169 | return __kgid_val(kgid); | ||
| 170 | } | ||
| 171 | |||
| 172 | static inline uid_t from_kuid_munged(struct user_namespace *to, kuid_t kuid) | ||
| 173 | { | ||
| 174 | uid_t uid = from_kuid(to, kuid); | ||
| 175 | if (uid == (uid_t)-1) | ||
| 176 | uid = overflowuid; | ||
| 177 | return uid; | ||
| 178 | } | ||
| 179 | |||
| 180 | static inline gid_t from_kgid_munged(struct user_namespace *to, kgid_t kgid) | ||
| 181 | { | ||
| 182 | gid_t gid = from_kgid(to, kgid); | ||
| 183 | if (gid == (gid_t)-1) | ||
| 184 | gid = overflowgid; | ||
| 185 | return gid; | ||
| 186 | } | ||
| 187 | |||
| 188 | static inline bool kuid_has_mapping(struct user_namespace *ns, kuid_t uid) | ||
| 189 | { | ||
| 190 | return true; | ||
| 191 | } | ||
| 192 | |||
| 193 | static inline bool kgid_has_mapping(struct user_namespace *ns, kgid_t gid) | ||
| 194 | { | ||
| 195 | return true; | ||
| 196 | } | ||
| 197 | |||
| 198 | #endif /* CONFIG_USER_NS */ | ||
| 199 | |||
| 200 | #endif /* _LINUX_UIDGID_H */ | ||
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index faf467944baf..4e72922e5a75 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h | |||
| @@ -6,14 +6,24 @@ | |||
| 6 | #include <linux/sched.h> | 6 | #include <linux/sched.h> |
| 7 | #include <linux/err.h> | 7 | #include <linux/err.h> |
| 8 | 8 | ||
| 9 | #define UIDHASH_BITS (CONFIG_BASE_SMALL ? 3 : 7) | 9 | #define UID_GID_MAP_MAX_EXTENTS 5 |
| 10 | #define UIDHASH_SZ (1 << UIDHASH_BITS) | 10 | |
| 11 | struct uid_gid_map { /* 64 bytes -- 1 cache line */ | ||
| 12 | u32 nr_extents; | ||
| 13 | struct uid_gid_extent { | ||
| 14 | u32 first; | ||
| 15 | u32 lower_first; | ||
| 16 | u32 count; | ||
| 17 | } extent[UID_GID_MAP_MAX_EXTENTS]; | ||
| 18 | }; | ||
| 11 | 19 | ||
| 12 | struct user_namespace { | 20 | struct user_namespace { |
| 21 | struct uid_gid_map uid_map; | ||
| 22 | struct uid_gid_map gid_map; | ||
| 13 | struct kref kref; | 23 | struct kref kref; |
| 14 | struct hlist_head uidhash_table[UIDHASH_SZ]; | 24 | struct user_namespace *parent; |
| 15 | struct user_struct *creator; | 25 | kuid_t owner; |
| 16 | struct work_struct destroyer; | 26 | kgid_t group; |
| 17 | }; | 27 | }; |
| 18 | 28 | ||
| 19 | extern struct user_namespace init_user_ns; | 29 | extern struct user_namespace init_user_ns; |
| @@ -36,9 +46,11 @@ static inline void put_user_ns(struct user_namespace *ns) | |||
| 36 | kref_put(&ns->kref, free_user_ns); | 46 | kref_put(&ns->kref, free_user_ns); |
| 37 | } | 47 | } |
| 38 | 48 | ||
| 39 | uid_t user_ns_map_uid(struct user_namespace *to, const struct cred *cred, uid_t uid); | 49 | struct seq_operations; |
| 40 | gid_t user_ns_map_gid(struct user_namespace *to, const struct cred *cred, gid_t gid); | 50 | extern struct seq_operations proc_uid_seq_operations; |
| 41 | 51 | extern struct seq_operations proc_gid_seq_operations; | |
| 52 | extern ssize_t proc_uid_map_write(struct file *, const char __user *, size_t, loff_t *); | ||
| 53 | extern ssize_t proc_gid_map_write(struct file *, const char __user *, size_t, loff_t *); | ||
| 42 | #else | 54 | #else |
| 43 | 55 | ||
| 44 | static inline struct user_namespace *get_user_ns(struct user_namespace *ns) | 56 | static inline struct user_namespace *get_user_ns(struct user_namespace *ns) |
| @@ -55,17 +67,6 @@ static inline void put_user_ns(struct user_namespace *ns) | |||
| 55 | { | 67 | { |
| 56 | } | 68 | } |
| 57 | 69 | ||
| 58 | static inline uid_t user_ns_map_uid(struct user_namespace *to, | ||
| 59 | const struct cred *cred, uid_t uid) | ||
| 60 | { | ||
| 61 | return uid; | ||
| 62 | } | ||
| 63 | static inline gid_t user_ns_map_gid(struct user_namespace *to, | ||
| 64 | const struct cred *cred, gid_t gid) | ||
| 65 | { | ||
| 66 | return gid; | ||
| 67 | } | ||
| 68 | |||
| 69 | #endif | 70 | #endif |
| 70 | 71 | ||
| 71 | #endif /* _LINUX_USER_H */ | 72 | #endif /* _LINUX_USER_H */ |
diff --git a/include/trace/events/ext3.h b/include/trace/events/ext3.h index 7b53c0573dc9..15d11a39be47 100644 --- a/include/trace/events/ext3.h +++ b/include/trace/events/ext3.h | |||
| @@ -24,8 +24,8 @@ TRACE_EVENT(ext3_free_inode, | |||
| 24 | __entry->dev = inode->i_sb->s_dev; | 24 | __entry->dev = inode->i_sb->s_dev; |
| 25 | __entry->ino = inode->i_ino; | 25 | __entry->ino = inode->i_ino; |
| 26 | __entry->mode = inode->i_mode; | 26 | __entry->mode = inode->i_mode; |
| 27 | __entry->uid = inode->i_uid; | 27 | __entry->uid = i_uid_read(inode); |
| 28 | __entry->gid = inode->i_gid; | 28 | __entry->gid = i_gid_read(inode); |
| 29 | __entry->blocks = inode->i_blocks; | 29 | __entry->blocks = inode->i_blocks; |
| 30 | ), | 30 | ), |
| 31 | 31 | ||
diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h index 319538bf17d2..69d8a69ea831 100644 --- a/include/trace/events/ext4.h +++ b/include/trace/events/ext4.h | |||
| @@ -36,8 +36,8 @@ TRACE_EVENT(ext4_free_inode, | |||
| 36 | __entry->dev = inode->i_sb->s_dev; | 36 | __entry->dev = inode->i_sb->s_dev; |
| 37 | __entry->ino = inode->i_ino; | 37 | __entry->ino = inode->i_ino; |
| 38 | __entry->mode = inode->i_mode; | 38 | __entry->mode = inode->i_mode; |
| 39 | __entry->uid = inode->i_uid; | 39 | __entry->uid = i_uid_read(inode); |
| 40 | __entry->gid = inode->i_gid; | 40 | __entry->gid = i_gid_read(inode); |
| 41 | __entry->blocks = inode->i_blocks; | 41 | __entry->blocks = inode->i_blocks; |
| 42 | ), | 42 | ), |
| 43 | 43 | ||
diff --git a/init/Kconfig b/init/Kconfig index a30fe085940e..ccb5248474c2 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
| @@ -873,7 +873,10 @@ config IPC_NS | |||
| 873 | config USER_NS | 873 | config USER_NS |
| 874 | bool "User namespace (EXPERIMENTAL)" | 874 | bool "User namespace (EXPERIMENTAL)" |
| 875 | depends on EXPERIMENTAL | 875 | depends on EXPERIMENTAL |
| 876 | default y | 876 | depends on UIDGID_CONVERTED |
| 877 | select UIDGID_STRICT_TYPE_CHECKS | ||
| 878 | |||
| 879 | default n | ||
| 877 | help | 880 | help |
| 878 | This allows containers, i.e. vservers, to use user namespaces | 881 | This allows containers, i.e. vservers, to use user namespaces |
| 879 | to provide different user info for different servers. | 882 | to provide different user info for different servers. |
| @@ -897,6 +900,131 @@ config NET_NS | |||
| 897 | 900 | ||
| 898 | endif # NAMESPACES | 901 | endif # NAMESPACES |
| 899 | 902 | ||
| 903 | config UIDGID_CONVERTED | ||
| 904 | # True if all of the selected software conmponents are known | ||
| 905 | # to have uid_t and gid_t converted to kuid_t and kgid_t | ||
| 906 | # where appropriate and are otherwise safe to use with | ||
| 907 | # the user namespace. | ||
| 908 | bool | ||
| 909 | default y | ||
| 910 | |||
| 911 | # List of kernel pieces that need user namespace work | ||
| 912 | # Features | ||
| 913 | depends on SYSVIPC = n | ||
| 914 | depends on IMA = n | ||
| 915 | depends on EVM = n | ||
| 916 | depends on KEYS = n | ||
| 917 | depends on AUDIT = n | ||
| 918 | depends on AUDITSYSCALL = n | ||
| 919 | depends on TASKSTATS = n | ||
| 920 | depends on TRACING = n | ||
| 921 | depends on FS_POSIX_ACL = n | ||
| 922 | depends on QUOTA = n | ||
| 923 | depends on QUOTACTL = n | ||
| 924 | depends on DEBUG_CREDENTIALS = n | ||
| 925 | depends on BSD_PROCESS_ACCT = n | ||
| 926 | depends on DRM = n | ||
| 927 | depends on PROC_EVENTS = n | ||
| 928 | |||
| 929 | # Networking | ||
| 930 | depends on NET = n | ||
| 931 | depends on NET_9P = n | ||
| 932 | depends on IPX = n | ||
| 933 | depends on PHONET = n | ||
| 934 | depends on NET_CLS_FLOW = n | ||
| 935 | depends on NETFILTER_XT_MATCH_OWNER = n | ||
| 936 | depends on NETFILTER_XT_MATCH_RECENT = n | ||
| 937 | depends on NETFILTER_XT_TARGET_LOG = n | ||
| 938 | depends on NETFILTER_NETLINK_LOG = n | ||
| 939 | depends on INET = n | ||
| 940 | depends on IPV6 = n | ||
| 941 | depends on IP_SCTP = n | ||
| 942 | depends on AF_RXRPC = n | ||
| 943 | depends on LLC2 = n | ||
| 944 | depends on NET_KEY = n | ||
| 945 | depends on INET_DIAG = n | ||
| 946 | depends on DNS_RESOLVER = n | ||
| 947 | depends on AX25 = n | ||
| 948 | depends on ATALK = n | ||
| 949 | |||
| 950 | # Filesystems | ||
| 951 | depends on USB_DEVICEFS = n | ||
| 952 | depends on USB_GADGETFS = n | ||
| 953 | depends on USB_FUNCTIONFS = n | ||
| 954 | depends on DEVTMPFS = n | ||
| 955 | depends on XENFS = n | ||
| 956 | |||
| 957 | depends on 9P_FS = n | ||
| 958 | depends on ADFS_FS = n | ||
| 959 | depends on AFFS_FS = n | ||
| 960 | depends on AFS_FS = n | ||
| 961 | depends on AUTOFS4_FS = n | ||
| 962 | depends on BEFS_FS = n | ||
| 963 | depends on BFS_FS = n | ||
| 964 | depends on BTRFS_FS = n | ||
| 965 | depends on CEPH_FS = n | ||
| 966 | depends on CIFS = n | ||
| 967 | depends on CODA_FS = n | ||
| 968 | depends on CONFIGFS_FS = n | ||
| 969 | depends on CRAMFS = n | ||
| 970 | depends on DEBUG_FS = n | ||
| 971 | depends on ECRYPT_FS = n | ||
| 972 | depends on EFS_FS = n | ||
| 973 | depends on EXOFS_FS = n | ||
| 974 | depends on FAT_FS = n | ||
| 975 | depends on FUSE_FS = n | ||
| 976 | depends on GFS2_FS = n | ||
| 977 | depends on HFS_FS = n | ||
| 978 | depends on HFSPLUS_FS = n | ||
| 979 | depends on HPFS_FS = n | ||
| 980 | depends on HUGETLBFS = n | ||
| 981 | depends on ISO9660_FS = n | ||
| 982 | depends on JFFS2_FS = n | ||
| 983 | depends on JFS_FS = n | ||
| 984 | depends on LOGFS = n | ||
| 985 | depends on MINIX_FS = n | ||
| 986 | depends on NCP_FS = n | ||
| 987 | depends on NFSD = n | ||
| 988 | depends on NFS_FS = n | ||
| 989 | depends on NILFS2_FS = n | ||
| 990 | depends on NTFS_FS = n | ||
| 991 | depends on OCFS2_FS = n | ||
| 992 | depends on OMFS_FS = n | ||
| 993 | depends on QNX4FS_FS = n | ||
| 994 | depends on QNX6FS_FS = n | ||
| 995 | depends on REISERFS_FS = n | ||
| 996 | depends on SQUASHFS = n | ||
| 997 | depends on SYSV_FS = n | ||
| 998 | depends on UBIFS_FS = n | ||
| 999 | depends on UDF_FS = n | ||
| 1000 | depends on UFS_FS = n | ||
| 1001 | depends on VXFS_FS = n | ||
| 1002 | depends on XFS_FS = n | ||
| 1003 | |||
| 1004 | depends on !UML || HOSTFS = n | ||
| 1005 | |||
| 1006 | # The rare drivers that won't build | ||
| 1007 | depends on AIRO = n | ||
| 1008 | depends on AIRO_CS = n | ||
| 1009 | depends on TUN = n | ||
| 1010 | depends on INFINIBAND_QIB = n | ||
| 1011 | depends on BLK_DEV_LOOP = n | ||
| 1012 | depends on ANDROID_BINDER_IPC = n | ||
| 1013 | |||
| 1014 | # Security modules | ||
| 1015 | depends on SECURITY_TOMOYO = n | ||
| 1016 | depends on SECURITY_APPARMOR = n | ||
| 1017 | |||
| 1018 | config UIDGID_STRICT_TYPE_CHECKS | ||
| 1019 | bool "Require conversions between uid/gids and their internal representation" | ||
| 1020 | depends on UIDGID_CONVERTED | ||
| 1021 | default n | ||
| 1022 | help | ||
| 1023 | While the nececessary conversions are being added to all subsystems this option allows | ||
| 1024 | the code to continue to build for unconverted subsystems. | ||
| 1025 | |||
| 1026 | Say Y here if you want the strict type checking enabled | ||
| 1027 | |||
| 900 | config SCHED_AUTOGROUP | 1028 | config SCHED_AUTOGROUP |
| 901 | bool "Automatic process group scheduling" | 1029 | bool "Automatic process group scheduling" |
| 902 | select EVENTFD | 1030 | select EVENTFD |
diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 28bd64ddeda3..b6a0d46fbad7 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c | |||
| @@ -66,6 +66,7 @@ struct mqueue_inode_info { | |||
| 66 | 66 | ||
| 67 | struct sigevent notify; | 67 | struct sigevent notify; |
| 68 | struct pid* notify_owner; | 68 | struct pid* notify_owner; |
| 69 | struct user_namespace *notify_user_ns; | ||
| 69 | struct user_struct *user; /* user who created, for accounting */ | 70 | struct user_struct *user; /* user who created, for accounting */ |
| 70 | struct sock *notify_sock; | 71 | struct sock *notify_sock; |
| 71 | struct sk_buff *notify_cookie; | 72 | struct sk_buff *notify_cookie; |
| @@ -139,6 +140,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb, | |||
| 139 | INIT_LIST_HEAD(&info->e_wait_q[0].list); | 140 | INIT_LIST_HEAD(&info->e_wait_q[0].list); |
| 140 | INIT_LIST_HEAD(&info->e_wait_q[1].list); | 141 | INIT_LIST_HEAD(&info->e_wait_q[1].list); |
| 141 | info->notify_owner = NULL; | 142 | info->notify_owner = NULL; |
| 143 | info->notify_user_ns = NULL; | ||
| 142 | info->qsize = 0; | 144 | info->qsize = 0; |
| 143 | info->user = NULL; /* set when all is ok */ | 145 | info->user = NULL; /* set when all is ok */ |
| 144 | memset(&info->attr, 0, sizeof(info->attr)); | 146 | memset(&info->attr, 0, sizeof(info->attr)); |
| @@ -536,8 +538,7 @@ static void __do_notify(struct mqueue_inode_info *info) | |||
| 536 | rcu_read_lock(); | 538 | rcu_read_lock(); |
| 537 | sig_i.si_pid = task_tgid_nr_ns(current, | 539 | sig_i.si_pid = task_tgid_nr_ns(current, |
| 538 | ns_of_pid(info->notify_owner)); | 540 | ns_of_pid(info->notify_owner)); |
| 539 | sig_i.si_uid = user_ns_map_uid(info->user->user_ns, | 541 | sig_i.si_uid = from_kuid_munged(info->notify_user_ns, current_uid()); |
| 540 | current_cred(), current_uid()); | ||
| 541 | rcu_read_unlock(); | 542 | rcu_read_unlock(); |
| 542 | 543 | ||
| 543 | kill_pid_info(info->notify.sigev_signo, | 544 | kill_pid_info(info->notify.sigev_signo, |
| @@ -550,7 +551,9 @@ static void __do_notify(struct mqueue_inode_info *info) | |||
| 550 | } | 551 | } |
| 551 | /* after notification unregisters process */ | 552 | /* after notification unregisters process */ |
| 552 | put_pid(info->notify_owner); | 553 | put_pid(info->notify_owner); |
| 554 | put_user_ns(info->notify_user_ns); | ||
| 553 | info->notify_owner = NULL; | 555 | info->notify_owner = NULL; |
| 556 | info->notify_user_ns = NULL; | ||
| 554 | } | 557 | } |
| 555 | wake_up(&info->wait_q); | 558 | wake_up(&info->wait_q); |
| 556 | } | 559 | } |
| @@ -575,7 +578,9 @@ static void remove_notification(struct mqueue_inode_info *info) | |||
| 575 | netlink_sendskb(info->notify_sock, info->notify_cookie); | 578 | netlink_sendskb(info->notify_sock, info->notify_cookie); |
| 576 | } | 579 | } |
| 577 | put_pid(info->notify_owner); | 580 | put_pid(info->notify_owner); |
| 581 | put_user_ns(info->notify_user_ns); | ||
| 578 | info->notify_owner = NULL; | 582 | info->notify_owner = NULL; |
| 583 | info->notify_user_ns = NULL; | ||
| 579 | } | 584 | } |
| 580 | 585 | ||
| 581 | static int mq_attr_ok(struct ipc_namespace *ipc_ns, struct mq_attr *attr) | 586 | static int mq_attr_ok(struct ipc_namespace *ipc_ns, struct mq_attr *attr) |
| @@ -1140,6 +1145,7 @@ retry: | |||
| 1140 | } | 1145 | } |
| 1141 | 1146 | ||
| 1142 | info->notify_owner = get_pid(task_tgid(current)); | 1147 | info->notify_owner = get_pid(task_tgid(current)); |
| 1148 | info->notify_user_ns = get_user_ns(current_user_ns()); | ||
| 1143 | inode->i_atime = inode->i_ctime = CURRENT_TIME; | 1149 | inode->i_atime = inode->i_ctime = CURRENT_TIME; |
| 1144 | } | 1150 | } |
| 1145 | spin_unlock(&info->lock); | 1151 | spin_unlock(&info->lock); |
diff --git a/ipc/namespace.c b/ipc/namespace.c index ce0a647869b1..f362298c5ce4 100644 --- a/ipc/namespace.c +++ b/ipc/namespace.c | |||
| @@ -46,7 +46,7 @@ static struct ipc_namespace *create_ipc_ns(struct task_struct *tsk, | |||
| 46 | ipcns_notify(IPCNS_CREATED); | 46 | ipcns_notify(IPCNS_CREATED); |
| 47 | register_ipcns_notifier(ns); | 47 | register_ipcns_notifier(ns); |
| 48 | 48 | ||
| 49 | ns->user_ns = get_user_ns(task_cred_xxx(tsk, user)->user_ns); | 49 | ns->user_ns = get_user_ns(task_cred_xxx(tsk, user_ns)); |
| 50 | 50 | ||
| 51 | return ns; | 51 | return ns; |
| 52 | } | 52 | } |
diff --git a/kernel/capability.c b/kernel/capability.c index 3f1adb6c6470..493d97259484 100644 --- a/kernel/capability.c +++ b/kernel/capability.c | |||
| @@ -419,3 +419,24 @@ bool nsown_capable(int cap) | |||
| 419 | { | 419 | { |
| 420 | return ns_capable(current_user_ns(), cap); | 420 | return ns_capable(current_user_ns(), cap); |
| 421 | } | 421 | } |
| 422 | |||
| 423 | /** | ||
| 424 | * inode_capable - Check superior capability over inode | ||
| 425 | * @inode: The inode in question | ||
| 426 | * @cap: The capability in question | ||
| 427 | * | ||
| 428 | * Return true if the current task has the given superior capability | ||
| 429 | * targeted at it's own user namespace and that the given inode is owned | ||
| 430 | * by the current user namespace or a child namespace. | ||
| 431 | * | ||
| 432 | * Currently we check to see if an inode is owned by the current | ||
| 433 | * user namespace by seeing if the inode's owner maps into the | ||
| 434 | * current user namespace. | ||
| 435 | * | ||
| 436 | */ | ||
| 437 | bool inode_capable(const struct inode *inode, int cap) | ||
| 438 | { | ||
| 439 | struct user_namespace *ns = current_user_ns(); | ||
| 440 | |||
| 441 | return ns_capable(ns, cap) && kuid_has_mapping(ns, inode->i_uid); | ||
| 442 | } | ||
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index ad8eae5bb801..a0c6af34d500 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
| @@ -2214,9 +2214,9 @@ retry_find_task: | |||
| 2214 | * only need to check permissions on one of them. | 2214 | * only need to check permissions on one of them. |
| 2215 | */ | 2215 | */ |
| 2216 | tcred = __task_cred(tsk); | 2216 | tcred = __task_cred(tsk); |
| 2217 | if (cred->euid && | 2217 | if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) && |
| 2218 | cred->euid != tcred->uid && | 2218 | !uid_eq(cred->euid, tcred->uid) && |
| 2219 | cred->euid != tcred->suid) { | 2219 | !uid_eq(cred->euid, tcred->suid)) { |
| 2220 | rcu_read_unlock(); | 2220 | rcu_read_unlock(); |
| 2221 | ret = -EACCES; | 2221 | ret = -EACCES; |
| 2222 | goto out_unlock_cgroup; | 2222 | goto out_unlock_cgroup; |
diff --git a/kernel/cred.c b/kernel/cred.c index e70683d9ec32..430557ea488f 100644 --- a/kernel/cred.c +++ b/kernel/cred.c | |||
| @@ -49,6 +49,14 @@ struct cred init_cred = { | |||
| 49 | .subscribers = ATOMIC_INIT(2), | 49 | .subscribers = ATOMIC_INIT(2), |
| 50 | .magic = CRED_MAGIC, | 50 | .magic = CRED_MAGIC, |
| 51 | #endif | 51 | #endif |
| 52 | .uid = GLOBAL_ROOT_UID, | ||
| 53 | .gid = GLOBAL_ROOT_GID, | ||
| 54 | .suid = GLOBAL_ROOT_UID, | ||
| 55 | .sgid = GLOBAL_ROOT_GID, | ||
| 56 | .euid = GLOBAL_ROOT_UID, | ||
| 57 | .egid = GLOBAL_ROOT_GID, | ||
| 58 | .fsuid = GLOBAL_ROOT_UID, | ||
| 59 | .fsgid = GLOBAL_ROOT_GID, | ||
| 52 | .securebits = SECUREBITS_DEFAULT, | 60 | .securebits = SECUREBITS_DEFAULT, |
| 53 | .cap_inheritable = CAP_EMPTY_SET, | 61 | .cap_inheritable = CAP_EMPTY_SET, |
| 54 | .cap_permitted = CAP_FULL_SET, | 62 | .cap_permitted = CAP_FULL_SET, |
| @@ -148,6 +156,7 @@ static void put_cred_rcu(struct rcu_head *rcu) | |||
| 148 | if (cred->group_info) | 156 | if (cred->group_info) |
| 149 | put_group_info(cred->group_info); | 157 | put_group_info(cred->group_info); |
| 150 | free_uid(cred->user); | 158 | free_uid(cred->user); |
| 159 | put_user_ns(cred->user_ns); | ||
| 151 | kmem_cache_free(cred_jar, cred); | 160 | kmem_cache_free(cred_jar, cred); |
| 152 | } | 161 | } |
| 153 | 162 | ||
| @@ -303,6 +312,7 @@ struct cred *prepare_creds(void) | |||
| 303 | set_cred_subscribers(new, 0); | 312 | set_cred_subscribers(new, 0); |
| 304 | get_group_info(new->group_info); | 313 | get_group_info(new->group_info); |
| 305 | get_uid(new->user); | 314 | get_uid(new->user); |
| 315 | get_user_ns(new->user_ns); | ||
| 306 | 316 | ||
| 307 | #ifdef CONFIG_KEYS | 317 | #ifdef CONFIG_KEYS |
| 308 | key_get(new->thread_keyring); | 318 | key_get(new->thread_keyring); |
| @@ -414,11 +424,6 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) | |||
| 414 | goto error_put; | 424 | goto error_put; |
| 415 | } | 425 | } |
| 416 | 426 | ||
| 417 | /* cache user_ns in cred. Doesn't need a refcount because it will | ||
| 418 | * stay pinned by cred->user | ||
| 419 | */ | ||
| 420 | new->user_ns = new->user->user_ns; | ||
| 421 | |||
| 422 | #ifdef CONFIG_KEYS | 427 | #ifdef CONFIG_KEYS |
| 423 | /* new threads get their own thread keyrings if their parent already | 428 | /* new threads get their own thread keyrings if their parent already |
| 424 | * had one */ | 429 | * had one */ |
| @@ -493,10 +498,10 @@ int commit_creds(struct cred *new) | |||
| 493 | get_cred(new); /* we will require a ref for the subj creds too */ | 498 | get_cred(new); /* we will require a ref for the subj creds too */ |
| 494 | 499 | ||
| 495 | /* dumpability changes */ | 500 | /* dumpability changes */ |
| 496 | if (old->euid != new->euid || | 501 | if (!uid_eq(old->euid, new->euid) || |
| 497 | old->egid != new->egid || | 502 | !gid_eq(old->egid, new->egid) || |
| 498 | old->fsuid != new->fsuid || | 503 | !uid_eq(old->fsuid, new->fsuid) || |
| 499 | old->fsgid != new->fsgid || | 504 | !gid_eq(old->fsgid, new->fsgid) || |
| 500 | !cap_issubset(new->cap_permitted, old->cap_permitted)) { | 505 | !cap_issubset(new->cap_permitted, old->cap_permitted)) { |
| 501 | if (task->mm) | 506 | if (task->mm) |
| 502 | set_dumpable(task->mm, suid_dumpable); | 507 | set_dumpable(task->mm, suid_dumpable); |
| @@ -505,9 +510,9 @@ int commit_creds(struct cred *new) | |||
| 505 | } | 510 | } |
| 506 | 511 | ||
| 507 | /* alter the thread keyring */ | 512 | /* alter the thread keyring */ |
| 508 | if (new->fsuid != old->fsuid) | 513 | if (!uid_eq(new->fsuid, old->fsuid)) |
| 509 | key_fsuid_changed(task); | 514 | key_fsuid_changed(task); |
| 510 | if (new->fsgid != old->fsgid) | 515 | if (!gid_eq(new->fsgid, old->fsgid)) |
| 511 | key_fsgid_changed(task); | 516 | key_fsgid_changed(task); |
| 512 | 517 | ||
| 513 | /* do it | 518 | /* do it |
| @@ -524,16 +529,16 @@ int commit_creds(struct cred *new) | |||
| 524 | alter_cred_subscribers(old, -2); | 529 | alter_cred_subscribers(old, -2); |
| 525 | 530 | ||
| 526 | /* send notifications */ | 531 | /* send notifications */ |
| 527 | if (new->uid != old->uid || | 532 | if (!uid_eq(new->uid, old->uid) || |
| 528 | new->euid != old->euid || | 533 | !uid_eq(new->euid, old->euid) || |
| 529 | new->suid != old->suid || | 534 | !uid_eq(new->suid, old->suid) || |
| 530 | new->fsuid != old->fsuid) | 535 | !uid_eq(new->fsuid, old->fsuid)) |
| 531 | proc_id_connector(task, PROC_EVENT_UID); | 536 | proc_id_connector(task, PROC_EVENT_UID); |
| 532 | 537 | ||
| 533 | if (new->gid != old->gid || | 538 | if (!gid_eq(new->gid, old->gid) || |
| 534 | new->egid != old->egid || | 539 | !gid_eq(new->egid, old->egid) || |
| 535 | new->sgid != old->sgid || | 540 | !gid_eq(new->sgid, old->sgid) || |
| 536 | new->fsgid != old->fsgid) | 541 | !gid_eq(new->fsgid, old->fsgid)) |
| 537 | proc_id_connector(task, PROC_EVENT_GID); | 542 | proc_id_connector(task, PROC_EVENT_GID); |
| 538 | 543 | ||
| 539 | /* release the old obj and subj refs both */ | 544 | /* release the old obj and subj refs both */ |
| @@ -678,6 +683,7 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon) | |||
| 678 | atomic_set(&new->usage, 1); | 683 | atomic_set(&new->usage, 1); |
| 679 | set_cred_subscribers(new, 0); | 684 | set_cred_subscribers(new, 0); |
| 680 | get_uid(new->user); | 685 | get_uid(new->user); |
| 686 | get_user_ns(new->user_ns); | ||
| 681 | get_group_info(new->group_info); | 687 | get_group_info(new->group_info); |
| 682 | 688 | ||
| 683 | #ifdef CONFIG_KEYS | 689 | #ifdef CONFIG_KEYS |
diff --git a/kernel/exit.c b/kernel/exit.c index d8bd3b425fa7..910a0716e17a 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
| @@ -1214,7 +1214,7 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p) | |||
| 1214 | unsigned long state; | 1214 | unsigned long state; |
| 1215 | int retval, status, traced; | 1215 | int retval, status, traced; |
| 1216 | pid_t pid = task_pid_vnr(p); | 1216 | pid_t pid = task_pid_vnr(p); |
| 1217 | uid_t uid = __task_cred(p)->uid; | 1217 | uid_t uid = from_kuid_munged(current_user_ns(), __task_cred(p)->uid); |
| 1218 | struct siginfo __user *infop; | 1218 | struct siginfo __user *infop; |
| 1219 | 1219 | ||
| 1220 | if (!likely(wo->wo_flags & WEXITED)) | 1220 | if (!likely(wo->wo_flags & WEXITED)) |
| @@ -1427,7 +1427,7 @@ static int wait_task_stopped(struct wait_opts *wo, | |||
| 1427 | if (!unlikely(wo->wo_flags & WNOWAIT)) | 1427 | if (!unlikely(wo->wo_flags & WNOWAIT)) |
| 1428 | *p_code = 0; | 1428 | *p_code = 0; |
| 1429 | 1429 | ||
| 1430 | uid = task_uid(p); | 1430 | uid = from_kuid_munged(current_user_ns(), task_uid(p)); |
| 1431 | unlock_sig: | 1431 | unlock_sig: |
| 1432 | spin_unlock_irq(&p->sighand->siglock); | 1432 | spin_unlock_irq(&p->sighand->siglock); |
| 1433 | if (!exit_code) | 1433 | if (!exit_code) |
| @@ -1500,7 +1500,7 @@ static int wait_task_continued(struct wait_opts *wo, struct task_struct *p) | |||
| 1500 | } | 1500 | } |
| 1501 | if (!unlikely(wo->wo_flags & WNOWAIT)) | 1501 | if (!unlikely(wo->wo_flags & WNOWAIT)) |
| 1502 | p->signal->flags &= ~SIGNAL_STOP_CONTINUED; | 1502 | p->signal->flags &= ~SIGNAL_STOP_CONTINUED; |
| 1503 | uid = task_uid(p); | 1503 | uid = from_kuid_munged(current_user_ns(), task_uid(p)); |
| 1504 | spin_unlock_irq(&p->sighand->siglock); | 1504 | spin_unlock_irq(&p->sighand->siglock); |
| 1505 | 1505 | ||
| 1506 | pid = task_pid_vnr(p); | 1506 | pid = task_pid_vnr(p); |
diff --git a/kernel/groups.c b/kernel/groups.c index 99b53d1eb7ea..6b2588dd04ff 100644 --- a/kernel/groups.c +++ b/kernel/groups.c | |||
| @@ -31,7 +31,7 @@ struct group_info *groups_alloc(int gidsetsize) | |||
| 31 | group_info->blocks[0] = group_info->small_block; | 31 | group_info->blocks[0] = group_info->small_block; |
| 32 | else { | 32 | else { |
| 33 | for (i = 0; i < nblocks; i++) { | 33 | for (i = 0; i < nblocks; i++) { |
| 34 | gid_t *b; | 34 | kgid_t *b; |
| 35 | b = (void *)__get_free_page(GFP_USER); | 35 | b = (void *)__get_free_page(GFP_USER); |
| 36 | if (!b) | 36 | if (!b) |
| 37 | goto out_undo_partial_alloc; | 37 | goto out_undo_partial_alloc; |
| @@ -66,18 +66,15 @@ EXPORT_SYMBOL(groups_free); | |||
| 66 | static int groups_to_user(gid_t __user *grouplist, | 66 | static int groups_to_user(gid_t __user *grouplist, |
| 67 | const struct group_info *group_info) | 67 | const struct group_info *group_info) |
| 68 | { | 68 | { |
| 69 | struct user_namespace *user_ns = current_user_ns(); | ||
| 69 | int i; | 70 | int i; |
| 70 | unsigned int count = group_info->ngroups; | 71 | unsigned int count = group_info->ngroups; |
| 71 | 72 | ||
| 72 | for (i = 0; i < group_info->nblocks; i++) { | 73 | for (i = 0; i < count; i++) { |
| 73 | unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); | 74 | gid_t gid; |
| 74 | unsigned int len = cp_count * sizeof(*grouplist); | 75 | gid = from_kgid_munged(user_ns, GROUP_AT(group_info, i)); |
| 75 | 76 | if (put_user(gid, grouplist+i)) | |
| 76 | if (copy_to_user(grouplist, group_info->blocks[i], len)) | ||
| 77 | return -EFAULT; | 77 | return -EFAULT; |
| 78 | |||
| 79 | grouplist += NGROUPS_PER_BLOCK; | ||
| 80 | count -= cp_count; | ||
| 81 | } | 78 | } |
| 82 | return 0; | 79 | return 0; |
| 83 | } | 80 | } |
| @@ -86,18 +83,21 @@ static int groups_to_user(gid_t __user *grouplist, | |||
| 86 | static int groups_from_user(struct group_info *group_info, | 83 | static int groups_from_user(struct group_info *group_info, |
| 87 | gid_t __user *grouplist) | 84 | gid_t __user *grouplist) |
| 88 | { | 85 | { |
| 86 | struct user_namespace *user_ns = current_user_ns(); | ||
| 89 | int i; | 87 | int i; |
| 90 | unsigned int count = group_info->ngroups; | 88 | unsigned int count = group_info->ngroups; |
| 91 | 89 | ||
| 92 | for (i = 0; i < group_info->nblocks; i++) { | 90 | for (i = 0; i < count; i++) { |
| 93 | unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); | 91 | gid_t gid; |
| 94 | unsigned int len = cp_count * sizeof(*grouplist); | 92 | kgid_t kgid; |
| 95 | 93 | if (get_user(gid, grouplist+i)) | |
| 96 | if (copy_from_user(group_info->blocks[i], grouplist, len)) | ||
| 97 | return -EFAULT; | 94 | return -EFAULT; |
| 98 | 95 | ||
| 99 | grouplist += NGROUPS_PER_BLOCK; | 96 | kgid = make_kgid(user_ns, gid); |
| 100 | count -= cp_count; | 97 | if (!gid_valid(kgid)) |
| 98 | return -EINVAL; | ||
| 99 | |||
| 100 | GROUP_AT(group_info, i) = kgid; | ||
| 101 | } | 101 | } |
| 102 | return 0; | 102 | return 0; |
| 103 | } | 103 | } |
| @@ -117,9 +117,9 @@ static void groups_sort(struct group_info *group_info) | |||
| 117 | for (base = 0; base < max; base++) { | 117 | for (base = 0; base < max; base++) { |
| 118 | int left = base; | 118 | int left = base; |
| 119 | int right = left + stride; | 119 | int right = left + stride; |
| 120 | gid_t tmp = GROUP_AT(group_info, right); | 120 | kgid_t tmp = GROUP_AT(group_info, right); |
| 121 | 121 | ||
| 122 | while (left >= 0 && GROUP_AT(group_info, left) > tmp) { | 122 | while (left >= 0 && gid_gt(GROUP_AT(group_info, left), tmp)) { |
| 123 | GROUP_AT(group_info, right) = | 123 | GROUP_AT(group_info, right) = |
| 124 | GROUP_AT(group_info, left); | 124 | GROUP_AT(group_info, left); |
| 125 | right = left; | 125 | right = left; |
| @@ -132,7 +132,7 @@ static void groups_sort(struct group_info *group_info) | |||
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | /* a simple bsearch */ | 134 | /* a simple bsearch */ |
| 135 | int groups_search(const struct group_info *group_info, gid_t grp) | 135 | int groups_search(const struct group_info *group_info, kgid_t grp) |
| 136 | { | 136 | { |
| 137 | unsigned int left, right; | 137 | unsigned int left, right; |
| 138 | 138 | ||
| @@ -143,9 +143,9 @@ int groups_search(const struct group_info *group_info, gid_t grp) | |||
| 143 | right = group_info->ngroups; | 143 | right = group_info->ngroups; |
| 144 | while (left < right) { | 144 | while (left < right) { |
| 145 | unsigned int mid = (left+right)/2; | 145 | unsigned int mid = (left+right)/2; |
| 146 | if (grp > GROUP_AT(group_info, mid)) | 146 | if (gid_gt(grp, GROUP_AT(group_info, mid))) |
| 147 | left = mid + 1; | 147 | left = mid + 1; |
| 148 | else if (grp < GROUP_AT(group_info, mid)) | 148 | else if (gid_lt(grp, GROUP_AT(group_info, mid))) |
| 149 | right = mid; | 149 | right = mid; |
| 150 | else | 150 | else |
| 151 | return 1; | 151 | return 1; |
| @@ -256,24 +256,24 @@ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist) | |||
| 256 | /* | 256 | /* |
| 257 | * Check whether we're fsgid/egid or in the supplemental group.. | 257 | * Check whether we're fsgid/egid or in the supplemental group.. |
| 258 | */ | 258 | */ |
| 259 | int in_group_p(gid_t grp) | 259 | int in_group_p(kgid_t grp) |
| 260 | { | 260 | { |
| 261 | const struct cred *cred = current_cred(); | 261 | const struct cred *cred = current_cred(); |
| 262 | int retval = 1; | 262 | int retval = 1; |
| 263 | 263 | ||
| 264 | if (grp != cred->fsgid) | 264 | if (!gid_eq(grp, cred->fsgid)) |
| 265 | retval = groups_search(cred->group_info, grp); | 265 | retval = groups_search(cred->group_info, grp); |
| 266 | return retval; | 266 | return retval; |
| 267 | } | 267 | } |
| 268 | 268 | ||
| 269 | EXPORT_SYMBOL(in_group_p); | 269 | EXPORT_SYMBOL(in_group_p); |
| 270 | 270 | ||
| 271 | int in_egroup_p(gid_t grp) | 271 | int in_egroup_p(kgid_t grp) |
| 272 | { | 272 | { |
| 273 | const struct cred *cred = current_cred(); | 273 | const struct cred *cred = current_cred(); |
| 274 | int retval = 1; | 274 | int retval = 1; |
| 275 | 275 | ||
| 276 | if (grp != cred->egid) | 276 | if (!gid_eq(grp, cred->egid)) |
| 277 | retval = groups_search(cred->group_info, grp); | 277 | retval = groups_search(cred->group_info, grp); |
| 278 | return retval; | 278 | return retval; |
| 279 | } | 279 | } |
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index ee8d49b9c309..a232bb59d93f 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
| @@ -198,15 +198,14 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode) | |||
| 198 | return 0; | 198 | return 0; |
| 199 | rcu_read_lock(); | 199 | rcu_read_lock(); |
| 200 | tcred = __task_cred(task); | 200 | tcred = __task_cred(task); |
| 201 | if (cred->user->user_ns == tcred->user->user_ns && | 201 | if (uid_eq(cred->uid, tcred->euid) && |
| 202 | (cred->uid == tcred->euid && | 202 | uid_eq(cred->uid, tcred->suid) && |
| 203 | cred->uid == tcred->suid && | 203 | uid_eq(cred->uid, tcred->uid) && |
| 204 | cred->uid == tcred->uid && | 204 | gid_eq(cred->gid, tcred->egid) && |
| 205 | cred->gid == tcred->egid && | 205 | gid_eq(cred->gid, tcred->sgid) && |
| 206 | cred->gid == tcred->sgid && | 206 | gid_eq(cred->gid, tcred->gid)) |
| 207 | cred->gid == tcred->gid)) | ||
| 208 | goto ok; | 207 | goto ok; |
| 209 | if (ptrace_has_cap(tcred->user->user_ns, mode)) | 208 | if (ptrace_has_cap(tcred->user_ns, mode)) |
| 210 | goto ok; | 209 | goto ok; |
| 211 | rcu_read_unlock(); | 210 | rcu_read_unlock(); |
| 212 | return -EPERM; | 211 | return -EPERM; |
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index a5a9d39b845c..39eb6011bc38 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c | |||
| @@ -4070,11 +4070,8 @@ static bool check_same_owner(struct task_struct *p) | |||
| 4070 | 4070 | ||
| 4071 | rcu_read_lock(); | 4071 | rcu_read_lock(); |
| 4072 | pcred = __task_cred(p); | 4072 | pcred = __task_cred(p); |
| 4073 | if (cred->user->user_ns == pcred->user->user_ns) | 4073 | match = (uid_eq(cred->euid, pcred->euid) || |
| 4074 | match = (cred->euid == pcred->euid || | 4074 | uid_eq(cred->euid, pcred->uid)); |
| 4075 | cred->euid == pcred->uid); | ||
| 4076 | else | ||
| 4077 | match = false; | ||
| 4078 | rcu_read_unlock(); | 4075 | rcu_read_unlock(); |
| 4079 | return match; | 4076 | return match; |
| 4080 | } | 4077 | } |
diff --git a/kernel/signal.c b/kernel/signal.c index 1a006b5d9d9d..21ebe75ff85f 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
| @@ -767,14 +767,13 @@ static int kill_ok_by_cred(struct task_struct *t) | |||
| 767 | const struct cred *cred = current_cred(); | 767 | const struct cred *cred = current_cred(); |
| 768 | const struct cred *tcred = __task_cred(t); | 768 | const struct cred *tcred = __task_cred(t); |
| 769 | 769 | ||
| 770 | if (cred->user->user_ns == tcred->user->user_ns && | 770 | if (uid_eq(cred->euid, tcred->suid) || |
| 771 | (cred->euid == tcred->suid || | 771 | uid_eq(cred->euid, tcred->uid) || |
| 772 | cred->euid == tcred->uid || | 772 | uid_eq(cred->uid, tcred->suid) || |
| 773 | cred->uid == tcred->suid || | 773 | uid_eq(cred->uid, tcred->uid)) |
| 774 | cred->uid == tcred->uid)) | ||
| 775 | return 1; | 774 | return 1; |
| 776 | 775 | ||
| 777 | if (ns_capable(tcred->user->user_ns, CAP_KILL)) | 776 | if (ns_capable(tcred->user_ns, CAP_KILL)) |
| 778 | return 1; | 777 | return 1; |
| 779 | 778 | ||
| 780 | return 0; | 779 | return 0; |
| @@ -1020,15 +1019,6 @@ static inline int legacy_queue(struct sigpending *signals, int sig) | |||
| 1020 | return (sig < SIGRTMIN) && sigismember(&signals->signal, sig); | 1019 | return (sig < SIGRTMIN) && sigismember(&signals->signal, sig); |
| 1021 | } | 1020 | } |
| 1022 | 1021 | ||
| 1023 | /* | ||
| 1024 | * map the uid in struct cred into user namespace *ns | ||
| 1025 | */ | ||
| 1026 | static inline uid_t map_cred_ns(const struct cred *cred, | ||
| 1027 | struct user_namespace *ns) | ||
| 1028 | { | ||
| 1029 | return user_ns_map_uid(ns, cred, cred->uid); | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | #ifdef CONFIG_USER_NS | 1022 | #ifdef CONFIG_USER_NS |
| 1033 | static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t) | 1023 | static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t) |
| 1034 | { | 1024 | { |
| @@ -1038,8 +1028,10 @@ static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_str | |||
| 1038 | if (SI_FROMKERNEL(info)) | 1028 | if (SI_FROMKERNEL(info)) |
| 1039 | return; | 1029 | return; |
| 1040 | 1030 | ||
| 1041 | info->si_uid = user_ns_map_uid(task_cred_xxx(t, user_ns), | 1031 | rcu_read_lock(); |
| 1042 | current_cred(), info->si_uid); | 1032 | info->si_uid = from_kuid_munged(task_cred_xxx(t, user_ns), |
| 1033 | make_kuid(current_user_ns(), info->si_uid)); | ||
| 1034 | rcu_read_unlock(); | ||
| 1043 | } | 1035 | } |
| 1044 | #else | 1036 | #else |
| 1045 | static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t) | 1037 | static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t) |
| @@ -1106,7 +1098,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, | |||
| 1106 | q->info.si_code = SI_USER; | 1098 | q->info.si_code = SI_USER; |
| 1107 | q->info.si_pid = task_tgid_nr_ns(current, | 1099 | q->info.si_pid = task_tgid_nr_ns(current, |
| 1108 | task_active_pid_ns(t)); | 1100 | task_active_pid_ns(t)); |
| 1109 | q->info.si_uid = current_uid(); | 1101 | q->info.si_uid = from_kuid_munged(current_user_ns(), current_uid()); |
| 1110 | break; | 1102 | break; |
| 1111 | case (unsigned long) SEND_SIG_PRIV: | 1103 | case (unsigned long) SEND_SIG_PRIV: |
| 1112 | q->info.si_signo = sig; | 1104 | q->info.si_signo = sig; |
| @@ -1387,10 +1379,8 @@ static int kill_as_cred_perm(const struct cred *cred, | |||
| 1387 | struct task_struct *target) | 1379 | struct task_struct *target) |
| 1388 | { | 1380 | { |
| 1389 | const struct cred *pcred = __task_cred(target); | 1381 | const struct cred *pcred = __task_cred(target); |
| 1390 | if (cred->user_ns != pcred->user_ns) | 1382 | if (!uid_eq(cred->euid, pcred->suid) && !uid_eq(cred->euid, pcred->uid) && |
| 1391 | return 0; | 1383 | !uid_eq(cred->uid, pcred->suid) && !uid_eq(cred->uid, pcred->uid)) |
| 1392 | if (cred->euid != pcred->suid && cred->euid != pcred->uid && | ||
| 1393 | cred->uid != pcred->suid && cred->uid != pcred->uid) | ||
| 1394 | return 0; | 1384 | return 0; |
| 1395 | return 1; | 1385 | return 1; |
| 1396 | } | 1386 | } |
| @@ -1678,8 +1668,8 @@ bool do_notify_parent(struct task_struct *tsk, int sig) | |||
| 1678 | */ | 1668 | */ |
| 1679 | rcu_read_lock(); | 1669 | rcu_read_lock(); |
| 1680 | info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns); | 1670 | info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns); |
| 1681 | info.si_uid = map_cred_ns(__task_cred(tsk), | 1671 | info.si_uid = from_kuid_munged(task_cred_xxx(tsk->parent, user_ns), |
| 1682 | task_cred_xxx(tsk->parent, user_ns)); | 1672 | task_uid(tsk)); |
| 1683 | rcu_read_unlock(); | 1673 | rcu_read_unlock(); |
| 1684 | 1674 | ||
| 1685 | info.si_utime = cputime_to_clock_t(tsk->utime + tsk->signal->utime); | 1675 | info.si_utime = cputime_to_clock_t(tsk->utime + tsk->signal->utime); |
| @@ -1762,8 +1752,7 @@ static void do_notify_parent_cldstop(struct task_struct *tsk, | |||
| 1762 | */ | 1752 | */ |
| 1763 | rcu_read_lock(); | 1753 | rcu_read_lock(); |
| 1764 | info.si_pid = task_pid_nr_ns(tsk, parent->nsproxy->pid_ns); | 1754 | info.si_pid = task_pid_nr_ns(tsk, parent->nsproxy->pid_ns); |
| 1765 | info.si_uid = map_cred_ns(__task_cred(tsk), | 1755 | info.si_uid = from_kuid_munged(task_cred_xxx(parent, user_ns), task_uid(tsk)); |
| 1766 | task_cred_xxx(parent, user_ns)); | ||
| 1767 | rcu_read_unlock(); | 1756 | rcu_read_unlock(); |
| 1768 | 1757 | ||
| 1769 | info.si_utime = cputime_to_clock_t(tsk->utime); | 1758 | info.si_utime = cputime_to_clock_t(tsk->utime); |
| @@ -1973,7 +1962,7 @@ static void ptrace_do_notify(int signr, int exit_code, int why) | |||
| 1973 | info.si_signo = signr; | 1962 | info.si_signo = signr; |
| 1974 | info.si_code = exit_code; | 1963 | info.si_code = exit_code; |
| 1975 | info.si_pid = task_pid_vnr(current); | 1964 | info.si_pid = task_pid_vnr(current); |
| 1976 | info.si_uid = current_uid(); | 1965 | info.si_uid = from_kuid_munged(current_user_ns(), current_uid()); |
| 1977 | 1966 | ||
| 1978 | /* Let the debugger run. */ | 1967 | /* Let the debugger run. */ |
| 1979 | ptrace_stop(exit_code, why, 1, &info); | 1968 | ptrace_stop(exit_code, why, 1, &info); |
| @@ -2181,8 +2170,8 @@ static int ptrace_signal(int signr, siginfo_t *info, | |||
| 2181 | info->si_code = SI_USER; | 2170 | info->si_code = SI_USER; |
| 2182 | rcu_read_lock(); | 2171 | rcu_read_lock(); |
| 2183 | info->si_pid = task_pid_vnr(current->parent); | 2172 | info->si_pid = task_pid_vnr(current->parent); |
| 2184 | info->si_uid = map_cred_ns(__task_cred(current->parent), | 2173 | info->si_uid = from_kuid_munged(current_user_ns(), |
| 2185 | current_user_ns()); | 2174 | task_uid(current->parent)); |
| 2186 | rcu_read_unlock(); | 2175 | rcu_read_unlock(); |
| 2187 | } | 2176 | } |
| 2188 | 2177 | ||
| @@ -2835,7 +2824,7 @@ SYSCALL_DEFINE2(kill, pid_t, pid, int, sig) | |||
| 2835 | info.si_errno = 0; | 2824 | info.si_errno = 0; |
| 2836 | info.si_code = SI_USER; | 2825 | info.si_code = SI_USER; |
| 2837 | info.si_pid = task_tgid_vnr(current); | 2826 | info.si_pid = task_tgid_vnr(current); |
| 2838 | info.si_uid = current_uid(); | 2827 | info.si_uid = from_kuid_munged(current_user_ns(), current_uid()); |
| 2839 | 2828 | ||
| 2840 | return kill_something_info(sig, &info, pid); | 2829 | return kill_something_info(sig, &info, pid); |
| 2841 | } | 2830 | } |
| @@ -2878,7 +2867,7 @@ static int do_tkill(pid_t tgid, pid_t pid, int sig) | |||
| 2878 | info.si_errno = 0; | 2867 | info.si_errno = 0; |
| 2879 | info.si_code = SI_TKILL; | 2868 | info.si_code = SI_TKILL; |
| 2880 | info.si_pid = task_tgid_vnr(current); | 2869 | info.si_pid = task_tgid_vnr(current); |
| 2881 | info.si_uid = current_uid(); | 2870 | info.si_uid = from_kuid_munged(current_user_ns(), current_uid()); |
| 2882 | 2871 | ||
| 2883 | return do_send_specific(tgid, pid, sig, &info); | 2872 | return do_send_specific(tgid, pid, sig, &info); |
| 2884 | } | 2873 | } |
diff --git a/kernel/sys.c b/kernel/sys.c index ba0ae8eea6fb..6df42624e454 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
| @@ -93,10 +93,8 @@ | |||
| 93 | int overflowuid = DEFAULT_OVERFLOWUID; | 93 | int overflowuid = DEFAULT_OVERFLOWUID; |
| 94 | int overflowgid = DEFAULT_OVERFLOWGID; | 94 | int overflowgid = DEFAULT_OVERFLOWGID; |
| 95 | 95 | ||
| 96 | #ifdef CONFIG_UID16 | ||
| 97 | EXPORT_SYMBOL(overflowuid); | 96 | EXPORT_SYMBOL(overflowuid); |
| 98 | EXPORT_SYMBOL(overflowgid); | 97 | EXPORT_SYMBOL(overflowgid); |
| 99 | #endif | ||
| 100 | 98 | ||
| 101 | /* | 99 | /* |
| 102 | * the same as above, but for filesystems which can only store a 16-bit | 100 | * the same as above, but for filesystems which can only store a 16-bit |
| @@ -133,11 +131,10 @@ static bool set_one_prio_perm(struct task_struct *p) | |||
| 133 | { | 131 | { |
| 134 | const struct cred *cred = current_cred(), *pcred = __task_cred(p); | 132 | const struct cred *cred = current_cred(), *pcred = __task_cred(p); |
| 135 | 133 | ||
| 136 | if (pcred->user->user_ns == cred->user->user_ns && | 134 | if (uid_eq(pcred->uid, cred->euid) || |
| 137 | (pcred->uid == cred->euid || | 135 | uid_eq(pcred->euid, cred->euid)) |
| 138 | pcred->euid == cred->euid)) | ||
| 139 | return true; | 136 | return true; |
| 140 | if (ns_capable(pcred->user->user_ns, CAP_SYS_NICE)) | 137 | if (ns_capable(pcred->user_ns, CAP_SYS_NICE)) |
| 141 | return true; | 138 | return true; |
| 142 | return false; | 139 | return false; |
| 143 | } | 140 | } |
| @@ -177,6 +174,7 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval) | |||
| 177 | const struct cred *cred = current_cred(); | 174 | const struct cred *cred = current_cred(); |
| 178 | int error = -EINVAL; | 175 | int error = -EINVAL; |
| 179 | struct pid *pgrp; | 176 | struct pid *pgrp; |
| 177 | kuid_t uid; | ||
| 180 | 178 | ||
| 181 | if (which > PRIO_USER || which < PRIO_PROCESS) | 179 | if (which > PRIO_USER || which < PRIO_PROCESS) |
| 182 | goto out; | 180 | goto out; |
| @@ -209,18 +207,19 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval) | |||
| 209 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); | 207 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); |
| 210 | break; | 208 | break; |
| 211 | case PRIO_USER: | 209 | case PRIO_USER: |
| 212 | user = (struct user_struct *) cred->user; | 210 | uid = make_kuid(cred->user_ns, who); |
| 211 | user = cred->user; | ||
| 213 | if (!who) | 212 | if (!who) |
| 214 | who = cred->uid; | 213 | uid = cred->uid; |
| 215 | else if ((who != cred->uid) && | 214 | else if (!uid_eq(uid, cred->uid) && |
| 216 | !(user = find_user(who))) | 215 | !(user = find_user(uid))) |
| 217 | goto out_unlock; /* No processes for this user */ | 216 | goto out_unlock; /* No processes for this user */ |
| 218 | 217 | ||
| 219 | do_each_thread(g, p) { | 218 | do_each_thread(g, p) { |
| 220 | if (__task_cred(p)->uid == who) | 219 | if (uid_eq(task_uid(p), uid)) |
| 221 | error = set_one_prio(p, niceval, error); | 220 | error = set_one_prio(p, niceval, error); |
| 222 | } while_each_thread(g, p); | 221 | } while_each_thread(g, p); |
| 223 | if (who != cred->uid) | 222 | if (!uid_eq(uid, cred->uid)) |
| 224 | free_uid(user); /* For find_user() */ | 223 | free_uid(user); /* For find_user() */ |
| 225 | break; | 224 | break; |
| 226 | } | 225 | } |
| @@ -244,6 +243,7 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who) | |||
| 244 | const struct cred *cred = current_cred(); | 243 | const struct cred *cred = current_cred(); |
| 245 | long niceval, retval = -ESRCH; | 244 | long niceval, retval = -ESRCH; |
| 246 | struct pid *pgrp; | 245 | struct pid *pgrp; |
| 246 | kuid_t uid; | ||
| 247 | 247 | ||
| 248 | if (which > PRIO_USER || which < PRIO_PROCESS) | 248 | if (which > PRIO_USER || which < PRIO_PROCESS) |
| 249 | return -EINVAL; | 249 | return -EINVAL; |
| @@ -274,21 +274,22 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who) | |||
| 274 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); | 274 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); |
| 275 | break; | 275 | break; |
| 276 | case PRIO_USER: | 276 | case PRIO_USER: |
| 277 | user = (struct user_struct *) cred->user; | 277 | uid = make_kuid(cred->user_ns, who); |
| 278 | user = cred->user; | ||
| 278 | if (!who) | 279 | if (!who) |
| 279 | who = cred->uid; | 280 | uid = cred->uid; |
| 280 | else if ((who != cred->uid) && | 281 | else if (!uid_eq(uid, cred->uid) && |
| 281 | !(user = find_user(who))) | 282 | !(user = find_user(uid))) |
| 282 | goto out_unlock; /* No processes for this user */ | 283 | goto out_unlock; /* No processes for this user */ |
| 283 | 284 | ||
| 284 | do_each_thread(g, p) { | 285 | do_each_thread(g, p) { |
| 285 | if (__task_cred(p)->uid == who) { | 286 | if (uid_eq(task_uid(p), uid)) { |
| 286 | niceval = 20 - task_nice(p); | 287 | niceval = 20 - task_nice(p); |
| 287 | if (niceval > retval) | 288 | if (niceval > retval) |
| 288 | retval = niceval; | 289 | retval = niceval; |
| 289 | } | 290 | } |
| 290 | } while_each_thread(g, p); | 291 | } while_each_thread(g, p); |
| 291 | if (who != cred->uid) | 292 | if (!uid_eq(uid, cred->uid)) |
| 292 | free_uid(user); /* for find_user() */ | 293 | free_uid(user); /* for find_user() */ |
| 293 | break; | 294 | break; |
| 294 | } | 295 | } |
| @@ -553,9 +554,19 @@ void ctrl_alt_del(void) | |||
| 553 | */ | 554 | */ |
| 554 | SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) | 555 | SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) |
| 555 | { | 556 | { |
| 557 | struct user_namespace *ns = current_user_ns(); | ||
| 556 | const struct cred *old; | 558 | const struct cred *old; |
| 557 | struct cred *new; | 559 | struct cred *new; |
| 558 | int retval; | 560 | int retval; |
| 561 | kgid_t krgid, kegid; | ||
| 562 | |||
| 563 | krgid = make_kgid(ns, rgid); | ||
| 564 | kegid = make_kgid(ns, egid); | ||
| 565 | |||
| 566 | if ((rgid != (gid_t) -1) && !gid_valid(krgid)) | ||
| 567 | return -EINVAL; | ||
| 568 | if ((egid != (gid_t) -1) && !gid_valid(kegid)) | ||
| 569 | return -EINVAL; | ||
| 559 | 570 | ||
| 560 | new = prepare_creds(); | 571 | new = prepare_creds(); |
| 561 | if (!new) | 572 | if (!new) |
| @@ -564,25 +575,25 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) | |||
| 564 | 575 | ||
| 565 | retval = -EPERM; | 576 | retval = -EPERM; |
| 566 | if (rgid != (gid_t) -1) { | 577 | if (rgid != (gid_t) -1) { |
| 567 | if (old->gid == rgid || | 578 | if (gid_eq(old->gid, krgid) || |
| 568 | old->egid == rgid || | 579 | gid_eq(old->egid, krgid) || |
| 569 | nsown_capable(CAP_SETGID)) | 580 | nsown_capable(CAP_SETGID)) |
| 570 | new->gid = rgid; | 581 | new->gid = krgid; |
| 571 | else | 582 | else |
| 572 | goto error; | 583 | goto error; |
| 573 | } | 584 | } |
| 574 | if (egid != (gid_t) -1) { | 585 | if (egid != (gid_t) -1) { |
| 575 | if (old->gid == egid || | 586 | if (gid_eq(old->gid, kegid) || |
| 576 | old->egid == egid || | 587 | gid_eq(old->egid, kegid) || |
| 577 | old->sgid == egid || | 588 | gid_eq(old->sgid, kegid) || |
| 578 | nsown_capable(CAP_SETGID)) | 589 | nsown_capable(CAP_SETGID)) |
| 579 | new->egid = egid; | 590 | new->egid = kegid; |
| 580 | else | 591 | else |
| 581 | goto error; | 592 | goto error; |
| 582 | } | 593 | } |
| 583 | 594 | ||
| 584 | if (rgid != (gid_t) -1 || | 595 | if (rgid != (gid_t) -1 || |
| 585 | (egid != (gid_t) -1 && egid != old->gid)) | 596 | (egid != (gid_t) -1 && !gid_eq(kegid, old->gid))) |
| 586 | new->sgid = new->egid; | 597 | new->sgid = new->egid; |
| 587 | new->fsgid = new->egid; | 598 | new->fsgid = new->egid; |
| 588 | 599 | ||
| @@ -600,9 +611,15 @@ error: | |||
| 600 | */ | 611 | */ |
| 601 | SYSCALL_DEFINE1(setgid, gid_t, gid) | 612 | SYSCALL_DEFINE1(setgid, gid_t, gid) |
| 602 | { | 613 | { |
| 614 | struct user_namespace *ns = current_user_ns(); | ||
| 603 | const struct cred *old; | 615 | const struct cred *old; |
| 604 | struct cred *new; | 616 | struct cred *new; |
| 605 | int retval; | 617 | int retval; |
| 618 | kgid_t kgid; | ||
| 619 | |||
| 620 | kgid = make_kgid(ns, gid); | ||
| 621 | if (!gid_valid(kgid)) | ||
| 622 | return -EINVAL; | ||
| 606 | 623 | ||
| 607 | new = prepare_creds(); | 624 | new = prepare_creds(); |
| 608 | if (!new) | 625 | if (!new) |
| @@ -611,9 +628,9 @@ SYSCALL_DEFINE1(setgid, gid_t, gid) | |||
| 611 | 628 | ||
| 612 | retval = -EPERM; | 629 | retval = -EPERM; |
| 613 | if (nsown_capable(CAP_SETGID)) | 630 | if (nsown_capable(CAP_SETGID)) |
| 614 | new->gid = new->egid = new->sgid = new->fsgid = gid; | 631 | new->gid = new->egid = new->sgid = new->fsgid = kgid; |
| 615 | else if (gid == old->gid || gid == old->sgid) | 632 | else if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid)) |
| 616 | new->egid = new->fsgid = gid; | 633 | new->egid = new->fsgid = kgid; |
| 617 | else | 634 | else |
| 618 | goto error; | 635 | goto error; |
| 619 | 636 | ||
| @@ -631,7 +648,7 @@ static int set_user(struct cred *new) | |||
| 631 | { | 648 | { |
| 632 | struct user_struct *new_user; | 649 | struct user_struct *new_user; |
| 633 | 650 | ||
| 634 | new_user = alloc_uid(current_user_ns(), new->uid); | 651 | new_user = alloc_uid(new->uid); |
| 635 | if (!new_user) | 652 | if (!new_user) |
| 636 | return -EAGAIN; | 653 | return -EAGAIN; |
| 637 | 654 | ||
| @@ -670,9 +687,19 @@ static int set_user(struct cred *new) | |||
| 670 | */ | 687 | */ |
| 671 | SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) | 688 | SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) |
| 672 | { | 689 | { |
| 690 | struct user_namespace *ns = current_user_ns(); | ||
| 673 | const struct cred *old; | 691 | const struct cred *old; |
| 674 | struct cred *new; | 692 | struct cred *new; |
| 675 | int retval; | 693 | int retval; |
| 694 | kuid_t kruid, keuid; | ||
| 695 | |||
| 696 | kruid = make_kuid(ns, ruid); | ||
| 697 | keuid = make_kuid(ns, euid); | ||
| 698 | |||
| 699 | if ((ruid != (uid_t) -1) && !uid_valid(kruid)) | ||
| 700 | return -EINVAL; | ||
| 701 | if ((euid != (uid_t) -1) && !uid_valid(keuid)) | ||
| 702 | return -EINVAL; | ||
| 676 | 703 | ||
| 677 | new = prepare_creds(); | 704 | new = prepare_creds(); |
| 678 | if (!new) | 705 | if (!new) |
| @@ -681,29 +708,29 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) | |||
| 681 | 708 | ||
| 682 | retval = -EPERM; | 709 | retval = -EPERM; |
| 683 | if (ruid != (uid_t) -1) { | 710 | if (ruid != (uid_t) -1) { |
| 684 | new->uid = ruid; | 711 | new->uid = kruid; |
| 685 | if (old->uid != ruid && | 712 | if (!uid_eq(old->uid, kruid) && |
| 686 | old->euid != ruid && | 713 | !uid_eq(old->euid, kruid) && |
| 687 | !nsown_capable(CAP_SETUID)) | 714 | !nsown_capable(CAP_SETUID)) |
| 688 | goto error; | 715 | goto error; |
| 689 | } | 716 | } |
| 690 | 717 | ||
| 691 | if (euid != (uid_t) -1) { | 718 | if (euid != (uid_t) -1) { |
| 692 | new->euid = euid; | 719 | new->euid = keuid; |
| 693 | if (old->uid != euid && | 720 | if (!uid_eq(old->uid, keuid) && |
| 694 | old->euid != euid && | 721 | !uid_eq(old->euid, keuid) && |
| 695 | old->suid != euid && | 722 | !uid_eq(old->suid, keuid) && |
| 696 | !nsown_capable(CAP_SETUID)) | 723 | !nsown_capable(CAP_SETUID)) |
| 697 | goto error; | 724 | goto error; |
| 698 | } | 725 | } |
| 699 | 726 | ||
| 700 | if (new->uid != old->uid) { | 727 | if (!uid_eq(new->uid, old->uid)) { |
| 701 | retval = set_user(new); | 728 | retval = set_user(new); |
| 702 | if (retval < 0) | 729 | if (retval < 0) |
| 703 | goto error; | 730 | goto error; |
| 704 | } | 731 | } |
| 705 | if (ruid != (uid_t) -1 || | 732 | if (ruid != (uid_t) -1 || |
| 706 | (euid != (uid_t) -1 && euid != old->uid)) | 733 | (euid != (uid_t) -1 && !uid_eq(keuid, old->uid))) |
| 707 | new->suid = new->euid; | 734 | new->suid = new->euid; |
| 708 | new->fsuid = new->euid; | 735 | new->fsuid = new->euid; |
| 709 | 736 | ||
| @@ -731,9 +758,15 @@ error: | |||
| 731 | */ | 758 | */ |
| 732 | SYSCALL_DEFINE1(setuid, uid_t, uid) | 759 | SYSCALL_DEFINE1(setuid, uid_t, uid) |
| 733 | { | 760 | { |
| 761 | struct user_namespace *ns = current_user_ns(); | ||
| 734 | const struct cred *old; | 762 | const struct cred *old; |
| 735 | struct cred *new; | 763 | struct cred *new; |
| 736 | int retval; | 764 | int retval; |
| 765 | kuid_t kuid; | ||
| 766 | |||
| 767 | kuid = make_kuid(ns, uid); | ||
| 768 | if (!uid_valid(kuid)) | ||
| 769 | return -EINVAL; | ||
| 737 | 770 | ||
| 738 | new = prepare_creds(); | 771 | new = prepare_creds(); |
| 739 | if (!new) | 772 | if (!new) |
| @@ -742,17 +775,17 @@ SYSCALL_DEFINE1(setuid, uid_t, uid) | |||
| 742 | 775 | ||
| 743 | retval = -EPERM; | 776 | retval = -EPERM; |
| 744 | if (nsown_capable(CAP_SETUID)) { | 777 | if (nsown_capable(CAP_SETUID)) { |
| 745 | new->suid = new->uid = uid; | 778 | new->suid = new->uid = kuid; |
| 746 | if (uid != old->uid) { | 779 | if (!uid_eq(kuid, old->uid)) { |
| 747 | retval = set_user(new); | 780 | retval = set_user(new); |
| 748 | if (retval < 0) | 781 | if (retval < 0) |
| 749 | goto error; | 782 | goto error; |
| 750 | } | 783 | } |
| 751 | } else if (uid != old->uid && uid != new->suid) { | 784 | } else if (!uid_eq(kuid, old->uid) && !uid_eq(kuid, new->suid)) { |
| 752 | goto error; | 785 | goto error; |
| 753 | } | 786 | } |
| 754 | 787 | ||
| 755 | new->fsuid = new->euid = uid; | 788 | new->fsuid = new->euid = kuid; |
| 756 | 789 | ||
| 757 | retval = security_task_fix_setuid(new, old, LSM_SETID_ID); | 790 | retval = security_task_fix_setuid(new, old, LSM_SETID_ID); |
| 758 | if (retval < 0) | 791 | if (retval < 0) |
| @@ -772,9 +805,24 @@ error: | |||
| 772 | */ | 805 | */ |
| 773 | SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) | 806 | SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) |
| 774 | { | 807 | { |
| 808 | struct user_namespace *ns = current_user_ns(); | ||
| 775 | const struct cred *old; | 809 | const struct cred *old; |
| 776 | struct cred *new; | 810 | struct cred *new; |
| 777 | int retval; | 811 | int retval; |
| 812 | kuid_t kruid, keuid, ksuid; | ||
| 813 | |||
| 814 | kruid = make_kuid(ns, ruid); | ||
| 815 | keuid = make_kuid(ns, euid); | ||
| 816 | ksuid = make_kuid(ns, suid); | ||
| 817 | |||
| 818 | if ((ruid != (uid_t) -1) && !uid_valid(kruid)) | ||
| 819 | return -EINVAL; | ||
| 820 | |||
| 821 | if ((euid != (uid_t) -1) && !uid_valid(keuid)) | ||
| 822 | return -EINVAL; | ||
| 823 | |||
| 824 | if ((suid != (uid_t) -1) && !uid_valid(ksuid)) | ||
| 825 | return -EINVAL; | ||
| 778 | 826 | ||
| 779 | new = prepare_creds(); | 827 | new = prepare_creds(); |
| 780 | if (!new) | 828 | if (!new) |
| @@ -784,29 +832,29 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) | |||
| 784 | 832 | ||
| 785 | retval = -EPERM; | 833 | retval = -EPERM; |
| 786 | if (!nsown_capable(CAP_SETUID)) { | 834 | if (!nsown_capable(CAP_SETUID)) { |
| 787 | if (ruid != (uid_t) -1 && ruid != old->uid && | 835 | if (ruid != (uid_t) -1 && !uid_eq(kruid, old->uid) && |
| 788 | ruid != old->euid && ruid != old->suid) | 836 | !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid)) |
| 789 | goto error; | 837 | goto error; |
| 790 | if (euid != (uid_t) -1 && euid != old->uid && | 838 | if (euid != (uid_t) -1 && !uid_eq(keuid, old->uid) && |
| 791 | euid != old->euid && euid != old->suid) | 839 | !uid_eq(keuid, old->euid) && !uid_eq(keuid, old->suid)) |
| 792 | goto error; | 840 | goto error; |
| 793 | if (suid != (uid_t) -1 && suid != old->uid && | 841 | if (suid != (uid_t) -1 && !uid_eq(ksuid, old->uid) && |
| 794 | suid != old->euid && suid != old->suid) | 842 | !uid_eq(ksuid, old->euid) && !uid_eq(ksuid, old->suid)) |
| 795 | goto error; | 843 | goto error; |
| 796 | } | 844 | } |
| 797 | 845 | ||
| 798 | if (ruid != (uid_t) -1) { | 846 | if (ruid != (uid_t) -1) { |
| 799 | new->uid = ruid; | 847 | new->uid = kruid; |
| 800 | if (ruid != old->uid) { | 848 | if (!uid_eq(kruid, old->uid)) { |
| 801 | retval = set_user(new); | 849 | retval = set_user(new); |
| 802 | if (retval < 0) | 850 | if (retval < 0) |
| 803 | goto error; | 851 | goto error; |
| 804 | } | 852 | } |
| 805 | } | 853 | } |
| 806 | if (euid != (uid_t) -1) | 854 | if (euid != (uid_t) -1) |
| 807 | new->euid = euid; | 855 | new->euid = keuid; |
| 808 | if (suid != (uid_t) -1) | 856 | if (suid != (uid_t) -1) |
| 809 | new->suid = suid; | 857 | new->suid = ksuid; |
| 810 | new->fsuid = new->euid; | 858 | new->fsuid = new->euid; |
| 811 | 859 | ||
| 812 | retval = security_task_fix_setuid(new, old, LSM_SETID_RES); | 860 | retval = security_task_fix_setuid(new, old, LSM_SETID_RES); |
| @@ -820,14 +868,19 @@ error: | |||
| 820 | return retval; | 868 | return retval; |
| 821 | } | 869 | } |
| 822 | 870 | ||
| 823 | SYSCALL_DEFINE3(getresuid, uid_t __user *, ruid, uid_t __user *, euid, uid_t __user *, suid) | 871 | SYSCALL_DEFINE3(getresuid, uid_t __user *, ruidp, uid_t __user *, euidp, uid_t __user *, suidp) |
| 824 | { | 872 | { |
| 825 | const struct cred *cred = current_cred(); | 873 | const struct cred *cred = current_cred(); |
| 826 | int retval; | 874 | int retval; |
| 875 | uid_t ruid, euid, suid; | ||
| 876 | |||
| 877 | ruid = from_kuid_munged(cred->user_ns, cred->uid); | ||
| 878 | euid = from_kuid_munged(cred->user_ns, cred->euid); | ||
| 879 | suid = from_kuid_munged(cred->user_ns, cred->suid); | ||
| 827 | 880 | ||
| 828 | if (!(retval = put_user(cred->uid, ruid)) && | 881 | if (!(retval = put_user(ruid, ruidp)) && |
| 829 | !(retval = put_user(cred->euid, euid))) | 882 | !(retval = put_user(euid, euidp))) |
| 830 | retval = put_user(cred->suid, suid); | 883 | retval = put_user(suid, suidp); |
| 831 | 884 | ||
| 832 | return retval; | 885 | return retval; |
| 833 | } | 886 | } |
| @@ -837,9 +890,22 @@ SYSCALL_DEFINE3(getresuid, uid_t __user *, ruid, uid_t __user *, euid, uid_t __u | |||
| 837 | */ | 890 | */ |
| 838 | SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) | 891 | SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) |
| 839 | { | 892 | { |
| 893 | struct user_namespace *ns = current_user_ns(); | ||
| 840 | const struct cred *old; | 894 | const struct cred *old; |
| 841 | struct cred *new; | 895 | struct cred *new; |
| 842 | int retval; | 896 | int retval; |
| 897 | kgid_t krgid, kegid, ksgid; | ||
| 898 | |||
| 899 | krgid = make_kgid(ns, rgid); | ||
| 900 | kegid = make_kgid(ns, egid); | ||
| 901 | ksgid = make_kgid(ns, sgid); | ||
| 902 | |||
| 903 | if ((rgid != (gid_t) -1) && !gid_valid(krgid)) | ||
| 904 | return -EINVAL; | ||
| 905 | if ((egid != (gid_t) -1) && !gid_valid(kegid)) | ||
| 906 | return -EINVAL; | ||
| 907 | if ((sgid != (gid_t) -1) && !gid_valid(ksgid)) | ||
| 908 | return -EINVAL; | ||
| 843 | 909 | ||
| 844 | new = prepare_creds(); | 910 | new = prepare_creds(); |
| 845 | if (!new) | 911 | if (!new) |
| @@ -848,23 +914,23 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) | |||
| 848 | 914 | ||
| 849 | retval = -EPERM; | 915 | retval = -EPERM; |
| 850 | if (!nsown_capable(CAP_SETGID)) { | 916 | if (!nsown_capable(CAP_SETGID)) { |
| 851 | if (rgid != (gid_t) -1 && rgid != old->gid && | 917 | if (rgid != (gid_t) -1 && !gid_eq(krgid, old->gid) && |
| 852 | rgid != old->egid && rgid != old->sgid) | 918 | !gid_eq(krgid, old->egid) && !gid_eq(krgid, old->sgid)) |
| 853 | goto error; | 919 | goto error; |
| 854 | if (egid != (gid_t) -1 && egid != old->gid && | 920 | if (egid != (gid_t) -1 && !gid_eq(kegid, old->gid) && |
| 855 | egid != old->egid && egid != old->sgid) | 921 | !gid_eq(kegid, old->egid) && !gid_eq(kegid, old->sgid)) |
| 856 | goto error; | 922 | goto error; |
| 857 | if (sgid != (gid_t) -1 && sgid != old->gid && | 923 | if (sgid != (gid_t) -1 && !gid_eq(ksgid, old->gid) && |
| 858 | sgid != old->egid && sgid != old->sgid) | 924 | !gid_eq(ksgid, old->egid) && !gid_eq(ksgid, old->sgid)) |
| 859 | goto error; | 925 | goto error; |
| 860 | } | 926 | } |
| 861 | 927 | ||
| 862 | if (rgid != (gid_t) -1) | 928 | if (rgid != (gid_t) -1) |
| 863 | new->gid = rgid; | 929 | new->gid = krgid; |
| 864 | if (egid != (gid_t) -1) | 930 | if (egid != (gid_t) -1) |
| 865 | new->egid = egid; | 931 | new->egid = kegid; |
| 866 | if (sgid != (gid_t) -1) | 932 | if (sgid != (gid_t) -1) |
| 867 | new->sgid = sgid; | 933 | new->sgid = ksgid; |
| 868 | new->fsgid = new->egid; | 934 | new->fsgid = new->egid; |
| 869 | 935 | ||
| 870 | return commit_creds(new); | 936 | return commit_creds(new); |
| @@ -874,14 +940,19 @@ error: | |||
| 874 | return retval; | 940 | return retval; |
| 875 | } | 941 | } |
| 876 | 942 | ||
| 877 | SYSCALL_DEFINE3(getresgid, gid_t __user *, rgid, gid_t __user *, egid, gid_t __user *, sgid) | 943 | SYSCALL_DEFINE3(getresgid, gid_t __user *, rgidp, gid_t __user *, egidp, gid_t __user *, sgidp) |
| 878 | { | 944 | { |
| 879 | const struct cred *cred = current_cred(); | 945 | const struct cred *cred = current_cred(); |
| 880 | int retval; | 946 | int retval; |
| 947 | gid_t rgid, egid, sgid; | ||
| 948 | |||
| 949 | rgid = from_kgid_munged(cred->user_ns, cred->gid); | ||
| 950 | egid = from_kgid_munged(cred->user_ns, cred->egid); | ||
| 951 | sgid = from_kgid_munged(cred->user_ns, cred->sgid); | ||
| 881 | 952 | ||
| 882 | if (!(retval = put_user(cred->gid, rgid)) && | 953 | if (!(retval = put_user(rgid, rgidp)) && |
| 883 | !(retval = put_user(cred->egid, egid))) | 954 | !(retval = put_user(egid, egidp))) |
| 884 | retval = put_user(cred->sgid, sgid); | 955 | retval = put_user(sgid, sgidp); |
| 885 | 956 | ||
| 886 | return retval; | 957 | return retval; |
| 887 | } | 958 | } |
| @@ -898,18 +969,24 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid) | |||
| 898 | const struct cred *old; | 969 | const struct cred *old; |
| 899 | struct cred *new; | 970 | struct cred *new; |
| 900 | uid_t old_fsuid; | 971 | uid_t old_fsuid; |
| 972 | kuid_t kuid; | ||
| 973 | |||
| 974 | old = current_cred(); | ||
| 975 | old_fsuid = from_kuid_munged(old->user_ns, old->fsuid); | ||
| 976 | |||
| 977 | kuid = make_kuid(old->user_ns, uid); | ||
| 978 | if (!uid_valid(kuid)) | ||
| 979 | return old_fsuid; | ||
| 901 | 980 | ||
| 902 | new = prepare_creds(); | 981 | new = prepare_creds(); |
| 903 | if (!new) | 982 | if (!new) |
| 904 | return current_fsuid(); | 983 | return old_fsuid; |
| 905 | old = current_cred(); | ||
| 906 | old_fsuid = old->fsuid; | ||
| 907 | 984 | ||
| 908 | if (uid == old->uid || uid == old->euid || | 985 | if (uid_eq(kuid, old->uid) || uid_eq(kuid, old->euid) || |
| 909 | uid == old->suid || uid == old->fsuid || | 986 | uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) || |
| 910 | nsown_capable(CAP_SETUID)) { | 987 | nsown_capable(CAP_SETUID)) { |
| 911 | if (uid != old_fsuid) { | 988 | if (!uid_eq(kuid, old->fsuid)) { |
| 912 | new->fsuid = uid; | 989 | new->fsuid = kuid; |
| 913 | if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) | 990 | if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) |
| 914 | goto change_okay; | 991 | goto change_okay; |
| 915 | } | 992 | } |
| @@ -931,18 +1008,24 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid) | |||
| 931 | const struct cred *old; | 1008 | const struct cred *old; |
| 932 | struct cred *new; | 1009 | struct cred *new; |
| 933 | gid_t old_fsgid; | 1010 | gid_t old_fsgid; |
| 1011 | kgid_t kgid; | ||
| 1012 | |||
| 1013 | old = current_cred(); | ||
| 1014 | old_fsgid = from_kgid_munged(old->user_ns, old->fsgid); | ||
| 1015 | |||
| 1016 | kgid = make_kgid(old->user_ns, gid); | ||
| 1017 | if (!gid_valid(kgid)) | ||
| 1018 | return old_fsgid; | ||
| 934 | 1019 | ||
| 935 | new = prepare_creds(); | 1020 | new = prepare_creds(); |
| 936 | if (!new) | 1021 | if (!new) |
| 937 | return current_fsgid(); | 1022 | return old_fsgid; |
| 938 | old = current_cred(); | ||
| 939 | old_fsgid = old->fsgid; | ||
| 940 | 1023 | ||
| 941 | if (gid == old->gid || gid == old->egid || | 1024 | if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->egid) || |
| 942 | gid == old->sgid || gid == old->fsgid || | 1025 | gid_eq(kgid, old->sgid) || gid_eq(kgid, old->fsgid) || |
| 943 | nsown_capable(CAP_SETGID)) { | 1026 | nsown_capable(CAP_SETGID)) { |
| 944 | if (gid != old_fsgid) { | 1027 | if (!gid_eq(kgid, old->fsgid)) { |
| 945 | new->fsgid = gid; | 1028 | new->fsgid = kgid; |
| 946 | goto change_okay; | 1029 | goto change_okay; |
| 947 | } | 1030 | } |
| 948 | } | 1031 | } |
| @@ -1498,15 +1581,14 @@ static int check_prlimit_permission(struct task_struct *task) | |||
| 1498 | return 0; | 1581 | return 0; |
| 1499 | 1582 | ||
| 1500 | tcred = __task_cred(task); | 1583 | tcred = __task_cred(task); |
| 1501 | if (cred->user->user_ns == tcred->user->user_ns && | 1584 | if (uid_eq(cred->uid, tcred->euid) && |
| 1502 | (cred->uid == tcred->euid && | 1585 | uid_eq(cred->uid, tcred->suid) && |
| 1503 | cred->uid == tcred->suid && | 1586 | uid_eq(cred->uid, tcred->uid) && |
| 1504 | cred->uid == tcred->uid && | 1587 | gid_eq(cred->gid, tcred->egid) && |
| 1505 | cred->gid == tcred->egid && | 1588 | gid_eq(cred->gid, tcred->sgid) && |
| 1506 | cred->gid == tcred->sgid && | 1589 | gid_eq(cred->gid, tcred->gid)) |
| 1507 | cred->gid == tcred->gid)) | ||
| 1508 | return 0; | 1590 | return 0; |
| 1509 | if (ns_capable(tcred->user->user_ns, CAP_SYS_RESOURCE)) | 1591 | if (ns_capable(tcred->user_ns, CAP_SYS_RESOURCE)) |
| 1510 | return 0; | 1592 | return 0; |
| 1511 | 1593 | ||
| 1512 | return -EPERM; | 1594 | return -EPERM; |
diff --git a/kernel/timer.c b/kernel/timer.c index 09de9a941cd7..6ec7e7e0db43 100644 --- a/kernel/timer.c +++ b/kernel/timer.c | |||
| @@ -1435,25 +1435,25 @@ SYSCALL_DEFINE0(getppid) | |||
| 1435 | SYSCALL_DEFINE0(getuid) | 1435 | SYSCALL_DEFINE0(getuid) |
| 1436 | { | 1436 | { |
| 1437 | /* Only we change this so SMP safe */ | 1437 | /* Only we change this so SMP safe */ |
| 1438 | return current_uid(); | 1438 | return from_kuid_munged(current_user_ns(), current_uid()); |
| 1439 | } | 1439 | } |
| 1440 | 1440 | ||
| 1441 | SYSCALL_DEFINE0(geteuid) | 1441 | SYSCALL_DEFINE0(geteuid) |
| 1442 | { | 1442 | { |
| 1443 | /* Only we change this so SMP safe */ | 1443 | /* Only we change this so SMP safe */ |
| 1444 | return current_euid(); | 1444 | return from_kuid_munged(current_user_ns(), current_euid()); |
| 1445 | } | 1445 | } |
| 1446 | 1446 | ||
| 1447 | SYSCALL_DEFINE0(getgid) | 1447 | SYSCALL_DEFINE0(getgid) |
| 1448 | { | 1448 | { |
| 1449 | /* Only we change this so SMP safe */ | 1449 | /* Only we change this so SMP safe */ |
| 1450 | return current_gid(); | 1450 | return from_kgid_munged(current_user_ns(), current_gid()); |
| 1451 | } | 1451 | } |
| 1452 | 1452 | ||
| 1453 | SYSCALL_DEFINE0(getegid) | 1453 | SYSCALL_DEFINE0(getegid) |
| 1454 | { | 1454 | { |
| 1455 | /* Only we change this so SMP safe */ | 1455 | /* Only we change this so SMP safe */ |
| 1456 | return current_egid(); | 1456 | return from_kgid_munged(current_user_ns(), current_egid()); |
| 1457 | } | 1457 | } |
| 1458 | 1458 | ||
| 1459 | #endif | 1459 | #endif |
diff --git a/kernel/uid16.c b/kernel/uid16.c index 51c6e89e8619..d7948eb10225 100644 --- a/kernel/uid16.c +++ b/kernel/uid16.c | |||
| @@ -81,14 +81,19 @@ SYSCALL_DEFINE3(setresuid16, old_uid_t, ruid, old_uid_t, euid, old_uid_t, suid) | |||
| 81 | return ret; | 81 | return ret; |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | SYSCALL_DEFINE3(getresuid16, old_uid_t __user *, ruid, old_uid_t __user *, euid, old_uid_t __user *, suid) | 84 | SYSCALL_DEFINE3(getresuid16, old_uid_t __user *, ruidp, old_uid_t __user *, euidp, old_uid_t __user *, suidp) |
| 85 | { | 85 | { |
| 86 | const struct cred *cred = current_cred(); | 86 | const struct cred *cred = current_cred(); |
| 87 | int retval; | 87 | int retval; |
| 88 | old_uid_t ruid, euid, suid; | ||
| 88 | 89 | ||
| 89 | if (!(retval = put_user(high2lowuid(cred->uid), ruid)) && | 90 | ruid = high2lowuid(from_kuid_munged(cred->user_ns, cred->uid)); |
| 90 | !(retval = put_user(high2lowuid(cred->euid), euid))) | 91 | euid = high2lowuid(from_kuid_munged(cred->user_ns, cred->euid)); |
| 91 | retval = put_user(high2lowuid(cred->suid), suid); | 92 | suid = high2lowuid(from_kuid_munged(cred->user_ns, cred->suid)); |
| 93 | |||
| 94 | if (!(retval = put_user(ruid, ruidp)) && | ||
| 95 | !(retval = put_user(euid, euidp))) | ||
| 96 | retval = put_user(suid, suidp); | ||
| 92 | 97 | ||
| 93 | return retval; | 98 | return retval; |
| 94 | } | 99 | } |
| @@ -103,14 +108,19 @@ SYSCALL_DEFINE3(setresgid16, old_gid_t, rgid, old_gid_t, egid, old_gid_t, sgid) | |||
| 103 | } | 108 | } |
| 104 | 109 | ||
| 105 | 110 | ||
| 106 | SYSCALL_DEFINE3(getresgid16, old_gid_t __user *, rgid, old_gid_t __user *, egid, old_gid_t __user *, sgid) | 111 | SYSCALL_DEFINE3(getresgid16, old_gid_t __user *, rgidp, old_gid_t __user *, egidp, old_gid_t __user *, sgidp) |
| 107 | { | 112 | { |
| 108 | const struct cred *cred = current_cred(); | 113 | const struct cred *cred = current_cred(); |
| 109 | int retval; | 114 | int retval; |
| 115 | old_gid_t rgid, egid, sgid; | ||
| 116 | |||
| 117 | rgid = high2lowgid(from_kgid_munged(cred->user_ns, cred->gid)); | ||
| 118 | egid = high2lowgid(from_kgid_munged(cred->user_ns, cred->egid)); | ||
| 119 | sgid = high2lowgid(from_kgid_munged(cred->user_ns, cred->sgid)); | ||
| 110 | 120 | ||
| 111 | if (!(retval = put_user(high2lowgid(cred->gid), rgid)) && | 121 | if (!(retval = put_user(rgid, rgidp)) && |
| 112 | !(retval = put_user(high2lowgid(cred->egid), egid))) | 122 | !(retval = put_user(egid, egidp))) |
| 113 | retval = put_user(high2lowgid(cred->sgid), sgid); | 123 | retval = put_user(sgid, sgidp); |
| 114 | 124 | ||
| 115 | return retval; | 125 | return retval; |
| 116 | } | 126 | } |
| @@ -134,11 +144,14 @@ SYSCALL_DEFINE1(setfsgid16, old_gid_t, gid) | |||
| 134 | static int groups16_to_user(old_gid_t __user *grouplist, | 144 | static int groups16_to_user(old_gid_t __user *grouplist, |
| 135 | struct group_info *group_info) | 145 | struct group_info *group_info) |
| 136 | { | 146 | { |
| 147 | struct user_namespace *user_ns = current_user_ns(); | ||
| 137 | int i; | 148 | int i; |
| 138 | old_gid_t group; | 149 | old_gid_t group; |
| 150 | kgid_t kgid; | ||
| 139 | 151 | ||
| 140 | for (i = 0; i < group_info->ngroups; i++) { | 152 | for (i = 0; i < group_info->ngroups; i++) { |
| 141 | group = high2lowgid(GROUP_AT(group_info, i)); | 153 | kgid = GROUP_AT(group_info, i); |
| 154 | group = high2lowgid(from_kgid_munged(user_ns, kgid)); | ||
| 142 | if (put_user(group, grouplist+i)) | 155 | if (put_user(group, grouplist+i)) |
| 143 | return -EFAULT; | 156 | return -EFAULT; |
| 144 | } | 157 | } |
| @@ -149,13 +162,20 @@ static int groups16_to_user(old_gid_t __user *grouplist, | |||
| 149 | static int groups16_from_user(struct group_info *group_info, | 162 | static int groups16_from_user(struct group_info *group_info, |
| 150 | old_gid_t __user *grouplist) | 163 | old_gid_t __user *grouplist) |
| 151 | { | 164 | { |
| 165 | struct user_namespace *user_ns = current_user_ns(); | ||
| 152 | int i; | 166 | int i; |
| 153 | old_gid_t group; | 167 | old_gid_t group; |
| 168 | kgid_t kgid; | ||
| 154 | 169 | ||
| 155 | for (i = 0; i < group_info->ngroups; i++) { | 170 | for (i = 0; i < group_info->ngroups; i++) { |
| 156 | if (get_user(group, grouplist+i)) | 171 | if (get_user(group, grouplist+i)) |
| 157 | return -EFAULT; | 172 | return -EFAULT; |
| 158 | GROUP_AT(group_info, i) = low2highgid(group); | 173 | |
| 174 | kgid = make_kgid(user_ns, low2highgid(group)); | ||
| 175 | if (!gid_valid(kgid)) | ||
| 176 | return -EINVAL; | ||
| 177 | |||
| 178 | GROUP_AT(group_info, i) = kgid; | ||
| 159 | } | 179 | } |
| 160 | 180 | ||
| 161 | return 0; | 181 | return 0; |
| @@ -211,20 +231,20 @@ SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist) | |||
| 211 | 231 | ||
| 212 | SYSCALL_DEFINE0(getuid16) | 232 | SYSCALL_DEFINE0(getuid16) |
| 213 | { | 233 | { |
| 214 | return high2lowuid(current_uid()); | 234 | return high2lowuid(from_kuid_munged(current_user_ns(), current_uid())); |
| 215 | } | 235 | } |
| 216 | 236 | ||
| 217 | SYSCALL_DEFINE0(geteuid16) | 237 | SYSCALL_DEFINE0(geteuid16) |
| 218 | { | 238 | { |
| 219 | return high2lowuid(current_euid()); | 239 | return high2lowuid(from_kuid_munged(current_user_ns(), current_euid())); |
| 220 | } | 240 | } |
| 221 | 241 | ||
| 222 | SYSCALL_DEFINE0(getgid16) | 242 | SYSCALL_DEFINE0(getgid16) |
| 223 | { | 243 | { |
| 224 | return high2lowgid(current_gid()); | 244 | return high2lowgid(from_kgid_munged(current_user_ns(), current_gid())); |
| 225 | } | 245 | } |
| 226 | 246 | ||
| 227 | SYSCALL_DEFINE0(getegid16) | 247 | SYSCALL_DEFINE0(getegid16) |
| 228 | { | 248 | { |
| 229 | return high2lowgid(current_egid()); | 249 | return high2lowgid(from_kgid_munged(current_user_ns(), current_egid())); |
| 230 | } | 250 | } |
diff --git a/kernel/user.c b/kernel/user.c index 71dd2363ab0f..b815fefbe76f 100644 --- a/kernel/user.c +++ b/kernel/user.c | |||
| @@ -22,10 +22,27 @@ | |||
| 22 | * and 1 for... ? | 22 | * and 1 for... ? |
| 23 | */ | 23 | */ |
| 24 | struct user_namespace init_user_ns = { | 24 | struct user_namespace init_user_ns = { |
| 25 | .uid_map = { | ||
| 26 | .nr_extents = 1, | ||
| 27 | .extent[0] = { | ||
| 28 | .first = 0, | ||
| 29 | .lower_first = 0, | ||
| 30 | .count = 4294967295U, | ||
| 31 | }, | ||
| 32 | }, | ||
| 33 | .gid_map = { | ||
| 34 | .nr_extents = 1, | ||
| 35 | .extent[0] = { | ||
| 36 | .first = 0, | ||
| 37 | .lower_first = 0, | ||
| 38 | .count = 4294967295U, | ||
| 39 | }, | ||
| 40 | }, | ||
| 25 | .kref = { | 41 | .kref = { |
| 26 | .refcount = ATOMIC_INIT(3), | 42 | .refcount = ATOMIC_INIT(3), |
| 27 | }, | 43 | }, |
| 28 | .creator = &root_user, | 44 | .owner = GLOBAL_ROOT_UID, |
| 45 | .group = GLOBAL_ROOT_GID, | ||
| 29 | }; | 46 | }; |
| 30 | EXPORT_SYMBOL_GPL(init_user_ns); | 47 | EXPORT_SYMBOL_GPL(init_user_ns); |
| 31 | 48 | ||
| @@ -34,11 +51,14 @@ EXPORT_SYMBOL_GPL(init_user_ns); | |||
| 34 | * when changing user ID's (ie setuid() and friends). | 51 | * when changing user ID's (ie setuid() and friends). |
| 35 | */ | 52 | */ |
| 36 | 53 | ||
| 54 | #define UIDHASH_BITS (CONFIG_BASE_SMALL ? 3 : 7) | ||
| 55 | #define UIDHASH_SZ (1 << UIDHASH_BITS) | ||
| 37 | #define UIDHASH_MASK (UIDHASH_SZ - 1) | 56 | #define UIDHASH_MASK (UIDHASH_SZ - 1) |
| 38 | #define __uidhashfn(uid) (((uid >> UIDHASH_BITS) + uid) & UIDHASH_MASK) | 57 | #define __uidhashfn(uid) (((uid >> UIDHASH_BITS) + uid) & UIDHASH_MASK) |
| 39 | #define uidhashentry(ns, uid) ((ns)->uidhash_table + __uidhashfn((uid))) | 58 | #define uidhashentry(uid) (uidhash_table + __uidhashfn((__kuid_val(uid)))) |
| 40 | 59 | ||
| 41 | static struct kmem_cache *uid_cachep; | 60 | static struct kmem_cache *uid_cachep; |
| 61 | struct hlist_head uidhash_table[UIDHASH_SZ]; | ||
| 42 | 62 | ||
| 43 | /* | 63 | /* |
| 44 | * The uidhash_lock is mostly taken from process context, but it is | 64 | * The uidhash_lock is mostly taken from process context, but it is |
| @@ -51,14 +71,14 @@ static struct kmem_cache *uid_cachep; | |||
| 51 | */ | 71 | */ |
| 52 | static DEFINE_SPINLOCK(uidhash_lock); | 72 | static DEFINE_SPINLOCK(uidhash_lock); |
| 53 | 73 | ||
| 54 | /* root_user.__count is 2, 1 for init task cred, 1 for init_user_ns->user_ns */ | 74 | /* root_user.__count is 1, for init task cred */ |
| 55 | struct user_struct root_user = { | 75 | struct user_struct root_user = { |
| 56 | .__count = ATOMIC_INIT(2), | 76 | .__count = ATOMIC_INIT(1), |
| 57 | .processes = ATOMIC_INIT(1), | 77 | .processes = ATOMIC_INIT(1), |
| 58 | .files = ATOMIC_INIT(0), | 78 | .files = ATOMIC_INIT(0), |
| 59 | .sigpending = ATOMIC_INIT(0), | 79 | .sigpending = ATOMIC_INIT(0), |
| 60 | .locked_shm = 0, | 80 | .locked_shm = 0, |
| 61 | .user_ns = &init_user_ns, | 81 | .uid = GLOBAL_ROOT_UID, |
| 62 | }; | 82 | }; |
| 63 | 83 | ||
| 64 | /* | 84 | /* |
| @@ -72,16 +92,15 @@ static void uid_hash_insert(struct user_struct *up, struct hlist_head *hashent) | |||
| 72 | static void uid_hash_remove(struct user_struct *up) | 92 | static void uid_hash_remove(struct user_struct *up) |
| 73 | { | 93 | { |
| 74 | hlist_del_init(&up->uidhash_node); | 94 | hlist_del_init(&up->uidhash_node); |
| 75 | put_user_ns(up->user_ns); | ||
| 76 | } | 95 | } |
| 77 | 96 | ||
| 78 | static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent) | 97 | static struct user_struct *uid_hash_find(kuid_t uid, struct hlist_head *hashent) |
| 79 | { | 98 | { |
| 80 | struct user_struct *user; | 99 | struct user_struct *user; |
| 81 | struct hlist_node *h; | 100 | struct hlist_node *h; |
| 82 | 101 | ||
| 83 | hlist_for_each_entry(user, h, hashent, uidhash_node) { | 102 | hlist_for_each_entry(user, h, hashent, uidhash_node) { |
| 84 | if (user->uid == uid) { | 103 | if (uid_eq(user->uid, uid)) { |
| 85 | atomic_inc(&user->__count); | 104 | atomic_inc(&user->__count); |
| 86 | return user; | 105 | return user; |
| 87 | } | 106 | } |
| @@ -110,14 +129,13 @@ static void free_user(struct user_struct *up, unsigned long flags) | |||
| 110 | * | 129 | * |
| 111 | * If the user_struct could not be found, return NULL. | 130 | * If the user_struct could not be found, return NULL. |
| 112 | */ | 131 | */ |
| 113 | struct user_struct *find_user(uid_t uid) | 132 | struct user_struct *find_user(kuid_t uid) |
| 114 | { | 133 | { |
| 115 | struct user_struct *ret; | 134 | struct user_struct *ret; |
| 116 | unsigned long flags; | 135 | unsigned long flags; |
| 117 | struct user_namespace *ns = current_user_ns(); | ||
| 118 | 136 | ||
| 119 | spin_lock_irqsave(&uidhash_lock, flags); | 137 | spin_lock_irqsave(&uidhash_lock, flags); |
| 120 | ret = uid_hash_find(uid, uidhashentry(ns, uid)); | 138 | ret = uid_hash_find(uid, uidhashentry(uid)); |
| 121 | spin_unlock_irqrestore(&uidhash_lock, flags); | 139 | spin_unlock_irqrestore(&uidhash_lock, flags); |
| 122 | return ret; | 140 | return ret; |
| 123 | } | 141 | } |
| @@ -136,9 +154,9 @@ void free_uid(struct user_struct *up) | |||
| 136 | local_irq_restore(flags); | 154 | local_irq_restore(flags); |
| 137 | } | 155 | } |
| 138 | 156 | ||
| 139 | struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid) | 157 | struct user_struct *alloc_uid(kuid_t uid) |
| 140 | { | 158 | { |
| 141 | struct hlist_head *hashent = uidhashentry(ns, uid); | 159 | struct hlist_head *hashent = uidhashentry(uid); |
| 142 | struct user_struct *up, *new; | 160 | struct user_struct *up, *new; |
| 143 | 161 | ||
| 144 | spin_lock_irq(&uidhash_lock); | 162 | spin_lock_irq(&uidhash_lock); |
| @@ -153,8 +171,6 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid) | |||
| 153 | new->uid = uid; | 171 | new->uid = uid; |
| 154 | atomic_set(&new->__count, 1); | 172 | atomic_set(&new->__count, 1); |
| 155 | 173 | ||
| 156 | new->user_ns = get_user_ns(ns); | ||
| 157 | |||
| 158 | /* | 174 | /* |
| 159 | * Before adding this, check whether we raced | 175 | * Before adding this, check whether we raced |
| 160 | * on adding the same user already.. | 176 | * on adding the same user already.. |
| @@ -162,7 +178,6 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid) | |||
| 162 | spin_lock_irq(&uidhash_lock); | 178 | spin_lock_irq(&uidhash_lock); |
| 163 | up = uid_hash_find(uid, hashent); | 179 | up = uid_hash_find(uid, hashent); |
| 164 | if (up) { | 180 | if (up) { |
| 165 | put_user_ns(ns); | ||
| 166 | key_put(new->uid_keyring); | 181 | key_put(new->uid_keyring); |
| 167 | key_put(new->session_keyring); | 182 | key_put(new->session_keyring); |
| 168 | kmem_cache_free(uid_cachep, new); | 183 | kmem_cache_free(uid_cachep, new); |
| @@ -187,11 +202,11 @@ static int __init uid_cache_init(void) | |||
| 187 | 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); | 202 | 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); |
| 188 | 203 | ||
| 189 | for(n = 0; n < UIDHASH_SZ; ++n) | 204 | for(n = 0; n < UIDHASH_SZ; ++n) |
| 190 | INIT_HLIST_HEAD(init_user_ns.uidhash_table + n); | 205 | INIT_HLIST_HEAD(uidhash_table + n); |
| 191 | 206 | ||
| 192 | /* Insert the root user immediately (init already runs as root) */ | 207 | /* Insert the root user immediately (init already runs as root) */ |
| 193 | spin_lock_irq(&uidhash_lock); | 208 | spin_lock_irq(&uidhash_lock); |
| 194 | uid_hash_insert(&root_user, uidhashentry(&init_user_ns, 0)); | 209 | uid_hash_insert(&root_user, uidhashentry(GLOBAL_ROOT_UID)); |
| 195 | spin_unlock_irq(&uidhash_lock); | 210 | spin_unlock_irq(&uidhash_lock); |
| 196 | 211 | ||
| 197 | return 0; | 212 | return 0; |
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 3b906e98b1db..86602316422d 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c | |||
| @@ -11,9 +11,20 @@ | |||
| 11 | #include <linux/user_namespace.h> | 11 | #include <linux/user_namespace.h> |
| 12 | #include <linux/highuid.h> | 12 | #include <linux/highuid.h> |
| 13 | #include <linux/cred.h> | 13 | #include <linux/cred.h> |
| 14 | #include <linux/securebits.h> | ||
| 15 | #include <linux/keyctl.h> | ||
| 16 | #include <linux/key-type.h> | ||
| 17 | #include <keys/user-type.h> | ||
| 18 | #include <linux/seq_file.h> | ||
| 19 | #include <linux/fs.h> | ||
| 20 | #include <linux/uaccess.h> | ||
| 21 | #include <linux/ctype.h> | ||
| 14 | 22 | ||
| 15 | static struct kmem_cache *user_ns_cachep __read_mostly; | 23 | static struct kmem_cache *user_ns_cachep __read_mostly; |
| 16 | 24 | ||
| 25 | static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid, | ||
| 26 | struct uid_gid_map *map); | ||
| 27 | |||
| 17 | /* | 28 | /* |
| 18 | * Create a new user namespace, deriving the creator from the user in the | 29 | * Create a new user namespace, deriving the creator from the user in the |
| 19 | * passed credentials, and replacing that user with the new root user for the | 30 | * passed credentials, and replacing that user with the new root user for the |
| @@ -24,109 +35,565 @@ static struct kmem_cache *user_ns_cachep __read_mostly; | |||
| 24 | */ | 35 | */ |
| 25 | int create_user_ns(struct cred *new) | 36 | int create_user_ns(struct cred *new) |
| 26 | { | 37 | { |
| 27 | struct user_namespace *ns; | 38 | struct user_namespace *ns, *parent_ns = new->user_ns; |
| 28 | struct user_struct *root_user; | 39 | kuid_t owner = new->euid; |
| 29 | int n; | 40 | kgid_t group = new->egid; |
| 41 | |||
| 42 | /* The creator needs a mapping in the parent user namespace | ||
| 43 | * or else we won't be able to reasonably tell userspace who | ||
| 44 | * created a user_namespace. | ||
| 45 | */ | ||
| 46 | if (!kuid_has_mapping(parent_ns, owner) || | ||
| 47 | !kgid_has_mapping(parent_ns, group)) | ||
| 48 | return -EPERM; | ||
| 30 | 49 | ||
| 31 | ns = kmem_cache_alloc(user_ns_cachep, GFP_KERNEL); | 50 | ns = kmem_cache_zalloc(user_ns_cachep, GFP_KERNEL); |
| 32 | if (!ns) | 51 | if (!ns) |
| 33 | return -ENOMEM; | 52 | return -ENOMEM; |
| 34 | 53 | ||
| 35 | kref_init(&ns->kref); | 54 | kref_init(&ns->kref); |
| 55 | ns->parent = parent_ns; | ||
| 56 | ns->owner = owner; | ||
| 57 | ns->group = group; | ||
| 36 | 58 | ||
| 37 | for (n = 0; n < UIDHASH_SZ; ++n) | 59 | /* Start with the same capabilities as init but useless for doing |
| 38 | INIT_HLIST_HEAD(ns->uidhash_table + n); | 60 | * anything as the capabilities are bound to the new user namespace. |
| 39 | 61 | */ | |
| 40 | /* Alloc new root user. */ | 62 | new->securebits = SECUREBITS_DEFAULT; |
| 41 | root_user = alloc_uid(ns, 0); | 63 | new->cap_inheritable = CAP_EMPTY_SET; |
| 42 | if (!root_user) { | 64 | new->cap_permitted = CAP_FULL_SET; |
| 43 | kmem_cache_free(user_ns_cachep, ns); | 65 | new->cap_effective = CAP_FULL_SET; |
| 44 | return -ENOMEM; | 66 | new->cap_bset = CAP_FULL_SET; |
| 45 | } | ||
| 46 | |||
| 47 | /* set the new root user in the credentials under preparation */ | ||
| 48 | ns->creator = new->user; | ||
| 49 | new->user = root_user; | ||
| 50 | new->uid = new->euid = new->suid = new->fsuid = 0; | ||
| 51 | new->gid = new->egid = new->sgid = new->fsgid = 0; | ||
| 52 | put_group_info(new->group_info); | ||
| 53 | new->group_info = get_group_info(&init_groups); | ||
| 54 | #ifdef CONFIG_KEYS | 67 | #ifdef CONFIG_KEYS |
| 55 | key_put(new->request_key_auth); | 68 | key_put(new->request_key_auth); |
| 56 | new->request_key_auth = NULL; | 69 | new->request_key_auth = NULL; |
| 57 | #endif | 70 | #endif |
| 58 | /* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */ | 71 | /* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */ |
| 59 | 72 | ||
| 60 | /* root_user holds a reference to ns, our reference can be dropped */ | 73 | /* Leave the new->user_ns reference with the new user namespace. */ |
| 61 | put_user_ns(ns); | 74 | /* Leave the reference to our user_ns with the new cred. */ |
| 75 | new->user_ns = ns; | ||
| 62 | 76 | ||
| 63 | return 0; | 77 | return 0; |
| 64 | } | 78 | } |
| 65 | 79 | ||
| 66 | /* | 80 | void free_user_ns(struct kref *kref) |
| 67 | * Deferred destructor for a user namespace. This is required because | ||
| 68 | * free_user_ns() may be called with uidhash_lock held, but we need to call | ||
| 69 | * back to free_uid() which will want to take the lock again. | ||
| 70 | */ | ||
| 71 | static void free_user_ns_work(struct work_struct *work) | ||
| 72 | { | 81 | { |
| 73 | struct user_namespace *ns = | 82 | struct user_namespace *parent, *ns = |
| 74 | container_of(work, struct user_namespace, destroyer); | 83 | container_of(kref, struct user_namespace, kref); |
| 75 | free_uid(ns->creator); | 84 | |
| 85 | parent = ns->parent; | ||
| 76 | kmem_cache_free(user_ns_cachep, ns); | 86 | kmem_cache_free(user_ns_cachep, ns); |
| 87 | put_user_ns(parent); | ||
| 77 | } | 88 | } |
| 89 | EXPORT_SYMBOL(free_user_ns); | ||
| 78 | 90 | ||
| 79 | void free_user_ns(struct kref *kref) | 91 | static u32 map_id_range_down(struct uid_gid_map *map, u32 id, u32 count) |
| 80 | { | 92 | { |
| 81 | struct user_namespace *ns = | 93 | unsigned idx, extents; |
| 82 | container_of(kref, struct user_namespace, kref); | 94 | u32 first, last, id2; |
| 95 | |||
| 96 | id2 = id + count - 1; | ||
| 97 | |||
| 98 | /* Find the matching extent */ | ||
| 99 | extents = map->nr_extents; | ||
| 100 | smp_read_barrier_depends(); | ||
| 101 | for (idx = 0; idx < extents; idx++) { | ||
| 102 | first = map->extent[idx].first; | ||
| 103 | last = first + map->extent[idx].count - 1; | ||
| 104 | if (id >= first && id <= last && | ||
| 105 | (id2 >= first && id2 <= last)) | ||
| 106 | break; | ||
| 107 | } | ||
| 108 | /* Map the id or note failure */ | ||
| 109 | if (idx < extents) | ||
| 110 | id = (id - first) + map->extent[idx].lower_first; | ||
| 111 | else | ||
| 112 | id = (u32) -1; | ||
| 83 | 113 | ||
| 84 | INIT_WORK(&ns->destroyer, free_user_ns_work); | 114 | return id; |
| 85 | schedule_work(&ns->destroyer); | ||
| 86 | } | 115 | } |
| 87 | EXPORT_SYMBOL(free_user_ns); | ||
| 88 | 116 | ||
| 89 | uid_t user_ns_map_uid(struct user_namespace *to, const struct cred *cred, uid_t uid) | 117 | static u32 map_id_down(struct uid_gid_map *map, u32 id) |
| 90 | { | 118 | { |
| 91 | struct user_namespace *tmp; | 119 | unsigned idx, extents; |
| 120 | u32 first, last; | ||
| 92 | 121 | ||
| 93 | if (likely(to == cred->user->user_ns)) | 122 | /* Find the matching extent */ |
| 94 | return uid; | 123 | extents = map->nr_extents; |
| 124 | smp_read_barrier_depends(); | ||
| 125 | for (idx = 0; idx < extents; idx++) { | ||
| 126 | first = map->extent[idx].first; | ||
| 127 | last = first + map->extent[idx].count - 1; | ||
| 128 | if (id >= first && id <= last) | ||
| 129 | break; | ||
| 130 | } | ||
| 131 | /* Map the id or note failure */ | ||
| 132 | if (idx < extents) | ||
| 133 | id = (id - first) + map->extent[idx].lower_first; | ||
| 134 | else | ||
| 135 | id = (u32) -1; | ||
| 95 | 136 | ||
| 137 | return id; | ||
| 138 | } | ||
| 96 | 139 | ||
| 97 | /* Is cred->user the creator of the target user_ns | 140 | static u32 map_id_up(struct uid_gid_map *map, u32 id) |
| 98 | * or the creator of one of it's parents? | 141 | { |
| 99 | */ | 142 | unsigned idx, extents; |
| 100 | for ( tmp = to; tmp != &init_user_ns; | 143 | u32 first, last; |
| 101 | tmp = tmp->creator->user_ns ) { | 144 | |
| 102 | if (cred->user == tmp->creator) { | 145 | /* Find the matching extent */ |
| 103 | return (uid_t)0; | 146 | extents = map->nr_extents; |
| 104 | } | 147 | smp_read_barrier_depends(); |
| 148 | for (idx = 0; idx < extents; idx++) { | ||
| 149 | first = map->extent[idx].lower_first; | ||
| 150 | last = first + map->extent[idx].count - 1; | ||
| 151 | if (id >= first && id <= last) | ||
| 152 | break; | ||
| 105 | } | 153 | } |
| 154 | /* Map the id or note failure */ | ||
| 155 | if (idx < extents) | ||
| 156 | id = (id - first) + map->extent[idx].first; | ||
| 157 | else | ||
| 158 | id = (u32) -1; | ||
| 159 | |||
| 160 | return id; | ||
| 161 | } | ||
| 162 | |||
| 163 | /** | ||
| 164 | * make_kuid - Map a user-namespace uid pair into a kuid. | ||
| 165 | * @ns: User namespace that the uid is in | ||
| 166 | * @uid: User identifier | ||
| 167 | * | ||
| 168 | * Maps a user-namespace uid pair into a kernel internal kuid, | ||
| 169 | * and returns that kuid. | ||
| 170 | * | ||
| 171 | * When there is no mapping defined for the user-namespace uid | ||
| 172 | * pair INVALID_UID is returned. Callers are expected to test | ||
| 173 | * for and handle handle INVALID_UID being returned. INVALID_UID | ||
| 174 | * may be tested for using uid_valid(). | ||
| 175 | */ | ||
| 176 | kuid_t make_kuid(struct user_namespace *ns, uid_t uid) | ||
| 177 | { | ||
| 178 | /* Map the uid to a global kernel uid */ | ||
| 179 | return KUIDT_INIT(map_id_down(&ns->uid_map, uid)); | ||
| 180 | } | ||
| 181 | EXPORT_SYMBOL(make_kuid); | ||
| 182 | |||
| 183 | /** | ||
| 184 | * from_kuid - Create a uid from a kuid user-namespace pair. | ||
| 185 | * @targ: The user namespace we want a uid in. | ||
| 186 | * @kuid: The kernel internal uid to start with. | ||
| 187 | * | ||
| 188 | * Map @kuid into the user-namespace specified by @targ and | ||
| 189 | * return the resulting uid. | ||
| 190 | * | ||
| 191 | * There is always a mapping into the initial user_namespace. | ||
| 192 | * | ||
| 193 | * If @kuid has no mapping in @targ (uid_t)-1 is returned. | ||
| 194 | */ | ||
| 195 | uid_t from_kuid(struct user_namespace *targ, kuid_t kuid) | ||
| 196 | { | ||
| 197 | /* Map the uid from a global kernel uid */ | ||
| 198 | return map_id_up(&targ->uid_map, __kuid_val(kuid)); | ||
| 199 | } | ||
| 200 | EXPORT_SYMBOL(from_kuid); | ||
| 106 | 201 | ||
| 107 | /* No useful relationship so no mapping */ | 202 | /** |
| 108 | return overflowuid; | 203 | * from_kuid_munged - Create a uid from a kuid user-namespace pair. |
| 204 | * @targ: The user namespace we want a uid in. | ||
| 205 | * @kuid: The kernel internal uid to start with. | ||
| 206 | * | ||
| 207 | * Map @kuid into the user-namespace specified by @targ and | ||
| 208 | * return the resulting uid. | ||
| 209 | * | ||
| 210 | * There is always a mapping into the initial user_namespace. | ||
| 211 | * | ||
| 212 | * Unlike from_kuid from_kuid_munged never fails and always | ||
| 213 | * returns a valid uid. This makes from_kuid_munged appropriate | ||
| 214 | * for use in syscalls like stat and getuid where failing the | ||
| 215 | * system call and failing to provide a valid uid are not an | ||
| 216 | * options. | ||
| 217 | * | ||
| 218 | * If @kuid has no mapping in @targ overflowuid is returned. | ||
| 219 | */ | ||
| 220 | uid_t from_kuid_munged(struct user_namespace *targ, kuid_t kuid) | ||
| 221 | { | ||
| 222 | uid_t uid; | ||
| 223 | uid = from_kuid(targ, kuid); | ||
| 224 | |||
| 225 | if (uid == (uid_t) -1) | ||
| 226 | uid = overflowuid; | ||
| 227 | return uid; | ||
| 109 | } | 228 | } |
| 229 | EXPORT_SYMBOL(from_kuid_munged); | ||
| 110 | 230 | ||
| 111 | gid_t user_ns_map_gid(struct user_namespace *to, const struct cred *cred, gid_t gid) | 231 | /** |
| 232 | * make_kgid - Map a user-namespace gid pair into a kgid. | ||
| 233 | * @ns: User namespace that the gid is in | ||
| 234 | * @uid: group identifier | ||
| 235 | * | ||
| 236 | * Maps a user-namespace gid pair into a kernel internal kgid, | ||
| 237 | * and returns that kgid. | ||
| 238 | * | ||
| 239 | * When there is no mapping defined for the user-namespace gid | ||
| 240 | * pair INVALID_GID is returned. Callers are expected to test | ||
| 241 | * for and handle INVALID_GID being returned. INVALID_GID may be | ||
| 242 | * tested for using gid_valid(). | ||
| 243 | */ | ||
| 244 | kgid_t make_kgid(struct user_namespace *ns, gid_t gid) | ||
| 112 | { | 245 | { |
| 113 | struct user_namespace *tmp; | 246 | /* Map the gid to a global kernel gid */ |
| 247 | return KGIDT_INIT(map_id_down(&ns->gid_map, gid)); | ||
| 248 | } | ||
| 249 | EXPORT_SYMBOL(make_kgid); | ||
| 114 | 250 | ||
| 115 | if (likely(to == cred->user->user_ns)) | 251 | /** |
| 116 | return gid; | 252 | * from_kgid - Create a gid from a kgid user-namespace pair. |
| 253 | * @targ: The user namespace we want a gid in. | ||
| 254 | * @kgid: The kernel internal gid to start with. | ||
| 255 | * | ||
| 256 | * Map @kgid into the user-namespace specified by @targ and | ||
| 257 | * return the resulting gid. | ||
| 258 | * | ||
| 259 | * There is always a mapping into the initial user_namespace. | ||
| 260 | * | ||
| 261 | * If @kgid has no mapping in @targ (gid_t)-1 is returned. | ||
| 262 | */ | ||
| 263 | gid_t from_kgid(struct user_namespace *targ, kgid_t kgid) | ||
| 264 | { | ||
| 265 | /* Map the gid from a global kernel gid */ | ||
| 266 | return map_id_up(&targ->gid_map, __kgid_val(kgid)); | ||
| 267 | } | ||
| 268 | EXPORT_SYMBOL(from_kgid); | ||
| 269 | |||
| 270 | /** | ||
| 271 | * from_kgid_munged - Create a gid from a kgid user-namespace pair. | ||
| 272 | * @targ: The user namespace we want a gid in. | ||
| 273 | * @kgid: The kernel internal gid to start with. | ||
| 274 | * | ||
| 275 | * Map @kgid into the user-namespace specified by @targ and | ||
| 276 | * return the resulting gid. | ||
| 277 | * | ||
| 278 | * There is always a mapping into the initial user_namespace. | ||
| 279 | * | ||
| 280 | * Unlike from_kgid from_kgid_munged never fails and always | ||
| 281 | * returns a valid gid. This makes from_kgid_munged appropriate | ||
| 282 | * for use in syscalls like stat and getgid where failing the | ||
| 283 | * system call and failing to provide a valid gid are not options. | ||
| 284 | * | ||
| 285 | * If @kgid has no mapping in @targ overflowgid is returned. | ||
| 286 | */ | ||
| 287 | gid_t from_kgid_munged(struct user_namespace *targ, kgid_t kgid) | ||
| 288 | { | ||
| 289 | gid_t gid; | ||
| 290 | gid = from_kgid(targ, kgid); | ||
| 117 | 291 | ||
| 118 | /* Is cred->user the creator of the target user_ns | 292 | if (gid == (gid_t) -1) |
| 119 | * or the creator of one of it's parents? | 293 | gid = overflowgid; |
| 294 | return gid; | ||
| 295 | } | ||
| 296 | EXPORT_SYMBOL(from_kgid_munged); | ||
| 297 | |||
| 298 | static int uid_m_show(struct seq_file *seq, void *v) | ||
| 299 | { | ||
| 300 | struct user_namespace *ns = seq->private; | ||
| 301 | struct uid_gid_extent *extent = v; | ||
| 302 | struct user_namespace *lower_ns; | ||
| 303 | uid_t lower; | ||
| 304 | |||
| 305 | lower_ns = current_user_ns(); | ||
| 306 | if ((lower_ns == ns) && lower_ns->parent) | ||
| 307 | lower_ns = lower_ns->parent; | ||
| 308 | |||
| 309 | lower = from_kuid(lower_ns, KUIDT_INIT(extent->lower_first)); | ||
| 310 | |||
| 311 | seq_printf(seq, "%10u %10u %10u\n", | ||
| 312 | extent->first, | ||
| 313 | lower, | ||
| 314 | extent->count); | ||
| 315 | |||
| 316 | return 0; | ||
| 317 | } | ||
| 318 | |||
| 319 | static int gid_m_show(struct seq_file *seq, void *v) | ||
| 320 | { | ||
| 321 | struct user_namespace *ns = seq->private; | ||
| 322 | struct uid_gid_extent *extent = v; | ||
| 323 | struct user_namespace *lower_ns; | ||
| 324 | gid_t lower; | ||
| 325 | |||
| 326 | lower_ns = current_user_ns(); | ||
| 327 | if ((lower_ns == ns) && lower_ns->parent) | ||
| 328 | lower_ns = lower_ns->parent; | ||
| 329 | |||
| 330 | lower = from_kgid(lower_ns, KGIDT_INIT(extent->lower_first)); | ||
| 331 | |||
| 332 | seq_printf(seq, "%10u %10u %10u\n", | ||
| 333 | extent->first, | ||
| 334 | lower, | ||
| 335 | extent->count); | ||
| 336 | |||
| 337 | return 0; | ||
| 338 | } | ||
| 339 | |||
| 340 | static void *m_start(struct seq_file *seq, loff_t *ppos, struct uid_gid_map *map) | ||
| 341 | { | ||
| 342 | struct uid_gid_extent *extent = NULL; | ||
| 343 | loff_t pos = *ppos; | ||
| 344 | |||
| 345 | if (pos < map->nr_extents) | ||
| 346 | extent = &map->extent[pos]; | ||
| 347 | |||
| 348 | return extent; | ||
| 349 | } | ||
| 350 | |||
| 351 | static void *uid_m_start(struct seq_file *seq, loff_t *ppos) | ||
| 352 | { | ||
| 353 | struct user_namespace *ns = seq->private; | ||
| 354 | |||
| 355 | return m_start(seq, ppos, &ns->uid_map); | ||
| 356 | } | ||
| 357 | |||
| 358 | static void *gid_m_start(struct seq_file *seq, loff_t *ppos) | ||
| 359 | { | ||
| 360 | struct user_namespace *ns = seq->private; | ||
| 361 | |||
| 362 | return m_start(seq, ppos, &ns->gid_map); | ||
| 363 | } | ||
| 364 | |||
| 365 | static void *m_next(struct seq_file *seq, void *v, loff_t *pos) | ||
| 366 | { | ||
| 367 | (*pos)++; | ||
| 368 | return seq->op->start(seq, pos); | ||
| 369 | } | ||
| 370 | |||
| 371 | static void m_stop(struct seq_file *seq, void *v) | ||
| 372 | { | ||
| 373 | return; | ||
| 374 | } | ||
| 375 | |||
| 376 | struct seq_operations proc_uid_seq_operations = { | ||
| 377 | .start = uid_m_start, | ||
| 378 | .stop = m_stop, | ||
| 379 | .next = m_next, | ||
| 380 | .show = uid_m_show, | ||
| 381 | }; | ||
| 382 | |||
| 383 | struct seq_operations proc_gid_seq_operations = { | ||
| 384 | .start = gid_m_start, | ||
| 385 | .stop = m_stop, | ||
| 386 | .next = m_next, | ||
| 387 | .show = gid_m_show, | ||
| 388 | }; | ||
| 389 | |||
| 390 | static DEFINE_MUTEX(id_map_mutex); | ||
| 391 | |||
| 392 | static ssize_t map_write(struct file *file, const char __user *buf, | ||
| 393 | size_t count, loff_t *ppos, | ||
| 394 | int cap_setid, | ||
| 395 | struct uid_gid_map *map, | ||
| 396 | struct uid_gid_map *parent_map) | ||
| 397 | { | ||
| 398 | struct seq_file *seq = file->private_data; | ||
| 399 | struct user_namespace *ns = seq->private; | ||
| 400 | struct uid_gid_map new_map; | ||
| 401 | unsigned idx; | ||
| 402 | struct uid_gid_extent *extent, *last = NULL; | ||
| 403 | unsigned long page = 0; | ||
| 404 | char *kbuf, *pos, *next_line; | ||
| 405 | ssize_t ret = -EINVAL; | ||
| 406 | |||
| 407 | /* | ||
| 408 | * The id_map_mutex serializes all writes to any given map. | ||
| 409 | * | ||
| 410 | * Any map is only ever written once. | ||
| 411 | * | ||
| 412 | * An id map fits within 1 cache line on most architectures. | ||
| 413 | * | ||
| 414 | * On read nothing needs to be done unless you are on an | ||
| 415 | * architecture with a crazy cache coherency model like alpha. | ||
| 416 | * | ||
| 417 | * There is a one time data dependency between reading the | ||
| 418 | * count of the extents and the values of the extents. The | ||
| 419 | * desired behavior is to see the values of the extents that | ||
| 420 | * were written before the count of the extents. | ||
| 421 | * | ||
| 422 | * To achieve this smp_wmb() is used on guarantee the write | ||
| 423 | * order and smp_read_barrier_depends() is guaranteed that we | ||
| 424 | * don't have crazy architectures returning stale data. | ||
| 425 | * | ||
| 120 | */ | 426 | */ |
| 121 | for ( tmp = to; tmp != &init_user_ns; | 427 | mutex_lock(&id_map_mutex); |
| 122 | tmp = tmp->creator->user_ns ) { | 428 | |
| 123 | if (cred->user == tmp->creator) { | 429 | ret = -EPERM; |
| 124 | return (gid_t)0; | 430 | /* Only allow one successful write to the map */ |
| 431 | if (map->nr_extents != 0) | ||
| 432 | goto out; | ||
| 433 | |||
| 434 | /* Require the appropriate privilege CAP_SETUID or CAP_SETGID | ||
| 435 | * over the user namespace in order to set the id mapping. | ||
| 436 | */ | ||
| 437 | if (!ns_capable(ns, cap_setid)) | ||
| 438 | goto out; | ||
| 439 | |||
| 440 | /* Get a buffer */ | ||
| 441 | ret = -ENOMEM; | ||
| 442 | page = __get_free_page(GFP_TEMPORARY); | ||
| 443 | kbuf = (char *) page; | ||
| 444 | if (!page) | ||
| 445 | goto out; | ||
| 446 | |||
| 447 | /* Only allow <= page size writes at the beginning of the file */ | ||
| 448 | ret = -EINVAL; | ||
| 449 | if ((*ppos != 0) || (count >= PAGE_SIZE)) | ||
| 450 | goto out; | ||
| 451 | |||
| 452 | /* Slurp in the user data */ | ||
| 453 | ret = -EFAULT; | ||
| 454 | if (copy_from_user(kbuf, buf, count)) | ||
| 455 | goto out; | ||
| 456 | kbuf[count] = '\0'; | ||
| 457 | |||
| 458 | /* Parse the user data */ | ||
| 459 | ret = -EINVAL; | ||
| 460 | pos = kbuf; | ||
| 461 | new_map.nr_extents = 0; | ||
| 462 | for (;pos; pos = next_line) { | ||
| 463 | extent = &new_map.extent[new_map.nr_extents]; | ||
| 464 | |||
| 465 | /* Find the end of line and ensure I don't look past it */ | ||
| 466 | next_line = strchr(pos, '\n'); | ||
| 467 | if (next_line) { | ||
| 468 | *next_line = '\0'; | ||
| 469 | next_line++; | ||
| 470 | if (*next_line == '\0') | ||
| 471 | next_line = NULL; | ||
| 125 | } | 472 | } |
| 473 | |||
| 474 | pos = skip_spaces(pos); | ||
| 475 | extent->first = simple_strtoul(pos, &pos, 10); | ||
| 476 | if (!isspace(*pos)) | ||
| 477 | goto out; | ||
| 478 | |||
| 479 | pos = skip_spaces(pos); | ||
| 480 | extent->lower_first = simple_strtoul(pos, &pos, 10); | ||
| 481 | if (!isspace(*pos)) | ||
| 482 | goto out; | ||
| 483 | |||
| 484 | pos = skip_spaces(pos); | ||
| 485 | extent->count = simple_strtoul(pos, &pos, 10); | ||
| 486 | if (*pos && !isspace(*pos)) | ||
| 487 | goto out; | ||
| 488 | |||
| 489 | /* Verify there is not trailing junk on the line */ | ||
| 490 | pos = skip_spaces(pos); | ||
| 491 | if (*pos != '\0') | ||
| 492 | goto out; | ||
| 493 | |||
| 494 | /* Verify we have been given valid starting values */ | ||
| 495 | if ((extent->first == (u32) -1) || | ||
| 496 | (extent->lower_first == (u32) -1 )) | ||
| 497 | goto out; | ||
| 498 | |||
| 499 | /* Verify count is not zero and does not cause the extent to wrap */ | ||
| 500 | if ((extent->first + extent->count) <= extent->first) | ||
| 501 | goto out; | ||
| 502 | if ((extent->lower_first + extent->count) <= extent->lower_first) | ||
| 503 | goto out; | ||
| 504 | |||
| 505 | /* For now only accept extents that are strictly in order */ | ||
| 506 | if (last && | ||
| 507 | (((last->first + last->count) > extent->first) || | ||
| 508 | ((last->lower_first + last->count) > extent->lower_first))) | ||
| 509 | goto out; | ||
| 510 | |||
| 511 | new_map.nr_extents++; | ||
| 512 | last = extent; | ||
| 513 | |||
| 514 | /* Fail if the file contains too many extents */ | ||
| 515 | if ((new_map.nr_extents == UID_GID_MAP_MAX_EXTENTS) && | ||
| 516 | (next_line != NULL)) | ||
| 517 | goto out; | ||
| 518 | } | ||
| 519 | /* Be very certaint the new map actually exists */ | ||
| 520 | if (new_map.nr_extents == 0) | ||
| 521 | goto out; | ||
| 522 | |||
| 523 | ret = -EPERM; | ||
| 524 | /* Validate the user is allowed to use user id's mapped to. */ | ||
| 525 | if (!new_idmap_permitted(ns, cap_setid, &new_map)) | ||
| 526 | goto out; | ||
| 527 | |||
| 528 | /* Map the lower ids from the parent user namespace to the | ||
| 529 | * kernel global id space. | ||
| 530 | */ | ||
| 531 | for (idx = 0; idx < new_map.nr_extents; idx++) { | ||
| 532 | u32 lower_first; | ||
| 533 | extent = &new_map.extent[idx]; | ||
| 534 | |||
| 535 | lower_first = map_id_range_down(parent_map, | ||
| 536 | extent->lower_first, | ||
| 537 | extent->count); | ||
| 538 | |||
| 539 | /* Fail if we can not map the specified extent to | ||
| 540 | * the kernel global id space. | ||
| 541 | */ | ||
| 542 | if (lower_first == (u32) -1) | ||
| 543 | goto out; | ||
| 544 | |||
| 545 | extent->lower_first = lower_first; | ||
| 126 | } | 546 | } |
| 127 | 547 | ||
| 128 | /* No useful relationship so no mapping */ | 548 | /* Install the map */ |
| 129 | return overflowgid; | 549 | memcpy(map->extent, new_map.extent, |
| 550 | new_map.nr_extents*sizeof(new_map.extent[0])); | ||
| 551 | smp_wmb(); | ||
| 552 | map->nr_extents = new_map.nr_extents; | ||
| 553 | |||
| 554 | *ppos = count; | ||
| 555 | ret = count; | ||
| 556 | out: | ||
| 557 | mutex_unlock(&id_map_mutex); | ||
| 558 | if (page) | ||
| 559 | free_page(page); | ||
| 560 | return ret; | ||
| 561 | } | ||
| 562 | |||
| 563 | ssize_t proc_uid_map_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos) | ||
| 564 | { | ||
| 565 | struct seq_file *seq = file->private_data; | ||
| 566 | struct user_namespace *ns = seq->private; | ||
| 567 | |||
| 568 | if (!ns->parent) | ||
| 569 | return -EPERM; | ||
| 570 | |||
| 571 | return map_write(file, buf, size, ppos, CAP_SETUID, | ||
| 572 | &ns->uid_map, &ns->parent->uid_map); | ||
| 573 | } | ||
| 574 | |||
| 575 | ssize_t proc_gid_map_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos) | ||
| 576 | { | ||
| 577 | struct seq_file *seq = file->private_data; | ||
| 578 | struct user_namespace *ns = seq->private; | ||
| 579 | |||
| 580 | if (!ns->parent) | ||
| 581 | return -EPERM; | ||
| 582 | |||
| 583 | return map_write(file, buf, size, ppos, CAP_SETGID, | ||
| 584 | &ns->gid_map, &ns->parent->gid_map); | ||
| 585 | } | ||
| 586 | |||
| 587 | static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid, | ||
| 588 | struct uid_gid_map *new_map) | ||
| 589 | { | ||
| 590 | /* Allow the specified ids if we have the appropriate capability | ||
| 591 | * (CAP_SETUID or CAP_SETGID) over the parent user namespace. | ||
| 592 | */ | ||
| 593 | if (ns_capable(ns->parent, cap_setid)) | ||
| 594 | return true; | ||
| 595 | |||
| 596 | return false; | ||
| 130 | } | 597 | } |
| 131 | 598 | ||
| 132 | static __init int user_namespaces_init(void) | 599 | static __init int user_namespaces_init(void) |
diff --git a/kernel/utsname.c b/kernel/utsname.c index 405caf91aad5..679d97a5d3fd 100644 --- a/kernel/utsname.c +++ b/kernel/utsname.c | |||
| @@ -43,7 +43,7 @@ static struct uts_namespace *clone_uts_ns(struct task_struct *tsk, | |||
| 43 | 43 | ||
| 44 | down_read(&uts_sem); | 44 | down_read(&uts_sem); |
| 45 | memcpy(&ns->name, &old_ns->name, sizeof(ns->name)); | 45 | memcpy(&ns->name, &old_ns->name, sizeof(ns->name)); |
| 46 | ns->user_ns = get_user_ns(task_cred_xxx(tsk, user)->user_ns); | 46 | ns->user_ns = get_user_ns(task_cred_xxx(tsk, user_ns)); |
| 47 | up_read(&uts_sem); | 47 | up_read(&uts_sem); |
| 48 | return ns; | 48 | return ns; |
| 49 | } | 49 | } |
diff --git a/mm/mempolicy.c b/mm/mempolicy.c index b19569137529..39fd416ae14f 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c | |||
| @@ -1334,8 +1334,8 @@ SYSCALL_DEFINE4(migrate_pages, pid_t, pid, unsigned long, maxnode, | |||
| 1334 | * userid as the target process. | 1334 | * userid as the target process. |
| 1335 | */ | 1335 | */ |
| 1336 | tcred = __task_cred(task); | 1336 | tcred = __task_cred(task); |
| 1337 | if (cred->euid != tcred->suid && cred->euid != tcred->uid && | 1337 | if (!uid_eq(cred->euid, tcred->suid) && !uid_eq(cred->euid, tcred->uid) && |
| 1338 | cred->uid != tcred->suid && cred->uid != tcred->uid && | 1338 | !uid_eq(cred->uid, tcred->suid) && !uid_eq(cred->uid, tcred->uid) && |
| 1339 | !capable(CAP_SYS_NICE)) { | 1339 | !capable(CAP_SYS_NICE)) { |
| 1340 | rcu_read_unlock(); | 1340 | rcu_read_unlock(); |
| 1341 | err = -EPERM; | 1341 | err = -EPERM; |
diff --git a/mm/migrate.c b/mm/migrate.c index 11072383ae12..ab81d482ae6f 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
| @@ -1371,8 +1371,8 @@ SYSCALL_DEFINE6(move_pages, pid_t, pid, unsigned long, nr_pages, | |||
| 1371 | * userid as the target process. | 1371 | * userid as the target process. |
| 1372 | */ | 1372 | */ |
| 1373 | tcred = __task_cred(task); | 1373 | tcred = __task_cred(task); |
| 1374 | if (cred->euid != tcred->suid && cred->euid != tcred->uid && | 1374 | if (!uid_eq(cred->euid, tcred->suid) && !uid_eq(cred->euid, tcred->uid) && |
| 1375 | cred->uid != tcred->suid && cred->uid != tcred->uid && | 1375 | !uid_eq(cred->uid, tcred->suid) && !uid_eq(cred->uid, tcred->uid) && |
| 1376 | !capable(CAP_SYS_NICE)) { | 1376 | !capable(CAP_SYS_NICE)) { |
| 1377 | rcu_read_unlock(); | 1377 | rcu_read_unlock(); |
| 1378 | err = -EPERM; | 1378 | err = -EPERM; |
diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 46bf2ed5594c..9f09a1fde9f9 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c | |||
| @@ -410,8 +410,8 @@ static void dump_tasks(const struct mem_cgroup *memcg, const nodemask_t *nodemas | |||
| 410 | } | 410 | } |
| 411 | 411 | ||
| 412 | pr_info("[%5d] %5d %5d %8lu %8lu %3u %3d %5d %s\n", | 412 | pr_info("[%5d] %5d %5d %8lu %8lu %3u %3d %5d %s\n", |
| 413 | task->pid, task_uid(task), task->tgid, | 413 | task->pid, from_kuid(&init_user_ns, task_uid(task)), |
| 414 | task->mm->total_vm, get_mm_rss(task->mm), | 414 | task->tgid, task->mm->total_vm, get_mm_rss(task->mm), |
| 415 | task_cpu(task), task->signal->oom_adj, | 415 | task_cpu(task), task->signal->oom_adj, |
| 416 | task->signal->oom_score_adj, task->comm); | 416 | task->signal->oom_score_adj, task->comm); |
| 417 | task_unlock(task); | 417 | task_unlock(task); |
diff --git a/mm/shmem.c b/mm/shmem.c index f99ff3e50bd6..d7b433a1ef5e 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
| @@ -2075,6 +2075,8 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo, | |||
| 2075 | bool remount) | 2075 | bool remount) |
| 2076 | { | 2076 | { |
| 2077 | char *this_char, *value, *rest; | 2077 | char *this_char, *value, *rest; |
| 2078 | uid_t uid; | ||
| 2079 | gid_t gid; | ||
| 2078 | 2080 | ||
| 2079 | while (options != NULL) { | 2081 | while (options != NULL) { |
| 2080 | this_char = options; | 2082 | this_char = options; |
| @@ -2134,15 +2136,21 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo, | |||
| 2134 | } else if (!strcmp(this_char,"uid")) { | 2136 | } else if (!strcmp(this_char,"uid")) { |
| 2135 | if (remount) | 2137 | if (remount) |
| 2136 | continue; | 2138 | continue; |
| 2137 | sbinfo->uid = simple_strtoul(value, &rest, 0); | 2139 | uid = simple_strtoul(value, &rest, 0); |
| 2138 | if (*rest) | 2140 | if (*rest) |
| 2139 | goto bad_val; | 2141 | goto bad_val; |
| 2142 | sbinfo->uid = make_kuid(current_user_ns(), uid); | ||
| 2143 | if (!uid_valid(sbinfo->uid)) | ||
| 2144 | goto bad_val; | ||
| 2140 | } else if (!strcmp(this_char,"gid")) { | 2145 | } else if (!strcmp(this_char,"gid")) { |
| 2141 | if (remount) | 2146 | if (remount) |
| 2142 | continue; | 2147 | continue; |
| 2143 | sbinfo->gid = simple_strtoul(value, &rest, 0); | 2148 | gid = simple_strtoul(value, &rest, 0); |
| 2144 | if (*rest) | 2149 | if (*rest) |
| 2145 | goto bad_val; | 2150 | goto bad_val; |
| 2151 | sbinfo->gid = make_kgid(current_user_ns(), gid); | ||
| 2152 | if (!gid_valid(sbinfo->gid)) | ||
| 2153 | goto bad_val; | ||
| 2146 | } else if (!strcmp(this_char,"mpol")) { | 2154 | } else if (!strcmp(this_char,"mpol")) { |
| 2147 | if (mpol_parse_str(value, &sbinfo->mpol, 1)) | 2155 | if (mpol_parse_str(value, &sbinfo->mpol, 1)) |
| 2148 | goto bad_val; | 2156 | goto bad_val; |
| @@ -2210,10 +2218,12 @@ static int shmem_show_options(struct seq_file *seq, struct dentry *root) | |||
| 2210 | seq_printf(seq, ",nr_inodes=%lu", sbinfo->max_inodes); | 2218 | seq_printf(seq, ",nr_inodes=%lu", sbinfo->max_inodes); |
| 2211 | if (sbinfo->mode != (S_IRWXUGO | S_ISVTX)) | 2219 | if (sbinfo->mode != (S_IRWXUGO | S_ISVTX)) |
| 2212 | seq_printf(seq, ",mode=%03ho", sbinfo->mode); | 2220 | seq_printf(seq, ",mode=%03ho", sbinfo->mode); |
| 2213 | if (sbinfo->uid != 0) | 2221 | if (!uid_eq(sbinfo->uid, GLOBAL_ROOT_UID)) |
| 2214 | seq_printf(seq, ",uid=%u", sbinfo->uid); | 2222 | seq_printf(seq, ",uid=%u", |
| 2215 | if (sbinfo->gid != 0) | 2223 | from_kuid_munged(&init_user_ns, sbinfo->uid)); |
| 2216 | seq_printf(seq, ",gid=%u", sbinfo->gid); | 2224 | if (!gid_eq(sbinfo->gid, GLOBAL_ROOT_GID)) |
| 2225 | seq_printf(seq, ",gid=%u", | ||
| 2226 | from_kgid_munged(&init_user_ns, sbinfo->gid)); | ||
| 2217 | shmem_show_mpol(seq, sbinfo->mpol); | 2227 | shmem_show_mpol(seq, sbinfo->mpol); |
| 2218 | return 0; | 2228 | return 0; |
| 2219 | } | 2229 | } |
diff --git a/net/core/sock.c b/net/core/sock.c index f372d9bf4976..653f8c0aedc5 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
| @@ -813,8 +813,8 @@ void cred_to_ucred(struct pid *pid, const struct cred *cred, | |||
| 813 | if (cred) { | 813 | if (cred) { |
| 814 | struct user_namespace *current_ns = current_user_ns(); | 814 | struct user_namespace *current_ns = current_user_ns(); |
| 815 | 815 | ||
| 816 | ucred->uid = user_ns_map_uid(current_ns, cred, cred->euid); | 816 | ucred->uid = from_kuid(current_ns, cred->euid); |
| 817 | ucred->gid = user_ns_map_gid(current_ns, cred, cred->egid); | 817 | ucred->gid = from_kgid(current_ns, cred->egid); |
| 818 | } | 818 | } |
| 819 | } | 819 | } |
| 820 | EXPORT_SYMBOL_GPL(cred_to_ucred); | 820 | EXPORT_SYMBOL_GPL(cred_to_ucred); |
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 6e930c7174dd..2c00e8bf684d 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c | |||
| @@ -207,17 +207,22 @@ static int ping_init_sock(struct sock *sk) | |||
| 207 | gid_t range[2]; | 207 | gid_t range[2]; |
| 208 | struct group_info *group_info = get_current_groups(); | 208 | struct group_info *group_info = get_current_groups(); |
| 209 | int i, j, count = group_info->ngroups; | 209 | int i, j, count = group_info->ngroups; |
| 210 | kgid_t low, high; | ||
| 210 | 211 | ||
| 211 | inet_get_ping_group_range_net(net, range, range+1); | 212 | inet_get_ping_group_range_net(net, range, range+1); |
| 213 | low = make_kgid(&init_user_ns, range[0]); | ||
| 214 | high = make_kgid(&init_user_ns, range[1]); | ||
| 215 | if (!gid_valid(low) || !gid_valid(high) || gid_lt(high, low)) | ||
| 216 | return -EACCES; | ||
| 217 | |||
| 212 | if (range[0] <= group && group <= range[1]) | 218 | if (range[0] <= group && group <= range[1]) |
| 213 | return 0; | 219 | return 0; |
| 214 | 220 | ||
| 215 | for (i = 0; i < group_info->nblocks; i++) { | 221 | for (i = 0; i < group_info->nblocks; i++) { |
| 216 | int cp_count = min_t(int, NGROUPS_PER_BLOCK, count); | 222 | int cp_count = min_t(int, NGROUPS_PER_BLOCK, count); |
| 217 | |||
| 218 | for (j = 0; j < cp_count; j++) { | 223 | for (j = 0; j < cp_count; j++) { |
| 219 | group = group_info->blocks[i][j]; | 224 | kgid_t gid = group_info->blocks[i][j]; |
| 220 | if (range[0] <= group && group <= range[1]) | 225 | if (gid_lte(low, gid) && gid_lte(gid, high)) |
| 221 | return 0; | 226 | return 0; |
| 222 | } | 227 | } |
| 223 | 228 | ||
diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c index 75762f346975..6ed6f201b022 100644 --- a/net/sunrpc/auth_generic.c +++ b/net/sunrpc/auth_generic.c | |||
| @@ -160,8 +160,8 @@ generic_match(struct auth_cred *acred, struct rpc_cred *cred, int flags) | |||
| 160 | if (gcred->acred.group_info->ngroups != acred->group_info->ngroups) | 160 | if (gcred->acred.group_info->ngroups != acred->group_info->ngroups) |
| 161 | goto out_nomatch; | 161 | goto out_nomatch; |
| 162 | for (i = 0; i < gcred->acred.group_info->ngroups; i++) { | 162 | for (i = 0; i < gcred->acred.group_info->ngroups; i++) { |
| 163 | if (GROUP_AT(gcred->acred.group_info, i) != | 163 | if (!gid_eq(GROUP_AT(gcred->acred.group_info, i), |
| 164 | GROUP_AT(acred->group_info, i)) | 164 | GROUP_AT(acred->group_info, i))) |
| 165 | goto out_nomatch; | 165 | goto out_nomatch; |
| 166 | } | 166 | } |
| 167 | out_match: | 167 | out_match: |
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 1600cfb1618c..28b62dbb6d1e 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c | |||
| @@ -41,6 +41,7 @@ | |||
| 41 | #include <linux/types.h> | 41 | #include <linux/types.h> |
| 42 | #include <linux/module.h> | 42 | #include <linux/module.h> |
| 43 | #include <linux/pagemap.h> | 43 | #include <linux/pagemap.h> |
| 44 | #include <linux/user_namespace.h> | ||
| 44 | 45 | ||
| 45 | #include <linux/sunrpc/auth_gss.h> | 46 | #include <linux/sunrpc/auth_gss.h> |
| 46 | #include <linux/sunrpc/gss_err.h> | 47 | #include <linux/sunrpc/gss_err.h> |
| @@ -470,9 +471,13 @@ static int rsc_parse(struct cache_detail *cd, | |||
| 470 | status = -EINVAL; | 471 | status = -EINVAL; |
| 471 | for (i=0; i<N; i++) { | 472 | for (i=0; i<N; i++) { |
| 472 | gid_t gid; | 473 | gid_t gid; |
| 474 | kgid_t kgid; | ||
| 473 | if (get_int(&mesg, &gid)) | 475 | if (get_int(&mesg, &gid)) |
| 474 | goto out; | 476 | goto out; |
| 475 | GROUP_AT(rsci.cred.cr_group_info, i) = gid; | 477 | kgid = make_kgid(&init_user_ns, gid); |
| 478 | if (!gid_valid(kgid)) | ||
| 479 | goto out; | ||
| 480 | GROUP_AT(rsci.cred.cr_group_info, i) = kgid; | ||
| 476 | } | 481 | } |
| 477 | 482 | ||
| 478 | /* mech name */ | 483 | /* mech name */ |
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c index e50502d8ceb7..52c5abdee211 100644 --- a/net/sunrpc/auth_unix.c +++ b/net/sunrpc/auth_unix.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/sunrpc/clnt.h> | 13 | #include <linux/sunrpc/clnt.h> |
| 14 | #include <linux/sunrpc/auth.h> | 14 | #include <linux/sunrpc/auth.h> |
| 15 | #include <linux/user_namespace.h> | ||
| 15 | 16 | ||
| 16 | #define NFS_NGROUPS 16 | 17 | #define NFS_NGROUPS 16 |
| 17 | 18 | ||
| @@ -78,8 +79,11 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) | |||
| 78 | groups = NFS_NGROUPS; | 79 | groups = NFS_NGROUPS; |
| 79 | 80 | ||
| 80 | cred->uc_gid = acred->gid; | 81 | cred->uc_gid = acred->gid; |
| 81 | for (i = 0; i < groups; i++) | 82 | for (i = 0; i < groups; i++) { |
| 82 | cred->uc_gids[i] = GROUP_AT(acred->group_info, i); | 83 | gid_t gid; |
| 84 | gid = from_kgid(&init_user_ns, GROUP_AT(acred->group_info, i)); | ||
| 85 | cred->uc_gids[i] = gid; | ||
| 86 | } | ||
| 83 | if (i < NFS_NGROUPS) | 87 | if (i < NFS_NGROUPS) |
| 84 | cred->uc_gids[i] = NOGROUP; | 88 | cred->uc_gids[i] = NOGROUP; |
| 85 | 89 | ||
| @@ -126,9 +130,12 @@ unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags) | |||
| 126 | groups = acred->group_info->ngroups; | 130 | groups = acred->group_info->ngroups; |
| 127 | if (groups > NFS_NGROUPS) | 131 | if (groups > NFS_NGROUPS) |
| 128 | groups = NFS_NGROUPS; | 132 | groups = NFS_NGROUPS; |
| 129 | for (i = 0; i < groups ; i++) | 133 | for (i = 0; i < groups ; i++) { |
| 130 | if (cred->uc_gids[i] != GROUP_AT(acred->group_info, i)) | 134 | gid_t gid; |
| 135 | gid = from_kgid(&init_user_ns, GROUP_AT(acred->group_info, i)); | ||
| 136 | if (cred->uc_gids[i] != gid) | ||
| 131 | return 0; | 137 | return 0; |
| 138 | } | ||
| 132 | if (groups < NFS_NGROUPS && | 139 | if (groups < NFS_NGROUPS && |
| 133 | cred->uc_gids[groups] != NOGROUP) | 140 | cred->uc_gids[groups] != NOGROUP) |
| 134 | return 0; | 141 | return 0; |
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 521d8f7dc833..71ec8530ec8c 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <net/sock.h> | 14 | #include <net/sock.h> |
| 15 | #include <net/ipv6.h> | 15 | #include <net/ipv6.h> |
| 16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
| 17 | #include <linux/user_namespace.h> | ||
| 17 | #define RPCDBG_FACILITY RPCDBG_AUTH | 18 | #define RPCDBG_FACILITY RPCDBG_AUTH |
| 18 | 19 | ||
| 19 | #include <linux/sunrpc/clnt.h> | 20 | #include <linux/sunrpc/clnt.h> |
| @@ -530,11 +531,15 @@ static int unix_gid_parse(struct cache_detail *cd, | |||
| 530 | 531 | ||
| 531 | for (i = 0 ; i < gids ; i++) { | 532 | for (i = 0 ; i < gids ; i++) { |
| 532 | int gid; | 533 | int gid; |
| 534 | kgid_t kgid; | ||
| 533 | rv = get_int(&mesg, &gid); | 535 | rv = get_int(&mesg, &gid); |
| 534 | err = -EINVAL; | 536 | err = -EINVAL; |
| 535 | if (rv) | 537 | if (rv) |
| 536 | goto out; | 538 | goto out; |
| 537 | GROUP_AT(ug.gi, i) = gid; | 539 | kgid = make_kgid(&init_user_ns, gid); |
| 540 | if (!gid_valid(kgid)) | ||
| 541 | goto out; | ||
| 542 | GROUP_AT(ug.gi, i) = kgid; | ||
| 538 | } | 543 | } |
| 539 | 544 | ||
| 540 | ugp = unix_gid_lookup(cd, uid); | 545 | ugp = unix_gid_lookup(cd, uid); |
| @@ -563,6 +568,7 @@ static int unix_gid_show(struct seq_file *m, | |||
| 563 | struct cache_detail *cd, | 568 | struct cache_detail *cd, |
| 564 | struct cache_head *h) | 569 | struct cache_head *h) |
| 565 | { | 570 | { |
| 571 | struct user_namespace *user_ns = current_user_ns(); | ||
| 566 | struct unix_gid *ug; | 572 | struct unix_gid *ug; |
| 567 | int i; | 573 | int i; |
| 568 | int glen; | 574 | int glen; |
| @@ -580,7 +586,7 @@ static int unix_gid_show(struct seq_file *m, | |||
| 580 | 586 | ||
| 581 | seq_printf(m, "%u %d:", ug->uid, glen); | 587 | seq_printf(m, "%u %d:", ug->uid, glen); |
| 582 | for (i = 0; i < glen; i++) | 588 | for (i = 0; i < glen; i++) |
| 583 | seq_printf(m, " %d", GROUP_AT(ug->gi, i)); | 589 | seq_printf(m, " %d", from_kgid_munged(user_ns, GROUP_AT(ug->gi, i))); |
| 584 | seq_printf(m, "\n"); | 590 | seq_printf(m, "\n"); |
| 585 | return 0; | 591 | return 0; |
| 586 | } | 592 | } |
| @@ -831,8 +837,12 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp) | |||
| 831 | cred->cr_group_info = groups_alloc(slen); | 837 | cred->cr_group_info = groups_alloc(slen); |
| 832 | if (cred->cr_group_info == NULL) | 838 | if (cred->cr_group_info == NULL) |
| 833 | return SVC_CLOSE; | 839 | return SVC_CLOSE; |
| 834 | for (i = 0; i < slen; i++) | 840 | for (i = 0; i < slen; i++) { |
| 835 | GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv); | 841 | kgid_t kgid = make_kgid(&init_user_ns, svc_getnl(argv)); |
| 842 | if (!gid_valid(kgid)) | ||
| 843 | goto badcred; | ||
| 844 | GROUP_AT(cred->cr_group_info, i) = kgid; | ||
| 845 | } | ||
| 836 | if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) { | 846 | if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) { |
| 837 | *authp = rpc_autherr_badverf; | 847 | *authp = rpc_autherr_badverf; |
| 838 | return SVC_DENIED; | 848 | return SVC_DENIED; |
diff --git a/security/commoncap.c b/security/commoncap.c index f80d11609391..e771cb1b2d79 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
| @@ -77,12 +77,12 @@ int cap_capable(const struct cred *cred, struct user_namespace *targ_ns, | |||
| 77 | int cap, int audit) | 77 | int cap, int audit) |
| 78 | { | 78 | { |
| 79 | for (;;) { | 79 | for (;;) { |
| 80 | /* The creator of the user namespace has all caps. */ | 80 | /* The owner of the user namespace has all caps. */ |
| 81 | if (targ_ns != &init_user_ns && targ_ns->creator == cred->user) | 81 | if (targ_ns != &init_user_ns && uid_eq(targ_ns->owner, cred->euid)) |
| 82 | return 0; | 82 | return 0; |
| 83 | 83 | ||
| 84 | /* Do we have the necessary capabilities? */ | 84 | /* Do we have the necessary capabilities? */ |
| 85 | if (targ_ns == cred->user->user_ns) | 85 | if (targ_ns == cred->user_ns) |
| 86 | return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM; | 86 | return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM; |
| 87 | 87 | ||
| 88 | /* Have we tried all of the parent namespaces? */ | 88 | /* Have we tried all of the parent namespaces? */ |
| @@ -93,7 +93,7 @@ int cap_capable(const struct cred *cred, struct user_namespace *targ_ns, | |||
| 93 | *If you have a capability in a parent user ns, then you have | 93 | *If you have a capability in a parent user ns, then you have |
| 94 | * it over all children user namespaces as well. | 94 | * it over all children user namespaces as well. |
| 95 | */ | 95 | */ |
| 96 | targ_ns = targ_ns->creator->user_ns; | 96 | targ_ns = targ_ns->parent; |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | /* We never get here */ | 99 | /* We never get here */ |
| @@ -137,10 +137,10 @@ int cap_ptrace_access_check(struct task_struct *child, unsigned int mode) | |||
| 137 | rcu_read_lock(); | 137 | rcu_read_lock(); |
| 138 | cred = current_cred(); | 138 | cred = current_cred(); |
| 139 | child_cred = __task_cred(child); | 139 | child_cred = __task_cred(child); |
| 140 | if (cred->user->user_ns == child_cred->user->user_ns && | 140 | if (cred->user_ns == child_cred->user_ns && |
| 141 | cap_issubset(child_cred->cap_permitted, cred->cap_permitted)) | 141 | cap_issubset(child_cred->cap_permitted, cred->cap_permitted)) |
| 142 | goto out; | 142 | goto out; |
| 143 | if (ns_capable(child_cred->user->user_ns, CAP_SYS_PTRACE)) | 143 | if (ns_capable(child_cred->user_ns, CAP_SYS_PTRACE)) |
| 144 | goto out; | 144 | goto out; |
| 145 | ret = -EPERM; | 145 | ret = -EPERM; |
| 146 | out: | 146 | out: |
| @@ -169,10 +169,10 @@ int cap_ptrace_traceme(struct task_struct *parent) | |||
| 169 | rcu_read_lock(); | 169 | rcu_read_lock(); |
| 170 | cred = __task_cred(parent); | 170 | cred = __task_cred(parent); |
| 171 | child_cred = current_cred(); | 171 | child_cred = current_cred(); |
| 172 | if (cred->user->user_ns == child_cred->user->user_ns && | 172 | if (cred->user_ns == child_cred->user_ns && |
| 173 | cap_issubset(child_cred->cap_permitted, cred->cap_permitted)) | 173 | cap_issubset(child_cred->cap_permitted, cred->cap_permitted)) |
| 174 | goto out; | 174 | goto out; |
| 175 | if (has_ns_capability(parent, child_cred->user->user_ns, CAP_SYS_PTRACE)) | 175 | if (has_ns_capability(parent, child_cred->user_ns, CAP_SYS_PTRACE)) |
| 176 | goto out; | 176 | goto out; |
| 177 | ret = -EPERM; | 177 | ret = -EPERM; |
| 178 | out: | 178 | out: |
| @@ -215,7 +215,7 @@ static inline int cap_inh_is_capped(void) | |||
| 215 | /* they are so limited unless the current task has the CAP_SETPCAP | 215 | /* they are so limited unless the current task has the CAP_SETPCAP |
| 216 | * capability | 216 | * capability |
| 217 | */ | 217 | */ |
| 218 | if (cap_capable(current_cred(), current_cred()->user->user_ns, | 218 | if (cap_capable(current_cred(), current_cred()->user_ns, |
| 219 | CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0) | 219 | CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0) |
| 220 | return 0; | 220 | return 0; |
| 221 | return 1; | 221 | return 1; |
| @@ -473,19 +473,22 @@ int cap_bprm_set_creds(struct linux_binprm *bprm) | |||
| 473 | struct cred *new = bprm->cred; | 473 | struct cred *new = bprm->cred; |
| 474 | bool effective, has_cap = false; | 474 | bool effective, has_cap = false; |
| 475 | int ret; | 475 | int ret; |
| 476 | kuid_t root_uid; | ||
| 476 | 477 | ||
| 477 | effective = false; | 478 | effective = false; |
| 478 | ret = get_file_caps(bprm, &effective, &has_cap); | 479 | ret = get_file_caps(bprm, &effective, &has_cap); |
| 479 | if (ret < 0) | 480 | if (ret < 0) |
| 480 | return ret; | 481 | return ret; |
| 481 | 482 | ||
| 483 | root_uid = make_kuid(new->user_ns, 0); | ||
| 484 | |||
| 482 | if (!issecure(SECURE_NOROOT)) { | 485 | if (!issecure(SECURE_NOROOT)) { |
| 483 | /* | 486 | /* |
| 484 | * If the legacy file capability is set, then don't set privs | 487 | * If the legacy file capability is set, then don't set privs |
| 485 | * for a setuid root binary run by a non-root user. Do set it | 488 | * for a setuid root binary run by a non-root user. Do set it |
| 486 | * for a root user just to cause least surprise to an admin. | 489 | * for a root user just to cause least surprise to an admin. |
| 487 | */ | 490 | */ |
| 488 | if (has_cap && new->uid != 0 && new->euid == 0) { | 491 | if (has_cap && !uid_eq(new->uid, root_uid) && uid_eq(new->euid, root_uid)) { |
| 489 | warn_setuid_and_fcaps_mixed(bprm->filename); | 492 | warn_setuid_and_fcaps_mixed(bprm->filename); |
| 490 | goto skip; | 493 | goto skip; |
| 491 | } | 494 | } |
| @@ -496,12 +499,12 @@ int cap_bprm_set_creds(struct linux_binprm *bprm) | |||
| 496 | * | 499 | * |
| 497 | * If only the real uid is 0, we do not set the effective bit. | 500 | * If only the real uid is 0, we do not set the effective bit. |
| 498 | */ | 501 | */ |
| 499 | if (new->euid == 0 || new->uid == 0) { | 502 | if (uid_eq(new->euid, root_uid) || uid_eq(new->uid, root_uid)) { |
| 500 | /* pP' = (cap_bset & ~0) | (pI & ~0) */ | 503 | /* pP' = (cap_bset & ~0) | (pI & ~0) */ |
| 501 | new->cap_permitted = cap_combine(old->cap_bset, | 504 | new->cap_permitted = cap_combine(old->cap_bset, |
| 502 | old->cap_inheritable); | 505 | old->cap_inheritable); |
| 503 | } | 506 | } |
| 504 | if (new->euid == 0) | 507 | if (uid_eq(new->euid, root_uid)) |
| 505 | effective = true; | 508 | effective = true; |
| 506 | } | 509 | } |
| 507 | skip: | 510 | skip: |
| @@ -516,8 +519,8 @@ skip: | |||
| 516 | * | 519 | * |
| 517 | * In addition, if NO_NEW_PRIVS, then ensure we get no new privs. | 520 | * In addition, if NO_NEW_PRIVS, then ensure we get no new privs. |
| 518 | */ | 521 | */ |
| 519 | if ((new->euid != old->uid || | 522 | if ((!uid_eq(new->euid, old->uid) || |
| 520 | new->egid != old->gid || | 523 | !gid_eq(new->egid, old->gid) || |
| 521 | !cap_issubset(new->cap_permitted, old->cap_permitted)) && | 524 | !cap_issubset(new->cap_permitted, old->cap_permitted)) && |
| 522 | bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) { | 525 | bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) { |
| 523 | /* downgrade; they get no more than they had, and maybe less */ | 526 | /* downgrade; they get no more than they had, and maybe less */ |
| @@ -553,7 +556,7 @@ skip: | |||
| 553 | */ | 556 | */ |
| 554 | if (!cap_isclear(new->cap_effective)) { | 557 | if (!cap_isclear(new->cap_effective)) { |
| 555 | if (!cap_issubset(CAP_FULL_SET, new->cap_effective) || | 558 | if (!cap_issubset(CAP_FULL_SET, new->cap_effective) || |
| 556 | new->euid != 0 || new->uid != 0 || | 559 | !uid_eq(new->euid, root_uid) || !uid_eq(new->uid, root_uid) || |
| 557 | issecure(SECURE_NOROOT)) { | 560 | issecure(SECURE_NOROOT)) { |
| 558 | ret = audit_log_bprm_fcaps(bprm, new, old); | 561 | ret = audit_log_bprm_fcaps(bprm, new, old); |
| 559 | if (ret < 0) | 562 | if (ret < 0) |
| @@ -578,16 +581,17 @@ skip: | |||
| 578 | int cap_bprm_secureexec(struct linux_binprm *bprm) | 581 | int cap_bprm_secureexec(struct linux_binprm *bprm) |
| 579 | { | 582 | { |
| 580 | const struct cred *cred = current_cred(); | 583 | const struct cred *cred = current_cred(); |
| 584 | kuid_t root_uid = make_kuid(cred->user_ns, 0); | ||
| 581 | 585 | ||
| 582 | if (cred->uid != 0) { | 586 | if (!uid_eq(cred->uid, root_uid)) { |
| 583 | if (bprm->cap_effective) | 587 | if (bprm->cap_effective) |
| 584 | return 1; | 588 | return 1; |
| 585 | if (!cap_isclear(cred->cap_permitted)) | 589 | if (!cap_isclear(cred->cap_permitted)) |
| 586 | return 1; | 590 | return 1; |
| 587 | } | 591 | } |
| 588 | 592 | ||
| 589 | return (cred->euid != cred->uid || | 593 | return (!uid_eq(cred->euid, cred->uid) || |
| 590 | cred->egid != cred->gid); | 594 | !gid_eq(cred->egid, cred->gid)); |
| 591 | } | 595 | } |
| 592 | 596 | ||
| 593 | /** | 597 | /** |
| @@ -677,15 +681,21 @@ int cap_inode_removexattr(struct dentry *dentry, const char *name) | |||
| 677 | */ | 681 | */ |
| 678 | static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old) | 682 | static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old) |
| 679 | { | 683 | { |
| 680 | if ((old->uid == 0 || old->euid == 0 || old->suid == 0) && | 684 | kuid_t root_uid = make_kuid(old->user_ns, 0); |
| 681 | (new->uid != 0 && new->euid != 0 && new->suid != 0) && | 685 | |
| 686 | if ((uid_eq(old->uid, root_uid) || | ||
| 687 | uid_eq(old->euid, root_uid) || | ||
| 688 | uid_eq(old->suid, root_uid)) && | ||
| 689 | (!uid_eq(new->uid, root_uid) && | ||
| 690 | !uid_eq(new->euid, root_uid) && | ||
| 691 | !uid_eq(new->suid, root_uid)) && | ||
| 682 | !issecure(SECURE_KEEP_CAPS)) { | 692 | !issecure(SECURE_KEEP_CAPS)) { |
| 683 | cap_clear(new->cap_permitted); | 693 | cap_clear(new->cap_permitted); |
| 684 | cap_clear(new->cap_effective); | 694 | cap_clear(new->cap_effective); |
| 685 | } | 695 | } |
| 686 | if (old->euid == 0 && new->euid != 0) | 696 | if (uid_eq(old->euid, root_uid) && !uid_eq(new->euid, root_uid)) |
| 687 | cap_clear(new->cap_effective); | 697 | cap_clear(new->cap_effective); |
| 688 | if (old->euid != 0 && new->euid == 0) | 698 | if (!uid_eq(old->euid, root_uid) && uid_eq(new->euid, root_uid)) |
| 689 | new->cap_effective = new->cap_permitted; | 699 | new->cap_effective = new->cap_permitted; |
| 690 | } | 700 | } |
| 691 | 701 | ||
| @@ -718,11 +728,12 @@ int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags) | |||
| 718 | * if not, we might be a bit too harsh here. | 728 | * if not, we might be a bit too harsh here. |
| 719 | */ | 729 | */ |
| 720 | if (!issecure(SECURE_NO_SETUID_FIXUP)) { | 730 | if (!issecure(SECURE_NO_SETUID_FIXUP)) { |
| 721 | if (old->fsuid == 0 && new->fsuid != 0) | 731 | kuid_t root_uid = make_kuid(old->user_ns, 0); |
| 732 | if (uid_eq(old->fsuid, root_uid) && !uid_eq(new->fsuid, root_uid)) | ||
| 722 | new->cap_effective = | 733 | new->cap_effective = |
| 723 | cap_drop_fs_set(new->cap_effective); | 734 | cap_drop_fs_set(new->cap_effective); |
| 724 | 735 | ||
| 725 | if (old->fsuid != 0 && new->fsuid == 0) | 736 | if (!uid_eq(old->fsuid, root_uid) && uid_eq(new->fsuid, root_uid)) |
| 726 | new->cap_effective = | 737 | new->cap_effective = |
| 727 | cap_raise_fs_set(new->cap_effective, | 738 | cap_raise_fs_set(new->cap_effective, |
| 728 | new->cap_permitted); | 739 | new->cap_permitted); |
| @@ -875,7 +886,7 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
| 875 | || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ | 886 | || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ |
| 876 | || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ | 887 | || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ |
| 877 | || (cap_capable(current_cred(), | 888 | || (cap_capable(current_cred(), |
| 878 | current_cred()->user->user_ns, CAP_SETPCAP, | 889 | current_cred()->user_ns, CAP_SETPCAP, |
| 879 | SECURITY_CAP_AUDIT) != 0) /*[4]*/ | 890 | SECURITY_CAP_AUDIT) != 0) /*[4]*/ |
| 880 | /* | 891 | /* |
| 881 | * [1] no changing of bits that are locked | 892 | * [1] no changing of bits that are locked |
diff --git a/security/keys/key.c b/security/keys/key.c index c9bf66ac36e0..50d96d4e06f2 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
| @@ -253,7 +253,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, | |||
| 253 | quotalen = desclen + type->def_datalen; | 253 | quotalen = desclen + type->def_datalen; |
| 254 | 254 | ||
| 255 | /* get hold of the key tracking for this user */ | 255 | /* get hold of the key tracking for this user */ |
| 256 | user = key_user_lookup(uid, cred->user->user_ns); | 256 | user = key_user_lookup(uid, cred->user_ns); |
| 257 | if (!user) | 257 | if (!user) |
| 258 | goto no_memory_1; | 258 | goto no_memory_1; |
| 259 | 259 | ||
diff --git a/security/keys/permission.c b/security/keys/permission.c index 57d96363d7f1..0b4d019e027d 100644 --- a/security/keys/permission.c +++ b/security/keys/permission.c | |||
| @@ -36,7 +36,7 @@ int key_task_permission(const key_ref_t key_ref, const struct cred *cred, | |||
| 36 | 36 | ||
| 37 | key = key_ref_to_ptr(key_ref); | 37 | key = key_ref_to_ptr(key_ref); |
| 38 | 38 | ||
| 39 | if (key->user->user_ns != cred->user->user_ns) | 39 | if (key->user->user_ns != cred->user_ns) |
| 40 | goto use_other_perms; | 40 | goto use_other_perms; |
| 41 | 41 | ||
| 42 | /* use the second 8-bits of permissions for keys the caller owns */ | 42 | /* use the second 8-bits of permissions for keys the caller owns */ |
| @@ -53,7 +53,8 @@ int key_task_permission(const key_ref_t key_ref, const struct cred *cred, | |||
| 53 | goto use_these_perms; | 53 | goto use_these_perms; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | ret = groups_search(cred->group_info, key->gid); | 56 | ret = groups_search(cred->group_info, |
| 57 | make_kgid(current_user_ns(), key->gid)); | ||
| 57 | if (ret) { | 58 | if (ret) { |
| 58 | kperm = key->perm >> 8; | 59 | kperm = key->perm >> 8; |
| 59 | goto use_these_perms; | 60 | goto use_these_perms; |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index e137fcd7042c..d71056db7b67 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
| @@ -860,7 +860,7 @@ void key_replace_session_keyring(void) | |||
| 860 | new-> sgid = old-> sgid; | 860 | new-> sgid = old-> sgid; |
| 861 | new->fsgid = old->fsgid; | 861 | new->fsgid = old->fsgid; |
| 862 | new->user = get_uid(old->user); | 862 | new->user = get_uid(old->user); |
| 863 | new->user_ns = new->user->user_ns; | 863 | new->user_ns = get_user_ns(new->user_ns); |
| 864 | new->group_info = get_group_info(old->group_info); | 864 | new->group_info = get_group_info(old->group_info); |
| 865 | 865 | ||
| 866 | new->securebits = old->securebits; | 866 | new->securebits = old->securebits; |
