1 /* $NetBSD: linux_uid16.c,v 1.6 2026/09/20 13:43:51 riastradh 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.6 2026/09/20 13:43:51 riastradh 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 memset(&bca, 0, sizeof(bca)); 66 SCARG(&bca, path) = SCARG(uap, path); 67 SCARG(&bca, uid) = LINUXTOBSD_UID(SCARG(uap, uid)); 68 SCARG(&bca, gid) = LINUXTOBSD_GID(SCARG(uap, gid)); 69 70 return sys___posix_chown(l, &bca, retval); 71 } 72 73 int 74 linux_sys_fchown16(struct lwp *l, const struct linux_sys_fchown16_args *uap, register_t *retval) 75 { 76 /* { 77 syscallarg(int) fd; 78 syscallarg(linux_uid16_t) uid; 79 syscallarg(linux_gid16_t) gid; 80 } */ 81 struct sys___posix_fchown_args bfa; 82 83 memset(&bfa, 0, sizeof(bfa)); 84 SCARG(&bfa, fd) = SCARG(uap, fd); 85 SCARG(&bfa, uid) = LINUXTOBSD_UID(SCARG(uap, uid)); 86 SCARG(&bfa, gid) = LINUXTOBSD_GID(SCARG(uap, gid)); 87 88 return sys___posix_fchown(l, &bfa, retval); 89 } 90 91 int 92 linux_sys_lchown16(struct lwp *l, const struct linux_sys_lchown16_args *uap, register_t *retval) 93 { 94 /* { 95 syscallarg(char *) path; 96 syscallarg(linux_uid16_t) uid; 97 syscallarg(linux_gid16_t) gid; 98 } */ 99 struct sys___posix_lchown_args bla; 100 101 memset(&bla, 0, sizeof(bla)); 102 SCARG(&bla, path) = SCARG(uap, path); 103 SCARG(&bla, uid) = LINUXTOBSD_UID(SCARG(uap, uid)); 104 SCARG(&bla, gid) = LINUXTOBSD_GID(SCARG(uap, gid)); 105 106 return sys___posix_lchown(l, &bla, retval); 107 } 108 109 int 110 linux_sys_setreuid16(struct lwp *l, const struct linux_sys_setreuid16_args *uap, register_t *retval) 111 { 112 /* { 113 syscallarg(linux_uid16_t) ruid; 114 syscallarg(linux_uid16_t) euid; 115 } */ 116 struct sys_setreuid_args bsa; 117 118 memset(&bsa, 0, sizeof(bsa)); 119 SCARG(&bsa, ruid) = LINUXTOBSD_UID(SCARG(uap, ruid)); 120 SCARG(&bsa, euid) = LINUXTOBSD_UID(SCARG(uap, euid)); 121 122 return sys_setreuid(l, &bsa, retval); 123 } 124 125 int 126 linux_sys_setregid16(struct lwp *l, const struct linux_sys_setregid16_args *uap, register_t *retval) 127 { 128 /* { 129 syscallarg(linux_gid16_t) rgid; 130 syscallarg(linux_gid16_t) egid; 131 } */ 132 struct sys_setregid_args bsa; 133 134 memset(&bsa, 0, sizeof(bsa)); 135 SCARG(&bsa, rgid) = LINUXTOBSD_GID(SCARG(uap, rgid)); 136 SCARG(&bsa, egid) = LINUXTOBSD_GID(SCARG(uap, egid)); 137 138 return sys_setregid(l, &bsa, retval); 139 } 140 141 int 142 linux_sys_setresuid16(struct lwp *l, const struct linux_sys_setresuid16_args *uap, register_t *retval) 143 { 144 /* { 145 syscallarg(linux_uid16_t) ruid; 146 syscallarg(linux_uid16_t) euid; 147 syscallarg(linux_uid16_t) suid; 148 } */ 149 struct linux_sys_setresuid_args lsa; 150 151 memset(&lsa, 0, sizeof(lsa)); 152 SCARG(&lsa, ruid) = LINUXTOBSD_UID(SCARG(uap, ruid)); 153 SCARG(&lsa, euid) = LINUXTOBSD_UID(SCARG(uap, euid)); 154 SCARG(&lsa, suid) = LINUXTOBSD_UID(SCARG(uap, suid)); 155 156 return linux_sys_setresuid(l, &lsa, retval); 157 } 158 159 int 160 linux_sys_setresgid16(struct lwp *l, const struct linux_sys_setresgid16_args *uap, register_t *retval) 161 { 162 /* { 163 syscallarg(linux_gid16_t) rgid; 164 syscallarg(linux_gid16_t) egid; 165 syscallarg(linux_gid16_t) sgid; 166 } */ 167 struct linux_sys_setresgid_args lsa; 168 169 memset(&lsa, 0, sizeof(lsa)); 170 SCARG(&lsa, rgid) = LINUXTOBSD_GID(SCARG(uap, rgid)); 171 SCARG(&lsa, egid) = LINUXTOBSD_GID(SCARG(uap, egid)); 172 SCARG(&lsa, sgid) = LINUXTOBSD_GID(SCARG(uap, sgid)); 173 174 return linux_sys_setresgid(l, &lsa, retval); 175 } 176 177 int 178 linux_sys_getresuid16(struct lwp *l, const struct linux_sys_getresuid16_args *uap, register_t *retval) 179 { 180 /* { 181 syscallarg(linux_uid16_t *) ruid; 182 syscallarg(linux_uid16_t *) euid; 183 syscallarg(linux_uid16_t *) suid; 184 } */ 185 kauth_cred_t pc = l->l_cred; 186 int error; 187 uid_t buid; 188 linux_uid16_t luid; 189 190 buid = kauth_cred_getuid(pc); 191 luid = BSDTOLINUX_UID(buid); 192 if ((error = copyout(&luid, SCARG(uap, ruid), sizeof(luid))) != 0) 193 return error; 194 195 buid = kauth_cred_geteuid(pc); 196 luid = BSDTOLINUX_UID(buid); 197 if ((error = copyout(&luid, SCARG(uap, euid), sizeof(luid))) != 0) 198 return error; 199 200 buid = kauth_cred_getsvuid(pc); 201 luid = BSDTOLINUX_UID(buid); 202 return (copyout(&luid, SCARG(uap, suid), sizeof(luid))); 203 } 204 205 int 206 linux_sys_getresgid16(struct lwp *l, const struct linux_sys_getresgid16_args *uap, register_t *retval) 207 { 208 /* { 209 syscallarg(linux_gid16_t *) rgid; 210 syscallarg(linux_gid16_t *) egid; 211 syscallarg(linux_gid16_t *) sgid; 212 } */ 213 kauth_cred_t pc = l->l_cred; 214 int error; 215 gid_t bgid; 216 linux_gid16_t lgid; 217 218 bgid = kauth_cred_getgid(pc); 219 lgid = BSDTOLINUX_GID(bgid); 220 if ((error = copyout(&lgid, SCARG(uap, rgid), sizeof(lgid))) != 0) 221 return error; 222 223 bgid = kauth_cred_getegid(pc); 224 lgid = BSDTOLINUX_GID(bgid); 225 if ((error = copyout(&lgid, SCARG(uap, egid), sizeof(lgid))) != 0) 226 return error; 227 228 bgid = kauth_cred_getsvgid(pc); 229 lgid = BSDTOLINUX_GID(bgid); 230 return (copyout(&lgid, SCARG(uap, sgid), sizeof(lgid))); 231 } 232 #endif /* !COMPAT_LINUX32 */ 233 234 int 235 linux_sys_getgroups16(struct lwp *l, const struct linux_sys_getgroups16_args *uap, register_t *retval) 236 { 237 /* { 238 syscallarg(int) gidsetsize; 239 syscallarg(linux_gid16_t *) gidset; 240 } */ 241 linux_gid16_t lset[16]; 242 linux_gid16_t *gidset; 243 unsigned int ngrps; 244 int i, n, j; 245 int error; 246 247 ngrps = kauth_cred_ngroups(l->l_cred); 248 *retval = ngrps; 249 if (SCARG(uap, gidsetsize) == 0) 250 return 0; 251 if (SCARG(uap, gidsetsize) < (int)ngrps) 252 return EINVAL; 253 254 gidset = SCARG(uap, gidset); 255 for (i = 0; i < (n = ngrps); i += n, gidset += n) { 256 n -= i; 257 if (n > __arraycount(lset)) 258 n = __arraycount(lset); 259 for (j = 0; j < n; j++) 260 lset[j] = kauth_cred_group(l->l_cred, i + j); 261 error = copyout(lset, gidset, n * sizeof(lset[0])); 262 if (error != 0) 263 return error; 264 } 265 266 return 0; 267 } 268 269 /* 270 * It is very unlikly that any problem using 16bit groups is written 271 * to allow for more than 16 of them, so don't bother trying to 272 * support that. 273 */ 274 #define COMPAT_NGROUPS16 16 275 276 int 277 linux_sys_setgroups16(struct lwp *l, const struct linux_sys_setgroups16_args *uap, register_t *retval) 278 { 279 /* { 280 syscallarg(int) gidsetsize; 281 syscallarg(linux_gid16_t *) gidset; 282 } */ 283 linux_gid16_t lset[COMPAT_NGROUPS16]; 284 kauth_cred_t ncred; 285 int error; 286 gid_t grbuf[COMPAT_NGROUPS16]; 287 unsigned int i, ngroups = SCARG(uap, gidsetsize); 288 289 if (ngroups > COMPAT_NGROUPS16) 290 return EINVAL; 291 CTASSERT(COMPAT_NGROUPS16 <= SIZE_MAX/sizeof(lset[0])); 292 error = copyin(SCARG(uap, gidset), lset, ngroups * sizeof(lset[0])); 293 if (error != 0) 294 return error; 295 296 for (i = 0; i < ngroups; i++) 297 grbuf[i] = lset[i]; 298 299 ncred = kauth_cred_alloc(); 300 error = kauth_cred_setgroups(ncred, grbuf, SCARG(uap, gidsetsize), 301 -1, UIO_SYSSPACE); 302 if (error != 0) { 303 kauth_cred_free(ncred); 304 return error; 305 } 306 307 return kauth_proc_setgroups(l, ncred); 308 } 309