Wed Jul 22 14:25:39 2015 UTC ()
Memory leak, triggerable from an unprivileged user.


(maxv)
diff -r1.41 -r1.42 src/sys/compat/netbsd32/netbsd32_socket.c

cvs diff -r1.41 -r1.42 src/sys/compat/netbsd32/netbsd32_socket.c (switch to unified diff)

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