1 | /* $NetBSD: linux_uid16.c,v 1.4 2014/05/20 17:31:18 njoly Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Frank van der Linden and Eric Haszlakiewicz. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | #include <sys/cdefs.h> |
33 | __KERNEL_RCSID(0, "$NetBSD: linux_uid16.c,v 1.4 2014/05/20 17:31:18 njoly Exp $" ); |
34 | |
35 | #include <sys/param.h> |
36 | #include <sys/proc.h> |
37 | #include <sys/kauth.h> |
38 | #include <sys/syscallargs.h> |
39 | |
40 | #include <compat/linux/common/linux_types.h> |
41 | #include <compat/linux/common/linux_signal.h> |
42 | #include <compat/linux/linux_syscallargs.h> |
43 | |
44 | #define LINUXTOBSD_UID(u) \ |
45 | (((u) == (linux_uid16_t)-1) ? -1 : (u)) |
46 | #define LINUXTOBSD_GID(g) \ |
47 | (((g) == (linux_gid16_t)-1) ? -1 : (g)) |
48 | |
49 | #define BSDTOLINUX_UID(u) \ |
50 | (((u) & ~0xffff) ? (linux_uid16_t)65534 : (linux_uid16_t)(u)) |
51 | #define BSDTOLINUX_GID(g) \ |
52 | (((g) & ~0xffff) ? (linux_gid16_t)65534 : (linux_gid16_t)(g)) |
53 | |
54 | #ifndef COMPAT_LINUX32 |
55 | int |
56 | linux_sys_chown16(struct lwp *l, const struct linux_sys_chown16_args *uap, register_t *retval) |
57 | { |
58 | /* { |
59 | syscallarg(const char *) path; |
60 | syscallarg(linux_uid16_t) uid; |
61 | syscallarg(linux_gid16_t) gid; |
62 | } */ |
63 | struct sys___posix_chown_args bca; |
64 | |
65 | SCARG(&bca, path) = SCARG(uap, path); |
66 | SCARG(&bca, uid) = LINUXTOBSD_UID(SCARG(uap, uid)); |
67 | SCARG(&bca, gid) = LINUXTOBSD_GID(SCARG(uap, gid)); |
68 | |
69 | return sys___posix_chown(l, &bca, retval); |
70 | } |
71 | |
72 | int |
73 | linux_sys_fchown16(struct lwp *l, const struct linux_sys_fchown16_args *uap, register_t *retval) |
74 | { |
75 | /* { |
76 | syscallarg(int) fd; |
77 | syscallarg(linux_uid16_t) uid; |
78 | syscallarg(linux_gid16_t) gid; |
79 | } */ |
80 | struct sys___posix_fchown_args bfa; |
81 | |
82 | SCARG(&bfa, fd) = SCARG(uap, fd); |
83 | SCARG(&bfa, uid) = LINUXTOBSD_UID(SCARG(uap, uid)); |
84 | SCARG(&bfa, gid) = LINUXTOBSD_GID(SCARG(uap, gid)); |
85 | |
86 | return sys___posix_fchown(l, &bfa, retval); |
87 | } |
88 | |
89 | int |
90 | linux_sys_lchown16(struct lwp *l, const struct linux_sys_lchown16_args *uap, register_t *retval) |
91 | { |
92 | /* { |
93 | syscallarg(char *) path; |
94 | syscallarg(linux_uid16_t) uid; |
95 | syscallarg(linux_gid16_t) gid; |
96 | } */ |
97 | struct sys___posix_lchown_args bla; |
98 | |
99 | SCARG(&bla, path) = SCARG(uap, path); |
100 | SCARG(&bla, uid) = LINUXTOBSD_UID(SCARG(uap, uid)); |
101 | SCARG(&bla, gid) = LINUXTOBSD_GID(SCARG(uap, gid)); |
102 | |
103 | return sys___posix_lchown(l, &bla, retval); |
104 | } |
105 | |
106 | int |
107 | linux_sys_setreuid16(struct lwp *l, const struct linux_sys_setreuid16_args *uap, register_t *retval) |
108 | { |
109 | /* { |
110 | syscallarg(linux_uid16_t) ruid; |
111 | syscallarg(linux_uid16_t) euid; |
112 | } */ |
113 | struct sys_setreuid_args bsa; |
114 | |
115 | SCARG(&bsa, ruid) = LINUXTOBSD_UID(SCARG(uap, ruid)); |
116 | SCARG(&bsa, euid) = LINUXTOBSD_UID(SCARG(uap, euid)); |
117 | |
118 | return sys_setreuid(l, &bsa, retval); |
119 | } |
120 | |
121 | int |
122 | linux_sys_setregid16(struct lwp *l, const struct linux_sys_setregid16_args *uap, register_t *retval) |
123 | { |
124 | /* { |
125 | syscallarg(linux_gid16_t) rgid; |
126 | syscallarg(linux_gid16_t) egid; |
127 | } */ |
128 | struct sys_setregid_args bsa; |
129 | |
130 | SCARG(&bsa, rgid) = LINUXTOBSD_GID(SCARG(uap, rgid)); |
131 | SCARG(&bsa, egid) = LINUXTOBSD_GID(SCARG(uap, egid)); |
132 | |
133 | return sys_setregid(l, &bsa, retval); |
134 | } |
135 | |
136 | int |
137 | linux_sys_setresuid16(struct lwp *l, const struct linux_sys_setresuid16_args *uap, register_t *retval) |
138 | { |
139 | /* { |
140 | syscallarg(linux_uid16_t) ruid; |
141 | syscallarg(linux_uid16_t) euid; |
142 | syscallarg(linux_uid16_t) suid; |
143 | } */ |
144 | struct linux_sys_setresuid_args lsa; |
145 | |
146 | SCARG(&lsa, ruid) = LINUXTOBSD_UID(SCARG(uap, ruid)); |
147 | SCARG(&lsa, euid) = LINUXTOBSD_UID(SCARG(uap, euid)); |
148 | SCARG(&lsa, suid) = LINUXTOBSD_UID(SCARG(uap, suid)); |
149 | |
150 | return linux_sys_setresuid(l, &lsa, retval); |
151 | } |
152 | |
153 | int |
154 | linux_sys_setresgid16(struct lwp *l, const struct linux_sys_setresgid16_args *uap, register_t *retval) |
155 | { |
156 | /* { |
157 | syscallarg(linux_gid16_t) rgid; |
158 | syscallarg(linux_gid16_t) egid; |
159 | syscallarg(linux_gid16_t) sgid; |
160 | } */ |
161 | struct linux_sys_setresgid_args lsa; |
162 | |
163 | SCARG(&lsa, rgid) = LINUXTOBSD_GID(SCARG(uap, rgid)); |
164 | SCARG(&lsa, egid) = LINUXTOBSD_GID(SCARG(uap, egid)); |
165 | SCARG(&lsa, sgid) = LINUXTOBSD_GID(SCARG(uap, sgid)); |
166 | |
167 | return linux_sys_setresgid(l, &lsa, retval); |
168 | } |
169 | |
170 | int |
171 | linux_sys_getresuid16(struct lwp *l, const struct linux_sys_getresuid16_args *uap, register_t *retval) |
172 | { |
173 | /* { |
174 | syscallarg(linux_uid16_t *) ruid; |
175 | syscallarg(linux_uid16_t *) euid; |
176 | syscallarg(linux_uid16_t *) suid; |
177 | } */ |
178 | kauth_cred_t pc = l->l_cred; |
179 | int error; |
180 | uid_t buid; |
181 | linux_uid16_t luid; |
182 | |
183 | buid = kauth_cred_getuid(pc); |
184 | luid = BSDTOLINUX_UID(buid); |
185 | if ((error = copyout(&luid, SCARG(uap, ruid), sizeof(luid))) != 0) |
186 | return error; |
187 | |
188 | buid = kauth_cred_geteuid(pc); |
189 | luid = BSDTOLINUX_UID(buid); |
190 | if ((error = copyout(&luid, SCARG(uap, euid), sizeof(luid))) != 0) |
191 | return error; |
192 | |
193 | buid = kauth_cred_getsvuid(pc); |
194 | luid = BSDTOLINUX_UID(buid); |
195 | return (copyout(&luid, SCARG(uap, suid), sizeof(luid))); |
196 | } |
197 | |
198 | int |
199 | linux_sys_getresgid16(struct lwp *l, const struct linux_sys_getresgid16_args *uap, register_t *retval) |
200 | { |
201 | /* { |
202 | syscallarg(linux_gid16_t *) rgid; |
203 | syscallarg(linux_gid16_t *) egid; |
204 | syscallarg(linux_gid16_t *) sgid; |
205 | } */ |
206 | kauth_cred_t pc = l->l_cred; |
207 | int error; |
208 | gid_t bgid; |
209 | linux_gid16_t lgid; |
210 | |
211 | bgid = kauth_cred_getgid(pc); |
212 | lgid = BSDTOLINUX_GID(bgid); |
213 | if ((error = copyout(&lgid, SCARG(uap, rgid), sizeof(lgid))) != 0) |
214 | return error; |
215 | |
216 | bgid = kauth_cred_getegid(pc); |
217 | lgid = BSDTOLINUX_GID(bgid); |
218 | if ((error = copyout(&lgid, SCARG(uap, egid), sizeof(lgid))) != 0) |
219 | return error; |
220 | |
221 | bgid = kauth_cred_getsvgid(pc); |
222 | lgid = BSDTOLINUX_GID(bgid); |
223 | return (copyout(&lgid, SCARG(uap, sgid), sizeof(lgid))); |
224 | } |
225 | #endif /* !COMPAT_LINUX32 */ |
226 | |
227 | int |
228 | linux_sys_getgroups16(struct lwp *l, const struct linux_sys_getgroups16_args *uap, register_t *retval) |
229 | { |
230 | /* { |
231 | syscallarg(int) gidsetsize; |
232 | syscallarg(linux_gid16_t *) gidset; |
233 | } */ |
234 | linux_gid16_t lset[16]; |
235 | linux_gid16_t *gidset; |
236 | unsigned int ngrps; |
237 | int i, n, j; |
238 | int error; |
239 | |
240 | ngrps = kauth_cred_ngroups(l->l_cred); |
241 | *retval = ngrps; |
242 | if (SCARG(uap, gidsetsize) == 0) |
243 | return 0; |
244 | if (SCARG(uap, gidsetsize) < (int)ngrps) |
245 | return EINVAL; |
246 | |
247 | gidset = SCARG(uap, gidset); |
248 | for (i = 0; i < (n = ngrps); i += n, gidset += n) { |
249 | n -= i; |
250 | if (n > __arraycount(lset)) |
251 | n = __arraycount(lset); |
252 | for (j = 0; j < n; j++) |
253 | lset[j] = kauth_cred_group(l->l_cred, i + j); |
254 | error = copyout(lset, gidset, n * sizeof(lset[0])); |
255 | if (error != 0) |
256 | return error; |
257 | } |
258 | |
259 | return 0; |
260 | } |
261 | |
262 | /* |
263 | * It is very unlikly that any problem using 16bit groups is written |
264 | * to allow for more than 16 of them, so don't bother trying to |
265 | * support that. |
266 | */ |
267 | #define COMPAT_NGROUPS16 16 |
268 | |
269 | int |
270 | linux_sys_setgroups16(struct lwp *l, const struct linux_sys_setgroups16_args *uap, register_t *retval) |
271 | { |
272 | /* { |
273 | syscallarg(int) gidsetsize; |
274 | syscallarg(linux_gid16_t *) gidset; |
275 | } */ |
276 | linux_gid16_t lset[COMPAT_NGROUPS16]; |
277 | kauth_cred_t ncred; |
278 | int error; |
279 | gid_t grbuf[COMPAT_NGROUPS16]; |
280 | unsigned int i, ngroups = SCARG(uap, gidsetsize); |
281 | |
282 | if (ngroups > COMPAT_NGROUPS16) |
283 | return EINVAL; |
284 | error = copyin(SCARG(uap, gidset), lset, ngroups); |
285 | if (error != 0) |
286 | return error; |
287 | |
288 | for (i = 0; i < ngroups; i++) |
289 | grbuf[i] = lset[i]; |
290 | |
291 | ncred = kauth_cred_alloc(); |
292 | error = kauth_cred_setgroups(ncred, grbuf, SCARG(uap, gidsetsize), |
293 | -1, UIO_SYSSPACE); |
294 | if (error != 0) { |
295 | kauth_cred_free(ncred); |
296 | return error; |
297 | } |
298 | |
299 | return kauth_proc_setgroups(l, ncred); |
300 | } |
301 | |