diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2011-11-14 18:56:38 -0500 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2012-05-03 06:27:21 -0400 |
commit | ae2975bc3476243b45a1e2344236d7920c268f38 (patch) | |
tree | e4b2a8472f6047734b6e7e2bdc994375b2790323 | |
parent | 22d917d80e842829d0ca0a561967d728eb1d6303 (diff) |
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>
-rw-r--r-- | arch/s390/kernel/compat_linux.c | 14 | ||||
-rw-r--r-- | fs/nfsd/auth.c | 5 | ||||
-rw-r--r-- | fs/proc/array.c | 5 | ||||
-rw-r--r-- | include/linux/cred.h | 9 | ||||
-rw-r--r-- | kernel/groups.c | 48 | ||||
-rw-r--r-- | kernel/uid16.c | 14 | ||||
-rw-r--r-- | net/ipv4/ping.c | 11 | ||||
-rw-r--r-- | net/sunrpc/auth_generic.c | 4 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/svcauth_gss.c | 7 | ||||
-rw-r--r-- | net/sunrpc/auth_unix.c | 15 | ||||
-rw-r--r-- | net/sunrpc/svcauth_unix.c | 18 | ||||
-rw-r--r-- | security/keys/permission.c | 3 |
12 files changed, 104 insertions, 49 deletions
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index ab64bdbab2ae..f0273ed760ef 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; |
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 | } |
diff --git a/fs/proc/array.c b/fs/proc/array.c index f9bd395b3473..36a0a9192ece 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; |
@@ -205,7 +207,8 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, | |||
205 | task_unlock(p); | 207 | task_unlock(p); |
206 | 208 | ||
207 | for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++) | 209 | for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++) |
208 | seq_printf(m, "%d ", GROUP_AT(group_info, g)); | 210 | seq_printf(m, "%d ", |
211 | from_kgid_munged(user_ns, GROUP_AT(group_info, g))); | ||
209 | put_cred(cred); | 212 | put_cred(cred); |
210 | 213 | ||
211 | seq_putc(m, '\n'); | 214 | seq_putc(m, '\n'); |
diff --git a/include/linux/cred.h b/include/linux/cred.h index 2c60ec802678..0ab3cda4a774 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,7 +67,7 @@ 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) \ |
diff --git a/kernel/groups.c b/kernel/groups.c index 99b53d1eb7ea..84156f2d4c8c 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; |
@@ -262,7 +262,8 @@ int in_group_p(gid_t grp) | |||
262 | int retval = 1; | 262 | int retval = 1; |
263 | 263 | ||
264 | if (grp != cred->fsgid) | 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 | return retval; | 267 | return retval; |
267 | } | 268 | } |
268 | 269 | ||
@@ -274,7 +275,8 @@ int in_egroup_p(gid_t grp) | |||
274 | int retval = 1; | 275 | int retval = 1; |
275 | 276 | ||
276 | if (grp != cred->egid) | 277 | if (grp != cred->egid) |
277 | retval = groups_search(cred->group_info, grp); | 278 | retval = groups_search(cred->group_info, |
279 | make_kgid(cred->user_ns, grp)); | ||
278 | return retval; | 280 | return retval; |
279 | } | 281 | } |
280 | 282 | ||
diff --git a/kernel/uid16.c b/kernel/uid16.c index 51c6e89e8619..e530bc34c4cf 100644 --- a/kernel/uid16.c +++ b/kernel/uid16.c | |||
@@ -134,11 +134,14 @@ SYSCALL_DEFINE1(setfsgid16, old_gid_t, gid) | |||
134 | static int groups16_to_user(old_gid_t __user *grouplist, | 134 | static int groups16_to_user(old_gid_t __user *grouplist, |
135 | struct group_info *group_info) | 135 | struct group_info *group_info) |
136 | { | 136 | { |
137 | struct user_namespace *user_ns = current_user_ns(); | ||
137 | int i; | 138 | int i; |
138 | old_gid_t group; | 139 | old_gid_t group; |
140 | kgid_t kgid; | ||
139 | 141 | ||
140 | for (i = 0; i < group_info->ngroups; i++) { | 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 | if (put_user(group, grouplist+i)) | 145 | if (put_user(group, grouplist+i)) |
143 | return -EFAULT; | 146 | return -EFAULT; |
144 | } | 147 | } |
@@ -149,13 +152,20 @@ static int groups16_to_user(old_gid_t __user *grouplist, | |||
149 | static int groups16_from_user(struct group_info *group_info, | 152 | static int groups16_from_user(struct group_info *group_info, |
150 | old_gid_t __user *grouplist) | 153 | old_gid_t __user *grouplist) |
151 | { | 154 | { |
155 | struct user_namespace *user_ns = current_user_ns(); | ||
152 | int i; | 156 | int i; |
153 | old_gid_t group; | 157 | old_gid_t group; |
158 | kgid_t kgid; | ||
154 | 159 | ||
155 | for (i = 0; i < group_info->ngroups; i++) { | 160 | for (i = 0; i < group_info->ngroups; i++) { |
156 | if (get_user(group, grouplist+i)) | 161 | if (get_user(group, grouplist+i)) |
157 | return -EFAULT; | 162 | return -EFAULT; |
158 | GROUP_AT(group_info, i) = low2highgid(group); | 163 | |
164 | kgid = make_kgid(user_ns, low2highgid(group)); | ||
165 | if (!gid_valid(kgid)) | ||
166 | return -EINVAL; | ||
167 | |||
168 | GROUP_AT(group_info, i) = kgid; | ||
159 | } | 169 | } |
160 | 170 | ||
161 | return 0; | 171 | return 0; |
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 50009c787bcd..9d3044ff45b9 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c | |||
@@ -205,17 +205,22 @@ static int ping_init_sock(struct sock *sk) | |||
205 | gid_t range[2]; | 205 | gid_t range[2]; |
206 | struct group_info *group_info = get_current_groups(); | 206 | struct group_info *group_info = get_current_groups(); |
207 | int i, j, count = group_info->ngroups; | 207 | int i, j, count = group_info->ngroups; |
208 | kgid_t low, high; | ||
208 | 209 | ||
209 | inet_get_ping_group_range_net(net, range, range+1); | 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 | if (range[0] <= group && group <= range[1]) | 216 | if (range[0] <= group && group <= range[1]) |
211 | return 0; | 217 | return 0; |
212 | 218 | ||
213 | for (i = 0; i < group_info->nblocks; i++) { | 219 | for (i = 0; i < group_info->nblocks; i++) { |
214 | int cp_count = min_t(int, NGROUPS_PER_BLOCK, count); | 220 | int cp_count = min_t(int, NGROUPS_PER_BLOCK, count); |
215 | |||
216 | for (j = 0; j < cp_count; j++) { | 221 | for (j = 0; j < cp_count; j++) { |
217 | group = group_info->blocks[i][j]; | 222 | kgid_t gid = group_info->blocks[i][j]; |
218 | if (range[0] <= group && group <= range[1]) | 223 | if (gid_lte(low, gid) && gid_lte(gid, high)) |
219 | return 0; | 224 | return 0; |
220 | } | 225 | } |
221 | 226 | ||
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/keys/permission.c b/security/keys/permission.c index e146cbd714bd..5442900d2929 100644 --- a/security/keys/permission.c +++ b/security/keys/permission.c | |||
@@ -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; |