From dbc5d26b29a15721884c53467fed16f30716e2f9 Mon Sep 17 00:00:00 2001 From: Eugene Syromyatnikov Date: Mon, 7 May 2018 08:28:38 +0200 Subject: [PATCH] nlattr: add ability to pass nla_type to decoder in decode_nlattr As of now, it's impossible to introduce a dispatching nlattr decoder that performs actions based on the type of the message, so let's use a combination of zero decoder list size and non-zero decoder pointer for this. This is going to be used later in IFLA_AF_SPEC decoding. * nlattr.c (decode_nlattr_with_data): Handle zero size and non-NULL decoders in a special way. (decode_nlattr): Add an error message about ignoring of opaque_data argument when zero size and non-NULL decoders are provided. * nlattr.h (decode_nlattr): Add a comment about the new special case. --- nlattr.c | 22 +++++++++++++++++----- nlattr.h | 8 +++++++- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/nlattr.c b/nlattr.c index 8dea4847..f65d9cf6 100644 --- a/nlattr.c +++ b/nlattr.c @@ -101,13 +101,18 @@ decode_nlattr_with_data(struct tcb *const tcp, print_nlattr(nla, table, dflt); if (nla_len > NLA_HDRLEN) { + const unsigned int idx = size ? nla->nla_type : 0; + tprints(", "); if (!decoders - || nla->nla_type >= size - || !decoders[nla->nla_type] - || !decoders[nla->nla_type](tcp, addr + NLA_HDRLEN, - nla_len - NLA_HDRLEN, - opaque_data)) + || (size && idx >= size) + || !decoders[idx] + || !decoders[idx]( + tcp, addr + NLA_HDRLEN, + nla_len - NLA_HDRLEN, + size ? opaque_data + : (const void *) (uintptr_t) nla->nla_type) + ) printstr_ex(tcp, addr + NLA_HDRLEN, nla_len - NLA_HDRLEN, QUOTE_FORCE_HEX); tprints("}"); @@ -128,6 +133,13 @@ decode_nlattr(struct tcb *const tcp, bool is_array = false; unsigned int elt; + if (decoders && !size && opaque_data) + error_func_msg("[xlat %p, dflt \"%s\", decoders %p] " + "size is zero (going to pass nla_type as " + "decoder argument), but opaque data (%p) is not " + "- will be ignored", + table, dflt, decoders, opaque_data); + for (elt = 0; fetch_nlattr(tcp, &nla, addr, len, is_array); elt++) { if (abbrev(tcp) && elt == max_strlen) { tprints("..."); diff --git a/nlattr.h b/nlattr.h index 7f0ee0cd..765aba82 100644 --- a/nlattr.h +++ b/nlattr.h @@ -42,13 +42,19 @@ struct decode_nla_xlat_opts { typedef bool (*nla_decoder_t)(struct tcb *, kernel_ulong_t addr, unsigned int len, const void *opaque_data); + +/** + * The case of non-NULL decoders and zero size is handled in a special way: + * the zeroth decoder is always called with nla_type being passed as opaque + * data. + */ extern void decode_nlattr(struct tcb *, kernel_ulong_t addr, unsigned int len, const struct xlat *, const char *dflt, - const nla_decoder_t *, + const nla_decoder_t *decoders, unsigned int size, const void *opaque_data); -- 2.50.0