xref: /freebsd/sys/compat/linux/linux_uid16.c (revision b17b639832e707aab0e9514cf94727498e2d67bd)
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/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/param.h>
33 #include <sys/fcntl.h>
34 #include <sys/lock.h>
35 #include <sys/malloc.h>
36 #include <sys/mutex.h>
37 #include <sys/priv.h>
38 #include <sys/proc.h>
39 #include <sys/syscallsubr.h>
40 #include <sys/sysproto.h>
41 
42 #ifdef COMPAT_LINUX32
43 #include <machine/../linux32/linux.h>
44 #include <machine/../linux32/linux32_proto.h>
45 #else
46 #include <machine/../linux/linux.h>
47 #include <machine/../linux/linux_proto.h>
48 #endif
49 
50 #include <compat/linux/linux_dtrace.h>
51 #include <compat/linux/linux_util.h>
52 
53 /* DTrace init */
54 LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
55 
56 /**
57  * DTrace probes in this module.
58  */
59 LIN_SDT_PROBE_DEFINE1(uid16, linux_chown16, conv_path, "char *");
60 LIN_SDT_PROBE_DEFINE1(uid16, linux_lchown16, conv_path, "char *");
61 LIN_SDT_PROBE_DEFINE1(uid16, linux_setgroups16, copyin_error, "int");
62 LIN_SDT_PROBE_DEFINE1(uid16, linux_setgroups16, priv_check_cred_error, "int");
63 LIN_SDT_PROBE_DEFINE1(uid16, linux_getgroups16, copyout_error, "int");
64 
65 DUMMY(setfsuid16);
66 DUMMY(setfsgid16);
67 DUMMY(getresuid16);
68 DUMMY(getresgid16);
69 
70 #define	CAST_NOCHG(x)	((x == 0xFFFF) ? -1 : x)
71 
72 int
73 linux_chown16(struct thread *td, struct linux_chown16_args *args)
74 {
75 
76 	return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE,
77 	    CAST_NOCHG(args->uid), CAST_NOCHG(args->gid), 0));
78 }
79 
80 int
81 linux_lchown16(struct thread *td, struct linux_lchown16_args *args)
82 {
83 
84 	return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE,
85 	    CAST_NOCHG(args->uid), CAST_NOCHG(args->gid), AT_SYMLINK_NOFOLLOW));
86 }
87 
88 int
89 linux_setgroups16(struct thread *td, struct linux_setgroups16_args *args)
90 {
91 	struct ucred *newcred, *oldcred;
92 	l_gid16_t *linux_gidset;
93 	gid_t *bsd_gidset;
94 	int ngrp, error;
95 	struct proc *p;
96 
97 	ngrp = args->gidsetsize;
98 	if (ngrp < 0 || ngrp >= ngroups_max + 1)
99 		return (EINVAL);
100 	linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_LINUX, M_WAITOK);
101 	error = copyin(args->gidset, linux_gidset, ngrp * sizeof(l_gid16_t));
102 	if (error) {
103 		LIN_SDT_PROBE1(uid16, linux_setgroups16, copyin_error, error);
104 		free(linux_gidset, M_LINUX);
105 		return (error);
106 	}
107 	newcred = crget();
108 	p = td->td_proc;
109 	PROC_LOCK(p);
110 	oldcred = crcopysafe(p, newcred);
111 
112 	/*
113 	 * cr_groups[0] holds egid. Setting the whole set from
114 	 * the supplied set will cause egid to be changed too.
115 	 * Keep cr_groups[0] unchanged to prevent that.
116 	 */
117 
118 	if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS)) != 0) {
119 		PROC_UNLOCK(p);
120 		crfree(newcred);
121 
122 		LIN_SDT_PROBE1(uid16, linux_setgroups16, priv_check_cred_error,
123 		    error);
124 		goto out;
125 	}
126 
127 	if (ngrp > 0) {
128 		newcred->cr_ngroups = ngrp + 1;
129 
130 		bsd_gidset = newcred->cr_groups;
131 		ngrp--;
132 		while (ngrp >= 0) {
133 			bsd_gidset[ngrp + 1] = linux_gidset[ngrp];
134 			ngrp--;
135 		}
136 	}
137 	else
138 		newcred->cr_ngroups = 1;
139 
140 	setsugid(td->td_proc);
141 	proc_set_cred(p, newcred);
142 	PROC_UNLOCK(p);
143 	crfree(oldcred);
144 	error = 0;
145 out:
146 	free(linux_gidset, M_LINUX);
147 
148 	return (error);
149 }
150 
151 int
152 linux_getgroups16(struct thread *td, struct linux_getgroups16_args *args)
153 {
154 	struct ucred *cred;
155 	l_gid16_t *linux_gidset;
156 	gid_t *bsd_gidset;
157 	int bsd_gidsetsz, ngrp, error;
158 
159 	cred = td->td_ucred;
160 	bsd_gidset = cred->cr_groups;
161 	bsd_gidsetsz = cred->cr_ngroups - 1;
162 
163 	/*
164 	 * cr_groups[0] holds egid. Returning the whole set
165 	 * here will cause a duplicate. Exclude cr_groups[0]
166 	 * to prevent that.
167 	 */
168 
169 	if ((ngrp = args->gidsetsize) == 0) {
170 		td->td_retval[0] = bsd_gidsetsz;
171 		return (0);
172 	}
173 
174 	if (ngrp < bsd_gidsetsz)
175 		return (EINVAL);
176 
177 	ngrp = 0;
178 	linux_gidset = malloc(bsd_gidsetsz * sizeof(*linux_gidset),
179 	    M_LINUX, M_WAITOK);
180 	while (ngrp < bsd_gidsetsz) {
181 		linux_gidset[ngrp] = bsd_gidset[ngrp + 1];
182 		ngrp++;
183 	}
184 
185 	error = copyout(linux_gidset, args->gidset, ngrp * sizeof(l_gid16_t));
186 	free(linux_gidset, M_LINUX);
187 	if (error) {
188 		LIN_SDT_PROBE1(uid16, linux_getgroups16, copyout_error, error);
189 		return (error);
190 	}
191 
192 	td->td_retval[0] = ngrp;
193 
194 	return (0);
195 }
196 
197 int
198 linux_getgid16(struct thread *td, struct linux_getgid16_args *args)
199 {
200 
201 	td->td_retval[0] = td->td_ucred->cr_rgid;
202 
203 	return (0);
204 }
205 
206 int
207 linux_getuid16(struct thread *td, struct linux_getuid16_args *args)
208 {
209 
210 	td->td_retval[0] = td->td_ucred->cr_ruid;
211 
212 	return (0);
213 }
214 
215 int
216 linux_getegid16(struct thread *td, struct linux_getegid16_args *args)
217 {
218 	struct getegid_args bsd;
219 	int error;
220 
221 	error = sys_getegid(td, &bsd);
222 
223 	return (error);
224 }
225 
226 int
227 linux_geteuid16(struct thread *td, struct linux_geteuid16_args *args)
228 {
229 	struct geteuid_args bsd;
230 	int error;
231 
232 	error = sys_geteuid(td, &bsd);
233 
234 	return (error);
235 }
236 
237 int
238 linux_setgid16(struct thread *td, struct linux_setgid16_args *args)
239 {
240 	struct setgid_args bsd;
241 	int error;
242 
243 	bsd.gid = args->gid;
244 	error = sys_setgid(td, &bsd);
245 
246 	return (error);
247 }
248 
249 int
250 linux_setuid16(struct thread *td, struct linux_setuid16_args *args)
251 {
252 	struct setuid_args bsd;
253 	int error;
254 
255 	bsd.uid = args->uid;
256 	error = sys_setuid(td, &bsd);
257 
258 	return (error);
259 }
260 
261 int
262 linux_setregid16(struct thread *td, struct linux_setregid16_args *args)
263 {
264 	struct setregid_args bsd;
265 	int error;
266 
267 	bsd.rgid = CAST_NOCHG(args->rgid);
268 	bsd.egid = CAST_NOCHG(args->egid);
269 	error = sys_setregid(td, &bsd);
270 
271 	return (error);
272 }
273 
274 int
275 linux_setreuid16(struct thread *td, struct linux_setreuid16_args *args)
276 {
277 	struct setreuid_args bsd;
278 	int error;
279 
280 	bsd.ruid = CAST_NOCHG(args->ruid);
281 	bsd.euid = CAST_NOCHG(args->euid);
282 	error = sys_setreuid(td, &bsd);
283 
284 	return (error);
285 }
286 
287 int
288 linux_setresgid16(struct thread *td, struct linux_setresgid16_args *args)
289 {
290 	struct setresgid_args bsd;
291 	int error;
292 
293 	bsd.rgid = CAST_NOCHG(args->rgid);
294 	bsd.egid = CAST_NOCHG(args->egid);
295 	bsd.sgid = CAST_NOCHG(args->sgid);
296 	error = sys_setresgid(td, &bsd);
297 
298 	return (error);
299 }
300 
301 int
302 linux_setresuid16(struct thread *td, struct linux_setresuid16_args *args)
303 {
304 	struct setresuid_args bsd;
305 	int error;
306 
307 	bsd.ruid = CAST_NOCHG(args->ruid);
308 	bsd.euid = CAST_NOCHG(args->euid);
309 	bsd.suid = CAST_NOCHG(args->suid);
310 	error = sys_setresuid(td, &bsd);
311 
312 	return (error);
313 }
314