Home | History | Annotate | Line # | Download | only in netbsd32
netbsd32_socket.c revision 1.41.14.1.6.1
      1 /*	$NetBSD: netbsd32_socket.c,v 1.41.14.1.6.1 2018/11/21 12:09:54 martin Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1998, 2001 Matthew R. Green
      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 ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * 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 __KERNEL_RCSID(0, "$NetBSD: netbsd32_socket.c,v 1.41.14.1.6.1 2018/11/21 12:09:54 martin Exp $");
     31 
     32 #include <sys/param.h>
     33 #include <sys/systm.h>
     34 #define msg __msg /* Don't ask me! */
     35 #include <sys/mount.h>
     36 #include <sys/socket.h>
     37 #include <sys/sockio.h>
     38 #include <sys/socketvar.h>
     39 #include <sys/mbuf.h>
     40 #include <sys/ktrace.h>
     41 #include <sys/file.h>
     42 #include <sys/filedesc.h>
     43 #include <sys/syscallargs.h>
     44 #include <sys/proc.h>
     45 #include <sys/dirent.h>
     46 
     47 #include <compat/netbsd32/netbsd32.h>
     48 #include <compat/netbsd32/netbsd32_syscallargs.h>
     49 #include <compat/netbsd32/netbsd32_conv.h>
     50 
     51 /*
     52  * XXX Assumes that struct sockaddr is compatible.
     53  */
     54 
     55 #define	CMSG32_ALIGN(n)	(((n) + ALIGNBYTES32) & ~ALIGNBYTES32)
     56 #define	CMSG32_DATA(cmsg) \
     57 	((u_char *)(void *)(cmsg) + CMSG32_ALIGN(sizeof(struct cmsghdr)))
     58 
     59 #define	CMSG32_NXTHDR(mhdr, cmsg)	\
     60 	(((char *)(cmsg) + CMSG32_ALIGN((cmsg)->cmsg_len) + \
     61 			    CMSG32_ALIGN(sizeof(struct cmsghdr)) > \
     62 	    (((char *)(mhdr)->msg_control) + (mhdr)->msg_controllen)) ? \
     63 	    (struct cmsghdr *)0 : \
     64 	    (struct cmsghdr *)((char *)(cmsg) + \
     65 	        CMSG32_ALIGN((cmsg)->cmsg_len)))
     66 #define	CMSG32_FIRSTHDR(mhdr) \
     67 	((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \
     68 	 (struct cmsghdr *)(mhdr)->msg_control : \
     69 	 (struct cmsghdr *)0)
     70 
     71 #define CMSG32_SPACE(l)	(CMSG32_ALIGN(sizeof(struct cmsghdr)) + CMSG32_ALIGN(l))
     72 #define CMSG32_LEN(l)	(CMSG32_ALIGN(sizeof(struct cmsghdr)) + (l))
     73 
     74 static int
     75 copyout32_msg_control_mbuf(struct lwp *l, struct msghdr *mp, int *len, struct mbuf *m, char **q, bool *truncated)
     76 {
     77 	struct cmsghdr *cmsg, cmsg32;
     78 	int i, j, error;
     79 
     80 	*truncated = false;
     81 	cmsg = mtod(m, struct cmsghdr *);
     82 	do {
     83 		if ((char *)cmsg == mtod(m, char *) + m->m_len)
     84 			break;
     85 		if ((char *)cmsg > mtod(m, char *) + m->m_len - sizeof(*cmsg))
     86 			return EINVAL;
     87 		cmsg32 = *cmsg;
     88 		j = cmsg->cmsg_len - CMSG_LEN(0);
     89 		i = cmsg32.cmsg_len = CMSG32_LEN(j);
     90 		if (i > *len) {
     91 			mp->msg_flags |= MSG_CTRUNC;
     92 			if (cmsg->cmsg_level == SOL_SOCKET
     93 			    && cmsg->cmsg_type == SCM_RIGHTS) {
     94 				*truncated = true;
     95 				return 0;
     96 			}
     97 			j -= i - *len;
     98 			i = *len;
     99 		}
    100 
    101 		ktrkuser("msgcontrol", cmsg, cmsg->cmsg_len);
    102 		error = copyout(&cmsg32, *q, MIN(i, sizeof(cmsg32)));
    103 		if (error)
    104 			return (error);
    105 		if (i > CMSG32_LEN(0)) {
    106 			error = copyout(CMSG_DATA(cmsg), *q + CMSG32_LEN(0), i - CMSG32_LEN(0));
    107 			if (error)
    108 				return (error);
    109 		}
    110 		j = CMSG32_SPACE(cmsg->cmsg_len - CMSG_LEN(0));
    111 		if (*len >= j) {
    112 			*len -= j;
    113 			*q += j;
    114 		} else {
    115 			*q += i;
    116 			*len = 0;
    117 		}
    118 		cmsg = (void *)((char *)cmsg + CMSG_ALIGN(cmsg->cmsg_len));
    119 	} while (*len > 0);
    120 
    121 	return 0;
    122 }
    123 
    124 static int
    125 copyout32_msg_control(struct lwp *l, struct msghdr *mp, struct mbuf *control)
    126 {
    127 	int len, error = 0;
    128 	struct mbuf *m;
    129 	char *q;
    130 	bool truncated;
    131 
    132 	len = mp->msg_controllen;
    133 	if (len <= 0 || control == 0) {
    134 		mp->msg_controllen = 0;
    135 		free_control_mbuf(l, control, control);
    136 		return 0;
    137 	}
    138 
    139 	q = (char *)mp->msg_control;
    140 
    141 	for (m = control; len > 0 && m != NULL; m = m->m_next) {
    142 		error = copyout32_msg_control_mbuf(l, mp, &len, m, &q, &truncated);
    143 		if (truncated) {
    144 			m = control;
    145 			break;
    146 		}
    147 		if (error)
    148 			break;
    149 	}
    150 
    151 	free_control_mbuf(l, control, m);
    152 
    153 	mp->msg_controllen = q - (char *)mp->msg_control;
    154 	return error;
    155 }
    156 
    157 int
    158 netbsd32_recvmsg(struct lwp *l, const struct netbsd32_recvmsg_args *uap, register_t *retval)
    159 {
    160 	/* {
    161 		syscallarg(int) s;
    162 		syscallarg(netbsd32_msghdrp_t) msg;
    163 		syscallarg(int) flags;
    164 	} */
    165 	struct netbsd32_msghdr	msg32;
    166 	struct iovec aiov[UIO_SMALLIOV], *iov;
    167 	struct msghdr	msg;
    168 	int		error;
    169 	struct mbuf	*from, *control;
    170 	size_t iovsz;
    171 
    172 	error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32));
    173 	if (error)
    174 		return (error);
    175 
    176 	iovsz = msg32.msg_iovlen * sizeof(struct iovec);
    177 	if (msg32.msg_iovlen > UIO_SMALLIOV) {
    178 		if (msg32.msg_iovlen > IOV_MAX)
    179 			return (EMSGSIZE);
    180 		iov = kmem_alloc(iovsz, KM_SLEEP);
    181 	} else
    182 		iov = aiov;
    183 	error = netbsd32_to_iovecin(NETBSD32PTR64(msg32.msg_iov), iov,
    184 	    msg32.msg_iovlen);
    185 	if (error)
    186 		goto done;
    187 
    188 	msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS;
    189 	msg.msg_name = NETBSD32PTR64(msg32.msg_name);
    190 	msg.msg_namelen = msg32.msg_namelen;
    191 	msg.msg_control = NETBSD32PTR64(msg32.msg_control);
    192 	msg.msg_controllen = msg32.msg_controllen;
    193 	msg.msg_iov = iov;
    194 	msg.msg_iovlen = msg32.msg_iovlen;
    195 
    196 	error = do_sys_recvmsg(l, SCARG(uap, s), &msg, &from,
    197 	    msg.msg_control != NULL ? &control : NULL, retval);
    198 	if (error != 0)
    199 		goto done;
    200 
    201 	if (msg.msg_control != NULL)
    202 		error = copyout32_msg_control(l, &msg, control);
    203 
    204 	if (error == 0)
    205 		error = copyout_sockname(msg.msg_name, &msg.msg_namelen, 0,
    206 			from);
    207 	if (from != NULL)
    208 		m_free(from);
    209 	if (error == 0) {
    210 		ktrkuser("msghdr", &msg, sizeof msg);
    211 		msg32.msg_namelen = msg.msg_namelen;
    212 		msg32.msg_controllen = msg.msg_controllen;
    213 		msg32.msg_flags = msg.msg_flags;
    214 		error = copyout(&msg32, SCARG_P32(uap, msg), sizeof(msg32));
    215 	}
    216 
    217  done:
    218 	if (iov != aiov)
    219 		kmem_free(iov, iovsz);
    220 	return (error);
    221 }
    222 
    223 static int
    224 copyin32_msg_control(struct lwp *l, struct msghdr *mp)
    225 {
    226 	/*
    227 	 * Handle cmsg if there is any.
    228 	 */
    229 	struct cmsghdr *cmsg, cmsg32, *cc;
    230 	struct mbuf *ctl_mbuf;
    231 	ssize_t resid = mp->msg_controllen;
    232 	size_t clen, cidx = 0, cspace;
    233 	u_int8_t *control;
    234 	int error;
    235 
    236 	ctl_mbuf = m_get(M_WAIT, MT_CONTROL);
    237 	clen = MLEN;
    238 	control = mtod(ctl_mbuf, void *);
    239 	memset(control, 0, clen);
    240 
    241 	cc = CMSG32_FIRSTHDR(mp);
    242 	do {
    243 		error = copyin(cc, &cmsg32, sizeof(cmsg32));
    244 		if (error)
    245 			goto failure;
    246 
    247 		/*
    248 		 * Sanity check the control message length.
    249 		 */
    250 		if (cmsg32.cmsg_len > resid ||
    251 		    cmsg32.cmsg_len < sizeof(cmsg32)) {
    252 			error = EINVAL;
    253 			goto failure;
    254 		}
    255 
    256 		cspace = CMSG_SPACE(cmsg32.cmsg_len - CMSG32_LEN(0));
    257 
    258 		/* Check the buffer is big enough */
    259 		if (__predict_false(cidx + cspace > clen)) {
    260 			u_int8_t *nc;
    261 			size_t nclen;
    262 
    263 			nclen = cidx + cspace;
    264 			if (nclen >= PAGE_SIZE) {
    265 				error = EINVAL;
    266 				goto failure;
    267 			}
    268 			nc = realloc(clen <= MLEN ? NULL : control,
    269 				     nclen, M_TEMP, M_WAITOK);
    270 			if (!nc) {
    271 				error = ENOMEM;
    272 				goto failure;
    273 			}
    274 			if (cidx <= MLEN) {
    275 				/* Old buffer was in mbuf... */
    276 				memcpy(nc, control, cidx);
    277 				memset(nc + cidx, 0, nclen - cidx);
    278 			} else {
    279 				memset(nc + nclen, 0, nclen - clen);
    280 			}
    281 			control = nc;
    282 			clen = nclen;
    283 		}
    284 
    285 		/* Copy header */
    286 		cmsg = (void *)&control[cidx];
    287 		cmsg->cmsg_len = CMSG_LEN(cmsg32.cmsg_len - CMSG32_LEN(0));
    288 		cmsg->cmsg_level = cmsg32.cmsg_level;
    289 		cmsg->cmsg_type = cmsg32.cmsg_type;
    290 
    291 		/* Copyin the data */
    292 		error = copyin(CMSG32_DATA(cc), CMSG_DATA(cmsg),
    293 		    cmsg32.cmsg_len - CMSG32_LEN(0));
    294 		if (error)
    295 			goto failure;
    296 
    297 		resid -= CMSG32_ALIGN(cmsg32.cmsg_len);
    298 		cidx += cmsg->cmsg_len;
    299 	} while (resid > 0 && (cc = CMSG32_NXTHDR(mp, &cmsg32)));
    300 
    301 	/* If we allocated a buffer, attach to mbuf */
    302 	if (cidx > MLEN) {
    303 		MEXTADD(ctl_mbuf, control, clen, M_MBUF, NULL, NULL);
    304 		ctl_mbuf->m_flags |= M_EXT_RW;
    305 	}
    306 	control = NULL;
    307 	mp->msg_controllen = ctl_mbuf->m_len = CMSG_ALIGN(cidx);
    308 
    309 	mp->msg_control = ctl_mbuf;
    310 	mp->msg_flags |= MSG_CONTROLMBUF;
    311 
    312 	ktrkuser("msgcontrol", mtod(ctl_mbuf, void *),
    313 	    mp->msg_controllen);
    314 
    315 	return 0;
    316 
    317 failure:
    318 	if (control != mtod(ctl_mbuf, void *))
    319 		free(control, M_MBUF);
    320 	m_free(ctl_mbuf);
    321 	return error;
    322 }
    323 
    324 int
    325 netbsd32_sendmsg(struct lwp *l, const struct netbsd32_sendmsg_args *uap, register_t *retval)
    326 {
    327 	/* {
    328 		syscallarg(int) s;
    329 		syscallarg(const netbsd32_msghdrp_t) msg;
    330 		syscallarg(int) flags;
    331 	} */
    332 	struct msghdr msg;
    333 	struct netbsd32_msghdr msg32;
    334 	struct iovec aiov[UIO_SMALLIOV], *iov = aiov;
    335 	struct netbsd32_iovec *iov32;
    336 	size_t iovsz;
    337 	int error;
    338 
    339 	error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32));
    340 	if (error)
    341 		return (error);
    342 	netbsd32_to_msghdr(&msg32, &msg);
    343 	msg.msg_flags = 0;
    344 
    345 	if (CMSG32_FIRSTHDR(&msg)) {
    346 		error = copyin32_msg_control(l, &msg);
    347 		if (error)
    348 			return (error);
    349 		/* From here on, msg.msg_control is allocated */
    350 	} else {
    351 		msg.msg_control = NULL;
    352 		msg.msg_controllen = 0;
    353 	}
    354 
    355 	iovsz = msg.msg_iovlen * sizeof(struct iovec);
    356 	if ((u_int)msg.msg_iovlen > UIO_SMALLIOV) {
    357 		if ((u_int)msg.msg_iovlen > IOV_MAX) {
    358 			error = EMSGSIZE;
    359 			goto out;
    360 		}
    361 		iov = kmem_alloc(iovsz, KM_SLEEP);
    362 	}
    363 
    364 	iov32 = NETBSD32PTR64(msg32.msg_iov);
    365 	error = netbsd32_to_iovecin(iov32, iov, msg.msg_iovlen);
    366 	if (error)
    367 		goto out;
    368 	msg.msg_iov = iov;
    369 
    370 	error = do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
    371 	/* msg.msg_control freed by do_sys_sendmsg() */
    372 
    373 	if (iov != aiov)
    374 		kmem_free(iov, iovsz);
    375 	return (error);
    376 
    377 out:
    378 	if (iov != aiov)
    379 		kmem_free(iov, iovsz);
    380 	if (msg.msg_control)
    381 		m_free(msg.msg_control);
    382 	return error;
    383 }
    384 
    385 int
    386 netbsd32_recvfrom(struct lwp *l, const struct netbsd32_recvfrom_args *uap, register_t *retval)
    387 {
    388 	/* {
    389 		syscallarg(int) s;
    390 		syscallarg(netbsd32_voidp) buf;
    391 		syscallarg(netbsd32_size_t) len;
    392 		syscallarg(int) flags;
    393 		syscallarg(netbsd32_sockaddrp_t) from;
    394 		syscallarg(netbsd32_intp) fromlenaddr;
    395 	} */
    396 	struct msghdr	msg;
    397 	struct iovec	aiov;
    398 	int		error;
    399 	struct mbuf	*from;
    400 
    401 	msg.msg_name = NULL;
    402 	msg.msg_iov = &aiov;
    403 	msg.msg_iovlen = 1;
    404 	aiov.iov_base = SCARG_P32(uap, buf);
    405 	aiov.iov_len = SCARG(uap, len);
    406 	msg.msg_control = NULL;
    407 	msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS;
    408 
    409 	error = do_sys_recvmsg(l, SCARG(uap, s), &msg, &from, NULL, retval);
    410 	if (error != 0)
    411 		return error;
    412 
    413 	error = copyout_sockname(SCARG_P32(uap, from), SCARG_P32(uap, fromlenaddr),
    414 	    MSG_LENUSRSPACE, from);
    415 	if (from != NULL)
    416 		m_free(from);
    417 	return error;
    418 }
    419 
    420 int
    421 netbsd32_sendto(struct lwp *l, const struct netbsd32_sendto_args *uap, register_t *retval)
    422 {
    423 	/* {
    424 		syscallarg(int) s;
    425 		syscallarg(const netbsd32_voidp) buf;
    426 		syscallarg(netbsd32_size_t) len;
    427 		syscallarg(int) flags;
    428 		syscallarg(const netbsd32_sockaddrp_t) to;
    429 		syscallarg(int) tolen;
    430 	} */
    431 	struct msghdr msg;
    432 	struct iovec aiov;
    433 
    434 	msg.msg_name = SCARG_P32(uap, to); /* XXX kills const */
    435 	msg.msg_namelen = SCARG(uap, tolen);
    436 	msg.msg_iov = &aiov;
    437 	msg.msg_iovlen = 1;
    438 	msg.msg_control = 0;
    439 	aiov.iov_base = SCARG_P32(uap, buf);	/* XXX kills const */
    440 	aiov.iov_len = SCARG(uap, len);
    441 	msg.msg_flags = 0;
    442 	return do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
    443 }
    444