1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2001 The FreeBSD Project
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/param.h>
30 #include <sys/fcntl.h>
31 #include <sys/lock.h>
32 #include <sys/malloc.h>
33 #include <sys/mutex.h>
34 #include <sys/priv.h>
35 #include <sys/proc.h>
36 #include <sys/syscallsubr.h>
37 #include <sys/sysproto.h>
38
39 #ifdef COMPAT_LINUX32
40 #include <machine/../linux32/linux.h>
41 #include <machine/../linux32/linux32_proto.h>
42 #else
43 #include <machine/../linux/linux.h>
44 #include <machine/../linux/linux_proto.h>
45 #endif
46
47 #include <compat/linux/linux_dtrace.h>
48 #include <compat/linux/linux_util.h>
49
50 /* DTrace init */
51 LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
52
53 /**
54 * DTrace probes in this module.
55 */
56 LIN_SDT_PROBE_DEFINE1(uid16, linux_chown16, conv_path, "char *");
57 LIN_SDT_PROBE_DEFINE1(uid16, linux_lchown16, conv_path, "char *");
58 LIN_SDT_PROBE_DEFINE1(uid16, linux_setgroups16, copyin_error, "int");
59 LIN_SDT_PROBE_DEFINE1(uid16, linux_setgroups16, priv_check_cred_error, "int");
60 LIN_SDT_PROBE_DEFINE1(uid16, linux_getgroups16, copyout_error, "int");
61
62 DUMMY(setfsuid16);
63 DUMMY(setfsgid16);
64 DUMMY(getresuid16);
65 DUMMY(getresgid16);
66
67 #define CAST_NOCHG(x) ((x == 0xFFFF) ? -1 : x)
68
69 int
linux_chown16(struct thread * td,struct linux_chown16_args * args)70 linux_chown16(struct thread *td, struct linux_chown16_args *args)
71 {
72
73 return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE,
74 CAST_NOCHG(args->uid), CAST_NOCHG(args->gid), 0));
75 }
76
77 int
linux_lchown16(struct thread * td,struct linux_lchown16_args * args)78 linux_lchown16(struct thread *td, struct linux_lchown16_args *args)
79 {
80
81 return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE,
82 CAST_NOCHG(args->uid), CAST_NOCHG(args->gid), AT_SYMLINK_NOFOLLOW));
83 }
84
85 int
linux_setgroups16(struct thread * td,struct linux_setgroups16_args * args)86 linux_setgroups16(struct thread *td, struct linux_setgroups16_args *args)
87 {
88 const int ngrp = args->gidsetsize;
89 struct ucred *newcred, *oldcred;
90 l_gid16_t *linux_gidset;
91 int error;
92 struct proc *p;
93
94 if (ngrp < 0 || ngrp > ngroups_max)
95 return (EINVAL);
96 linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_LINUX, M_WAITOK);
97 error = copyin(args->gidset, linux_gidset, ngrp * sizeof(l_gid16_t));
98 if (error) {
99 LIN_SDT_PROBE1(uid16, linux_setgroups16, copyin_error, error);
100 free(linux_gidset, M_LINUX);
101 return (error);
102 }
103
104 newcred = crget();
105 crextend(newcred, ngrp);
106 p = td->td_proc;
107 PROC_LOCK(p);
108 oldcred = crcopysafe(p, newcred);
109
110 if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS)) != 0) {
111 PROC_UNLOCK(p);
112 crfree(newcred);
113
114 LIN_SDT_PROBE1(uid16, linux_setgroups16, priv_check_cred_error,
115 error);
116 goto out;
117 }
118
119 newcred->cr_ngroups = ngrp;
120 for (int i = 0; i < ngrp; i++)
121 newcred->cr_groups[i] = linux_gidset[i];
122 newcred->cr_flags |= CRED_FLAG_GROUPSET;
123
124 setsugid(td->td_proc);
125 proc_set_cred(p, newcred);
126 PROC_UNLOCK(p);
127 crfree(oldcred);
128 error = 0;
129 out:
130 free(linux_gidset, M_LINUX);
131
132 return (error);
133 }
134
135 int
linux_getgroups16(struct thread * td,struct linux_getgroups16_args * args)136 linux_getgroups16(struct thread *td, struct linux_getgroups16_args *args)
137 {
138 const struct ucred *const cred = td->td_ucred;
139 l_gid16_t *linux_gidset;
140 int ngrp, error;
141
142 ngrp = args->gidsetsize;
143
144 if (ngrp == 0) {
145 td->td_retval[0] = cred->cr_ngroups;
146 return (0);
147 }
148 if (ngrp < cred->cr_ngroups)
149 return (EINVAL);
150
151 ngrp = cred->cr_ngroups;
152
153 linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_LINUX, M_WAITOK);
154 for (int i = 0; i < ngrp; ++i)
155 linux_gidset[i] = cred->cr_groups[i];
156
157 error = copyout(linux_gidset, args->gidset, ngrp * sizeof(l_gid16_t));
158 free(linux_gidset, M_LINUX);
159
160 if (error != 0) {
161 LIN_SDT_PROBE1(uid16, linux_getgroups16, copyout_error, error);
162 return (error);
163 }
164
165 td->td_retval[0] = ngrp;
166
167 return (0);
168 }
169
170 int
linux_getgid16(struct thread * td,struct linux_getgid16_args * args)171 linux_getgid16(struct thread *td, struct linux_getgid16_args *args)
172 {
173
174 td->td_retval[0] = td->td_ucred->cr_rgid;
175
176 return (0);
177 }
178
179 int
linux_getuid16(struct thread * td,struct linux_getuid16_args * args)180 linux_getuid16(struct thread *td, struct linux_getuid16_args *args)
181 {
182
183 td->td_retval[0] = td->td_ucred->cr_ruid;
184
185 return (0);
186 }
187
188 int
linux_getegid16(struct thread * td,struct linux_getegid16_args * args)189 linux_getegid16(struct thread *td, struct linux_getegid16_args *args)
190 {
191 struct getegid_args bsd;
192 int error;
193
194 error = sys_getegid(td, &bsd);
195
196 return (error);
197 }
198
199 int
linux_geteuid16(struct thread * td,struct linux_geteuid16_args * args)200 linux_geteuid16(struct thread *td, struct linux_geteuid16_args *args)
201 {
202 struct geteuid_args bsd;
203 int error;
204
205 error = sys_geteuid(td, &bsd);
206
207 return (error);
208 }
209
210 int
linux_setgid16(struct thread * td,struct linux_setgid16_args * args)211 linux_setgid16(struct thread *td, struct linux_setgid16_args *args)
212 {
213 struct setgid_args bsd;
214 int error;
215
216 bsd.gid = args->gid;
217 error = sys_setgid(td, &bsd);
218
219 return (error);
220 }
221
222 int
linux_setuid16(struct thread * td,struct linux_setuid16_args * args)223 linux_setuid16(struct thread *td, struct linux_setuid16_args *args)
224 {
225 struct setuid_args bsd;
226 int error;
227
228 bsd.uid = args->uid;
229 error = sys_setuid(td, &bsd);
230
231 return (error);
232 }
233
234 int
linux_setregid16(struct thread * td,struct linux_setregid16_args * args)235 linux_setregid16(struct thread *td, struct linux_setregid16_args *args)
236 {
237 struct setregid_args bsd;
238 int error;
239
240 bsd.rgid = CAST_NOCHG(args->rgid);
241 bsd.egid = CAST_NOCHG(args->egid);
242 error = sys_setregid(td, &bsd);
243
244 return (error);
245 }
246
247 int
linux_setreuid16(struct thread * td,struct linux_setreuid16_args * args)248 linux_setreuid16(struct thread *td, struct linux_setreuid16_args *args)
249 {
250 struct setreuid_args bsd;
251 int error;
252
253 bsd.ruid = CAST_NOCHG(args->ruid);
254 bsd.euid = CAST_NOCHG(args->euid);
255 error = sys_setreuid(td, &bsd);
256
257 return (error);
258 }
259
260 int
linux_setresgid16(struct thread * td,struct linux_setresgid16_args * args)261 linux_setresgid16(struct thread *td, struct linux_setresgid16_args *args)
262 {
263 struct setresgid_args bsd;
264 int error;
265
266 bsd.rgid = CAST_NOCHG(args->rgid);
267 bsd.egid = CAST_NOCHG(args->egid);
268 bsd.sgid = CAST_NOCHG(args->sgid);
269 error = sys_setresgid(td, &bsd);
270
271 return (error);
272 }
273
274 int
linux_setresuid16(struct thread * td,struct linux_setresuid16_args * args)275 linux_setresuid16(struct thread *td, struct linux_setresuid16_args *args)
276 {
277 struct setresuid_args bsd;
278 int error;
279
280 bsd.ruid = CAST_NOCHG(args->ruid);
281 bsd.euid = CAST_NOCHG(args->euid);
282 bsd.suid = CAST_NOCHG(args->suid);
283 error = sys_setresuid(td, &bsd);
284
285 return (error);
286 }
287