xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/recvmsg/recvmsg01.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2001 Wayne Boyer International Business Machines
4  * Copyright (c) Linux Test Project, 2002-2022
5  * Copyright (c) 2023 Wei Gao <[email protected]>
6  */
7 
8 /*\
9  * [Description]
10  *
11  * Verify that recvmsg() returns the proper errno for various failure cases.
12  */
13 
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <sys/wait.h>
17 #include "tst_test.h"
18 
19 #define MSG "from recvmsg01 server"
20 #define BUF_SIZE 1024
21 #define CONTROL_LEN (128 * 1024)
22 
23 static char recv_buf[BUF_SIZE], cbuf[BUF_SIZE];
24 static int sock;
25 static struct sockaddr_in sin1, from;
26 static struct sockaddr_un sun1;
27 static struct msghdr msgdat;
28 static struct cmsghdr *control;
29 static int controllen;
30 static struct iovec iov[1];
31 static int sfd;			/* shared between do_child and start_server */
32 static int ufd;			/* shared between do_child and start_server */
33 static pid_t pid;
34 static char tmpsunpath[BUF_SIZE];
35 
36 static void setup_all(void);
37 static void setup_invalid_sock(int);
38 static void setup_valid_sock(int);
39 static void setup_valid_msg_control(int);
40 static void setup_large_msg_control(int);
41 static void cleanup_all(void);
42 static void cleanup_invalid_sock(int);
43 static void cleanup_close_sock(int);
44 static void cleanup_reset_all(int);
45 static void do_child(void);
46 static pid_t start_server(struct sockaddr_in *, struct sockaddr_un *);
47 
48 static struct tcase {
49 	int domain;
50 	int type;
51 	int protocol;
52 	struct iovec *iov;
53 	int iovcnt;
54 	void *recv_buf;
55 	int buflen;
56 	struct msghdr *msg;
57 	unsigned int flags;
58 	struct sockaddr *from;
59 	int fromlen;
60 	int exp_errno;
61 	void (*setup)(int n);
62 	void (*cleanup)(int n);
63 	char *desc;
64 } tcases[] = {
65 	{
66 		.domain = PF_INET,
67 		.type = SOCK_STREAM,
68 		.iov = iov,
69 		.iovcnt = 1,
70 		.recv_buf = recv_buf,
71 		.buflen = sizeof(recv_buf),
72 		.msg = &msgdat,
73 		.from = (struct sockaddr *)&from,
74 		.fromlen = sizeof(from),
75 		.exp_errno = EBADF,
76 		.setup = setup_invalid_sock,
77 		.cleanup = cleanup_invalid_sock,
78 		.desc = "bad file descriptor",
79 	},
80 	{
81 		.domain = PF_INET,
82 		.type = SOCK_STREAM,
83 		.iov = iov,
84 		.iovcnt = 1,
85 		.recv_buf = (void *)recv_buf,
86 		.buflen = sizeof(recv_buf),
87 		.msg = &msgdat,
88 		.from = (struct sockaddr *)&from,
89 		.fromlen = sizeof(from),
90 		.exp_errno = ENOTSOCK,
91 		.setup = setup_invalid_sock,
92 		.cleanup = cleanup_invalid_sock,
93 		.desc = "invalid socket",
94 	},
95 	{
96 		.domain = PF_INET,
97 		.type = SOCK_STREAM,
98 		.iov = iov,
99 		.iovcnt = 1,
100 		.recv_buf = (void *)recv_buf,
101 		.buflen = sizeof(recv_buf),
102 		.msg = &msgdat,
103 		.flags = -1,
104 		.from = (struct sockaddr *)&from,
105 		.fromlen = -1,
106 		.exp_errno = EINVAL,
107 		.setup = setup_valid_sock,
108 		.cleanup = cleanup_close_sock,
109 		.desc = "invalid socket length",
110 	},
111 	{
112 		.domain = PF_INET,
113 		.type = SOCK_STREAM,
114 		.iov = iov,
115 		.iovcnt = 1,
116 		.recv_buf = (void *)-1,
117 		.buflen = sizeof(recv_buf),
118 		.msg = &msgdat,
119 		.from = (struct sockaddr *)&from,
120 		.fromlen = sizeof(from),
121 		.exp_errno = EFAULT,
122 		.setup = setup_valid_sock,
123 		.cleanup = cleanup_close_sock,
124 		.desc = "invalid recv buffer",
125 	},
126 	{
127 		.domain = PF_INET,
128 		.type = SOCK_STREAM,
129 		.iovcnt = 1,
130 		.recv_buf = recv_buf,
131 		.buflen = sizeof(recv_buf),
132 		.msg = &msgdat,
133 		.from = (struct sockaddr *)&from,
134 		.fromlen = sizeof(from),
135 		.exp_errno = EFAULT,
136 		.setup = setup_valid_sock,
137 		.cleanup = cleanup_close_sock,
138 		.desc = "invalid iovec buffer",
139 	},
140 	{
141 		.domain = PF_INET,
142 		.type = SOCK_STREAM,
143 		.iov = iov,
144 		.iovcnt = -1,
145 		.recv_buf = recv_buf,
146 		.buflen = sizeof(recv_buf),
147 		.msg = &msgdat,
148 		.from = (struct sockaddr *)&from,
149 		.fromlen = sizeof(from),
150 		.exp_errno = EMSGSIZE,
151 		.setup = setup_valid_sock,
152 		.cleanup = cleanup_close_sock,
153 		.desc = "invalid iovec count",
154 	},
155 	{
156 		.domain = PF_INET,
157 		.type = SOCK_STREAM,
158 		.iov = iov,
159 		.iovcnt = 1,
160 		.recv_buf = recv_buf,
161 		.buflen = sizeof(recv_buf),
162 		.msg = &msgdat,
163 		.from = (struct sockaddr *)&from,
164 		.fromlen = sizeof(from),
165 		.setup = setup_valid_msg_control,
166 		.cleanup = cleanup_reset_all,
167 		.desc = "permission reception",
168 	},
169 	{
170 		.domain = PF_INET,
171 		.type = SOCK_STREAM,
172 		.iov = iov,
173 		.iovcnt = 1,
174 		.recv_buf = recv_buf,
175 		.buflen = sizeof(recv_buf),
176 		.msg = &msgdat,
177 		.flags = MSG_OOB,
178 		.from = (struct sockaddr *)&from,
179 		.fromlen = sizeof(from),
180 		.exp_errno = EINVAL,
181 		.setup = setup_valid_sock,
182 		.cleanup = cleanup_close_sock,
183 		.desc = "invalid MSG_OOB flag set",
184 	},
185 	{
186 		.domain = PF_INET,
187 		.type = SOCK_STREAM,
188 		.iov = iov,
189 		.iovcnt = 1,
190 		.recv_buf = recv_buf,
191 		.buflen = sizeof(recv_buf),
192 		.msg = &msgdat,
193 		.flags = MSG_ERRQUEUE,
194 		.from = (struct sockaddr *)&from,
195 		.fromlen = sizeof(from),
196 		.exp_errno = EAGAIN,
197 		.setup = setup_valid_sock,
198 		.cleanup = cleanup_close_sock,
199 		.desc = "invalid MSG_ERRQUEUE flag set",
200 	},
201 	{
202 		.domain = PF_INET,
203 		.type = SOCK_STREAM,
204 		.iov = iov,
205 		.iovcnt = 1,
206 		.recv_buf = recv_buf,
207 		.buflen = sizeof(recv_buf),
208 		.msg = &msgdat,
209 		.from = (struct sockaddr *)&from,
210 		.fromlen = sizeof(from),
211 		.setup = setup_large_msg_control,
212 		.cleanup = cleanup_reset_all,
213 		.desc = "large cmesg length",
214 	},
215 
216 };
217 
run(unsigned int n)218 static void run(unsigned int n)
219 {
220 	struct tcase *tc = &tcases[n];
221 	int ret = tc->exp_errno ? -1 : 0;
222 
223 	if ((tst_kvercmp(3, 17, 0) < 0)
224 			&& (tc->flags & MSG_ERRQUEUE)
225 			&& (tc->type & SOCK_STREAM)) {
226 		tst_res(TCONF, "MSG_ERRQUEUE requires kernel >= 3.17");
227 		return;
228 	}
229 
230 	setup_all();
231 	tc->setup(n);
232 
233 	iov[0].iov_base = tc->recv_buf;
234 	iov[0].iov_len = tc->buflen;
235 	msgdat.msg_name = tc->from;
236 	msgdat.msg_namelen = tc->fromlen;
237 	msgdat.msg_iov = tc->iov;
238 	msgdat.msg_iovlen = tc->iovcnt;
239 	msgdat.msg_control = control;
240 	msgdat.msg_controllen = controllen;
241 	msgdat.msg_flags = 0;
242 
243 	TEST(recvmsg(sock, tc->msg, tc->flags));
244 	if (TST_RET >= 0)
245 		TST_RET = 0;
246 
247 	if (TST_RET != ret) {
248 		tst_res(TFAIL | TTERRNO, "%s: expected %d, returned %ld",
249 			tc->desc, ret, TST_RET);
250 	} else if (TST_ERR != tc->exp_errno) {
251 		tst_res(TFAIL | TTERRNO,
252 			"%s: expected %s",
253 			tc->desc, tst_strerrno(tc->exp_errno));
254 	} else {
255 		tst_res(TPASS, "%s passed", tc->desc);
256 	}
257 
258 	tc->cleanup(n);
259 	cleanup_all();
260 }
261 
262 
setup_all(void)263 static void setup_all(void)
264 {
265 	int tfd;
266 
267 	sun1.sun_family = AF_UNIX;
268 
269 	(void)strcpy(tmpsunpath, "udsockXXXXXX");
270 	tfd = mkstemp(tmpsunpath);
271 	SAFE_CLOSE(tfd);
272 	SAFE_UNLINK(tmpsunpath);
273 	(void)strcpy(sun1.sun_path, tmpsunpath);
274 	SAFE_SIGNAL(SIGPIPE, SIG_IGN);
275 	pid = start_server(&sin1, &sun1);
276 }
277 
cleanup_all(void)278 static void cleanup_all(void)
279 {
280 	if (pid > 0) {
281 		(void)kill(pid, SIGKILL);	/* kill server */
282 		wait(NULL);
283 	}
284 
285 	if (tmpsunpath[0] != '\0')
286 		(void)SAFE_UNLINK(tmpsunpath);
287 }
288 
setup_invalid_sock(int n)289 static void setup_invalid_sock(int n)
290 {
291 	if (tcases[n].exp_errno == EBADF)
292 		sock = 400;	/* anything not an open file */
293 	else
294 		sock = SAFE_OPEN("/dev/null", O_WRONLY);
295 }
296 
cleanup_invalid_sock(int n)297 static void cleanup_invalid_sock(int n)
298 {
299 	if (tcases[n].exp_errno == EBADF)
300 		sock = -1;
301 	else
302 		SAFE_CLOSE(sock);
303 }
304 
setup_valid_sock(int n)305 static void setup_valid_sock(int n)
306 {
307 	fd_set rdfds;
308 	struct timeval timeout;
309 
310 	sock = SAFE_SOCKET(tcases[n].domain, tcases[n].type, tcases[n].protocol);
311 
312 	if (tcases[n].type == SOCK_STREAM) {
313 		if (tcases[n].domain == PF_INET) {
314 			SAFE_CONNECT(sock, (struct sockaddr *)&sin1, sizeof(sin1));
315 			/* Wait for something to be readable, else we won't detect EFAULT on recv */
316 			FD_ZERO(&rdfds);
317 			FD_SET(sock, &rdfds);
318 			timeout.tv_sec = 2;
319 			timeout.tv_usec = 0;
320 			n = select(sock + 1, &rdfds, 0, 0, &timeout);
321 
322 			if (n != 1 || !FD_ISSET(sock, &rdfds))
323 				tst_brk(TBROK, "no message ready in %d sec", (int)timeout.tv_sec);
324 
325 		} else if (tcases[n].domain == PF_UNIX) {
326 			SAFE_CONNECT(sock, (struct sockaddr *)&sun1, sizeof(sun1));
327 		}
328 	}
329 }
330 
setup_valid_msg_control(int n)331 static void setup_valid_msg_control(int n)
332 {
333 	setup_valid_sock(n);
334 	SAFE_SEND(1, sock, "R", 1, 0);
335 	control = (struct cmsghdr *)cbuf;
336 	controllen = control->cmsg_len = sizeof(cbuf);
337 }
338 
setup_large_msg_control(int n)339 static void setup_large_msg_control(int n)
340 {
341 	setup_valid_msg_control(n);
342 	controllen = CONTROL_LEN;
343 }
344 
cleanup_close_sock(int n LTP_ATTRIBUTE_UNUSED)345 static void cleanup_close_sock(int n LTP_ATTRIBUTE_UNUSED)
346 {
347 	SAFE_CLOSE(sock);
348 }
349 
cleanup_reset_all(int n LTP_ATTRIBUTE_UNUSED)350 static void cleanup_reset_all(int n LTP_ATTRIBUTE_UNUSED)
351 {
352 	SAFE_CLOSE(sock);
353 
354 	control = 0;
355 	controllen = 0;
356 }
357 
start_server(struct sockaddr_in * ssin,struct sockaddr_un * ssun)358 pid_t start_server(struct sockaddr_in *ssin, struct sockaddr_un *ssun)
359 {
360 	pid_t pid;
361 	socklen_t slen = sizeof(*ssin);
362 
363 	ssin->sin_family = AF_INET;
364 	ssin->sin_port = 0; /* pick random free port */
365 	ssin->sin_addr.s_addr = INADDR_ANY;
366 
367 	/* set up inet socket */
368 	sfd = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0);
369 	SAFE_BIND(sfd, (struct sockaddr *)ssin, sizeof(*ssin));
370 	SAFE_LISTEN(sfd, 10);
371 	SAFE_GETSOCKNAME(sfd, (struct sockaddr *)ssin, &slen);
372 
373 	/* set up UNIX-domain socket */
374 	ufd = SAFE_SOCKET(PF_UNIX, SOCK_STREAM, 0);
375 	SAFE_BIND(ufd, (struct sockaddr *)ssun, sizeof(*ssun));
376 	SAFE_LISTEN(ufd, 10);
377 
378 	pid = SAFE_FORK();
379 	if (!pid) {
380 		do_child();
381 		exit(1);
382 	}
383 
384 	SAFE_CLOSE(sfd);
385 	SAFE_CLOSE(ufd);
386 
387 	return pid;
388 }
389 
390 /* for permission test */
sender(int fd)391 static void sender(int fd)
392 {
393 	struct msghdr mh = {};
394 	struct cmsghdr *control;
395 	char tmpfn[BUF_SIZE] = "";
396 	char snd_cbuf[BUF_SIZE] = "";
397 	int tfd;
398 
399 	(void)strcpy(tmpfn, "smtXXXXXX");
400 	tfd = mkstemp(tmpfn);
401 	if (tfd < 0)
402 		return;
403 
404 	/* set up cmsghdr */
405 	control = (struct cmsghdr *)snd_cbuf;
406 	control->cmsg_len = sizeof(struct cmsghdr) + 4;
407 	control->cmsg_level = SOL_SOCKET;
408 	control->cmsg_type = SCM_RIGHTS;
409 	*(int *)CMSG_DATA(control) = tfd;
410 
411 	/* set up msghdr */
412 	iov[0].iov_base = MSG;
413 	iov[0].iov_len = sizeof(MSG);
414 	mh.msg_iov = iov;
415 	mh.msg_iovlen = 1;
416 	mh.msg_flags = 0;
417 	mh.msg_control = control;
418 	mh.msg_controllen = control->cmsg_len;
419 
420 	/* do it */
421 	SAFE_SENDMSG(sizeof(MSG), fd, &mh, 0);
422 	SAFE_CLOSE(tfd);
423 	(void)SAFE_UNLINK(tmpfn);
424 }
425 
do_child(void)426 static void do_child(void)
427 {
428 	struct sockaddr_in fsin;
429 	struct sockaddr_un fsun;
430 	fd_set afds, rfds;
431 	int nfds, fd;
432 
433 	FD_ZERO(&afds);
434 	FD_SET(sfd, &afds);
435 	FD_SET(ufd, &afds);
436 
437 	nfds = MAX(sfd + 1, ufd + 1);
438 
439 	/* accept connections until killed */
440 	while (1) {
441 		socklen_t fromlen;
442 
443 		memcpy(&rfds, &afds, sizeof(rfds));
444 
445 		if (select(nfds, &rfds, NULL, NULL,
446 			   NULL) < 0) {
447 			if (errno != EINTR) {
448 				perror("server select");
449 				exit(1);
450 			}
451 			continue;
452 		}
453 		if (FD_ISSET(sfd, &rfds)) {
454 			int newfd;
455 
456 			fromlen = sizeof(fsin);
457 			newfd = SAFE_ACCEPT(sfd, (struct sockaddr *)&fsin, &fromlen);
458 			if (newfd >= 0) {
459 				FD_SET(newfd, &afds);
460 				nfds = MAX(nfds, newfd + 1);
461 				/* send something back */
462 				SAFE_SEND(1, newfd, "hi", 2, 0);
463 			}
464 		}
465 		if (FD_ISSET(ufd, &rfds)) {
466 			int newfd;
467 
468 			fromlen = sizeof(fsun);
469 			newfd = SAFE_ACCEPT(ufd, (struct sockaddr *)&fsun, &fromlen);
470 			if (newfd >= 0) {
471 				FD_SET(newfd, &afds);
472 				nfds = MAX(nfds, newfd + 1);
473 			}
474 		}
475 		for (fd = 0; fd < nfds; ++fd)
476 			if (fd != sfd && fd != ufd && FD_ISSET(fd, &rfds)) {
477 				char rbuf[BUF_SIZE];
478 
479 				TEST(read(fd, rbuf, sizeof(rbuf)));
480 				if (TST_RET > 0 && rbuf[0] == 'R')
481 					sender(fd);
482 				if (TST_RET == 0 || (TST_RET < 0 && TST_ERR != EINTR)) {
483 					close(fd);
484 					FD_CLR(fd, &afds);
485 				}
486 			}
487 	}
488 }
489 
490 static struct tst_test test = {
491 	.test = run,
492 	.tcnt = ARRAY_SIZE(tcases),
493 	.forks_child = 1,
494 	.needs_tmpdir = 1,
495 };
496