Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

userns: Convert group_info values from gid_t to kgid_t.

As a first step to converting struct cred to be all kuid_t and kgid_t
values convert the group values stored in group_info to always be
kgid_t values. Unless user namespaces are used this change should
have no effect.

Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>

+104 -49
+12 -2
arch/s390/kernel/compat_linux.c
··· 173 173 174 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 177 int i; 177 178 u16 group; 179 + kgid_t kgid; 178 180 179 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 184 if (put_user(group, grouplist+i)) 182 185 return -EFAULT; 183 186 } ··· 190 187 191 188 static int groups16_from_user(struct group_info *group_info, u16 __user *grouplist) 192 189 { 190 + struct user_namespace *user_ns = current_user_ns(); 193 191 int i; 194 192 u16 group; 193 + kgid_t kgid; 195 194 196 195 for (i = 0; i < group_info->ngroups; i++) { 197 196 if (get_user(group, grouplist+i)) 198 197 return -EFAULT; 199 - GROUP_AT(group_info, i) = (gid_t)group; 198 + 199 + kgid = make_kgid(user_ns, (gid_t)group); 200 + if (!gid_valid(kgid)) 201 + return -EINVAL; 202 + 203 + GROUP_AT(group_info, i) = kgid; 200 204 } 201 205 202 206 return 0;
+3 -2
fs/nfsd/auth.c
··· 1 1 /* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> */ 2 2 3 3 #include <linux/sched.h> 4 + #include <linux/user_namespace.h> 4 5 #include "nfsd.h" 5 6 #include "auth.h" 6 7 ··· 57 56 goto oom; 58 57 59 58 for (i = 0; i < rqgi->ngroups; i++) { 60 - if (!GROUP_AT(rqgi, i)) 61 - GROUP_AT(gi, i) = exp->ex_anon_gid; 59 + if (gid_eq(GLOBAL_ROOT_GID, GROUP_AT(rqgi, i))) 60 + GROUP_AT(gi, i) = make_kgid(&init_user_ns, exp->ex_anon_gid); 62 61 else 63 62 GROUP_AT(gi, i) = GROUP_AT(rqgi, i); 64 63 }
+4 -1
fs/proc/array.c
··· 81 81 #include <linux/pid_namespace.h> 82 82 #include <linux/ptrace.h> 83 83 #include <linux/tracehook.h> 84 + #include <linux/user_namespace.h> 84 85 85 86 #include <asm/pgtable.h> 86 87 #include <asm/processor.h> ··· 162 161 static inline void task_state(struct seq_file *m, struct pid_namespace *ns, 163 162 struct pid *pid, struct task_struct *p) 164 163 { 164 + struct user_namespace *user_ns = current_user_ns(); 165 165 struct group_info *group_info; 166 166 int g; 167 167 struct fdtable *fdt = NULL; ··· 207 205 task_unlock(p); 208 206 209 207 for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++) 210 - seq_printf(m, "%d ", GROUP_AT(group_info, g)); 208 + seq_printf(m, "%d ", 209 + from_kgid_munged(user_ns, GROUP_AT(group_info, g))); 211 210 put_cred(cred); 212 211 213 212 seq_putc(m, '\n');
+5 -4
include/linux/cred.h
··· 17 17 #include <linux/key.h> 18 18 #include <linux/selinux.h> 19 19 #include <linux/atomic.h> 20 + #include <linux/uidgid.h> 20 21 21 22 struct user_struct; 22 23 struct cred; ··· 27 26 * COW Supplementary groups list 28 27 */ 29 28 #define NGROUPS_SMALL 32 30 - #define NGROUPS_PER_BLOCK ((unsigned int)(PAGE_SIZE / sizeof(gid_t))) 29 + #define NGROUPS_PER_BLOCK ((unsigned int)(PAGE_SIZE / sizeof(kgid_t))) 31 30 32 31 struct group_info { 33 32 atomic_t usage; 34 33 int ngroups; 35 34 int nblocks; 36 - gid_t small_block[NGROUPS_SMALL]; 37 - gid_t *blocks[0]; 35 + kgid_t small_block[NGROUPS_SMALL]; 36 + kgid_t *blocks[0]; 38 37 }; 39 38 40 39 /** ··· 67 66 extern void groups_free(struct group_info *); 68 67 extern int set_current_groups(struct group_info *); 69 68 extern int set_groups(struct cred *, struct group_info *); 70 - extern int groups_search(const struct group_info *, gid_t); 69 + extern int groups_search(const struct group_info *, kgid_t); 71 70 72 71 /* access the groups "array" with this macro */ 73 72 #define GROUP_AT(gi, i) \
+25 -23
kernel/groups.c
··· 31 31 group_info->blocks[0] = group_info->small_block; 32 32 else { 33 33 for (i = 0; i < nblocks; i++) { 34 - gid_t *b; 34 + kgid_t *b; 35 35 b = (void *)__get_free_page(GFP_USER); 36 36 if (!b) 37 37 goto out_undo_partial_alloc; ··· 66 66 static int groups_to_user(gid_t __user *grouplist, 67 67 const struct group_info *group_info) 68 68 { 69 + struct user_namespace *user_ns = current_user_ns(); 69 70 int i; 70 71 unsigned int count = group_info->ngroups; 71 72 72 - for (i = 0; i < group_info->nblocks; i++) { 73 - unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); 74 - unsigned int len = cp_count * sizeof(*grouplist); 75 - 76 - if (copy_to_user(grouplist, group_info->blocks[i], len)) 73 + for (i = 0; i < count; i++) { 74 + gid_t gid; 75 + gid = from_kgid_munged(user_ns, GROUP_AT(group_info, i)); 76 + if (put_user(gid, grouplist+i)) 77 77 return -EFAULT; 78 - 79 - grouplist += NGROUPS_PER_BLOCK; 80 - count -= cp_count; 81 78 } 82 79 return 0; 83 80 } ··· 83 86 static int groups_from_user(struct group_info *group_info, 84 87 gid_t __user *grouplist) 85 88 { 89 + struct user_namespace *user_ns = current_user_ns(); 86 90 int i; 87 91 unsigned int count = group_info->ngroups; 88 92 89 - for (i = 0; i < group_info->nblocks; i++) { 90 - unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); 91 - unsigned int len = cp_count * sizeof(*grouplist); 92 - 93 - if (copy_from_user(group_info->blocks[i], grouplist, len)) 93 + for (i = 0; i < count; i++) { 94 + gid_t gid; 95 + kgid_t kgid; 96 + if (get_user(gid, grouplist+i)) 94 97 return -EFAULT; 95 98 96 - grouplist += NGROUPS_PER_BLOCK; 97 - count -= cp_count; 99 + kgid = make_kgid(user_ns, gid); 100 + if (!gid_valid(kgid)) 101 + return -EINVAL; 102 + 103 + GROUP_AT(group_info, i) = kgid; 98 104 } 99 105 return 0; 100 106 } ··· 117 117 for (base = 0; base < max; base++) { 118 118 int left = base; 119 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 123 GROUP_AT(group_info, right) = 124 124 GROUP_AT(group_info, left); 125 125 right = left; ··· 132 132 } 133 133 134 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 137 unsigned int left, right; 138 138 ··· 143 143 right = group_info->ngroups; 144 144 while (left < right) { 145 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 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 149 right = mid; 150 150 else 151 151 return 1; ··· 262 262 int retval = 1; 263 263 264 264 if (grp != cred->fsgid) 265 - retval = groups_search(cred->group_info, grp); 265 + retval = groups_search(cred->group_info, 266 + make_kgid(cred->user_ns, grp)); 266 267 return retval; 267 268 } 268 269 ··· 275 274 int retval = 1; 276 275 277 276 if (grp != cred->egid) 278 - retval = groups_search(cred->group_info, grp); 277 + retval = groups_search(cred->group_info, 278 + make_kgid(cred->user_ns, grp)); 279 279 return retval; 280 280 } 281 281
+12 -2
kernel/uid16.c
··· 134 134 static int groups16_to_user(old_gid_t __user *grouplist, 135 135 struct group_info *group_info) 136 136 { 137 + struct user_namespace *user_ns = current_user_ns(); 137 138 int i; 138 139 old_gid_t group; 140 + kgid_t kgid; 139 141 140 142 for (i = 0; i < group_info->ngroups; i++) { 141 - group = high2lowgid(GROUP_AT(group_info, i)); 143 + kgid = GROUP_AT(group_info, i); 144 + group = high2lowgid(from_kgid_munged(user_ns, kgid)); 142 145 if (put_user(group, grouplist+i)) 143 146 return -EFAULT; 144 147 } ··· 152 149 static int groups16_from_user(struct group_info *group_info, 153 150 old_gid_t __user *grouplist) 154 151 { 152 + struct user_namespace *user_ns = current_user_ns(); 155 153 int i; 156 154 old_gid_t group; 155 + kgid_t kgid; 157 156 158 157 for (i = 0; i < group_info->ngroups; i++) { 159 158 if (get_user(group, grouplist+i)) 160 159 return -EFAULT; 161 - GROUP_AT(group_info, i) = low2highgid(group); 160 + 161 + kgid = make_kgid(user_ns, low2highgid(group)); 162 + if (!gid_valid(kgid)) 163 + return -EINVAL; 164 + 165 + GROUP_AT(group_info, i) = kgid; 162 166 } 163 167 164 168 return 0;
+8 -3
net/ipv4/ping.c
··· 205 205 gid_t range[2]; 206 206 struct group_info *group_info = get_current_groups(); 207 207 int i, j, count = group_info->ngroups; 208 + kgid_t low, high; 208 209 209 210 inet_get_ping_group_range_net(net, range, range+1); 211 + low = make_kgid(&init_user_ns, range[0]); 212 + high = make_kgid(&init_user_ns, range[1]); 213 + if (!gid_valid(low) || !gid_valid(high) || gid_lt(high, low)) 214 + return -EACCES; 215 + 210 216 if (range[0] <= group && group <= range[1]) 211 217 return 0; 212 218 213 219 for (i = 0; i < group_info->nblocks; i++) { 214 220 int cp_count = min_t(int, NGROUPS_PER_BLOCK, count); 215 - 216 221 for (j = 0; j < cp_count; j++) { 217 - group = group_info->blocks[i][j]; 218 - if (range[0] <= group && group <= range[1]) 222 + kgid_t gid = group_info->blocks[i][j]; 223 + if (gid_lte(low, gid) && gid_lte(gid, high)) 219 224 return 0; 220 225 } 221 226
+2 -2
net/sunrpc/auth_generic.c
··· 160 160 if (gcred->acred.group_info->ngroups != acred->group_info->ngroups) 161 161 goto out_nomatch; 162 162 for (i = 0; i < gcred->acred.group_info->ngroups; i++) { 163 - if (GROUP_AT(gcred->acred.group_info, i) != 164 - GROUP_AT(acred->group_info, i)) 163 + if (!gid_eq(GROUP_AT(gcred->acred.group_info, i), 164 + GROUP_AT(acred->group_info, i))) 165 165 goto out_nomatch; 166 166 } 167 167 out_match:
+6 -1
net/sunrpc/auth_gss/svcauth_gss.c
··· 41 41 #include <linux/types.h> 42 42 #include <linux/module.h> 43 43 #include <linux/pagemap.h> 44 + #include <linux/user_namespace.h> 44 45 45 46 #include <linux/sunrpc/auth_gss.h> 46 47 #include <linux/sunrpc/gss_err.h> ··· 471 470 status = -EINVAL; 472 471 for (i=0; i<N; i++) { 473 472 gid_t gid; 473 + kgid_t kgid; 474 474 if (get_int(&mesg, &gid)) 475 475 goto out; 476 - GROUP_AT(rsci.cred.cr_group_info, i) = gid; 476 + kgid = make_kgid(&init_user_ns, gid); 477 + if (!gid_valid(kgid)) 478 + goto out; 479 + GROUP_AT(rsci.cred.cr_group_info, i) = kgid; 477 480 } 478 481 479 482 /* mech name */
+11 -4
net/sunrpc/auth_unix.c
··· 12 12 #include <linux/module.h> 13 13 #include <linux/sunrpc/clnt.h> 14 14 #include <linux/sunrpc/auth.h> 15 + #include <linux/user_namespace.h> 15 16 16 17 #define NFS_NGROUPS 16 17 18 ··· 79 78 groups = NFS_NGROUPS; 80 79 81 80 cred->uc_gid = acred->gid; 82 - for (i = 0; i < groups; i++) 83 - cred->uc_gids[i] = GROUP_AT(acred->group_info, i); 81 + for (i = 0; i < groups; i++) { 82 + gid_t gid; 83 + gid = from_kgid(&init_user_ns, GROUP_AT(acred->group_info, i)); 84 + cred->uc_gids[i] = gid; 85 + } 84 86 if (i < NFS_NGROUPS) 85 87 cred->uc_gids[i] = NOGROUP; 86 88 ··· 130 126 groups = acred->group_info->ngroups; 131 127 if (groups > NFS_NGROUPS) 132 128 groups = NFS_NGROUPS; 133 - for (i = 0; i < groups ; i++) 134 - if (cred->uc_gids[i] != GROUP_AT(acred->group_info, i)) 129 + for (i = 0; i < groups ; i++) { 130 + gid_t gid; 131 + gid = from_kgid(&init_user_ns, GROUP_AT(acred->group_info, i)); 132 + if (cred->uc_gids[i] != gid) 135 133 return 0; 134 + } 136 135 if (groups < NFS_NGROUPS && 137 136 cred->uc_gids[groups] != NOGROUP) 138 137 return 0;
+14 -4
net/sunrpc/svcauth_unix.c
··· 14 14 #include <net/sock.h> 15 15 #include <net/ipv6.h> 16 16 #include <linux/kernel.h> 17 + #include <linux/user_namespace.h> 17 18 #define RPCDBG_FACILITY RPCDBG_AUTH 18 19 19 20 #include <linux/sunrpc/clnt.h> ··· 531 530 532 531 for (i = 0 ; i < gids ; i++) { 533 532 int gid; 533 + kgid_t kgid; 534 534 rv = get_int(&mesg, &gid); 535 535 err = -EINVAL; 536 536 if (rv) 537 537 goto out; 538 - GROUP_AT(ug.gi, i) = gid; 538 + kgid = make_kgid(&init_user_ns, gid); 539 + if (!gid_valid(kgid)) 540 + goto out; 541 + GROUP_AT(ug.gi, i) = kgid; 539 542 } 540 543 541 544 ugp = unix_gid_lookup(cd, uid); ··· 568 563 struct cache_detail *cd, 569 564 struct cache_head *h) 570 565 { 566 + struct user_namespace *user_ns = current_user_ns(); 571 567 struct unix_gid *ug; 572 568 int i; 573 569 int glen; ··· 586 580 587 581 seq_printf(m, "%u %d:", ug->uid, glen); 588 582 for (i = 0; i < glen; i++) 589 - seq_printf(m, " %d", GROUP_AT(ug->gi, i)); 583 + seq_printf(m, " %d", from_kgid_munged(user_ns, GROUP_AT(ug->gi, i))); 590 584 seq_printf(m, "\n"); 591 585 return 0; 592 586 } ··· 837 831 cred->cr_group_info = groups_alloc(slen); 838 832 if (cred->cr_group_info == NULL) 839 833 return SVC_CLOSE; 840 - for (i = 0; i < slen; i++) 841 - GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv); 834 + for (i = 0; i < slen; i++) { 835 + kgid_t kgid = make_kgid(&init_user_ns, svc_getnl(argv)); 836 + if (!gid_valid(kgid)) 837 + goto badcred; 838 + GROUP_AT(cred->cr_group_info, i) = kgid; 839 + } 842 840 if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) { 843 841 *authp = rpc_autherr_badverf; 844 842 return SVC_DENIED;
+2 -1
security/keys/permission.c
··· 53 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 58 if (ret) { 58 59 kperm = key->perm >> 8; 59 60 goto use_these_perms;