blob: 315d69941a0c42ff922a3e007947a8224cccc970 [file] [log] [blame]
Elliott Hughesdc75b012017-07-05 13:54:44 -07001/*
2 * Copyright (c) 2016 Fabien Siron <fabien.siron@epita.fr>
3 * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
Elliott Hughes28e98bc2018-06-14 16:59:04 -07004 * Copyright (c) 2016-2018 The strace developers.
Elliott Hughesdc75b012017-07-05 13:54:44 -07005 * 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"
Elliott Hughes77c3ff82017-09-08 17:11:00 -070031#include <endian.h>
Elliott Hughesdc75b012017-07-05 13:54:44 -070032#include "netlink.h"
33#include "nlattr.h"
Elliott Hughes77c3ff82017-09-08 17:11:00 -070034#include <netinet/in.h>
35#include <arpa/inet.h>
36#include <linux/sock_diag.h>
Elliott Hughes28e98bc2018-06-14 16:59:04 -070037#include "static_assert.h"
Elliott Hughesdc75b012017-07-05 13:54:44 -070038
Elliott Hughes03a418e2018-06-15 13:11:40 -070039#include "xlat/netlink_sk_meminfo_indices.h"
40
Elliott Hughesdc75b012017-07-05 13:54:44 -070041static bool
42fetch_nlattr(struct tcb *const tcp, struct nlattr *const nlattr,
Elliott Hughes03a418e2018-06-15 13:11:40 -070043 const kernel_ulong_t addr, const unsigned int len,
44 const bool in_array)
Elliott Hughesdc75b012017-07-05 13:54:44 -070045{
46 if (len < sizeof(struct nlattr)) {
Elliott Hughes77c3ff82017-09-08 17:11:00 -070047 printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
Elliott Hughesdc75b012017-07-05 13:54:44 -070048 return false;
49 }
50
Elliott Hughes03a418e2018-06-15 13:11:40 -070051 if (tfetch_obj(tcp, addr, nlattr))
52 return true;
Elliott Hughesdc75b012017-07-05 13:54:44 -070053
Elliott Hughes03a418e2018-06-15 13:11:40 -070054 if (in_array) {
55 tprints("...");
56 printaddr_comment(addr);
57 } else {
58 printaddr(addr);
59 }
60
61 return false;
Elliott Hughesdc75b012017-07-05 13:54:44 -070062}
63
64static void
65print_nlattr(const struct nlattr *const nla,
66 const struct xlat *const table,
67 const char *const dflt)
68{
Elliott Hughes28e98bc2018-06-14 16:59:04 -070069 static_assert(NLA_TYPE_MASK == ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER),
70 "wrong NLA_TYPE_MASK");
71
Elliott Hughesdc75b012017-07-05 13:54:44 -070072 tprintf("{nla_len=%u, nla_type=", nla->nla_len);
Elliott Hughes03a418e2018-06-15 13:11:40 -070073 if (nla->nla_type & NLA_F_NESTED) {
74 print_xlat(NLA_F_NESTED);
75 tprints("|");
76 }
77 if (nla->nla_type & NLA_F_NET_BYTEORDER) {
78 print_xlat(NLA_F_NET_BYTEORDER);
79 tprints("|");
80 }
Elliott Hughesdc75b012017-07-05 13:54:44 -070081 printxval(table, nla->nla_type & NLA_TYPE_MASK, dflt);
82 tprints("}");
83}
84
85static void
86decode_nlattr_with_data(struct tcb *const tcp,
87 const struct nlattr *const nla,
88 const kernel_ulong_t addr,
Elliott Hughes77c3ff82017-09-08 17:11:00 -070089 const unsigned int len,
Elliott Hughesdc75b012017-07-05 13:54:44 -070090 const struct xlat *const table,
91 const char *const dflt,
92 const nla_decoder_t *const decoders,
93 const unsigned int size,
94 const void *const opaque_data)
95{
Elliott Hughes03a418e2018-06-15 13:11:40 -070096 const unsigned int nla_len = MIN(nla->nla_len, len);
Elliott Hughesdc75b012017-07-05 13:54:44 -070097
98 if (nla_len > NLA_HDRLEN)
99 tprints("{");
100
101 print_nlattr(nla, table, dflt);
102
103 if (nla_len > NLA_HDRLEN) {
Elliott Hughesc1873762018-12-19 15:13:36 -0800104 const unsigned int idx =
105 size ? nla->nla_type & NLA_TYPE_MASK : 0;
Elliott Hughes03a418e2018-06-15 13:11:40 -0700106
Elliott Hughesdc75b012017-07-05 13:54:44 -0700107 tprints(", ");
108 if (!decoders
Elliott Hughes03a418e2018-06-15 13:11:40 -0700109 || (size && idx >= size)
110 || !decoders[idx]
111 || !decoders[idx](
112 tcp, addr + NLA_HDRLEN,
113 nla_len - NLA_HDRLEN,
114 size ? opaque_data
115 : (const void *) (uintptr_t) nla->nla_type)
116 )
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700117 printstr_ex(tcp, addr + NLA_HDRLEN,
118 nla_len - NLA_HDRLEN, QUOTE_FORCE_HEX);
Elliott Hughesdc75b012017-07-05 13:54:44 -0700119 tprints("}");
120 }
121}
122
123void
124decode_nlattr(struct tcb *const tcp,
125 kernel_ulong_t addr,
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700126 unsigned int len,
Elliott Hughesdc75b012017-07-05 13:54:44 -0700127 const struct xlat *const table,
128 const char *const dflt,
129 const nla_decoder_t *const decoders,
130 const unsigned int size,
131 const void *const opaque_data)
132{
133 struct nlattr nla;
Elliott Hughes03a418e2018-06-15 13:11:40 -0700134 bool is_array = false;
Elliott Hughesdc75b012017-07-05 13:54:44 -0700135 unsigned int elt;
136
Elliott Hughes03a418e2018-06-15 13:11:40 -0700137 if (decoders && !size && opaque_data)
138 error_func_msg("[xlat %p, dflt \"%s\", decoders %p] "
139 "size is zero (going to pass nla_type as "
140 "decoder argument), but opaque data (%p) is not "
141 "- will be ignored",
142 table, dflt, decoders, opaque_data);
143
144 for (elt = 0; fetch_nlattr(tcp, &nla, addr, len, is_array); elt++) {
Elliott Hughesdc75b012017-07-05 13:54:44 -0700145 if (abbrev(tcp) && elt == max_strlen) {
146 tprints("...");
147 break;
148 }
149
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700150 const unsigned int nla_len = NLA_ALIGN(nla.nla_len);
Elliott Hughesdc75b012017-07-05 13:54:44 -0700151 kernel_ulong_t next_addr = 0;
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700152 unsigned int next_len = 0;
Elliott Hughesdc75b012017-07-05 13:54:44 -0700153
154 if (nla.nla_len >= NLA_HDRLEN) {
155 next_len = (len >= nla_len) ? len - nla_len : 0;
156
157 if (next_len && addr + nla_len > addr)
158 next_addr = addr + nla_len;
159 }
160
Elliott Hughes03a418e2018-06-15 13:11:40 -0700161 if (!is_array && next_addr) {
Elliott Hughesdc75b012017-07-05 13:54:44 -0700162 tprints("[");
Elliott Hughes03a418e2018-06-15 13:11:40 -0700163 is_array = true;
Elliott Hughesdc75b012017-07-05 13:54:44 -0700164 }
165
166 decode_nlattr_with_data(tcp, &nla, addr, len, table, dflt,
167 decoders, size, opaque_data);
168
169 if (!next_addr)
170 break;
171
172 tprints(", ");
173 addr = next_addr;
174 len = next_len;
175 }
176
Elliott Hughes03a418e2018-06-15 13:11:40 -0700177 if (is_array) {
Elliott Hughesdc75b012017-07-05 13:54:44 -0700178 tprints("]");
179 }
180}
181
182bool
183decode_nla_str(struct tcb *const tcp,
184 const kernel_ulong_t addr,
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700185 const unsigned int len,
Elliott Hughesdc75b012017-07-05 13:54:44 -0700186 const void *const opaque_data)
187{
188 printstr_ex(tcp, addr, len, QUOTE_0_TERMINATED);
189
190 return true;
191}
192
193bool
194decode_nla_strn(struct tcb *const tcp,
195 const kernel_ulong_t addr,
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700196 const unsigned int len,
Elliott Hughesdc75b012017-07-05 13:54:44 -0700197 const void *const opaque_data)
198{
199 printstrn(tcp, addr, len);
200
201 return true;
202}
203
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700204bool
205decode_nla_meminfo(struct tcb *const tcp,
206 const kernel_ulong_t addr,
207 const unsigned int len,
208 const void *const opaque_data)
209{
210 uint32_t mem;
211 const size_t nmemb = len / sizeof(mem);
212
213 if (!nmemb)
214 return false;
215
216 unsigned int count = 0;
Elliott Hughes03a418e2018-06-15 13:11:40 -0700217 print_array_ex(tcp, addr, nmemb, &mem, sizeof(mem),
218 tfetch_mem, print_uint32_array_member, &count,
219 PAF_PRINT_INDICES | PAF_INDEX_XLAT_VALUE_INDEXED
220 | XLAT_STYLE_FMT_U,
221 ARRSZ_PAIR(netlink_sk_meminfo_indices),
222 "SK_MEMINFO_???");
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700223
224 return true;
225}
226
227bool
Elliott Hughesb7556142018-02-20 17:03:16 -0800228decode_nla_fd(struct tcb *const tcp,
229 const kernel_ulong_t addr,
230 const unsigned int len,
231 const void *const opaque_data)
232{
233 int fd;
234
235 if (len < sizeof(fd))
236 return false;
237 else if (!umove_or_printaddr(tcp, addr, &fd))
238 printfd(tcp, fd);
239
240 return true;
241}
242
243bool
Elliott Hughes03a418e2018-06-15 13:11:40 -0700244decode_nla_uid(struct tcb *const tcp,
245 const kernel_ulong_t addr,
246 const unsigned int len,
247 const void *const opaque_data)
248{
249 uint32_t uid;
250
251 if (len < sizeof(uid))
252 return false;
253 else if (!umove_or_printaddr(tcp, addr, &uid))
254 printuid("", uid);
255
256 return true;
257}
258
259bool
260decode_nla_gid(struct tcb *const tcp,
261 const kernel_ulong_t addr,
262 const unsigned int len,
263 const void *const opaque_data)
264{
265 return decode_nla_uid(tcp, addr, len, opaque_data);
266}
267
268bool
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700269decode_nla_ifindex(struct tcb *const tcp,
270 const kernel_ulong_t addr,
271 const unsigned int len,
272 const void *const opaque_data)
273{
274 uint32_t ifindex;
275
276 if (len < sizeof(ifindex))
277 return false;
278 else if (!umove_or_printaddr(tcp, addr, &ifindex))
279 print_ifindex(ifindex);
280
281 return true;
282}
283
284bool
Elliott Hughes03a418e2018-06-15 13:11:40 -0700285decode_nla_xval(struct tcb *const tcp,
286 const kernel_ulong_t addr,
287 unsigned int len,
288 const void *const opaque_data)
289{
290 const struct decode_nla_xlat_opts * const opts = opaque_data;
291 union {
292 uint64_t val;
293 uint8_t bytes[sizeof(uint64_t)];
294 } data = { .val = 0 };
295
296 if (len > sizeof(data) || len < opts->size)
297 return false;
298
299 if (opts->size)
300 len = MIN(len, opts->size);
301
302 const size_t bytes_offs = is_bigendian ? sizeof(data) - len : 0;
303
304 if (!umoven_or_printaddr(tcp, addr, len, data.bytes + bytes_offs)) {
305 if (opts->process_fn)
306 data.val = opts->process_fn(data.val);
307 if (opts->prefix)
308 tprints(opts->prefix);
309 printxval_dispatch_ex(opts->xlat, opts->xlat_size, data.val,
310 opts->dflt, opts->xt, opts->style);
311 if (opts->suffix)
312 tprints(opts->suffix);
313 }
314
315 return true;
316}
317
318static uint64_t
319process_host_order(uint64_t val)
320{
321 return ntohs(val);
322}
323
324bool
325decode_nla_ether_proto(struct tcb *const tcp,
326 const kernel_ulong_t addr,
327 const unsigned int len,
328 const void *const opaque_data)
329{
330 const struct decode_nla_xlat_opts opts = {
331 .xlat = ethernet_protocols,
332 .xlat_size = ethernet_protocols_size,
333 .dflt = "ETHER_P_???",
334 .xt = XT_SORTED,
335 .prefix = "htons(",
336 .suffix = ")",
337 .size = 2,
338 .process_fn = process_host_order,
339 };
340
341 return decode_nla_xval(tcp, addr, len, &opts);
342}
343
344bool
345decode_nla_ip_proto(struct tcb *const tcp,
346 const kernel_ulong_t addr,
347 const unsigned int len,
348 const void *const opaque_data)
349{
350 const struct decode_nla_xlat_opts opts = {
351 .xlat = inet_protocols,
352 .xlat_size = inet_protocols_size,
353 .xt = XT_SORTED,
354 .dflt = "IPPROTO_???",
355 .size = 1,
356 };
357
358 return decode_nla_xval(tcp, addr, len, &opts);
359}
360
361bool
Elliott Hughesc1873762018-12-19 15:13:36 -0800362decode_nla_in_addr(struct tcb *const tcp,
363 const kernel_ulong_t addr,
364 const unsigned int len,
365 const void *const opaque_data)
366{
367 struct in_addr in;
368
369 if (len < sizeof(in))
370 return false;
371 else if (!umove_or_printaddr(tcp, addr, &in))
372 print_inet_addr(AF_INET, &in, sizeof(in), NULL);
373
374 return true;
375}
376
377bool
378decode_nla_in6_addr(struct tcb *const tcp,
379 const kernel_ulong_t addr,
380 const unsigned int len,
381 const void *const opaque_data)
382{
383 struct in6_addr in6;
384
385 if (len < sizeof(in6))
386 return false;
387 else if (!umove_or_printaddr(tcp, addr, &in6))
388 print_inet_addr(AF_INET6, &in6, sizeof(in6), NULL);
389
390 return true;
391}
392
393bool
Elliott Hughes03a418e2018-06-15 13:11:40 -0700394decode_nla_flags(struct tcb *const tcp,
395 const kernel_ulong_t addr,
396 unsigned int len,
397 const void *const opaque_data)
398{
399 const struct decode_nla_xlat_opts * const opts = opaque_data;
400 union {
401 uint64_t flags;
402 uint8_t bytes[sizeof(uint64_t)];
403 } data = { .flags = 0 };
404
405 if (len > sizeof(data) || len < opts->size)
406 return false;
407
408 if (opts->size)
409 len = MIN(len, opts->size);
410
411 const size_t bytes_offs = is_bigendian ? sizeof(data) - len : 0;
412
413 if (opts->xt == XT_INDEXED)
414 error_func_msg("indexed xlats are currently incompatible with "
415 "printflags");
416
417 if (!umoven_or_printaddr(tcp, addr, len, data.bytes + bytes_offs)) {
418 if (opts->process_fn)
419 data.flags = opts->process_fn(data.flags);
420 if (opts->prefix)
421 tprints(opts->prefix);
422 printflags_ex(data.flags, opts->dflt, opts->style, opts->xlat,
423 NULL);
424 if (opts->suffix)
425 tprints(opts->suffix);
426 }
427
428 return true;
429}
430
431bool
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700432decode_nla_be16(struct tcb *const tcp,
433 const kernel_ulong_t addr,
434 const unsigned int len,
435 const void *const opaque_data)
436{
437 uint16_t num;
438
439 if (len < sizeof(num))
440 return false;
441 else if (!umove_or_printaddr(tcp, addr, &num))
442 tprintf("htons(%u)", ntohs(num));
443
444 return true;
445}
446
447bool
448decode_nla_be64(struct tcb *const tcp,
449 const kernel_ulong_t addr,
450 const unsigned int len,
451 const void *const opaque_data)
452{
453#if defined HAVE_BE64TOH || defined be64toh
454 uint64_t num;
455
456 if (len < sizeof(num))
457 return false;
458 else if (!umove_or_printaddr(tcp, addr, &num))
459 tprintf("htobe64(%" PRIu64 ")", be64toh(num));
460
461 return true;
462#else
463 return false;
464#endif
465}
466
Elliott Hughesdc75b012017-07-05 13:54:44 -0700467#define DECODE_NLA_INTEGER(name, type, fmt) \
468bool \
469decode_nla_ ## name(struct tcb *const tcp, \
470 const kernel_ulong_t addr, \
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700471 const unsigned int len, \
Elliott Hughesdc75b012017-07-05 13:54:44 -0700472 const void *const opaque_data) \
473{ \
474 type num; \
475 \
476 if (len < sizeof(num)) \
477 return false; \
478 if (!umove_or_printaddr(tcp, addr, &num)) \
479 tprintf(fmt, num); \
480 return true; \
481}
482
Elliott Hughes03a418e2018-06-15 13:11:40 -0700483DECODE_NLA_INTEGER(x8, uint8_t, "%#" PRIx8)
484DECODE_NLA_INTEGER(x16, uint16_t, "%#" PRIx16)
485DECODE_NLA_INTEGER(x32, uint32_t, "%#" PRIx32)
486DECODE_NLA_INTEGER(x64, uint64_t, "%#" PRIx64)
Elliott Hughesdc75b012017-07-05 13:54:44 -0700487DECODE_NLA_INTEGER(u8, uint8_t, "%" PRIu8)
488DECODE_NLA_INTEGER(u16, uint16_t, "%" PRIu16)
489DECODE_NLA_INTEGER(u32, uint32_t, "%" PRIu32)
490DECODE_NLA_INTEGER(u64, uint64_t, "%" PRIu64)
491DECODE_NLA_INTEGER(s8, int8_t, "%" PRId8)
492DECODE_NLA_INTEGER(s16, int16_t, "%" PRId16)
493DECODE_NLA_INTEGER(s32, int32_t, "%" PRId32)
494DECODE_NLA_INTEGER(s64, int64_t, "%" PRId64)