]> granicus.if.org Git - strace/blob - netlink_sock_diag.c
netlink_sock_diag: ensure that structure field names are printed properly
[strace] / netlink_sock_diag.c
1 /*
2  * Copyright (c) 2016 Fabien Siron <fabien.siron@epita.fr>
3  * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
4  * Copyright (c) 2017 The strace developers.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "defs.h"
31 #include "netlink.h"
32 #include "nlattr.h"
33
34 #include <arpa/inet.h>
35 #include <linux/inet_diag.h>
36 #include <linux/netlink_diag.h>
37 #include <linux/packet_diag.h>
38 #ifdef AF_SMC
39 # include <linux/smc_diag.h>
40 #endif
41 #include <linux/unix_diag.h>
42
43 #include "xlat/inet_diag_extended_flags.h"
44
45 #include "xlat/tcp_states.h"
46 #include "xlat/tcp_state_flags.h"
47
48 #include "xlat/netlink_diag_show.h"
49 #include "xlat/netlink_states.h"
50
51 #include "xlat/packet_diag_show.h"
52
53 #ifdef AF_SMC
54 # include "xlat/smc_diag_extended_flags.h"
55 # include "xlat/smc_states.h"
56 #endif
57
58 #include "xlat/unix_diag_attrs.h"
59 #include "xlat/unix_diag_show.h"
60
61 #define PRINT_FIELD_U(prefix_, where_, field_)                          \
62         tprintf("%s%s=%llu", (prefix_), #field_,                        \
63                 zero_extend_signed_to_ull((where_).field_))
64
65 #define PRINT_FIELD_COOKIE(prefix_, where_, field_)                     \
66         tprintf("%s%s=[%llu, %llu]", (prefix_), #field_,                \
67                 zero_extend_signed_to_ull((where_).field_[0]),          \
68                 zero_extend_signed_to_ull((where_).field_[1]))
69
70 #define PRINT_FIELD_FLAGS(prefix_, where_, field_, xlat_, dflt_)        \
71         do {                                                            \
72                 tprintf("%s%s=", (prefix_), #field_);                   \
73                 printflags((xlat_), (where_).field_, (dflt_));          \
74         } while (0)
75
76 #define PRINT_FIELD_XVAL(prefix_, where_, field_, xlat_, dflt_)         \
77         do {                                                            \
78                 tprintf("%s%s=", (prefix_), #field_);                   \
79                 printxval((xlat_), (where_).field_, (dflt_));           \
80         } while (0)
81
82 static void
83 decode_family(struct tcb *const tcp, const uint8_t family,
84               const kernel_ulong_t addr, const kernel_ulong_t len)
85 {
86         tprints("{family=");
87         printxval(addrfams, family, "AF_???");
88         if (len > sizeof(family)) {
89                 tprints(", ");
90                 printstrn(tcp, addr + sizeof(family),
91                           len - sizeof(family));
92         }
93         tprints("}");
94 }
95
96 static void
97 decode_unix_diag_req(struct tcb *const tcp,
98                      const struct nlmsghdr *const nlmsghdr,
99                      const uint8_t family,
100                      const kernel_ulong_t addr,
101                      const kernel_ulong_t len)
102 {
103         struct unix_diag_req req = { .sdiag_family = family };
104         const size_t offset = sizeof(req.sdiag_family);
105
106         PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???");
107         tprints(", ");
108         if (len >= sizeof(req)) {
109                 if (!umoven_or_printaddr(tcp, addr + offset,
110                                          sizeof(req) - offset,
111                                          (void *) &req + offset)) {
112                         PRINT_FIELD_U("", req, sdiag_protocol);
113                         PRINT_FIELD_FLAGS(", ", req, udiag_states,
114                                           tcp_state_flags, "1<<TCP_???");
115                         PRINT_FIELD_U(", ", req, udiag_ino);
116                         PRINT_FIELD_FLAGS(", ", req, udiag_show,
117                                           unix_diag_show, "UDIAG_SHOW_???");
118                         PRINT_FIELD_COOKIE(", ", req, udiag_cookie);
119                 }
120         } else
121                 tprints("...");
122         tprints("}");
123 }
124
125 static void
126 decode_unix_diag_msg(struct tcb *const tcp,
127                      const struct nlmsghdr *const nlmsghdr,
128                      const uint8_t family,
129                      const kernel_ulong_t addr,
130                      const kernel_ulong_t len)
131 {
132         struct unix_diag_msg msg = { .udiag_family = family };
133         size_t offset = sizeof(msg.udiag_family);
134         bool decode_nla = false;
135
136         PRINT_FIELD_XVAL("{", msg, udiag_family, addrfams, "AF_???");
137         tprints(", ");
138         if (len >= sizeof(msg)) {
139                 if (!umoven_or_printaddr(tcp, addr + offset,
140                                          sizeof(msg) - offset,
141                                          (void *) &msg + offset)) {
142                         PRINT_FIELD_XVAL("", msg, udiag_type,
143                                          socktypes, "SOCK_???");
144                         PRINT_FIELD_XVAL(", ", msg, udiag_state,
145                                          tcp_states, "TCP_???");
146                         PRINT_FIELD_U(", ", msg, udiag_ino);
147                         PRINT_FIELD_COOKIE(", ", msg, udiag_cookie);
148                         decode_nla = true;
149                 }
150         } else
151                 tprints("...");
152         tprints("}");
153
154         offset = NLMSG_ALIGN(sizeof(msg));
155         if (decode_nla && len > offset) {
156                 tprints(", ");
157                 decode_nlattr(tcp, addr + offset, len - offset,
158                               unix_diag_attrs, "UNIX_DIAG_???");
159         }
160 }
161
162 static void
163 decode_netlink_diag_req(struct tcb *const tcp,
164                         const struct nlmsghdr *const nlmsghdr,
165                         const uint8_t family,
166                         const kernel_ulong_t addr,
167                         const kernel_ulong_t len)
168 {
169         struct netlink_diag_req req = { .sdiag_family = family };
170         const size_t offset = sizeof(req.sdiag_family);
171
172         PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???");
173         tprints(", ");
174         if (len >= sizeof(req)) {
175                 if (!umoven_or_printaddr(tcp, addr + offset,
176                                          sizeof(req) - offset,
177                                          (void *) &req + offset)) {
178                         if (NDIAG_PROTO_ALL == req.sdiag_protocol)
179                                 tprintf("%s=%s",
180                                         "sdiag_protocol", "NDIAG_PROTO_ALL");
181                         else
182                                 PRINT_FIELD_XVAL("", req, sdiag_protocol,
183                                                  netlink_protocols,
184                                                  "NETLINK_???");
185                         PRINT_FIELD_U(", ", req, ndiag_ino);
186                         PRINT_FIELD_FLAGS(", ", req, ndiag_show,
187                                           netlink_diag_show, "NDIAG_SHOW_???");
188                         PRINT_FIELD_COOKIE(", ", req, ndiag_cookie);
189                 }
190         } else
191                 tprints("...");
192         tprints("}");
193 }
194
195 static void
196 decode_netlink_diag_msg(struct tcb *const tcp,
197                         const struct nlmsghdr *const nlmsghdr,
198                         const uint8_t family,
199                         const kernel_ulong_t addr,
200                         const kernel_ulong_t len)
201 {
202         struct netlink_diag_msg msg = { .ndiag_family = family };
203         const size_t offset = sizeof(msg.ndiag_family);
204
205         PRINT_FIELD_XVAL("{", msg, ndiag_family, addrfams, "AF_???");
206         tprints(", ");
207         if (len >= sizeof(msg)) {
208                 if (!umoven_or_printaddr(tcp, addr + offset,
209                                          sizeof(msg) - offset,
210                                          (void *) &msg + offset)) {
211                         PRINT_FIELD_XVAL("", msg, ndiag_type,
212                                          socktypes, "SOCK_???");
213                         PRINT_FIELD_XVAL(", ", msg, ndiag_protocol,
214                                          netlink_protocols, "NETLINK_???");
215                         PRINT_FIELD_XVAL(", ", msg, ndiag_state,
216                                          netlink_states, "NETLINK_???");
217                         PRINT_FIELD_U(", ", msg, ndiag_portid);
218                         PRINT_FIELD_U(", ", msg, ndiag_dst_portid);
219                         PRINT_FIELD_U(", ", msg, ndiag_dst_group);
220                         PRINT_FIELD_U(", ", msg, ndiag_ino);
221                         PRINT_FIELD_COOKIE(", ", msg, ndiag_cookie);
222                 }
223         } else
224                 tprints("...");
225         tprints("}");
226 }
227
228 static void
229 decode_packet_diag_req(struct tcb *const tcp,
230                        const struct nlmsghdr *const nlmsghdr,
231                        const uint8_t family,
232                        const kernel_ulong_t addr,
233                        const kernel_ulong_t len)
234 {
235         struct packet_diag_req req = { .sdiag_family = family };
236         const size_t offset = sizeof(req.sdiag_family);
237
238         PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???");
239         tprints(", ");
240         if (len >= sizeof(req)) {
241                 if (!umoven_or_printaddr(tcp, addr + offset,
242                                          sizeof(req) - offset,
243                                          (void *) &req + offset)) {
244                         PRINT_FIELD_XVAL("", req, sdiag_protocol,
245                                          ethernet_protocols, "ETH_P_???");
246                         PRINT_FIELD_U(", ", req, pdiag_ino);
247                         PRINT_FIELD_FLAGS(", ", req, pdiag_show,
248                                           packet_diag_show, "PACKET_SHOW_???");
249                         PRINT_FIELD_COOKIE(", ", req, pdiag_cookie);
250                 }
251         } else
252                 tprints("...");
253         tprints("}");
254 }
255
256 static void
257 decode_packet_diag_msg(struct tcb *const tcp,
258                        const struct nlmsghdr *const nlmsghdr,
259                        const uint8_t family,
260                        const kernel_ulong_t addr,
261                        const kernel_ulong_t len)
262 {
263         struct packet_diag_msg msg = { .pdiag_family = family };
264         const size_t offset = sizeof(msg.pdiag_family);
265
266         PRINT_FIELD_XVAL("{", msg, pdiag_family, addrfams, "AF_???");
267         tprints(", ");
268         if (len >= sizeof(msg)) {
269                 if (!umoven_or_printaddr(tcp, addr + offset,
270                                          sizeof(msg) - offset,
271                                          (void *) &msg + offset)) {
272                         PRINT_FIELD_XVAL("", msg, pdiag_type,
273                                          socktypes, "SOCK_???");
274                         PRINT_FIELD_U(", ", msg, pdiag_num);
275                         PRINT_FIELD_U(", ", msg, pdiag_ino);
276                         PRINT_FIELD_COOKIE(", ", msg, pdiag_cookie);
277                 }
278         } else
279                 tprints("...");
280         tprints("}");
281 }
282
283 static void
284 print_inet_diag_sockid(const struct inet_diag_sockid *id, const uint8_t family)
285 {
286         tprintf("{idiag_sport=htons(%u), idiag_dport=htons(%u)",
287                 ntohs(id->idiag_sport), ntohs(id->idiag_dport));
288
289         tprints(", ");
290         print_inet_addr(family, id->idiag_src,
291                         sizeof(id->idiag_src), "idiag_src");
292         tprints(", ");
293         print_inet_addr(family, id->idiag_dst,
294                         sizeof(id->idiag_dst), "idiag_dst");
295
296         PRINT_FIELD_U(", ", *id, idiag_if);
297         PRINT_FIELD_COOKIE(", ", *id, idiag_cookie);
298
299         tprints("}");
300 }
301
302 static void
303 decode_inet_diag_req_compat(struct tcb *const tcp,
304                             const struct nlmsghdr *const nlmsghdr,
305                             const uint8_t family,
306                             const kernel_ulong_t addr,
307                             const kernel_ulong_t len)
308 {
309         struct inet_diag_req req = { .idiag_family = family };
310         const size_t offset = sizeof(req.idiag_family);
311
312         PRINT_FIELD_XVAL("{", req, idiag_family, addrfams, "AF_???");
313         tprints(", ");
314         if (len >= sizeof(req)) {
315                 if (!umoven_or_printaddr(tcp, addr + offset,
316                                          sizeof(req) - offset,
317                                          (void *) &req + offset)) {
318                         PRINT_FIELD_U("", req, idiag_src_len);
319                         PRINT_FIELD_U(", ", req, idiag_dst_len);
320                         PRINT_FIELD_FLAGS(", ", req, idiag_ext,
321                                           inet_diag_extended_flags,
322                                           "1<<INET_DIAG_\?\?\?-1");
323                         tprints(", id=");
324                         print_inet_diag_sockid(&req.id, req.idiag_family);
325                         PRINT_FIELD_FLAGS(", ", req, idiag_states,
326                                           tcp_state_flags, "1<<TCP_???");
327                         PRINT_FIELD_U(", ", req, idiag_dbs);
328                 }
329         } else
330                 tprints("...");
331         tprints("}");
332 }
333
334 static void
335 decode_inet_diag_req_v2(struct tcb *const tcp,
336                         const struct nlmsghdr *const nlmsghdr,
337                         const uint8_t family,
338                         const kernel_ulong_t addr,
339                         const kernel_ulong_t len)
340 {
341         struct inet_diag_req_v2 req = { .sdiag_family = family };
342         const size_t offset = sizeof(req.sdiag_family);
343
344         PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???");
345         tprints(", ");
346         if (len >= sizeof(req)) {
347                 if (!umoven_or_printaddr(tcp, addr + offset,
348                                          sizeof(req) - offset,
349                                          (void *) &req + offset)) {
350                         PRINT_FIELD_XVAL("", req, sdiag_protocol,
351                                          inet_protocols, "IPPROTO_???");
352                         PRINT_FIELD_FLAGS(", ", req, idiag_ext,
353                                           inet_diag_extended_flags,
354                                           "1<<INET_DIAG_\?\?\?-1");
355                         PRINT_FIELD_FLAGS(", ", req, idiag_states,
356                                           tcp_state_flags, "1<<TCP_???");
357                         tprints(", id=");
358                         print_inet_diag_sockid(&req.id, req.sdiag_family);
359                 }
360         } else
361                 tprints("...");
362         tprints("}");
363 }
364
365 static void
366 decode_inet_diag_req(struct tcb *const tcp,
367                      const struct nlmsghdr *const nlmsghdr,
368                      const uint8_t family,
369                      const kernel_ulong_t addr,
370                      const kernel_ulong_t len)
371 {
372         if (nlmsghdr->nlmsg_type == TCPDIAG_GETSOCK
373             || nlmsghdr->nlmsg_type == DCCPDIAG_GETSOCK)
374                 return decode_inet_diag_req_compat(tcp, nlmsghdr,
375                                                    family, addr, len);
376         else
377                 return decode_inet_diag_req_v2(tcp, nlmsghdr,
378                                                family, addr, len);
379 }
380
381 static void
382 decode_inet_diag_msg(struct tcb *const tcp,
383                      const struct nlmsghdr *const nlmsghdr,
384                      const uint8_t family,
385                      const kernel_ulong_t addr,
386                      const kernel_ulong_t len)
387 {
388         struct inet_diag_msg msg = { .idiag_family = family };
389         const size_t offset = sizeof(msg.idiag_family);
390
391         PRINT_FIELD_XVAL("{", msg, idiag_family, addrfams, "AF_???");
392         tprints(", ");
393         if (len >= sizeof(msg)) {
394                 if (!umoven_or_printaddr(tcp, addr + offset,
395                                          sizeof(msg) - offset,
396                                          (void *) &msg + offset)) {
397                         PRINT_FIELD_XVAL("", msg, idiag_state,
398                                          tcp_states, "TCP_???");
399                         PRINT_FIELD_U(", ", msg, idiag_timer);
400                         PRINT_FIELD_U(", ", msg, idiag_retrans);
401                         tprints(", id=");
402                         print_inet_diag_sockid(&msg.id, msg.idiag_family);
403                         PRINT_FIELD_U(", ", msg, idiag_expires);
404                         PRINT_FIELD_U(", ", msg, idiag_rqueue);
405                         PRINT_FIELD_U(", ", msg, idiag_wqueue);
406                         PRINT_FIELD_U(", ", msg, idiag_uid);
407                         PRINT_FIELD_U(", ", msg, idiag_inode);
408                 }
409         } else
410                 tprints("...");
411         tprints("}");
412 }
413
414 #ifdef AF_SMC
415 static void
416 decode_smc_diag_req(struct tcb *const tcp,
417                     const struct nlmsghdr *const nlmsghdr,
418                     const uint8_t family,
419                     const kernel_ulong_t addr,
420                     const kernel_ulong_t len)
421 {
422         struct smc_diag_req req = { .diag_family = family };
423         const size_t offset = sizeof(req.diag_family);
424
425         PRINT_FIELD_XVAL("{", req, diag_family, addrfams, "AF_???");
426         tprints(", ");
427         if (len >= sizeof(req)) {
428                 if (!umoven_or_printaddr(tcp, addr + offset,
429                                          sizeof(req) - offset,
430                                          (void *) &req + offset)) {
431                         PRINT_FIELD_FLAGS("", req, diag_ext,
432                                           smc_diag_extended_flags,
433                                           "1<<SMC_DIAG_\?\?\?-1");
434                         tprints(", id=");
435                         /*
436                          * AF_SMC protocol family socket handler
437                          * keeping the AF_INET sock address.
438                          */
439                         print_inet_diag_sockid(&req.id, AF_INET);
440                 }
441         } else
442                 tprints("...");
443         tprints("}");
444 }
445
446 static void
447 decode_smc_diag_msg(struct tcb *const tcp,
448                     const struct nlmsghdr *const nlmsghdr,
449                     const uint8_t family,
450                     const kernel_ulong_t addr,
451                     const kernel_ulong_t len)
452 {
453         struct smc_diag_msg msg = { .diag_family = family };
454         const size_t offset = sizeof(msg.diag_family);
455
456         PRINT_FIELD_XVAL("{", msg, diag_family, addrfams, "AF_???");
457         tprints(", ");
458         if (len >= sizeof(msg)) {
459                 if (!umoven_or_printaddr(tcp, addr + offset,
460                                          sizeof(msg) - offset,
461                                          (void *) &msg + offset)) {
462                         PRINT_FIELD_XVAL("", msg, diag_state,
463                                          smc_states, "SMC_???");
464                         PRINT_FIELD_U(", ", msg, diag_fallback);
465                         PRINT_FIELD_U(", ", msg, diag_shutdown);
466                         tprints(", id=");
467                         /*
468                          * AF_SMC protocol family socket handler
469                          * keeping the AF_INET sock address.
470                          */
471                         print_inet_diag_sockid(&msg.id, AF_INET);
472                         PRINT_FIELD_U(", ", msg, diag_uid);
473                         PRINT_FIELD_U(", ", msg, diag_inode);
474                 }
475         } else
476                 tprints("...");
477         tprints("}");
478
479 }
480 #endif
481
482 typedef void (*netlink_diag_decoder_t)(struct tcb *,
483                                        const struct nlmsghdr *,
484                                        uint8_t family,
485                                        kernel_ulong_t addr,
486                                        kernel_ulong_t len);
487
488 static const struct {
489         const netlink_diag_decoder_t request, response;
490 } diag_decoders[] = {
491         [AF_INET] = { decode_inet_diag_req, decode_inet_diag_msg },
492         [AF_INET6] = { decode_inet_diag_req, decode_inet_diag_msg },
493         [AF_NETLINK] = { decode_netlink_diag_req, decode_netlink_diag_msg },
494         [AF_PACKET] = { decode_packet_diag_req, decode_packet_diag_msg },
495 #ifdef AF_SMC
496         [AF_SMC] = { decode_smc_diag_req, decode_smc_diag_msg },
497 #endif
498         [AF_UNIX] = { decode_unix_diag_req, decode_unix_diag_msg }
499 };
500
501 bool
502 decode_netlink_sock_diag(struct tcb *const tcp,
503                          const struct nlmsghdr *const nlmsghdr,
504                          const kernel_ulong_t addr,
505                          const kernel_ulong_t len)
506 {
507         uint8_t family;
508
509         if (nlmsghdr->nlmsg_type == NLMSG_DONE)
510                 return false;
511
512         if (!umove_or_printaddr(tcp, addr, &family)) {
513                 if (family < ARRAY_SIZE(diag_decoders)
514                     && len > sizeof(family)) {
515                         const netlink_diag_decoder_t decoder =
516                                 (nlmsghdr->nlmsg_flags & NLM_F_REQUEST)
517                                 ? diag_decoders[family].request
518                                 : diag_decoders[family].response;
519
520                         if (decoder) {
521                                 decoder(tcp, nlmsghdr, family, addr, len);
522                                 return true;
523                         }
524                 }
525
526                 decode_family(tcp, family, addr, len);
527         }
528
529         return true;
530 }