xref: /freebsd/sys/compat/linux/linux.c (revision f5ef5f675d9d9eb6e35ed9142d70ecf774456ad4)
1 /*-
2  * Copyright (c) 2015 Dmitry Chagin
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <opt_inet6.h>
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/ctype.h>
35 #include <sys/jail.h>
36 #include <sys/lock.h>
37 #include <sys/malloc.h>
38 #include <sys/signalvar.h>
39 #include <sys/socket.h>
40 #include <sys/socketvar.h>
41 
42 #include <net/if.h>
43 #include <net/if_var.h>
44 #include <net/if_dl.h>
45 #include <net/if_types.h>
46 
47 #include <sys/un.h>
48 #include <netinet/in.h>
49 
50 #include <compat/linux/linux.h>
51 #include <compat/linux/linux_common.h>
52 #include <compat/linux/linux_util.h>
53 
54 struct futex_list futex_list;
55 struct mtx futex_mtx;			/* protects the futex list */
56 
57 CTASSERT(LINUX_IFNAMSIZ == IFNAMSIZ);
58 
59 static int bsd_to_linux_sigtbl[LINUX_SIGTBLSZ] = {
60 	LINUX_SIGHUP,	/* SIGHUP */
61 	LINUX_SIGINT,	/* SIGINT */
62 	LINUX_SIGQUIT,	/* SIGQUIT */
63 	LINUX_SIGILL,	/* SIGILL */
64 	LINUX_SIGTRAP,	/* SIGTRAP */
65 	LINUX_SIGABRT,	/* SIGABRT */
66 	0,		/* SIGEMT */
67 	LINUX_SIGFPE,	/* SIGFPE */
68 	LINUX_SIGKILL,	/* SIGKILL */
69 	LINUX_SIGBUS,	/* SIGBUS */
70 	LINUX_SIGSEGV,	/* SIGSEGV */
71 	LINUX_SIGSYS,	/* SIGSYS */
72 	LINUX_SIGPIPE,	/* SIGPIPE */
73 	LINUX_SIGALRM,	/* SIGALRM */
74 	LINUX_SIGTERM,	/* SIGTERM */
75 	LINUX_SIGURG,	/* SIGURG */
76 	LINUX_SIGSTOP,	/* SIGSTOP */
77 	LINUX_SIGTSTP,	/* SIGTSTP */
78 	LINUX_SIGCONT,	/* SIGCONT */
79 	LINUX_SIGCHLD,	/* SIGCHLD */
80 	LINUX_SIGTTIN,	/* SIGTTIN */
81 	LINUX_SIGTTOU,	/* SIGTTOU */
82 	LINUX_SIGIO,	/* SIGIO */
83 	LINUX_SIGXCPU,	/* SIGXCPU */
84 	LINUX_SIGXFSZ,	/* SIGXFSZ */
85 	LINUX_SIGVTALRM,/* SIGVTALRM */
86 	LINUX_SIGPROF,	/* SIGPROF */
87 	LINUX_SIGWINCH,	/* SIGWINCH */
88 	0,		/* SIGINFO */
89 	LINUX_SIGUSR1,	/* SIGUSR1 */
90 	LINUX_SIGUSR2	/* SIGUSR2 */
91 };
92 
93 static int linux_to_bsd_sigtbl[LINUX_SIGTBLSZ] = {
94 	SIGHUP,		/* LINUX_SIGHUP */
95 	SIGINT,		/* LINUX_SIGINT */
96 	SIGQUIT,	/* LINUX_SIGQUIT */
97 	SIGILL,		/* LINUX_SIGILL */
98 	SIGTRAP,	/* LINUX_SIGTRAP */
99 	SIGABRT,	/* LINUX_SIGABRT */
100 	SIGBUS,		/* LINUX_SIGBUS */
101 	SIGFPE,		/* LINUX_SIGFPE */
102 	SIGKILL,	/* LINUX_SIGKILL */
103 	SIGUSR1,	/* LINUX_SIGUSR1 */
104 	SIGSEGV,	/* LINUX_SIGSEGV */
105 	SIGUSR2,	/* LINUX_SIGUSR2 */
106 	SIGPIPE,	/* LINUX_SIGPIPE */
107 	SIGALRM,	/* LINUX_SIGALRM */
108 	SIGTERM,	/* LINUX_SIGTERM */
109 	SIGBUS,		/* LINUX_SIGSTKFLT */
110 	SIGCHLD,	/* LINUX_SIGCHLD */
111 	SIGCONT,	/* LINUX_SIGCONT */
112 	SIGSTOP,	/* LINUX_SIGSTOP */
113 	SIGTSTP,	/* LINUX_SIGTSTP */
114 	SIGTTIN,	/* LINUX_SIGTTIN */
115 	SIGTTOU,	/* LINUX_SIGTTOU */
116 	SIGURG,		/* LINUX_SIGURG */
117 	SIGXCPU,	/* LINUX_SIGXCPU */
118 	SIGXFSZ,	/* LINUX_SIGXFSZ */
119 	SIGVTALRM,	/* LINUX_SIGVTALARM */
120 	SIGPROF,	/* LINUX_SIGPROF */
121 	SIGWINCH,	/* LINUX_SIGWINCH */
122 	SIGIO,		/* LINUX_SIGIO */
123 	/*
124 	 * FreeBSD does not have SIGPWR signal, map Linux SIGPWR signal
125 	 * to the first unused FreeBSD signal number. Since Linux supports
126 	 * signals from 1 to 64 we are ok here as our SIGRTMIN = 65.
127 	 */
128 	SIGRTMIN,	/* LINUX_SIGPWR */
129 	SIGSYS		/* LINUX_SIGSYS */
130 };
131 
132 /*
133  * Map Linux RT signals to the FreeBSD RT signals.
134  */
135 static inline int
136 linux_to_bsd_rt_signal(int sig)
137 {
138 
139 	return (SIGRTMIN + 1 + sig - LINUX_SIGRTMIN);
140 }
141 
142 static inline int
143 bsd_to_linux_rt_signal(int sig)
144 {
145 
146 	return (sig - SIGRTMIN - 1 + LINUX_SIGRTMIN);
147 }
148 
149 int
150 linux_to_bsd_signal(int sig)
151 {
152 
153 	KASSERT(sig > 0 && sig <= LINUX_SIGRTMAX, ("invalid Linux signal %d\n", sig));
154 
155 	if (sig < LINUX_SIGRTMIN)
156 		return (linux_to_bsd_sigtbl[_SIG_IDX(sig)]);
157 
158 	return (linux_to_bsd_rt_signal(sig));
159 }
160 
161 int
162 bsd_to_linux_signal(int sig)
163 {
164 
165 	if (sig <= LINUX_SIGTBLSZ)
166 		return (bsd_to_linux_sigtbl[_SIG_IDX(sig)]);
167 	if (sig == SIGRTMIN)
168 		return (LINUX_SIGPWR);
169 
170 	return (bsd_to_linux_rt_signal(sig));
171 }
172 
173 int
174 linux_to_bsd_sigaltstack(int lsa)
175 {
176 	int bsa = 0;
177 
178 	if (lsa & LINUX_SS_DISABLE)
179 		bsa |= SS_DISABLE;
180 	/*
181 	 * Linux ignores SS_ONSTACK flag for ss
182 	 * parameter while FreeBSD prohibits it.
183 	 */
184 	return (bsa);
185 }
186 
187 int
188 bsd_to_linux_sigaltstack(int bsa)
189 {
190 	int lsa = 0;
191 
192 	if (bsa & SS_DISABLE)
193 		lsa |= LINUX_SS_DISABLE;
194 	if (bsa & SS_ONSTACK)
195 		lsa |= LINUX_SS_ONSTACK;
196 	return (lsa);
197 }
198 
199 void
200 linux_to_bsd_sigset(l_sigset_t *lss, sigset_t *bss)
201 {
202 	int b, l;
203 
204 	SIGEMPTYSET(*bss);
205 	for (l = 1; l <= LINUX_SIGRTMAX; l++) {
206 		if (LINUX_SIGISMEMBER(*lss, l)) {
207 			b = linux_to_bsd_signal(l);
208 			if (b)
209 				SIGADDSET(*bss, b);
210 		}
211 	}
212 }
213 
214 void
215 bsd_to_linux_sigset(sigset_t *bss, l_sigset_t *lss)
216 {
217 	int b, l;
218 
219 	LINUX_SIGEMPTYSET(*lss);
220 	for (b = 1; b <= SIGRTMAX; b++) {
221 		if (SIGISMEMBER(*bss, b)) {
222 			l = bsd_to_linux_signal(b);
223 			if (l)
224 				LINUX_SIGADDSET(*lss, l);
225 		}
226 	}
227 }
228 
229 /*
230  * Translate a Linux interface name to a FreeBSD interface name,
231  * and return the associated ifnet structure
232  * bsdname and lxname need to be least IFNAMSIZ bytes long, but
233  * can point to the same buffer.
234  */
235 struct ifnet *
236 ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname)
237 {
238 	struct ifnet *ifp;
239 	int len, unit;
240 	char *ep;
241 	int index;
242 	bool is_eth, is_lo;
243 
244 	for (len = 0; len < LINUX_IFNAMSIZ; ++len)
245 		if (!isalpha(lxname[len]) || lxname[len] == '\0')
246 			break;
247 	if (len == 0 || len == LINUX_IFNAMSIZ)
248 		return (NULL);
249 	/* Linux loopback interface name is lo (not lo0) */
250 	is_lo = (len == 2 && strncmp(lxname, "lo", len) == 0);
251 	unit = (int)strtoul(lxname + len, &ep, 10);
252 	if ((ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ) &&
253 	    is_lo == 0)
254 		return (NULL);
255 	index = 0;
256 	is_eth = (len == 3 && strncmp(lxname, "eth", len) == 0);
257 
258 	CURVNET_SET(TD_TO_VNET(td));
259 	IFNET_RLOCK();
260 	CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
261 		/*
262 		 * Allow Linux programs to use FreeBSD names. Don't presume
263 		 * we never have an interface named "eth", so don't make
264 		 * the test optional based on is_eth.
265 		 */
266 		if (strncmp(ifp->if_xname, lxname, LINUX_IFNAMSIZ) == 0)
267 			break;
268 		if (is_eth && IFP_IS_ETH(ifp) && unit == index++)
269 			break;
270 		if (is_lo && IFP_IS_LOOP(ifp))
271 			break;
272 	}
273 	IFNET_RUNLOCK();
274 	CURVNET_RESTORE();
275 	if (ifp != NULL && bsdname != NULL)
276 		strlcpy(bsdname, ifp->if_xname, IFNAMSIZ);
277 	return (ifp);
278 }
279 
280 void
281 linux_ifflags(struct ifnet *ifp, short *flags)
282 {
283 	unsigned short fl;
284 
285 	fl = (ifp->if_flags | ifp->if_drv_flags) & 0xffff;
286 	*flags = 0;
287 	if (fl & IFF_UP)
288 		*flags |= LINUX_IFF_UP;
289 	if (fl & IFF_BROADCAST)
290 		*flags |= LINUX_IFF_BROADCAST;
291 	if (fl & IFF_DEBUG)
292 		*flags |= LINUX_IFF_DEBUG;
293 	if (fl & IFF_LOOPBACK)
294 		*flags |= LINUX_IFF_LOOPBACK;
295 	if (fl & IFF_POINTOPOINT)
296 		*flags |= LINUX_IFF_POINTOPOINT;
297 	if (fl & IFF_DRV_RUNNING)
298 		*flags |= LINUX_IFF_RUNNING;
299 	if (fl & IFF_NOARP)
300 		*flags |= LINUX_IFF_NOARP;
301 	if (fl & IFF_PROMISC)
302 		*flags |= LINUX_IFF_PROMISC;
303 	if (fl & IFF_ALLMULTI)
304 		*flags |= LINUX_IFF_ALLMULTI;
305 	if (fl & IFF_MULTICAST)
306 		*flags |= LINUX_IFF_MULTICAST;
307 }
308 
309 int
310 linux_ifhwaddr(struct ifnet *ifp, struct l_sockaddr *lsa)
311 {
312 	struct ifaddr *ifa;
313 	struct sockaddr_dl *sdl;
314 
315 	if (IFP_IS_LOOP(ifp)) {
316 		bzero(lsa, sizeof(*lsa));
317 		lsa->sa_family = LINUX_ARPHRD_LOOPBACK;
318 		return (0);
319 	}
320 
321 	if (!IFP_IS_ETH(ifp))
322 		return (ENOENT);
323 
324 	CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
325 		sdl = (struct sockaddr_dl*)ifa->ifa_addr;
326 		if (sdl != NULL && (sdl->sdl_family == AF_LINK) &&
327 		    (sdl->sdl_type == IFT_ETHER)) {
328 			bzero(lsa, sizeof(*lsa));
329 			lsa->sa_family = LINUX_ARPHRD_ETHER;
330 			bcopy(LLADDR(sdl), lsa->sa_data, LINUX_IFHWADDRLEN);
331 			return (0);
332 		}
333 	}
334 
335 	return (ENOENT);
336 }
337 
338 int
339 linux_to_bsd_domain(int domain)
340 {
341 
342 	switch (domain) {
343 	case LINUX_AF_UNSPEC:
344 		return (AF_UNSPEC);
345 	case LINUX_AF_UNIX:
346 		return (AF_LOCAL);
347 	case LINUX_AF_INET:
348 		return (AF_INET);
349 	case LINUX_AF_INET6:
350 		return (AF_INET6);
351 	case LINUX_AF_AX25:
352 		return (AF_CCITT);
353 	case LINUX_AF_IPX:
354 		return (AF_IPX);
355 	case LINUX_AF_APPLETALK:
356 		return (AF_APPLETALK);
357 	}
358 	return (-1);
359 }
360 
361 int
362 bsd_to_linux_domain(int domain)
363 {
364 
365 	switch (domain) {
366 	case AF_UNSPEC:
367 		return (LINUX_AF_UNSPEC);
368 	case AF_LOCAL:
369 		return (LINUX_AF_UNIX);
370 	case AF_INET:
371 		return (LINUX_AF_INET);
372 	case AF_INET6:
373 		return (LINUX_AF_INET6);
374 	case AF_CCITT:
375 		return (LINUX_AF_AX25);
376 	case AF_IPX:
377 		return (LINUX_AF_IPX);
378 	case AF_APPLETALK:
379 		return (LINUX_AF_APPLETALK);
380 	}
381 	return (-1);
382 }
383 
384 /*
385  * Based on the fact that:
386  * 1. Native and Linux storage of struct sockaddr
387  * and struct sockaddr_in6 are equal.
388  * 2. On Linux sa_family is the first member of all struct sockaddr.
389  */
390 int
391 bsd_to_linux_sockaddr(const struct sockaddr *sa, struct l_sockaddr **lsa,
392     socklen_t len)
393 {
394 	struct l_sockaddr *kosa;
395 	int error, bdom;
396 
397 	*lsa = NULL;
398 	if (len < 2 || len > UCHAR_MAX)
399 		return (EINVAL);
400 
401 	kosa = malloc(len, M_SONAME, M_WAITOK);
402 	bcopy(sa, kosa, len);
403 
404 	bdom = bsd_to_linux_domain(sa->sa_family);
405 	if (bdom == -1) {
406 		error = EAFNOSUPPORT;
407 		goto out;
408 	}
409 
410 	kosa->sa_family = bdom;
411 	*lsa = kosa;
412 	return (0);
413 
414 out:
415 	free(kosa, M_SONAME);
416 	return (error);
417 }
418 
419 int
420 linux_to_bsd_sockaddr(const struct l_sockaddr *osa, struct sockaddr **sap,
421     socklen_t *len)
422 {
423 	struct sockaddr *sa;
424 	struct l_sockaddr *kosa;
425 #ifdef INET6
426 	struct sockaddr_in6 *sin6;
427 	bool  oldv6size;
428 #endif
429 	char *name;
430 	int salen, bdom, error, hdrlen, namelen;
431 
432 	if (*len < 2 || *len > UCHAR_MAX)
433 		return (EINVAL);
434 
435 	salen = *len;
436 
437 #ifdef INET6
438 	oldv6size = false;
439 	/*
440 	 * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
441 	 * if it's a v4-mapped address, so reserve the proper space
442 	 * for it.
443 	 */
444 	if (salen == sizeof(struct sockaddr_in6) - sizeof(uint32_t)) {
445 		salen += sizeof(uint32_t);
446 		oldv6size = true;
447 	}
448 #endif
449 
450 	kosa = malloc(salen, M_SONAME, M_WAITOK);
451 
452 	if ((error = copyin(osa, kosa, *len)))
453 		goto out;
454 
455 	bdom = linux_to_bsd_domain(kosa->sa_family);
456 	if (bdom == -1) {
457 		error = EAFNOSUPPORT;
458 		goto out;
459 	}
460 
461 #ifdef INET6
462 	/*
463 	 * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
464 	 * which lacks the scope id compared with RFC2553 one. If we detect
465 	 * the situation, reject the address and write a message to system log.
466 	 *
467 	 * Still accept addresses for which the scope id is not used.
468 	 */
469 	if (oldv6size) {
470 		if (bdom == AF_INET6) {
471 			sin6 = (struct sockaddr_in6 *)kosa;
472 			if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
473 			    (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
474 			     !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
475 			     !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
476 			     !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
477 			     !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
478 				sin6->sin6_scope_id = 0;
479 			} else {
480 				linux_msg(curthread,
481 				    "obsolete pre-RFC2553 sockaddr_in6 rejected\n");
482 				error = EINVAL;
483 				goto out;
484 			}
485 		} else
486 			salen -= sizeof(uint32_t);
487 	}
488 #endif
489 	if (bdom == AF_INET) {
490 		if (salen < sizeof(struct sockaddr_in)) {
491 			error = EINVAL;
492 			goto out;
493 		}
494 		salen = sizeof(struct sockaddr_in);
495 	}
496 
497 	if (bdom == AF_LOCAL && salen > sizeof(struct sockaddr_un)) {
498 		hdrlen = offsetof(struct sockaddr_un, sun_path);
499 		name = ((struct sockaddr_un *)kosa)->sun_path;
500 		if (*name == '\0') {
501 			/*
502 			 * Linux abstract namespace starts with a NULL byte.
503 			 * XXX We do not support abstract namespace yet.
504 			 */
505 			namelen = strnlen(name + 1, salen - hdrlen - 1) + 1;
506 		} else
507 			namelen = strnlen(name, salen - hdrlen);
508 		salen = hdrlen + namelen;
509 		if (salen > sizeof(struct sockaddr_un)) {
510 			error = ENAMETOOLONG;
511 			goto out;
512 		}
513 	}
514 
515 	sa = (struct sockaddr *)kosa;
516 	sa->sa_family = bdom;
517 	sa->sa_len = salen;
518 
519 	*sap = sa;
520 	*len = salen;
521 	return (0);
522 
523 out:
524 	free(kosa, M_SONAME);
525 	return (error);
526 }
527