]> granicus.if.org Git - strace/blob - tests/nlattr.c
1d6e2c42c4900edbd4f7c1cd3f36715a2f4944ed
[strace] / tests / nlattr.c
1 /*
2  * Check decoding of netlink attribute.
3  *
4  * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
5  * Copyright (c) 2017 The strace developers.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "tests.h"
32
33 #include <stdio.h>
34 #include <stdint.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <sys/socket.h>
38 #include <netinet/tcp.h>
39 #include "netlink.h"
40 #include <linux/rtnetlink.h>
41 #include <linux/sock_diag.h>
42 #include <linux/unix_diag.h>
43
44 static void
45 test_nlattr(const int fd)
46 {
47         static const struct msg {
48                 struct nlmsghdr nlh;
49                 struct unix_diag_msg udm;
50         } c_msg = {
51                 .nlh = {
52                         .nlmsg_len = sizeof(struct msg),
53                         .nlmsg_type = SOCK_DIAG_BY_FAMILY,
54                         .nlmsg_flags = NLM_F_DUMP
55                 },
56                 .udm = {
57                         .udiag_family = AF_UNIX,
58                         .udiag_type = SOCK_STREAM,
59                         .udiag_state = TCP_FIN_WAIT1
60                 }
61         };
62         struct msg *msg;
63         struct nlattr *nla;
64         unsigned int msg_len;
65         long rc;
66
67         /* fetch fail: len < sizeof(struct nlattr) */
68         msg_len = NLMSG_SPACE(sizeof(msg->udm)) + 2;
69         msg = tail_memdup(&c_msg, msg_len);
70         memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
71         nla = NLMSG_ATTR(msg, sizeof(msg->udm));
72         memcpy(nla, "12", 2);
73         rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
74         printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
75                ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
76                ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
77                ", udiag_ino=0, udiag_cookie=[0, 0]}, \"\\x31\\x32\"}, %u"
78                ", MSG_DONTWAIT, NULL, 0) = %s\n",
79                fd, msg_len, msg_len, sprintrc(rc));
80
81         /* fetch fail: short read */
82         msg_len = NLMSG_SPACE(sizeof(msg->udm)) + sizeof(*nla);
83         msg = tail_memdup(&c_msg, msg_len - 1);
84         memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
85         rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
86         printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
87                ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
88                ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
89                ", udiag_ino=0, udiag_cookie=[0, 0]}, %p}, %u"
90                ", MSG_DONTWAIT, NULL, 0) = %s\n",
91                fd, msg_len, (void *) msg + NLMSG_SPACE(sizeof(msg->udm)),
92                msg_len, sprintrc(rc));
93
94         /* print one struct nlattr */
95         msg_len = NLMSG_SPACE(sizeof(msg->udm)) + sizeof(*nla);
96         msg = tail_memdup(&c_msg, msg_len);
97         memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
98         nla = NLMSG_ATTR(msg, sizeof(msg->udm));
99         *nla = (struct nlattr) {
100                 .nla_len = sizeof(*nla),
101                 .nla_type = UNIX_DIAG_NAME
102         };
103         rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
104         printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
105                ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
106                ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
107                ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u"
108                ", nla_type=UNIX_DIAG_NAME}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
109                fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
110
111         /* print one struct nlattr with nla_len out of msg_len bounds */
112         nla->nla_len += 8;
113         rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
114         printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
115                ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
116                ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
117                ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u"
118                ", nla_type=UNIX_DIAG_NAME}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
119                fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
120
121         /* print one struct nlattr and some data */
122         msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN + 4;
123         msg = tail_memdup(&c_msg, msg_len);
124         memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
125         nla = NLMSG_ATTR(msg, sizeof(msg->udm));
126         *nla = (struct nlattr) {
127                 .nla_len = NLA_HDRLEN + 4,
128                 .nla_type = UNIX_DIAG_SHUTDOWN + 1
129         };
130         memcpy(RTA_DATA(nla), "1234", 4);
131         rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
132         printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
133                ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
134                ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
135                ", udiag_ino=0, udiag_cookie=[0, 0]}, {{nla_len=%u"
136                ", nla_type=%#x /* UNIX_DIAG_??? */}"
137                ", \"\\x31\\x32\\x33\\x34\"}}"
138                ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
139                fd, msg_len, nla->nla_len, UNIX_DIAG_SHUTDOWN + 1,
140                msg_len, sprintrc(rc));
141
142         /* print one struct nlattr and fetch fail second struct nlattr */
143         msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN + 2;
144         msg = tail_memdup(&c_msg, msg_len);
145         memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
146         nla = NLMSG_ATTR(msg, sizeof(msg->udm));
147         SET_STRUCT(struct nlattr, nla,
148                 .nla_len = NLA_HDRLEN,
149                 .nla_type = UNIX_DIAG_NAME
150         );
151         memcpy(nla + 1, "12", 2);
152         rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
153         printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
154                ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
155                ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
156                ", udiag_ino=0, udiag_cookie=[0, 0]}, [{nla_len=%u"
157                ", nla_type=UNIX_DIAG_NAME}, \"\\x31\\x32\"]}, %u"
158                ", MSG_DONTWAIT, NULL, 0) = %s\n",
159                fd, msg_len, NLA_HDRLEN, msg_len, sprintrc(rc));
160
161         /* print one struct nlattr and short read of second struct nlattr */
162         msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN * 2;
163         msg = tail_memdup(&c_msg, msg_len - 1);
164         memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
165         nla = NLMSG_ATTR(msg, sizeof(msg->udm));
166         SET_STRUCT(struct nlattr, nla,
167                 .nla_len = NLA_HDRLEN,
168                 .nla_type = UNIX_DIAG_NAME
169         );
170         rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
171         printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
172                ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
173                ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
174                ", udiag_ino=0, udiag_cookie=[0, 0]}, [{nla_len=%u"
175                ", nla_type=UNIX_DIAG_NAME}, ... /* %p */]}, %u"
176                ", MSG_DONTWAIT, NULL, 0) = %s\n",
177                fd, msg_len, NLA_HDRLEN, nla + 1, msg_len, sprintrc(rc));
178
179         /* print two struct nlattr */
180         msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN * 2;
181         msg = tail_memdup(&c_msg, msg_len);
182         memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
183         nla = NLMSG_ATTR(msg, sizeof(msg->udm));
184         *nla = (struct nlattr) {
185                 .nla_len = NLA_HDRLEN,
186                 .nla_type = UNIX_DIAG_NAME
187         };
188         *(nla + 1) = (struct nlattr) {
189                 .nla_len = NLA_HDRLEN,
190                 .nla_type = UNIX_DIAG_PEER
191         };
192         rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
193         printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
194                ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
195                ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
196                ", udiag_ino=0, udiag_cookie=[0, 0]}, [{nla_len=%u"
197                ", nla_type=UNIX_DIAG_NAME}, {nla_len=%u"
198                ", nla_type=UNIX_DIAG_PEER}]}, %u"
199                ", MSG_DONTWAIT, NULL, 0) = %s\n",
200                fd, msg_len, nla->nla_len, nla->nla_len,
201                msg_len, sprintrc(rc));
202
203         /* print first nlattr only when its nla_len is less than NLA_HDRLEN */
204         nla->nla_len = NLA_HDRLEN - 1;
205         rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
206         printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
207                ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
208                ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
209                ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u"
210                ", nla_type=UNIX_DIAG_NAME}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
211                fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
212
213         /* unrecognized attribute data, abbreviated output */
214 #define ABBREV_LEN (DEFAULT_STRLEN + 1)
215         msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN * ABBREV_LEN * 2;
216         msg = tail_alloc(msg_len);
217         memcpy(msg, &c_msg, sizeof(c_msg));
218         msg->nlh.nlmsg_len = msg_len;
219         unsigned int i;
220         nla = NLMSG_ATTR(msg, sizeof(msg->udm));
221         for (i = 0; i < ABBREV_LEN; ++i) {
222                 nla[i * 2] = (struct nlattr) {
223                         .nla_len = NLA_HDRLEN * 2 - 1,
224                         .nla_type = UNIX_DIAG_SHUTDOWN + 1 + i
225                 };
226                 fill_memory_ex(&nla[i * 2 + 1], NLA_HDRLEN,
227                                '0' + i, '~' - '0' - i);
228         }
229
230         rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
231         printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
232                ", flags=NLM_F_DUMP, seq=0, pid=0}"
233                ", {udiag_family=AF_UNIX, udiag_type=SOCK_STREAM"
234                ", udiag_state=TCP_FIN_WAIT1, udiag_ino=0"
235                ", udiag_cookie=[0, 0]}, [",
236                fd, msg_len);
237         for (i = 0; i < DEFAULT_STRLEN; ++i) {
238                 if (i)
239                         printf(", ");
240                 printf("{{nla_len=%u, nla_type=%#x /* UNIX_DIAG_??? */}, ",
241                        nla->nla_len, UNIX_DIAG_SHUTDOWN + 1 + i);
242                 print_quoted_hex(&nla[i * 2 + 1], NLA_HDRLEN - 1);
243                 printf("}");
244         }
245         printf(", ...]}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
246                msg_len, sprintrc(rc));
247 }
248
249 static void
250 test_nla_type(const int fd)
251 {
252         static const struct msg {
253                 struct nlmsghdr nlh;
254                 struct unix_diag_msg udm;
255         } c_msg = {
256                 .nlh = {
257                         .nlmsg_len = sizeof(struct msg),
258                         .nlmsg_type = SOCK_DIAG_BY_FAMILY,
259                         .nlmsg_flags = NLM_F_DUMP
260                 },
261                 .udm = {
262                         .udiag_family = AF_UNIX,
263                         .udiag_type = SOCK_STREAM,
264                         .udiag_state = TCP_FIN_WAIT1
265                 }
266         };
267         struct msg *msg;
268         struct nlattr *nla;
269         unsigned int msg_len;
270         long rc;
271
272         msg_len = NLMSG_SPACE(sizeof(msg->udm)) + sizeof(*nla);
273         msg = tail_memdup(&c_msg, msg_len);
274         memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
275         nla = NLMSG_ATTR(msg, sizeof(msg->udm));
276         *nla = (struct nlattr) {
277                 .nla_len = sizeof(*nla),
278                 .nla_type = NLA_F_NESTED | UNIX_DIAG_NAME
279         };
280         rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
281         printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
282                ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
283                ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
284                ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u"
285                ", nla_type=NLA_F_NESTED|UNIX_DIAG_NAME}}"
286                ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
287                fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
288
289         nla->nla_type = NLA_F_NET_BYTEORDER | UNIX_DIAG_NAME;
290         rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
291         printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
292                ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
293                ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
294                ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u"
295                ", nla_type=NLA_F_NET_BYTEORDER|UNIX_DIAG_NAME}}"
296                ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
297                fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
298
299         nla->nla_type = NLA_F_NESTED | NLA_F_NET_BYTEORDER | UNIX_DIAG_NAME;
300         rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
301         printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
302                ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
303                ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
304                ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u"
305                ", nla_type=NLA_F_NESTED|NLA_F_NET_BYTEORDER|UNIX_DIAG_NAME}}"
306                ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
307                fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
308
309         nla->nla_type = NLA_F_NESTED | (UNIX_DIAG_SHUTDOWN + 1);
310         rc = sendto(fd, msg, msg->nlh.nlmsg_len, MSG_DONTWAIT, NULL, 0);
311         printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
312                ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
313                ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
314                ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u"
315                ", nla_type=NLA_F_NESTED|%#x /* UNIX_DIAG_??? */}}"
316                ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
317                fd, msg->nlh.nlmsg_len, nla->nla_len, UNIX_DIAG_SHUTDOWN + 1,
318                msg->nlh.nlmsg_len, sprintrc(rc));
319 }
320
321 int main(void)
322 {
323         skip_if_unavailable("/proc/self/fd/");
324
325         const int fd = create_nl_socket(NETLINK_SOCK_DIAG);
326
327         test_nlattr(fd);
328         test_nla_type(fd);
329
330         puts("+++ exited with 0 +++");
331
332         return 0;
333 }