netbsd32_socket.c revision 1.39 1 /* $NetBSD: netbsd32_socket.c,v 1.39 2012/01/20 14:08:07 joerg 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.39 2012/01/20 14:08:07 joerg 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, MAX(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; 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 if (len <= 0)
150 break;
151 }
152
153 free_control_mbuf(l, control, m);
154
155 mp->msg_controllen = q - (char *)mp->msg_control;
156 return error;
157 }
158
159 int
160 netbsd32_recvmsg(struct lwp *l, const struct netbsd32_recvmsg_args *uap, register_t *retval)
161 {
162 /* {
163 syscallarg(int) s;
164 syscallarg(netbsd32_msghdrp_t) msg;
165 syscallarg(int) flags;
166 } */
167 struct netbsd32_msghdr msg32;
168 struct iovec aiov[UIO_SMALLIOV], *iov;
169 struct msghdr msg;
170 int error;
171 struct mbuf *from, *control;
172 size_t iovsz;
173
174 error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32));
175 if (error)
176 return (error);
177
178 iovsz = msg32.msg_iovlen * sizeof(struct iovec);
179 if (msg32.msg_iovlen > UIO_SMALLIOV) {
180 if (msg32.msg_iovlen > IOV_MAX)
181 return (EMSGSIZE);
182 iov = kmem_alloc(iovsz, KM_SLEEP);
183 } else
184 iov = aiov;
185 error = netbsd32_to_iovecin(NETBSD32PTR64(msg32.msg_iov), iov,
186 msg32.msg_iovlen);
187 if (error)
188 goto done;
189
190 msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS;
191 msg.msg_name = NETBSD32PTR64(msg32.msg_name);
192 msg.msg_namelen = msg32.msg_namelen;
193 msg.msg_control = NETBSD32PTR64(msg32.msg_control);
194 msg.msg_controllen = msg32.msg_controllen;
195 msg.msg_iov = iov;
196 msg.msg_iovlen = msg32.msg_iovlen;
197
198 error = do_sys_recvmsg(l, SCARG(uap, s), &msg, &from,
199 msg.msg_control != NULL ? &control : NULL, retval);
200 if (error != 0)
201 goto done;
202
203 if (msg.msg_control != NULL)
204 error = copyout32_msg_control(l, &msg, control);
205
206 if (error == 0)
207 error = copyout_sockname(msg.msg_name, &msg.msg_namelen, 0,
208 from);
209 if (from != NULL)
210 m_free(from);
211 if (error == 0) {
212 ktrkuser("msghdr", &msg, sizeof msg);
213 msg32.msg_namelen = msg.msg_namelen;
214 msg32.msg_controllen = msg.msg_controllen;
215 msg32.msg_flags = msg.msg_flags;
216 error = copyout(&msg32, SCARG_P32(uap, msg), sizeof(msg32));
217 }
218
219 done:
220 if (iov != aiov)
221 kmem_free(iov, iovsz);
222 return (error);
223 }
224
225 static int
226 copyin32_msg_control(struct lwp *l, struct msghdr *mp)
227 {
228 /*
229 * Handle cmsg if there is any.
230 */
231 struct cmsghdr *cmsg, cmsg32, *cc;
232 struct mbuf *ctl_mbuf;
233 ssize_t resid = mp->msg_controllen;
234 size_t clen, cidx = 0, cspace;
235 u_int8_t *control;
236 int error;
237
238 ctl_mbuf = m_get(M_WAIT, MT_CONTROL);
239 clen = MLEN;
240 control = mtod(ctl_mbuf, void *);
241 memset(control, 0, clen);
242
243 cc = CMSG32_FIRSTHDR(mp);
244 do {
245 error = copyin(cc, &cmsg32, sizeof(cmsg32));
246 if (error)
247 goto failure;
248
249 /*
250 * Sanity check the control message length.
251 */
252 if (cmsg32.cmsg_len > resid ||
253 cmsg32.cmsg_len < sizeof(cmsg32)) {
254 error = EINVAL;
255 goto failure;
256 }
257
258 cspace = CMSG_SPACE(cmsg32.cmsg_len - CMSG32_LEN(0));
259
260 /* Check the buffer is big enough */
261 if (__predict_false(cidx + cspace > clen)) {
262 u_int8_t *nc;
263 size_t nclen;
264
265 nclen = cidx + cspace;
266 if (nclen >= PAGE_SIZE) {
267 error = EINVAL;
268 goto failure;
269 }
270 nc = realloc(clen <= MLEN ? NULL : control,
271 nclen, M_TEMP, M_WAITOK);
272 if (!nc) {
273 error = ENOMEM;
274 goto failure;
275 }
276 if (cidx <= MLEN) {
277 /* Old buffer was in mbuf... */
278 memcpy(nc, control, cidx);
279 memset(nc + cidx, 0, nclen - cidx);
280 } else {
281 memset(nc + nclen, 0, nclen - clen);
282 }
283 control = nc;
284 clen = nclen;
285 }
286
287 /* Copy header */
288 cmsg = (void *)&control[cidx];
289 cmsg->cmsg_len = CMSG_LEN(cmsg32.cmsg_len - CMSG32_LEN(0));
290 cmsg->cmsg_level = cmsg32.cmsg_level;
291 cmsg->cmsg_type = cmsg32.cmsg_type;
292
293 /* Copyin the data */
294 error = copyin(CMSG32_DATA(cc), CMSG_DATA(cmsg),
295 cmsg32.cmsg_len - CMSG32_LEN(0));
296 if (error)
297 goto failure;
298
299 resid -= CMSG32_ALIGN(cmsg32.cmsg_len);
300 cidx += cmsg->cmsg_len;
301 } while ((cc = CMSG32_NXTHDR(mp, cc)) && resid > 0);
302
303 /* If we allocated a buffer, attach to mbuf */
304 if (cidx > MLEN) {
305 MEXTADD(ctl_mbuf, control, clen, M_MBUF, NULL, NULL);
306 ctl_mbuf->m_flags |= M_EXT_RW;
307 }
308 control = NULL;
309 mp->msg_controllen = ctl_mbuf->m_len = CMSG_ALIGN(cidx);
310
311 mp->msg_control = ctl_mbuf;
312 mp->msg_flags |= MSG_CONTROLMBUF;
313
314 ktrkuser("msgcontrol", mtod(ctl_mbuf, void *),
315 mp->msg_controllen);
316
317 return 0;
318
319 failure:
320 if (control != mtod(ctl_mbuf, void *))
321 free(control, M_MBUF);
322 m_free(ctl_mbuf);
323 return error;
324 }
325
326 int
327 netbsd32_sendmsg(struct lwp *l, const struct netbsd32_sendmsg_args *uap, register_t *retval)
328 {
329 /* {
330 syscallarg(int) s;
331 syscallarg(const netbsd32_msghdrp_t) msg;
332 syscallarg(int) flags;
333 } */
334 struct msghdr msg;
335 struct netbsd32_msghdr msg32;
336 struct iovec aiov[UIO_SMALLIOV], *iov;
337 struct netbsd32_iovec *iov32;
338 size_t iovsz;
339 int error;
340
341 error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32));
342 if (error)
343 return (error);
344 netbsd32_to_msghdr(&msg32, &msg);
345 msg.msg_flags = 0;
346
347 if (CMSG32_FIRSTHDR(&msg)) {
348 error = copyin32_msg_control(l, &msg);
349 if (error)
350 return (error);
351 } else {
352 msg.msg_control = NULL;
353 msg.msg_controllen = 0;
354 }
355
356 iovsz = msg.msg_iovlen * sizeof(struct iovec);
357 if ((u_int)msg.msg_iovlen > UIO_SMALLIOV) {
358 if ((u_int)msg.msg_iovlen > IOV_MAX)
359 return (EMSGSIZE);
360 iov = kmem_alloc(iovsz, KM_SLEEP);
361 } else
362 iov = aiov;
363
364 iov32 = NETBSD32PTR64(msg32.msg_iov);
365 error = netbsd32_to_iovecin(iov32, iov, msg.msg_iovlen);
366 if (error)
367 goto done;
368 msg.msg_iov = iov;
369
370 error = do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
371 done:
372 if (iov != aiov)
373 kmem_free(iov, iovsz);
374 return (error);
375 }
376
377 int
378 netbsd32_recvfrom(struct lwp *l, const struct netbsd32_recvfrom_args *uap, register_t *retval)
379 {
380 /* {
381 syscallarg(int) s;
382 syscallarg(netbsd32_voidp) buf;
383 syscallarg(netbsd32_size_t) len;
384 syscallarg(int) flags;
385 syscallarg(netbsd32_sockaddrp_t) from;
386 syscallarg(netbsd32_intp) fromlenaddr;
387 } */
388 struct msghdr msg;
389 struct iovec aiov;
390 int error;
391 struct mbuf *from;
392
393 msg.msg_name = NULL;
394 msg.msg_iov = &aiov;
395 msg.msg_iovlen = 1;
396 aiov.iov_base = SCARG_P32(uap, buf);
397 aiov.iov_len = SCARG(uap, len);
398 msg.msg_control = NULL;
399 msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS;
400
401 error = do_sys_recvmsg(l, SCARG(uap, s), &msg, &from, NULL, retval);
402 if (error != 0)
403 return error;
404
405 error = copyout_sockname(SCARG_P32(uap, from), SCARG_P32(uap, fromlenaddr),
406 MSG_LENUSRSPACE, from);
407 if (from != NULL)
408 m_free(from);
409 return error;
410 }
411
412 int
413 netbsd32_sendto(struct lwp *l, const struct netbsd32_sendto_args *uap, register_t *retval)
414 {
415 /* {
416 syscallarg(int) s;
417 syscallarg(const netbsd32_voidp) buf;
418 syscallarg(netbsd32_size_t) len;
419 syscallarg(int) flags;
420 syscallarg(const netbsd32_sockaddrp_t) to;
421 syscallarg(int) tolen;
422 } */
423 struct msghdr msg;
424 struct iovec aiov;
425
426 msg.msg_name = SCARG_P32(uap, to); /* XXX kills const */
427 msg.msg_namelen = SCARG(uap, tolen);
428 msg.msg_iov = &aiov;
429 msg.msg_iovlen = 1;
430 msg.msg_control = 0;
431 aiov.iov_base = SCARG_P32(uap, buf); /* XXX kills const */
432 aiov.iov_len = SCARG(uap, len);
433 msg.msg_flags = 0;
434 return do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
435 }
436