1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <assert.h>
27 #include <alloca.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <strings.h>
31 #include <macros.h>
32 #include <sys/brand.h>
33 #include <sys/reboot.h>
34 #include <sys/stat.h>
35 #include <sys/syscall.h>
36 #include <sys/sysmacros.h>
37 #include <sys/systeminfo.h>
38 #include <sys/types.h>
39 #include <sys/lx_types.h>
40 #include <sys/lx_debug.h>
41 #include <sys/lx_misc.h>
42 #include <sys/lx_stat.h>
43 #include <sys/lx_syscall.h>
44 #include <sys/lx_thunk_server.h>
45 #include <sys/lx_fcntl.h>
46 #include <unistd.h>
47 #include <libintl.h>
48 #include <zone.h>
49
50 extern int sethostname(char *, int);
51
52 /* ARGUSED */
53 int
54 lx_rename(uintptr_t p1, uintptr_t p2)
55 {
56 int ret;
57
58 ret = rename((const char *)p1, (const char *)p2);
59
60 if (ret < 0) {
61 /*
62 * If rename(2) failed and we're in install mode, return
63 * success if the the reason we failed was either because the
64 * source file didn't actually exist or if it was because we
65 * tried to rename it to be the name of a device currently in
66 * use (resulting in an EBUSY.)
67 *
68 * To help install along further, if the failure was due
69 * to an EBUSY, delete the original file so we don't leave
70 * extra files lying around.
71 */
72 if (lx_install != 0) {
73 if (errno == ENOENT)
74 return (0);
75
76 if (errno == EBUSY) {
77 (void) unlink((const char *)p1);
78 return (0);
79 }
80 }
81
82 return (-errno);
83 }
84
85 return (0);
86 }
87
88 int
89 lx_renameat(uintptr_t ext1, uintptr_t p1, uintptr_t ext2, uintptr_t p2)
90 {
91 int ret;
92 int atfd1 = (int)ext1;
93 int atfd2 = (int)ext2;
94
95 if (atfd1 == LX_AT_FDCWD)
96 atfd1 = AT_FDCWD;
97
98 if (atfd2 == LX_AT_FDCWD)
99 atfd2 = AT_FDCWD;
100
101 ret = renameat(atfd1, (const char *)p1, atfd2, (const char *)p2);
102
103 if (ret < 0) {
104 /* see lx_rename() for why we check lx_install */
105 if (lx_install != 0) {
106 if (errno == ENOENT)
107 return (0);
108
109 if (errno == EBUSY) {
110 (void) unlinkat(ext1, (const char *)p1, 0);
111 return (0);
112 }
113 }
114
115 return (-errno);
116 }
117
118 return (0);
119 }
120
121 /*ARGSUSED*/
122 int
123 lx_reboot(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4)
124 {
125 int magic = (int)p1;
126 int magic2 = (int)p2;
127 uint_t flag = (int)p3;
128 int rc;
129
130 if (magic != LINUX_REBOOT_MAGIC1)
131 return (-EINVAL);
132 if (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A &&
133 magic2 != LINUX_REBOOT_MAGIC2B && magic2 != LINUX_REBOOT_MAGIC2C &&
134 magic2 != LINUX_REBOOT_MAGIC2D)
135 return (-EINVAL);
136
137 if (geteuid() != 0)
138 return (-EPERM);
139
140 switch (flag) {
141 case LINUX_REBOOT_CMD_CAD_ON:
142 case LINUX_REBOOT_CMD_CAD_OFF:
143 /* ignored */
144 rc = 0;
145 break;
146 case LINUX_REBOOT_CMD_POWER_OFF:
147 case LINUX_REBOOT_CMD_HALT:
148 rc = reboot(RB_HALT, NULL);
149 break;
150 case LINUX_REBOOT_CMD_RESTART:
151 case LINUX_REBOOT_CMD_RESTART2:
152 /* RESTART2 may need more work */
153 lx_msg(gettext("Restarting system.\n"));
154 rc = reboot(RB_AUTOBOOT, NULL);
155 break;
156 default:
157 return (-EINVAL);
158 }
159
160 return ((rc == -1) ? -errno : rc);
161 }
162
163 /*
164 * getcwd() - Linux syscall semantics are slightly different; we need to return
165 * the length of the pathname copied (+ 1 for the terminating NULL byte.)
166 */
167 int
168 lx_getcwd(uintptr_t p1, uintptr_t p2)
169 {
170 char *buf;
171 size_t buflen = (size_t)p2;
172 size_t copylen, local_len;
173 size_t len = 0;
174
175 if ((getcwd((char *)p1, (size_t)p2)) == NULL)
176 return (-errno);
177
178 /*
179 * We need the length of the pathname getcwd() copied but we never want
180 * to dereference a Linux pointer for any reason.
181 *
182 * Thus, to get the string length we will uucopy() up to copylen bytes
183 * at a time into a local buffer and will walk each chunk looking for
184 * the string-terminating NULL byte.
185 *
186 * We can use strlen() to find the length of the string in the
187 * local buffer by delimiting the buffer with a NULL byte in the
188 * last element that will never be overwritten.
189 */
190 copylen = min(buflen, MAXPATHLEN + 1);
191 buf = SAFE_ALLOCA(copylen + 1);
192 if (buf == NULL)
193 return (-ENOMEM);
194 buf[copylen] = '\0';
195
196 for (;;) {
197 if (uucopy((char *)p1 + len, buf, copylen) != 0)
198 return (-errno);
199
200 local_len = strlen(buf);
201 len += local_len;
202
203 /*
204 * If the strlen() is less than copylen, we found the
205 * real end of the string -- not the NULL byte used to
206 * delimit the end of our buffer.
207 */
208 if (local_len != copylen)
209 break;
210
211 /* prepare to check the next chunk of the string */
212 buflen -= copylen;
213 copylen = min(buflen, copylen);
214 }
215
216 return (len + 1);
217 }
218
219 int
220 lx_get_kern_version(void)
221 {
222 /*
223 * Since this function is called quite often, and zone_getattr is slow,
224 * we cache the kernel version in kvers_cache. -1 signifies that no
225 * value has yet been cached.
226 */
227 static int kvers_cache = -1;
228 /* dummy variable for use in zone_getattr */
229 int kvers;
230
231 if (kvers_cache != -1)
232 return (kvers_cache);
233 if (zone_getattr(getzoneid(), LX_KERN_VERSION_NUM, &kvers, sizeof (int))
234 != sizeof (int))
235 return (kvers_cache = LX_KERN_2_4);
236 else
237 return (kvers_cache = kvers);
238 }
239
240 int
241 lx_uname(uintptr_t p1)
242 {
243 struct lx_utsname *un = (struct lx_utsname *)p1;
244 char buf[LX_SYS_UTS_LN + 1];
245
246 if (gethostname(un->nodename, sizeof (un->nodename)) == -1)
247 return (-errno);
248
249 (void) strlcpy(un->sysname, LX_UNAME_SYSNAME, LX_SYS_UTS_LN);
250 (void) strlcpy(un->release, lx_release, LX_SYS_UTS_LN);
251 (void) strlcpy(un->version, LX_UNAME_VERSION, LX_SYS_UTS_LN);
252 (void) strlcpy(un->machine, LX_UNAME_MACHINE, LX_SYS_UTS_LN);
253 if ((sysinfo(SI_SRPC_DOMAIN, buf, LX_SYS_UTS_LN) < 0))
254 un->domainname[0] = '\0';
255 else
256 (void) strlcpy(un->domainname, buf, LX_SYS_UTS_LN);
257
258 return (0);
259 }
260
261 /*
262 * {get,set}groups16() - Handle the conversion between 16-bit Linux gids and
263 * 32-bit Solaris gids.
264 */
265 int
266 lx_getgroups16(uintptr_t p1, uintptr_t p2)
267 {
268 int count = (int)p1;
269 lx_gid16_t *grouplist = (lx_gid16_t *)p2;
270 gid_t *grouplist32;
271 int ret;
272 int i;
273
274 grouplist32 = SAFE_ALLOCA(count * sizeof (gid_t));
275 if (grouplist32 == NULL)
276 return (-ENOMEM);
277 if ((ret = getgroups(count, grouplist32)) < 0)
278 return (-errno);
279
280 for (i = 0; i < ret; i++)
281 grouplist[i] = LX_GID32_TO_GID16(grouplist32[i]);
282
283 return (ret);
284 }
285
286 int
287 lx_setgroups16(uintptr_t p1, uintptr_t p2)
288 {
289 int count = (int)p1;
290 lx_gid16_t *grouplist = (lx_gid16_t *)p2;
291 gid_t *grouplist32;
292 int i;
293
294 grouplist32 = SAFE_ALLOCA(count * sizeof (gid_t));
295 if (grouplist32 == NULL)
296 return (-ENOMEM);
297 for (i = 0; i < count; i++)
298 grouplist32[i] = LX_GID16_TO_GID32(grouplist[i]);
299
300 return (setgroups(count, grouplist32) ? -errno : 0);
301 }
302
303 /*
304 * personality() - Solaris doesn't support Linux personalities, but we have to
305 * emulate enough to show that we support the basic personality.
306 */
307 #define LX_PER_LINUX 0x0
308
309 int
310 lx_personality(uintptr_t p1)
311 {
312 int per = (int)p1;
313
314 switch (per) {
315 case -1:
316 /* Request current personality */
317 return (LX_PER_LINUX);
318 case LX_PER_LINUX:
319 return (0);
320 default:
321 return (-EINVAL);
322 }
323 }
324
325 /*
326 * mknod() - Since we don't have the SYS_CONFIG privilege within a zone, the
327 * only mode we have to support is S_IFIFO. We also have to distinguish between
328 * an invalid type and insufficient privileges.
329 */
330 #define LX_S_IFMT 0170000
331 #define LX_S_IFDIR 0040000
332 #define LX_S_IFCHR 0020000
333 #define LX_S_IFBLK 0060000
334 #define LX_S_IFREG 0100000
335 #define LX_S_IFIFO 0010000
336 #define LX_S_IFLNK 0120000
337 #define LX_S_IFSOCK 0140000
338
339 /*ARGSUSED*/
340 int
341 lx_mknod(uintptr_t p1, uintptr_t p2, uintptr_t p3)
342 {
343 char *path = (char *)p1;
344 lx_dev_t lx_dev = (lx_dev_t)p3;
345 struct sockaddr_un sockaddr;
346 struct stat statbuf;
347 mode_t mode, type;
348 dev_t dev;
349 int fd;
350
351 type = ((mode_t)p2 & LX_S_IFMT);
352 mode = ((mode_t)p2 & 07777);
353
354 switch (type) {
355 case 0:
356 case LX_S_IFREG:
357 /* create a regular file */
358 if (stat(path, &statbuf) == 0)
359 return (-EEXIST);
360
361 if (errno != ENOENT)
362 return (-errno);
363
364 if ((fd = creat(path, mode)) < 0)
365 return (-errno);
366
367 (void) close(fd);
368 return (0);
369
370 case LX_S_IFSOCK:
371 /*
372 * Create a UNIX domain socket.
373 *
374 * Most programmers aren't even aware you can do this.
375 *
376 * Note you can also do this via Solaris' mknod(2), but
377 * Linux allows anyone who can create a UNIX domain
378 * socket via bind(2) to create one via mknod(2);
379 * Solaris requires the caller to be privileged.
380 */
381 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
382 return (-errno);
383
384 if (stat(path, &statbuf) == 0)
385 return (-EEXIST);
386
387 if (errno != ENOENT)
388 return (-errno);
389
390 if (uucopy(path, &sockaddr.sun_path,
391 sizeof (sockaddr.sun_path)) < 0)
392 return (-errno);
393
394 /* assure NULL termination of sockaddr.sun_path */
395 sockaddr.sun_path[sizeof (sockaddr.sun_path) - 1] = '\0';
396 sockaddr.sun_family = AF_UNIX;
397
398 if (bind(fd, (struct sockaddr *)&sockaddr,
399 strlen(sockaddr.sun_path) +
400 sizeof (sockaddr.sun_family)) < 0)
401 return (-errno);
402
403 (void) close(fd);
404 return (0);
405
406 case LX_S_IFIFO:
407 dev = 0;
408 break;
409
410 case LX_S_IFCHR:
411 case LX_S_IFBLK:
412 /*
413 * The "dev" RPM package wants to create all possible Linux
414 * device nodes, so just report its mknod()s as having
415 * succeeded if we're in install mode.
416 */
417 if (lx_install != 0) {
418 lx_debug("lx_mknod: install mode spoofed creation of "
419 "Linux device [%lld, %lld]\n",
420 LX_GETMAJOR(lx_dev), LX_GETMINOR(lx_dev));
421
422 return (0);
423 }
424
425 dev = makedevice(LX_GETMAJOR(lx_dev), LX_GETMINOR(lx_dev));
426 break;
427
428 default:
429 return (-EINVAL);
430 }
431
432 return (mknod(path, mode | type, dev) ? -errno : 0);
433 }
434
435 int
436 lx_sethostname(uintptr_t p1, uintptr_t p2)
437 {
438 char *name = (char *)p1;
439 int len = (size_t)p2;
440
441 return (sethostname(name, len) ? -errno : 0);
442 }
443
444 int
445 lx_setdomainname(uintptr_t p1, uintptr_t p2)
446 {
447 char *name = (char *)p1;
448 int len = (size_t)p2;
449 long rval;
450
451 if (len < 0 || len >= LX_SYS_UTS_LN)
452 return (-EINVAL);
453
454 rval = sysinfo(SI_SET_SRPC_DOMAIN, name, len);
455
456 return ((rval < 0) ? -errno : 0);
457 }
458
459 int
460 lx_getpid(void)
461 {
462 int pid;
463
464 /* First call the thunk server hook. */
465 if (lxt_server_pid(&pid) != 0)
466 return (pid);
467
468 pid = syscall(SYS_brand, B_EMULATE_SYSCALL + 20);
469 return ((pid == -1) ? -errno : pid);
470 }
471
472 int
473 lx_execve(uintptr_t p1, uintptr_t p2, uintptr_t p3)
474 {
475 char *filename = (char *)p1;
476 char **argv = (char **)p2;
477 char **envp = (char **)p3;
478 char *nullist[] = { NULL };
479 char path[64];
480
481 /* First call the thunk server hook. */
482 lxt_server_exec_check();
483
484 /* Get a copy of the executable we're trying to run */
485 path[0] = '\0';
486 (void) uucopystr(filename, path, sizeof (path));
487
488 /* Check if we're trying to run a native binary */
489 if (strncmp(path, "/native/usr/lib/brand/lx/lx_native",
490 sizeof (path)) == 0) {
491 /* Skip the first element in the argv array */
492 argv++;
493
494 /*
495 * The name of the new program to execute was the first
496 * parameter passed to lx_native.
497 */
498 if (uucopy(argv, &filename, sizeof (char *)) != 0)
499 return (-errno);
500
501 (void) syscall(SYS_brand, B_EXEC_NATIVE, filename, argv, envp,
502 NULL, NULL, NULL);
503 return (-errno);
504 }
505
506 if (argv == NULL)
507 argv = nullist;
508
509 /* This is a normal exec call. */
510 (void) execve(filename, argv, envp);
511
512 return (-errno);
513 }
514
515 int
516 lx_setgroups(uintptr_t p1, uintptr_t p2)
517 {
518 int ng = (int)p1;
519 gid_t *glist = NULL;
520 int i, r;
521
522 lx_debug("\tlx_setgroups(%d, 0x%p", ng, p2);
523
524 if (ng > 0) {
525 if ((glist = (gid_t *)SAFE_ALLOCA(ng * sizeof (gid_t))) == NULL)
526 return (-ENOMEM);
527
528 if (uucopy((void *)p2, glist, ng * sizeof (gid_t)) != 0)
529 return (-errno);
530
531 /*
532 * Linux doesn't check the validity of the group IDs, but
533 * Solaris does. Change any invalid group IDs to a known, valid
534 * value (yuck).
535 */
536 for (i = 0; i < ng; i++) {
537 if (glist[i] > MAXUID)
538 glist[i] = MAXUID;
539 }
540 }
541
542 r = syscall(SYS_brand, B_EMULATE_SYSCALL + LX_SYS_setgroups32,
543 ng, glist);
544
545 return ((r == -1) ? -errno : r);
546 }