[PATCH] netlink: introduce a dummy netlink attributes parser

Dmitry V. Levin ldv at altlinux.org
Fri Jun 16 21:22:48 UTC 2017


On Fri, Jun 16, 2017 at 01:35:07PM +0800, JingPiao Chen wrote:
> * defs.h (decode_nlattr): New prototype.
> * linux/unix_diag.h (UNIX_DIAG_*): New enum.
> * netlink.c (fetch_nlattr, print_nlattr,
> decode_nlattr_with_data, decode_nlattr): New functions.

Looks like there is no necessity to place these new nlattr related
functions into netlink.c, what do you think about creating a new source
file for this purpose, e.g. nlattr.c?

> * netlink_sock_diag.c: Include "xlat/unix_diag_attrs.h".
> (decode_unix_diag_msg): Use decode_nlattr.
> * xlat/unix_diag_attrs.in: New file.
> 
> co-authored-by: Fabien Siron <fabien.siron at epita.fr>
> ---
>  defs.h                  |  3 ++
>  linux/unix_diag.h       | 11 +++++--
>  netlink.c               | 76 +++++++++++++++++++++++++++++++++++++++++++++++++
>  netlink_sock_diag.c     |  4 +++
>  xlat/unix_diag_attrs.in |  7 +++++
>  5 files changed, 99 insertions(+), 2 deletions(-)
>  create mode 100644 xlat/unix_diag_attrs.in
> 
> diff --git a/defs.h b/defs.h
> index 487e51b..7e3912d 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -632,6 +632,9 @@ tprint_iov_upto(struct tcb *, kernel_ulong_t len, kernel_ulong_t addr,
>  
>  extern void
>  decode_netlink(struct tcb *, int fd, kernel_ulong_t addr, kernel_ulong_t len);
> +extern void
> +decode_nlattr(struct tcb *tcp, kernel_ulong_t addr, kernel_ulong_t len,
> +	      int, const struct xlat *, const char *);
>  
>  extern void tprint_open_modes(unsigned int);
>  extern const char *sprint_open_modes(unsigned int);
> diff --git a/linux/unix_diag.h b/linux/unix_diag.h
> index a6b62ba..3c9d99f 100644
> --- a/linux/unix_diag.h
> +++ b/linux/unix_diag.h
> @@ -27,7 +27,14 @@ struct unix_diag_msg {
>  	uint32_t udiag_cookie[2];
>  };
>  
> -#define UNIX_DIAG_NAME 0
> -#define UNIX_DIAG_PEER 2
> +enum {
> +	UNIX_DIAG_NAME,
> +	UNIX_DIAG_VFS,
> +	UNIX_DIAG_PEER,
> +	UNIX_DIAG_ICONS,
> +	UNIX_DIAG_RQLEN,
> +	UNIX_DIAG_MEMINFO,
> +	UNIX_DIAG_SHUTDOWN,
> +};
>  
>  #endif /* !STRACE_LINUX_UNIX_DIAG_H */
> diff --git a/netlink.c b/netlink.c
> index 4bef949..52f3806 100644
> --- a/netlink.c
> +++ b/netlink.c
> @@ -49,6 +49,82 @@
>  #undef NLMSG_HDRLEN
>  #define NLMSG_HDRLEN NLMSG_ALIGN(sizeof(struct nlmsghdr))
>  
> +static bool
> +fetch_nlattr(struct tcb *tcp, struct nlattr *nlattr,

You can add some const qualifiers here, like in fetch_nlmsghdr that was
used as a template for this new function.

> +	     const kernel_ulong_t addr, const kernel_ulong_t len)
> +{
> +	if (len < sizeof(struct nlattr)) {
> +		printstrn(tcp, addr, len);
> +		return false;
> +	}
> +
> +	if (umove_or_printaddr(tcp, addr, nlattr))
> +		return false;
> +
> +	return true;
> +}
> +
> +static void
> +print_nlattr(const struct nlattr *const nla,
> +	     const struct xlat *table, const char *dflt)
> +{
> +	tprintf("{nla_len=%u, nla_type=", nla->nla_len);
> +	if (nla->nla_type & NLA_F_NESTED)
> +		tprints("NLA_F_NESTED|");
> +	if (nla->nla_type & NLA_F_NET_BYTEORDER)
> +		tprints("NLA_F_NET_BYTEORDER|");
> +	printxval(table, nla->nla_type & NLA_TYPE_MASK, dflt);
> +	tprints("}");
> +}
> +
> +static void
> +decode_nlattr_with_data(struct tcb *tcp, kernel_ulong_t addr,
> +			kernel_ulong_t len, const struct xlat *table,
> +			const char *dflt)
> +{
> +	struct nlattr nlattr;
> +
> +	while (fetch_nlattr(tcp, &nlattr, addr, len)) {
> +		unsigned long nlattr_len = NLA_ALIGN(nlattr.nla_len);
> +		kernel_ulong_t next_addr = 0;
> +		kernel_ulong_t next_len = 0;

This new function is made after decode_netlink, which is fine,
but it misses the abbrev(tcp) logic which is present in decode_netlink.
Could you reintroduce it here, too, please?

> +
> +		if (nlattr.nla_len >= sizeof(struct nlattr)) {
> +			next_len = (len >= nlattr_len) ? len - nlattr_len : 0;
> +
> +			if (next_len && addr + nlattr_len > addr)
> +				next_addr = addr + nlattr_len;
> +		}
> +
> +		tprints("{");
> +		print_nlattr(&nlattr, table, dflt);
> +		if (nlattr.nla_len > NLA_HDRLEN) {
> +			tprints(", ");
> +			printstrn(tcp, addr + NLA_HDRLEN,
> +				  nlattr.nla_len - NLA_HDRLEN);
> +		}
> +		tprints("}");
> +
> +		if (!next_addr)
> +			break;
> +
> +		tprints(", ");
> +		addr = next_addr;
> +		len = next_len;
> +	}
> +}
> +
> +void
> +decode_nlattr(struct tcb *tcp, kernel_ulong_t addr, kernel_ulong_t len,
> +	      int hdrlen, const struct xlat *table, const char *dflt)
> +{
> +	if (len > NLMSG_ALIGN(hdrlen)) {
> +		tprints(", ");
> +		decode_nlattr_with_data(tcp, addr + NLMSG_ALIGN(hdrlen),
> +					len - NLMSG_ALIGN(hdrlen), table, dflt);
> +	}

I'm not sure we need this proxy function, the caller is capable of performing
the check and invoking the decoder with the right address and length.

> +}
> +
>  /*
>   * Fetch a struct nlmsghdr from the given address.
>   */
> diff --git a/netlink_sock_diag.c b/netlink_sock_diag.c
> index 8dbfd07..6d79ba4 100644
> --- a/netlink_sock_diag.c
> +++ b/netlink_sock_diag.c
> @@ -55,6 +55,7 @@
>  # include "xlat/smc_states.h"
>  #endif
>  
> +#include "xlat/unix_diag_attrs.h"
>  #include "xlat/unix_diag_show.h"
>  
>  static void
> @@ -109,32 +110,35 @@ static void
>  decode_unix_diag_msg(struct tcb *const tcp,
>  		     const struct nlmsghdr *const nlmsghdr,
>  		     const uint8_t family,
>  		     const kernel_ulong_t addr,
>  		     const kernel_ulong_t len)
>  {
>  	struct unix_diag_msg msg = { .udiag_family = family };
>  	const size_t offset = sizeof(msg.udiag_family);
>  
>  	tprints("{udiag_family=");
>  	printxval(addrfams, msg.udiag_family, "AF_???");
>  
>  	tprints(", ");
>  	if (len >= sizeof(msg)) {
>  		if (!umoven_or_printaddr(tcp, addr + offset,
>  					 sizeof(msg) - offset,
>  					 (void *) &msg + offset)) {
>  			tprints("udiag_type=");
>  			printxval(socktypes, msg.udiag_type, "SOCK_???");
>  			tprintf(", udiag_state=");
>  			printxval(tcp_states, msg.udiag_state, "TCP_???");
>  			tprintf(", udiag_ino=%" PRIu32
>  				", udiag_cookie=[%" PRIu32 ", %" PRIu32 "]",
>  				msg.udiag_ino,
>  				msg.udiag_cookie[0], msg.udiag_cookie[1]);

The invocation of nlattr decoder should be placed here:

			offset = NLMSG_ALIGN(sizeof(msg));
			if (len > offset) {
				tprints(", ");
				decode_nlattr(tcp, addr + offset, len - offset,
					      unix_diag_attrs, "UNIX_DIAG_???");
			}
>  		}
>  	} else
>  		tprints("...");
>  	tprints("}");
> +
> +	decode_nlattr(tcp, addr, len, sizeof(msg), unix_diag_attrs,
> +		      "UNIX_DIAG_???");
>  }
>  
>  static void
> diff --git a/xlat/unix_diag_attrs.in b/xlat/unix_diag_attrs.in
> new file mode 100644
> index 0000000..0fb2f23
> --- /dev/null
> +++ b/xlat/unix_diag_attrs.in
> @@ -0,0 +1,7 @@
> +UNIX_DIAG_NAME		0
> +UNIX_DIAG_VFS		1
> +UNIX_DIAG_PEER		2
> +UNIX_DIAG_ICONS		3
> +UNIX_DIAG_RQLEN		4
> +UNIX_DIAG_MEMINFO	5
> +UNIX_DIAG_SHUTDOWN	6

As these constants are guaranteed to be defined by local linux/unix_diag.h
file, there is no need to provide fallback definitions, just the opposite,
these xlat entries should be unconditional:

--- /dev/null
+++ b/xlat/unix_diag_attrs.in
@@ -0,0 +1,8 @@
+#unconditional
+UNIX_DIAG_NAME
+UNIX_DIAG_VFS
+UNIX_DIAG_PEER
+UNIX_DIAG_ICONS
+UNIX_DIAG_RQLEN
+UNIX_DIAG_MEMINFO
+UNIX_DIAG_SHUTDOWN


-- 
ldv
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.strace.io/pipermail/strace-devel/attachments/20170617/9b199af1/attachment.bin>


More information about the Strace-devel mailing list