]> granicus.if.org Git - strace/blob - netlink.c
Update MADV_* constants
[strace] / netlink.c
1 /*
2  * Copyright (c) 2016 Fabien Siron <fabien.siron@epita.fr>
3  * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
4  * Copyright (c) 2016-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 #include <linux/audit.h>
34 #include <linux/rtnetlink.h>
35 #include <linux/xfrm.h>
36 #include "xlat/netlink_ack_flags.h"
37 #include "xlat/netlink_flags.h"
38 #include "xlat/netlink_get_flags.h"
39 #include "xlat/netlink_new_flags.h"
40 #include "xlat/netlink_protocols.h"
41 #include "xlat/netlink_types.h"
42 #include "xlat/nl_audit_types.h"
43 #include "xlat/nl_crypto_types.h"
44 #include "xlat/nl_netfilter_msg_types.h"
45 #include "xlat/nl_netfilter_subsys_ids.h"
46 #include "xlat/nl_selinux_types.h"
47 #include "xlat/nl_sock_diag_types.h"
48 #include "xlat/nl_xfrm_types.h"
49 #include "xlat/nlmsgerr_attrs.h"
50
51 /*
52  * Fetch a struct nlmsghdr from the given address.
53  */
54 static bool
55 fetch_nlmsghdr(struct tcb *const tcp, struct nlmsghdr *const nlmsghdr,
56                const kernel_ulong_t addr, const kernel_ulong_t len)
57 {
58         if (len < sizeof(struct nlmsghdr)) {
59                 printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
60                 return false;
61         }
62
63         if (umove_or_printaddr(tcp, addr, nlmsghdr))
64                 return false;
65
66         return true;
67 }
68
69 static int
70 get_fd_nl_family(struct tcb *const tcp, const int fd)
71 {
72         const unsigned long inode = getfdinode(tcp, fd);
73         if (!inode)
74                 return -1;
75
76         const char *const details = get_sockaddr_by_inode(tcp, fd, inode);
77         if (!details)
78                 return -1;
79
80         const char *const nl_details = STR_STRIP_PREFIX(details, "NETLINK:[");
81         if (nl_details == details)
82                 return -1;
83
84         const struct xlat *xlats = netlink_protocols;
85         for (; xlats->str; ++xlats) {
86                 const char *name = STR_STRIP_PREFIX(xlats->str, "NETLINK_");
87                 if (!strncmp(nl_details, name, strlen(name)))
88                         return xlats->val;
89         }
90
91         if (*nl_details >= '0' && *nl_details <= '9')
92                 return atoi(nl_details);
93
94         return -1;
95 }
96
97 static void
98 decode_nlmsg_type_default(const struct xlat *const xlat,
99                           const uint16_t type,
100                           const char *const dflt)
101 {
102         printxval(xlat, type, dflt);
103 }
104
105 static void
106 decode_nlmsg_type_generic(const struct xlat *const xlat,
107                           const uint16_t type,
108                           const char *const dflt)
109 {
110         printxval(genl_families_xlat(), type, dflt);
111 }
112
113 static void
114 decode_nlmsg_type_netfilter(const struct xlat *const xlat,
115                             const uint16_t type,
116                             const char *const dflt)
117 {
118         /* Reserved control nfnetlink messages first. */
119         const char *const text = xlookup(nl_netfilter_msg_types, type);
120         if (text) {
121                 tprints(text);
122                 return;
123         }
124
125         /*
126          * Other netfilter message types are split
127          * in two pieces: 8 bits subsystem and 8 bits type.
128          */
129         const uint8_t subsys_id = (uint8_t) (type >> 8);
130         const uint8_t msg_type = (uint8_t) type;
131
132         printxval(xlat, subsys_id, dflt);
133
134         /*
135          * The type is subsystem specific,
136          * print it in numeric format for now.
137          */
138         tprintf("<<8|%#x", msg_type);
139 }
140
141 typedef void (*nlmsg_types_decoder_t)(const struct xlat *,
142                                       uint16_t type,
143                                       const char *dflt);
144
145 static const struct {
146         const nlmsg_types_decoder_t decoder;
147         const struct xlat *const xlat;
148         const char *const dflt;
149 } nlmsg_types[] = {
150         [NETLINK_AUDIT] = { NULL, nl_audit_types, "AUDIT_???" },
151         [NETLINK_CRYPTO] = { NULL, nl_crypto_types, "CRYPTO_MSG_???" },
152         [NETLINK_GENERIC] = {
153                 decode_nlmsg_type_generic,
154                 NULL,
155                 "GENERIC_FAMILY_???"
156         },
157         [NETLINK_NETFILTER] = {
158                 decode_nlmsg_type_netfilter,
159                 nl_netfilter_subsys_ids,
160                 "NFNL_SUBSYS_???"
161         },
162         [NETLINK_ROUTE] = { NULL, nl_route_types, "RTM_???" },
163         [NETLINK_SELINUX] = { NULL, nl_selinux_types, "SELNL_MSG_???" },
164         [NETLINK_SOCK_DIAG] = { NULL, nl_sock_diag_types, "SOCK_DIAG_???" },
165         [NETLINK_XFRM] = { NULL, nl_xfrm_types, "XFRM_MSG_???" }
166 };
167
168 /*
169  * As all valid netlink families are positive integers, use unsigned int
170  * for family here to filter out -1.
171  */
172 static void
173 decode_nlmsg_type(const uint16_t type, const unsigned int family)
174 {
175         nlmsg_types_decoder_t decoder = decode_nlmsg_type_default;
176         const struct xlat *xlat = netlink_types;
177         const char *dflt = "NLMSG_???";
178
179         /*
180          * type < NLMSG_MIN_TYPE are reserved control messages
181          * that need no family-specific decoding.
182          */
183         if (type >= NLMSG_MIN_TYPE && family < ARRAY_SIZE(nlmsg_types)) {
184                 if (nlmsg_types[family].decoder)
185                         decoder = nlmsg_types[family].decoder;
186                 if (nlmsg_types[family].xlat)
187                         xlat = nlmsg_types[family].xlat;
188                 if (nlmsg_types[family].dflt)
189                         dflt = nlmsg_types[family].dflt;
190         }
191
192         decoder(xlat, type, dflt);
193 }
194
195 static void
196 decode_nlmsg_flags(const uint16_t flags, const uint16_t type, const int family)
197 {
198         const struct xlat *table = NULL;
199
200         if (type < NLMSG_MIN_TYPE) {
201                 if (type == NLMSG_ERROR)
202                         table = netlink_ack_flags;
203                 goto end;
204         }
205
206         switch (family) {
207         case NETLINK_CRYPTO:
208                 switch (type) {
209                 case CRYPTO_MSG_NEWALG:
210                         table = netlink_new_flags;
211                         break;
212                 case CRYPTO_MSG_GETALG:
213                         table = netlink_get_flags;
214                         break;
215                 }
216                 break;
217         case NETLINK_SOCK_DIAG:
218                 table = netlink_get_flags;
219                 break;
220         case NETLINK_ROUTE:
221                 if (type == RTM_DELACTION) {
222                         table = netlink_get_flags;
223                         break;
224                 }
225                 switch (type & 3) {
226                 case  0:
227                         table = netlink_new_flags;
228                         break;
229                 case  2:
230                         table = netlink_get_flags;
231                         break;
232                 }
233                 break;
234         case NETLINK_XFRM:
235                 switch (type) {
236                 case XFRM_MSG_NEWSA:
237                 case XFRM_MSG_NEWPOLICY:
238                 case XFRM_MSG_NEWAE:
239                 case XFRM_MSG_NEWSADINFO:
240                 case XFRM_MSG_NEWSPDINFO:
241                         table = netlink_new_flags;
242                         break;
243
244                 case XFRM_MSG_GETSA:
245                 case XFRM_MSG_GETPOLICY:
246                 case XFRM_MSG_GETAE:
247                 case XFRM_MSG_GETSADINFO:
248                 case XFRM_MSG_GETSPDINFO:
249                         table = netlink_get_flags;
250                         break;
251                 }
252                 break;
253         }
254
255 end:
256         printflags_ex(flags, "NLM_F_???", netlink_flags, table, NULL);
257 }
258
259 static void
260 print_nlmsghdr(struct tcb *tcp,
261                const int fd,
262                const int family,
263                const struct nlmsghdr *const nlmsghdr)
264 {
265         /* print the whole structure regardless of its nlmsg_len */
266
267         tprintf("{len=%u, type=", nlmsghdr->nlmsg_len);
268
269         decode_nlmsg_type(nlmsghdr->nlmsg_type, family);
270
271         tprints(", flags=");
272         decode_nlmsg_flags(nlmsghdr->nlmsg_flags,
273                            nlmsghdr->nlmsg_type, family);
274
275         tprintf(", seq=%u, pid=%u}", nlmsghdr->nlmsg_seq,
276                 nlmsghdr->nlmsg_pid);
277 }
278
279 static bool
280 print_cookie(struct tcb *const tcp, void *const elem_buf,
281              const size_t elem_size, void *const opaque_data)
282 {
283         tprintf("%" PRIu8, *(uint8_t *) elem_buf);
284
285         return true;
286 }
287
288 static bool
289 decode_nlmsgerr_attr_cookie(struct tcb *const tcp,
290                             const kernel_ulong_t addr,
291                             const unsigned int len,
292                             const void *const opaque_data)
293 {
294         uint8_t cookie;
295         const size_t nmemb = len / sizeof(cookie);
296
297         print_array(tcp, addr, nmemb, &cookie, sizeof(cookie),
298                     umoven_or_printaddr, print_cookie, 0);
299
300         return true;
301 }
302
303 static const nla_decoder_t nlmsgerr_nla_decoders[] = {
304         [NLMSGERR_ATTR_MSG]     = decode_nla_str,
305         [NLMSGERR_ATTR_OFFS]    = decode_nla_u32,
306         [NLMSGERR_ATTR_COOKIE]  = decode_nlmsgerr_attr_cookie
307 };
308
309 static void
310 decode_nlmsghdr_with_payload(struct tcb *const tcp,
311                              const int fd,
312                              const int family,
313                              const struct nlmsghdr *const nlmsghdr,
314                              const kernel_ulong_t addr,
315                              const kernel_ulong_t len);
316
317 static void
318 decode_nlmsgerr(struct tcb *const tcp,
319                 const int fd,
320                 const int family,
321                 kernel_ulong_t addr,
322                 unsigned int len,
323                 const bool capped)
324 {
325         struct nlmsgerr err;
326
327         if (len < sizeof(err.error)) {
328                 printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
329                 return;
330         }
331
332         if (umove_or_printaddr(tcp, addr, &err.error))
333                 return;
334
335         tprints("{error=");
336         if (err.error < 0 && (unsigned) -err.error < nerrnos) {
337                 tprintf("-%s", errnoent[-err.error]);
338         } else {
339                 tprintf("%d", err.error);
340         }
341
342         addr += offsetof(struct nlmsgerr, msg);
343         len -= offsetof(struct nlmsgerr, msg);
344
345         if (len) {
346                 tprints(", msg=");
347                 if (fetch_nlmsghdr(tcp, &err.msg, addr, len)) {
348                         unsigned int payload =
349                                 capped ? sizeof(err.msg) : err.msg.nlmsg_len;
350                         if (payload > len)
351                                 payload = len;
352
353                         decode_nlmsghdr_with_payload(tcp, fd, family,
354                                                      &err.msg, addr, payload);
355                         if (len > payload) {
356                                 tprints(", ");
357                                 decode_nlattr(tcp, addr + payload,
358                                               len - payload, nlmsgerr_attrs,
359                                               "NLMSGERR_ATTR_???",
360                                               nlmsgerr_nla_decoders,
361                                               ARRAY_SIZE(nlmsgerr_nla_decoders),
362                                               NULL);
363                         }
364                 }
365         }
366
367         tprints("}");
368 }
369
370 static const netlink_decoder_t netlink_decoders[] = {
371 #ifdef HAVE_LINUX_CRYPTOUSER_H
372         [NETLINK_CRYPTO] = decode_netlink_crypto,
373 #endif
374         [NETLINK_ROUTE] = decode_netlink_route,
375         [NETLINK_SELINUX] = decode_netlink_selinux,
376         [NETLINK_SOCK_DIAG] = decode_netlink_sock_diag
377 };
378
379 static void
380 decode_payload(struct tcb *const tcp,
381                const int fd,
382                const int family,
383                const struct nlmsghdr *const nlmsghdr,
384                const kernel_ulong_t addr,
385                const unsigned int len)
386 {
387         if (nlmsghdr->nlmsg_type == NLMSG_ERROR) {
388                 decode_nlmsgerr(tcp, fd, family, addr, len,
389                                 nlmsghdr->nlmsg_flags & NLM_F_CAPPED);
390                 return;
391         }
392
393         /*
394          * While most of NLMSG_DONE messages indeed have payloads
395          * containing just a single integer, there are few exceptions,
396          * so pass payloads of NLMSG_DONE messages to family-specific
397          * netlink payload decoders.
398          *
399          * Other types of reserved control messages need no family-specific
400          * netlink payload decoding.
401          */
402         if ((nlmsghdr->nlmsg_type >= NLMSG_MIN_TYPE
403             || nlmsghdr->nlmsg_type == NLMSG_DONE)
404             && (unsigned int) family < ARRAY_SIZE(netlink_decoders)
405             && netlink_decoders[family]
406             && netlink_decoders[family](tcp, nlmsghdr, addr, len)) {
407                 return;
408         }
409
410         if (nlmsghdr->nlmsg_type == NLMSG_DONE && len == sizeof(int)) {
411                 int num;
412
413                 if (!umove_or_printaddr(tcp, addr, &num))
414                         tprintf("%d", num);
415                 return;
416         }
417
418         printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
419 }
420
421 static void
422 decode_nlmsghdr_with_payload(struct tcb *const tcp,
423                              const int fd,
424                              const int family,
425                              const struct nlmsghdr *const nlmsghdr,
426                              const kernel_ulong_t addr,
427                              const kernel_ulong_t len)
428 {
429         const unsigned int nlmsg_len =
430                 nlmsghdr->nlmsg_len > len ? len : nlmsghdr->nlmsg_len;
431
432         if (nlmsg_len > NLMSG_HDRLEN)
433                 tprints("{");
434
435         print_nlmsghdr(tcp, fd, family, nlmsghdr);
436
437         if (nlmsg_len > NLMSG_HDRLEN) {
438                 tprints(", ");
439                 decode_payload(tcp, fd, family, nlmsghdr, addr + NLMSG_HDRLEN,
440                                                      nlmsg_len - NLMSG_HDRLEN);
441                 tprints("}");
442         }
443 }
444
445 void
446 decode_netlink(struct tcb *const tcp,
447                const int fd,
448                kernel_ulong_t addr,
449                kernel_ulong_t len)
450 {
451         const int family = get_fd_nl_family(tcp, fd);
452
453         if (family == NETLINK_KOBJECT_UEVENT) {
454                 printstrn(tcp, addr, len);
455                 return;
456         }
457
458         struct nlmsghdr nlmsghdr;
459         bool print_array = false;
460         unsigned int elt;
461
462         for (elt = 0; fetch_nlmsghdr(tcp, &nlmsghdr, addr, len); elt++) {
463                 if (abbrev(tcp) && elt == max_strlen) {
464                         tprints("...");
465                         break;
466                 }
467
468                 unsigned int nlmsg_len = NLMSG_ALIGN(nlmsghdr.nlmsg_len);
469                 kernel_ulong_t next_addr = 0;
470                 kernel_ulong_t next_len = 0;
471
472                 if (nlmsghdr.nlmsg_len >= NLMSG_HDRLEN) {
473                         next_len = (len >= nlmsg_len) ? len - nlmsg_len : 0;
474
475                         if (next_len && addr + nlmsg_len > addr)
476                                 next_addr = addr + nlmsg_len;
477                 }
478
479                 if (!print_array && next_addr) {
480                         tprints("[");
481                         print_array = true;
482                 }
483
484                 decode_nlmsghdr_with_payload(tcp, fd, family,
485                                              &nlmsghdr, addr, len);
486
487                 if (!next_addr)
488                         break;
489
490                 tprints(", ");
491                 addr = next_addr;
492                 len = next_len;
493         }
494
495         if (print_array) {
496                 tprints("]");
497         }
498 }