blob: af7cc162e3606bd09fd8a40fa3caaca99b7869f3 [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 Hughes03a418e2018-06-15 13:11:40 -0700104 const unsigned int idx = size ? nla->nla_type : 0;
105
Elliott Hughesdc75b012017-07-05 13:54:44 -0700106 tprints(", ");
107 if (!decoders
Elliott Hughes03a418e2018-06-15 13:11:40 -0700108 || (size && idx >= size)
109 || !decoders[idx]
110 || !decoders[idx](
111 tcp, addr + NLA_HDRLEN,
112 nla_len - NLA_HDRLEN,
113 size ? opaque_data
114 : (const void *) (uintptr_t) nla->nla_type)
115 )
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700116 printstr_ex(tcp, addr + NLA_HDRLEN,
117 nla_len - NLA_HDRLEN, QUOTE_FORCE_HEX);
Elliott Hughesdc75b012017-07-05 13:54:44 -0700118 tprints("}");
119 }
120}
121
122void
123decode_nlattr(struct tcb *const tcp,
124 kernel_ulong_t addr,
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700125 unsigned int len,
Elliott Hughesdc75b012017-07-05 13:54:44 -0700126 const struct xlat *const table,
127 const char *const dflt,
128 const nla_decoder_t *const decoders,
129 const unsigned int size,
130 const void *const opaque_data)
131{
132 struct nlattr nla;
Elliott Hughes03a418e2018-06-15 13:11:40 -0700133 bool is_array = false;
Elliott Hughesdc75b012017-07-05 13:54:44 -0700134 unsigned int elt;
135
Elliott Hughes03a418e2018-06-15 13:11:40 -0700136 if (decoders && !size && opaque_data)
137 error_func_msg("[xlat %p, dflt \"%s\", decoders %p] "
138 "size is zero (going to pass nla_type as "
139 "decoder argument), but opaque data (%p) is not "
140 "- will be ignored",
141 table, dflt, decoders, opaque_data);
142
143 for (elt = 0; fetch_nlattr(tcp, &nla, addr, len, is_array); elt++) {
Elliott Hughesdc75b012017-07-05 13:54:44 -0700144 if (abbrev(tcp) && elt == max_strlen) {
145 tprints("...");
146 break;
147 }
148
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700149 const unsigned int nla_len = NLA_ALIGN(nla.nla_len);
Elliott Hughesdc75b012017-07-05 13:54:44 -0700150 kernel_ulong_t next_addr = 0;
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700151 unsigned int next_len = 0;
Elliott Hughesdc75b012017-07-05 13:54:44 -0700152
153 if (nla.nla_len >= NLA_HDRLEN) {
154 next_len = (len >= nla_len) ? len - nla_len : 0;
155
156 if (next_len && addr + nla_len > addr)
157 next_addr = addr + nla_len;
158 }
159
Elliott Hughes03a418e2018-06-15 13:11:40 -0700160 if (!is_array && next_addr) {
Elliott Hughesdc75b012017-07-05 13:54:44 -0700161 tprints("[");
Elliott Hughes03a418e2018-06-15 13:11:40 -0700162 is_array = true;
Elliott Hughesdc75b012017-07-05 13:54:44 -0700163 }
164
165 decode_nlattr_with_data(tcp, &nla, addr, len, table, dflt,
166 decoders, size, opaque_data);
167
168 if (!next_addr)
169 break;
170
171 tprints(", ");
172 addr = next_addr;
173 len = next_len;
174 }
175
Elliott Hughes03a418e2018-06-15 13:11:40 -0700176 if (is_array) {
Elliott Hughesdc75b012017-07-05 13:54:44 -0700177 tprints("]");
178 }
179}
180
181bool
182decode_nla_str(struct tcb *const tcp,
183 const kernel_ulong_t addr,
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700184 const unsigned int len,
Elliott Hughesdc75b012017-07-05 13:54:44 -0700185 const void *const opaque_data)
186{
187 printstr_ex(tcp, addr, len, QUOTE_0_TERMINATED);
188
189 return true;
190}
191
192bool
193decode_nla_strn(struct tcb *const tcp,
194 const kernel_ulong_t addr,
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700195 const unsigned int len,
Elliott Hughesdc75b012017-07-05 13:54:44 -0700196 const void *const opaque_data)
197{
198 printstrn(tcp, addr, len);
199
200 return true;
201}
202
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700203bool
204decode_nla_meminfo(struct tcb *const tcp,
205 const kernel_ulong_t addr,
206 const unsigned int len,
207 const void *const opaque_data)
208{
209 uint32_t mem;
210 const size_t nmemb = len / sizeof(mem);
211
212 if (!nmemb)
213 return false;
214
215 unsigned int count = 0;
Elliott Hughes03a418e2018-06-15 13:11:40 -0700216 print_array_ex(tcp, addr, nmemb, &mem, sizeof(mem),
217 tfetch_mem, print_uint32_array_member, &count,
218 PAF_PRINT_INDICES | PAF_INDEX_XLAT_VALUE_INDEXED
219 | XLAT_STYLE_FMT_U,
220 ARRSZ_PAIR(netlink_sk_meminfo_indices),
221 "SK_MEMINFO_???");
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700222
223 return true;
224}
225
226bool
Elliott Hughesb7556142018-02-20 17:03:16 -0800227decode_nla_fd(struct tcb *const tcp,
228 const kernel_ulong_t addr,
229 const unsigned int len,
230 const void *const opaque_data)
231{
232 int fd;
233
234 if (len < sizeof(fd))
235 return false;
236 else if (!umove_or_printaddr(tcp, addr, &fd))
237 printfd(tcp, fd);
238
239 return true;
240}
241
242bool
Elliott Hughes03a418e2018-06-15 13:11:40 -0700243decode_nla_uid(struct tcb *const tcp,
244 const kernel_ulong_t addr,
245 const unsigned int len,
246 const void *const opaque_data)
247{
248 uint32_t uid;
249
250 if (len < sizeof(uid))
251 return false;
252 else if (!umove_or_printaddr(tcp, addr, &uid))
253 printuid("", uid);
254
255 return true;
256}
257
258bool
259decode_nla_gid(struct tcb *const tcp,
260 const kernel_ulong_t addr,
261 const unsigned int len,
262 const void *const opaque_data)
263{
264 return decode_nla_uid(tcp, addr, len, opaque_data);
265}
266
267bool
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700268decode_nla_ifindex(struct tcb *const tcp,
269 const kernel_ulong_t addr,
270 const unsigned int len,
271 const void *const opaque_data)
272{
273 uint32_t ifindex;
274
275 if (len < sizeof(ifindex))
276 return false;
277 else if (!umove_or_printaddr(tcp, addr, &ifindex))
278 print_ifindex(ifindex);
279
280 return true;
281}
282
283bool
Elliott Hughes03a418e2018-06-15 13:11:40 -0700284decode_nla_xval(struct tcb *const tcp,
285 const kernel_ulong_t addr,
286 unsigned int len,
287 const void *const opaque_data)
288{
289 const struct decode_nla_xlat_opts * const opts = opaque_data;
290 union {
291 uint64_t val;
292 uint8_t bytes[sizeof(uint64_t)];
293 } data = { .val = 0 };
294
295 if (len > sizeof(data) || len < opts->size)
296 return false;
297
298 if (opts->size)
299 len = MIN(len, opts->size);
300
301 const size_t bytes_offs = is_bigendian ? sizeof(data) - len : 0;
302
303 if (!umoven_or_printaddr(tcp, addr, len, data.bytes + bytes_offs)) {
304 if (opts->process_fn)
305 data.val = opts->process_fn(data.val);
306 if (opts->prefix)
307 tprints(opts->prefix);
308 printxval_dispatch_ex(opts->xlat, opts->xlat_size, data.val,
309 opts->dflt, opts->xt, opts->style);
310 if (opts->suffix)
311 tprints(opts->suffix);
312 }
313
314 return true;
315}
316
317static uint64_t
318process_host_order(uint64_t val)
319{
320 return ntohs(val);
321}
322
323bool
324decode_nla_ether_proto(struct tcb *const tcp,
325 const kernel_ulong_t addr,
326 const unsigned int len,
327 const void *const opaque_data)
328{
329 const struct decode_nla_xlat_opts opts = {
330 .xlat = ethernet_protocols,
331 .xlat_size = ethernet_protocols_size,
332 .dflt = "ETHER_P_???",
333 .xt = XT_SORTED,
334 .prefix = "htons(",
335 .suffix = ")",
336 .size = 2,
337 .process_fn = process_host_order,
338 };
339
340 return decode_nla_xval(tcp, addr, len, &opts);
341}
342
343bool
344decode_nla_ip_proto(struct tcb *const tcp,
345 const kernel_ulong_t addr,
346 const unsigned int len,
347 const void *const opaque_data)
348{
349 const struct decode_nla_xlat_opts opts = {
350 .xlat = inet_protocols,
351 .xlat_size = inet_protocols_size,
352 .xt = XT_SORTED,
353 .dflt = "IPPROTO_???",
354 .size = 1,
355 };
356
357 return decode_nla_xval(tcp, addr, len, &opts);
358}
359
360bool
361decode_nla_flags(struct tcb *const tcp,
362 const kernel_ulong_t addr,
363 unsigned int len,
364 const void *const opaque_data)
365{
366 const struct decode_nla_xlat_opts * const opts = opaque_data;
367 union {
368 uint64_t flags;
369 uint8_t bytes[sizeof(uint64_t)];
370 } data = { .flags = 0 };
371
372 if (len > sizeof(data) || len < opts->size)
373 return false;
374
375 if (opts->size)
376 len = MIN(len, opts->size);
377
378 const size_t bytes_offs = is_bigendian ? sizeof(data) - len : 0;
379
380 if (opts->xt == XT_INDEXED)
381 error_func_msg("indexed xlats are currently incompatible with "
382 "printflags");
383
384 if (!umoven_or_printaddr(tcp, addr, len, data.bytes + bytes_offs)) {
385 if (opts->process_fn)
386 data.flags = opts->process_fn(data.flags);
387 if (opts->prefix)
388 tprints(opts->prefix);
389 printflags_ex(data.flags, opts->dflt, opts->style, opts->xlat,
390 NULL);
391 if (opts->suffix)
392 tprints(opts->suffix);
393 }
394
395 return true;
396}
397
398bool
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700399decode_nla_be16(struct tcb *const tcp,
400 const kernel_ulong_t addr,
401 const unsigned int len,
402 const void *const opaque_data)
403{
404 uint16_t num;
405
406 if (len < sizeof(num))
407 return false;
408 else if (!umove_or_printaddr(tcp, addr, &num))
409 tprintf("htons(%u)", ntohs(num));
410
411 return true;
412}
413
414bool
415decode_nla_be64(struct tcb *const tcp,
416 const kernel_ulong_t addr,
417 const unsigned int len,
418 const void *const opaque_data)
419{
420#if defined HAVE_BE64TOH || defined be64toh
421 uint64_t num;
422
423 if (len < sizeof(num))
424 return false;
425 else if (!umove_or_printaddr(tcp, addr, &num))
426 tprintf("htobe64(%" PRIu64 ")", be64toh(num));
427
428 return true;
429#else
430 return false;
431#endif
432}
433
Elliott Hughesdc75b012017-07-05 13:54:44 -0700434#define DECODE_NLA_INTEGER(name, type, fmt) \
435bool \
436decode_nla_ ## name(struct tcb *const tcp, \
437 const kernel_ulong_t addr, \
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700438 const unsigned int len, \
Elliott Hughesdc75b012017-07-05 13:54:44 -0700439 const void *const opaque_data) \
440{ \
441 type num; \
442 \
443 if (len < sizeof(num)) \
444 return false; \
445 if (!umove_or_printaddr(tcp, addr, &num)) \
446 tprintf(fmt, num); \
447 return true; \
448}
449
Elliott Hughes03a418e2018-06-15 13:11:40 -0700450DECODE_NLA_INTEGER(x8, uint8_t, "%#" PRIx8)
451DECODE_NLA_INTEGER(x16, uint16_t, "%#" PRIx16)
452DECODE_NLA_INTEGER(x32, uint32_t, "%#" PRIx32)
453DECODE_NLA_INTEGER(x64, uint64_t, "%#" PRIx64)
Elliott Hughesdc75b012017-07-05 13:54:44 -0700454DECODE_NLA_INTEGER(u8, uint8_t, "%" PRIu8)
455DECODE_NLA_INTEGER(u16, uint16_t, "%" PRIu16)
456DECODE_NLA_INTEGER(u32, uint32_t, "%" PRIu32)
457DECODE_NLA_INTEGER(u64, uint64_t, "%" PRIu64)
458DECODE_NLA_INTEGER(s8, int8_t, "%" PRId8)
459DECODE_NLA_INTEGER(s16, int16_t, "%" PRId16)
460DECODE_NLA_INTEGER(s32, int32_t, "%" PRId32)
461DECODE_NLA_INTEGER(s64, int64_t, "%" PRId64)