1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2016 Cyril Hrubis <chrubis@suse.cz>
4 * Copyright (c) 2016 Michal Kubecek <mkubecek@suse.cz>
5 */
6
7 /*
8 * This is a regression test for kernel commit:
9 *
10 * 197c949e7798 udp: properly support MSG_PEEK with truncated buffers
11 *
12 * NOTE: The testcase will hang on upatched stable kernel.
13 */
14
15 #include <string.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22
23 #include "tst_test.h"
24 #include "lapi/socket.h"
25
26 static const char msg[] = "Michael Gilfix was here\341\210\264\r\n";
27 static const unsigned msglen = ARRAY_SIZE(msg) - 1;
28 static unsigned char buff[25];
29 static const int bufflen = ARRAY_SIZE(buff);
30
31 static int sdr, sdw;
32
verify_recvmsg(void)33 static void verify_recvmsg(void)
34 {
35 struct sockaddr_in6 addr_init = {
36 .sin6_family = AF_INET6,
37 .sin6_port = htons(0),
38 .sin6_addr = IN6ADDR_LOOPBACK_INIT,
39 };
40 struct sockaddr_in6 addr_r, addr_w, addr_f;
41 socklen_t addrlen_r, addrlen_w;
42 struct iovec iov = {
43 .iov_base = buff,
44 .iov_len = sizeof(buff),
45 };
46 struct msghdr msghdr = {
47 .msg_name = &addr_f,
48 .msg_namelen = sizeof(addr_f),
49 .msg_iov = &iov,
50 .msg_iovlen = 1,
51 .msg_control = NULL,
52 .msg_controllen = 0,
53 .msg_flags = 0,
54 };
55 int R;
56
57 sdr = SAFE_SOCKET(PF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_IP);
58 SAFE_BIND(sdr, (struct sockaddr*)&addr_init, sizeof(addr_init));
59 addrlen_r = sizeof(addr_r);
60 SAFE_GETSOCKNAME(sdr, (struct sockaddr*)&addr_r, &addrlen_r);
61 sdw = SAFE_SOCKET(PF_INET6, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_IP);
62 SAFE_BIND(sdw, (struct sockaddr*)&addr_init, sizeof(addr_init));
63 addrlen_w = sizeof(addr_w);
64 SAFE_GETSOCKNAME(sdw, (struct sockaddr*)&addr_w, &addrlen_w);
65
66 R = sendto(sdw, msg, msglen, 0, (struct sockaddr*)&addr_r, addrlen_r);
67 if (R < 0)
68 tst_brk(TBROK | TERRNO, "sendto()");
69
70 R = recvmsg(sdr, &msghdr, MSG_PEEK);
71 if (R < 0) {
72 tst_res(TFAIL | TERRNO, "recvmsg(..., MSG_PEEK)");
73 return;
74 }
75
76 tst_res(TINFO, "received %d bytes", R);
77
78 if ((R == bufflen) && !memcmp(msg, buff, R))
79 tst_res(TPASS, "recvmsg(..., MSG_PEEK) works fine");
80 else
81 tst_res(TPASS, "recvmsg(..., MSG_PEEK) failed");
82
83 SAFE_CLOSE(sdw);
84 SAFE_CLOSE(sdr);
85 }
86
cleanup(void)87 static void cleanup(void)
88 {
89 if (sdw > 0)
90 SAFE_CLOSE(sdw);
91
92 if (sdr > 0)
93 SAFE_CLOSE(sdr);
94 }
95
96 static struct tst_test test = {
97 .min_kver = "2.6.27",
98 .test_all = verify_recvmsg,
99 .cleanup = cleanup,
100 .tags = (const struct tst_tag[]) {
101 {"linux-git", "197c949e7798"},
102 {}
103 }
104 };
105