xref: /illumos-gate/usr/src/uts/common/syscall/strcalls.c (revision 2aeafac3612e19716bf8164f89c3c9196342979c)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include <sys/types.h>
34 #include <sys/sysmacros.h>
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/errno.h>
38 #include <sys/vnode.h>
39 #include <sys/file.h>
40 #include <sys/proc.h>
41 #include <sys/stropts.h>
42 #include <sys/stream.h>
43 #include <sys/strsubr.h>
44 #include <sys/fs/fifonode.h>
45 #include <sys/socket.h>
46 #include <sys/socketvar.h>
47 #include <sys/debug.h>
48 
49 /*
50  * STREAMS system calls.
51  */
52 
53 int getmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int *flagsp);
54 int putmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int flags);
55 int getpmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int *prip,
56     int *flagsp);
57 int putpmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int pri,
58     int flags);
59 
60 static int msgio(int fdes, struct strbuf *ctl, struct strbuf *data, int *rval,
61     int mode, unsigned char *prip, int *flagsp);
62 
63 int
64 getmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int *flagsp)
65 {
66 	int error;
67 	int localflags;
68 	int realflags = 0;
69 	unsigned char pri = 0;
70 	int rv = 0;
71 
72 	/*
73 	 * Convert between old flags (localflags) and new flags (realflags).
74 	 */
75 	if (copyin(flagsp, &localflags, sizeof (*flagsp)))
76 		return (set_errno(EFAULT));
77 	switch (localflags) {
78 	case 0:
79 		realflags = MSG_ANY;
80 		break;
81 
82 	case RS_HIPRI:
83 		realflags = MSG_HIPRI;
84 		break;
85 
86 	default:
87 		return (set_errno(EINVAL));
88 	}
89 
90 	if ((error = msgio(fdes, ctl, data, &rv, FREAD, &pri,
91 	    &realflags)) == 0) {
92 		/*
93 		 * massage realflags based on localflags.
94 		 */
95 		if (realflags == MSG_HIPRI)
96 			localflags = RS_HIPRI;
97 		else
98 			localflags = 0;
99 		if (copyout(&localflags, flagsp, sizeof (*flagsp)))
100 			error = EFAULT;
101 	}
102 	if (error != 0)
103 		return (set_errno(error));
104 	return (rv);
105 }
106 
107 int
108 putmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int flags)
109 {
110 	unsigned char pri = 0;
111 	int realflags;
112 	int error;
113 	int rv = 0;
114 
115 	switch (flags) {
116 	case RS_HIPRI:
117 		realflags = MSG_HIPRI;
118 		break;
119 	case (RS_HIPRI|MSG_XPG4):
120 		realflags = MSG_HIPRI|MSG_XPG4;
121 		break;
122 	case MSG_XPG4:
123 		realflags = MSG_BAND|MSG_XPG4;
124 		break;
125 	case 0:
126 		realflags = MSG_BAND;
127 		break;
128 
129 	default:
130 		return (set_errno(EINVAL));
131 	}
132 	error = msgio(fdes, ctl, data, &rv, FWRITE, &pri, &realflags);
133 	if (error != 0)
134 		return (set_errno(error));
135 	return (rv);
136 }
137 
138 
139 int
140 getpmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int *prip,
141     int *flagsp)
142 {
143 	int error;
144 	int flags;
145 	int intpri;
146 	unsigned char pri;
147 	int rv = 0;
148 
149 	if (copyin(flagsp, &flags, sizeof (flags)))
150 		return (set_errno(EFAULT));
151 	if (copyin(prip, &intpri, sizeof (intpri)))
152 		return (set_errno(EFAULT));
153 	if ((intpri > 255) || (intpri < 0))
154 		return (set_errno(EINVAL));
155 	pri = (unsigned char)intpri;
156 	error = msgio(fdes, ctl, data, &rv, FREAD, &pri, &flags);
157 	if (error != 0)
158 		return (set_errno(error));
159 	if (copyout(&flags, flagsp, sizeof (flags)))
160 		return (set_errno(EFAULT));
161 	intpri = (int)pri;
162 	if (copyout(&intpri, prip, sizeof (intpri)))
163 		return (set_errno(EFAULT));
164 	return (rv);
165 }
166 
167 int
168 putpmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int intpri,
169     int flags)
170 {
171 	unsigned char pri;
172 	int rv = 0;
173 	int error;
174 
175 	if ((intpri > 255) || (intpri < 0))
176 		return (set_errno(EINVAL));
177 	pri = (unsigned char)intpri;
178 	error = msgio(fdes, ctl, data, &rv, FWRITE, &pri, &flags);
179 	if (error != 0)
180 		return (set_errno(error));
181 	return (rv);
182 }
183 
184 /*
185  * Common code for getmsg and putmsg calls: check permissions,
186  * copy in args, do preliminary setup, and switch to
187  * appropriate stream routine.
188  */
189 static int
190 msgio(int fdes, struct strbuf *ctl, struct strbuf *data, int *rval,
191     int mode, unsigned char *prip, int *flagsp)
192 {
193 	file_t *fp;
194 	vnode_t *vp;
195 	struct strbuf msgctl, msgdata;
196 	int error;
197 	int flag;
198 	klwp_t *lwp = ttolwp(curthread);
199 	rval_t rv;
200 
201 	if ((fp = getf(fdes)) == NULL)
202 		return (EBADF);
203 	if ((fp->f_flag & mode) == 0) {
204 		releasef(fdes);
205 		return (EBADF);
206 	}
207 	vp = fp->f_vnode;
208 	if (vp->v_type == VFIFO) {
209 		if (vp->v_stream) {
210 			/*
211 			 * must use sd_vnode, could be named pipe
212 			 */
213 			(void) fifo_vfastoff(vp->v_stream->sd_vnode);
214 		} else {
215 			releasef(fdes);
216 			return (ENOSTR);
217 		}
218 	} else if ((vp->v_type != VCHR && vp->v_type != VSOCK) ||
219 		    vp->v_stream == NULL) {
220 		releasef(fdes);
221 		return (ENOSTR);
222 	}
223 	if ((ctl != NULL) &&
224 	    copyin(ctl, &msgctl, sizeof (struct strbuf))) {
225 		releasef(fdes);
226 		return (EFAULT);
227 	}
228 	if ((data != NULL) &&
229 	    copyin(data, &msgdata, sizeof (struct strbuf))) {
230 		releasef(fdes);
231 		return (EFAULT);
232 	}
233 
234 	if (mode == FREAD) {
235 		if (ctl == NULL)
236 			msgctl.maxlen = -1;
237 		if (data == NULL)
238 			msgdata.maxlen = -1;
239 		flag = fp->f_flag;
240 		rv.r_val1 = 0;
241 		if (vp->v_type == VSOCK) {
242 			error = sock_getmsg(vp, &msgctl, &msgdata, prip,
243 			    flagsp, flag, &rv);
244 		} else {
245 			error = strgetmsg(vp, &msgctl, &msgdata, prip,
246 			    flagsp, flag, &rv);
247 		}
248 		*rval = rv.r_val1;
249 		if (error != 0) {
250 			releasef(fdes);
251 			return (error);
252 		}
253 		if (lwp != NULL)
254 			lwp->lwp_ru.msgrcv++;
255 		if (((ctl != NULL) &&
256 		    copyout(&msgctl, ctl, sizeof (struct strbuf))) ||
257 		    ((data != NULL) &&
258 		    copyout(&msgdata, data, sizeof (struct strbuf)))) {
259 			releasef(fdes);
260 			return (EFAULT);
261 		}
262 		releasef(fdes);
263 		return (0);
264 	}
265 
266 	/*
267 	 * FWRITE case
268 	 */
269 	if (ctl == NULL)
270 		msgctl.len = -1;
271 	if (data == NULL)
272 		msgdata.len = -1;
273 	flag = fp->f_flag;
274 	if (vp->v_type == VSOCK) {
275 		error = sock_putmsg(vp, &msgctl, &msgdata, *prip, *flagsp,
276 		    flag);
277 	} else {
278 		error = strputmsg(vp, &msgctl, &msgdata, *prip, *flagsp, flag);
279 	}
280 	releasef(fdes);
281 	if (error == 0 && lwp != NULL)
282 		lwp->lwp_ru.msgsnd++;
283 	return (error);
284 }
285 
286 
287 #if defined(_LP64) && defined(_SYSCALL32)
288 
289 static int msgio32(int fdes, struct strbuf32 *ctl, struct strbuf32 *data,
290     int *rval, int mode, unsigned char *prip, int *flagsp);
291 
292 int
293 getmsg32(int fdes, struct strbuf32 *ctl, struct strbuf32 *data, int32_t *flagsp)
294 {
295 	int error;
296 	int32_t localflags;
297 	int realflags = 0;
298 	unsigned char pri = 0;
299 	int rv = 0;
300 
301 	/*
302 	 * Convert between old flags (localflags) and new flags (realflags).
303 	 */
304 	if (copyin(flagsp, &localflags, sizeof (*flagsp)))
305 		return (set_errno(EFAULT));
306 	switch (localflags) {
307 	case 0:
308 		realflags = MSG_ANY;
309 		break;
310 
311 	case RS_HIPRI:
312 		realflags = MSG_HIPRI;
313 		break;
314 
315 	default:
316 		return (set_errno(EINVAL));
317 	}
318 
319 	if ((error = msgio32(fdes, ctl, data, &rv, FREAD, &pri,
320 	    &realflags)) == 0) {
321 		/*
322 		 * massage realflags based on localflags.
323 		 */
324 		if (realflags == MSG_HIPRI)
325 			localflags = RS_HIPRI;
326 		else
327 			localflags = 0;
328 		if (copyout(&localflags, flagsp, sizeof (*flagsp)))
329 			error = EFAULT;
330 	}
331 	if (error != 0)
332 		return (set_errno(error));
333 	return (rv);
334 }
335 
336 int
337 putmsg32(int fdes, struct strbuf32 *ctl, struct strbuf32 *data, int32_t flags)
338 {
339 	unsigned char pri = 0;
340 	int realflags;
341 	int error;
342 	int rv = 0;
343 
344 	switch (flags) {
345 	case RS_HIPRI:
346 		realflags = MSG_HIPRI;
347 		break;
348 	case (RS_HIPRI|MSG_XPG4):
349 		realflags = MSG_HIPRI|MSG_XPG4;
350 		break;
351 	case MSG_XPG4:
352 		realflags = MSG_BAND|MSG_XPG4;
353 		break;
354 	case 0:
355 		realflags = MSG_BAND;
356 		break;
357 
358 	default:
359 		return (set_errno(EINVAL));
360 	}
361 	error = msgio32(fdes, ctl, data, &rv, FWRITE, &pri, &realflags);
362 	if (error != 0)
363 		return (set_errno(error));
364 	return (rv);
365 }
366 
367 
368 int
369 getpmsg32(int fdes, struct strbuf32 *ctl, struct strbuf32 *data, int32_t *prip,
370     int32_t *flagsp)
371 {
372 	int error;
373 	int32_t flags;
374 	int32_t intpri;
375 	unsigned char pri;
376 	int rv = 0;
377 
378 	if (copyin(flagsp, &flags, sizeof (*flagsp)))
379 		return (set_errno(EFAULT));
380 	if (copyin(prip, &intpri, sizeof (intpri)))
381 		return (set_errno(EFAULT));
382 	if ((intpri > 255) || (intpri < 0))
383 		return (set_errno(EINVAL));
384 	pri = (unsigned char)intpri;
385 	error = msgio32(fdes, ctl, data, &rv, FREAD, &pri, &flags);
386 	if (error != 0)
387 		return (set_errno(error));
388 	if (copyout(&flags, flagsp, sizeof (flags)))
389 		return (set_errno(EFAULT));
390 	intpri = (int)pri;
391 	if (copyout(&intpri, prip, sizeof (intpri)))
392 		return (set_errno(EFAULT));
393 	return (rv);
394 }
395 
396 int
397 putpmsg32(int fdes, struct strbuf32 *ctl, struct strbuf32 *data, int32_t intpri,
398     int32_t flags)
399 {
400 	unsigned char pri;
401 	int rv = 0;
402 	int error;
403 
404 	if ((intpri > 255) || (intpri < 0))
405 		return (set_errno(EINVAL));
406 	pri = (unsigned char)intpri;
407 	error = msgio32(fdes, ctl, data, &rv, FWRITE, &pri, &flags);
408 	if (error != 0)
409 		return (set_errno(error));
410 	return (rv);
411 }
412 
413 /*
414  * Common code for getmsg and putmsg calls: check permissions,
415  * copy in args, do preliminary setup, and switch to
416  * appropriate stream routine.
417  */
418 static int
419 msgio32(int fdes, struct strbuf32 *ctl, struct strbuf32 *data, int *rval,
420     int mode, unsigned char *prip, int *flagsp)
421 {
422 	file_t *fp;
423 	vnode_t *vp;
424 	struct strbuf32 msgctl32, msgdata32;
425 	struct strbuf msgctl, msgdata;
426 	int error;
427 	int flag;
428 	klwp_t *lwp = ttolwp(curthread);
429 	rval_t rv;
430 
431 	if ((fp = getf(fdes)) == NULL)
432 		return (EBADF);
433 	if ((fp->f_flag & mode) == 0) {
434 		releasef(fdes);
435 		return (EBADF);
436 	}
437 	vp = fp->f_vnode;
438 	if (vp->v_type == VFIFO) {
439 		if (vp->v_stream) {
440 			/*
441 			 * must use sd_vnode, could be named pipe
442 			 */
443 			(void) fifo_vfastoff(vp->v_stream->sd_vnode);
444 		} else {
445 			releasef(fdes);
446 			return (ENOSTR);
447 		}
448 	} else if ((vp->v_type != VCHR && vp->v_type != VSOCK) ||
449 		    vp->v_stream == NULL) {
450 		releasef(fdes);
451 		return (ENOSTR);
452 	}
453 	if (ctl != NULL) {
454 		if (copyin(ctl, &msgctl32, sizeof (msgctl32))) {
455 			releasef(fdes);
456 			return (EFAULT);
457 		}
458 		msgctl.len = msgctl32.len;
459 		msgctl.maxlen = msgctl32.maxlen;
460 		msgctl.buf = (caddr_t)(uintptr_t)msgctl32.buf;
461 	}
462 	if (data != NULL) {
463 		if (copyin(data, &msgdata32, sizeof (msgdata32))) {
464 			releasef(fdes);
465 			return (EFAULT);
466 		}
467 		msgdata.len = msgdata32.len;
468 		msgdata.maxlen = msgdata32.maxlen;
469 		msgdata.buf = (caddr_t)(uintptr_t)msgdata32.buf;
470 	}
471 
472 	if (mode == FREAD) {
473 		if (ctl == NULL)
474 			msgctl.maxlen = -1;
475 		if (data == NULL)
476 			msgdata.maxlen = -1;
477 		flag = fp->f_flag;
478 		rv.r_val1 = 0;
479 		if (vp->v_type == VSOCK) {
480 			error = sock_getmsg(vp, &msgctl, &msgdata, prip,
481 			    flagsp, flag, &rv);
482 		} else {
483 			error = strgetmsg(vp, &msgctl, &msgdata, prip,
484 			    flagsp, flag, &rv);
485 		}
486 		*rval = rv.r_val1;
487 		if (error != 0) {
488 			releasef(fdes);
489 			return (error);
490 		}
491 		if (lwp != NULL)
492 			lwp->lwp_ru.msgrcv++;
493 		if (ctl != NULL) {
494 			/* XX64 - range check */
495 			msgctl32.len = msgctl.len;
496 			msgctl32.maxlen = msgctl.maxlen;
497 			msgctl32.buf = (caddr32_t)(uintptr_t)msgctl.buf;
498 			if (copyout(&msgctl32, ctl, sizeof (msgctl32))) {
499 				releasef(fdes);
500 				return (EFAULT);
501 			}
502 		}
503 		if (data != NULL) {
504 			/* XX64 - range check */
505 			msgdata32.len = msgdata.len;
506 			msgdata32.maxlen = msgdata.maxlen;
507 			msgdata32.buf = (caddr32_t)(uintptr_t)msgdata.buf;
508 			if (copyout(&msgdata32, data, sizeof (msgdata32))) {
509 				releasef(fdes);
510 				return (EFAULT);
511 			}
512 		}
513 		releasef(fdes);
514 		return (0);
515 	}
516 
517 	/*
518 	 * FWRITE case
519 	 */
520 	if (ctl == NULL)
521 		msgctl.len = -1;
522 	if (data == NULL)
523 		msgdata.len = -1;
524 	flag = fp->f_flag;
525 	if (vp->v_type == VSOCK) {
526 		error = sock_putmsg(vp, &msgctl, &msgdata, *prip, *flagsp,
527 		    flag);
528 	} else {
529 		error = strputmsg(vp, &msgctl, &msgdata, *prip, *flagsp, flag);
530 	}
531 	releasef(fdes);
532 	if (error == 0 && lwp != NULL)
533 		lwp->lwp_ru.msgsnd++;
534 	return (error);
535 }
536 
537 #endif /* _LP64 && _SYSCALL32 */
538