nlattr.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
  2. /*
  3. * NETLINK Netlink attributes
  4. *
  5. * Copyright (c) 2003-2013 Thomas Graf <[email protected]>
  6. */
  7. #include <errno.h>
  8. #include <string.h>
  9. #include <stdio.h>
  10. #include <linux/rtnetlink.h>
  11. #include "nlattr.h"
  12. #include "libbpf_internal.h"
  13. static uint16_t nla_attr_minlen[LIBBPF_NLA_TYPE_MAX+1] = {
  14. [LIBBPF_NLA_U8] = sizeof(uint8_t),
  15. [LIBBPF_NLA_U16] = sizeof(uint16_t),
  16. [LIBBPF_NLA_U32] = sizeof(uint32_t),
  17. [LIBBPF_NLA_U64] = sizeof(uint64_t),
  18. [LIBBPF_NLA_STRING] = 1,
  19. [LIBBPF_NLA_FLAG] = 0,
  20. };
  21. static struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
  22. {
  23. int totlen = NLA_ALIGN(nla->nla_len);
  24. *remaining -= totlen;
  25. return (struct nlattr *)((void *)nla + totlen);
  26. }
  27. static int nla_ok(const struct nlattr *nla, int remaining)
  28. {
  29. return remaining >= (int)sizeof(*nla) &&
  30. nla->nla_len >= sizeof(*nla) &&
  31. nla->nla_len <= remaining;
  32. }
  33. static int nla_type(const struct nlattr *nla)
  34. {
  35. return nla->nla_type & NLA_TYPE_MASK;
  36. }
  37. static int validate_nla(struct nlattr *nla, int maxtype,
  38. struct libbpf_nla_policy *policy)
  39. {
  40. struct libbpf_nla_policy *pt;
  41. unsigned int minlen = 0;
  42. int type = nla_type(nla);
  43. if (type < 0 || type > maxtype)
  44. return 0;
  45. pt = &policy[type];
  46. if (pt->type > LIBBPF_NLA_TYPE_MAX)
  47. return 0;
  48. if (pt->minlen)
  49. minlen = pt->minlen;
  50. else if (pt->type != LIBBPF_NLA_UNSPEC)
  51. minlen = nla_attr_minlen[pt->type];
  52. if (libbpf_nla_len(nla) < minlen)
  53. return -1;
  54. if (pt->maxlen && libbpf_nla_len(nla) > pt->maxlen)
  55. return -1;
  56. if (pt->type == LIBBPF_NLA_STRING) {
  57. char *data = libbpf_nla_data(nla);
  58. if (data[libbpf_nla_len(nla) - 1] != '\0')
  59. return -1;
  60. }
  61. return 0;
  62. }
  63. static inline int nlmsg_len(const struct nlmsghdr *nlh)
  64. {
  65. return nlh->nlmsg_len - NLMSG_HDRLEN;
  66. }
  67. /**
  68. * Create attribute index based on a stream of attributes.
  69. * @arg tb Index array to be filled (maxtype+1 elements).
  70. * @arg maxtype Maximum attribute type expected and accepted.
  71. * @arg head Head of attribute stream.
  72. * @arg len Length of attribute stream.
  73. * @arg policy Attribute validation policy.
  74. *
  75. * Iterates over the stream of attributes and stores a pointer to each
  76. * attribute in the index array using the attribute type as index to
  77. * the array. Attribute with a type greater than the maximum type
  78. * specified will be silently ignored in order to maintain backwards
  79. * compatibility. If \a policy is not NULL, the attribute will be
  80. * validated using the specified policy.
  81. *
  82. * @see nla_validate
  83. * @return 0 on success or a negative error code.
  84. */
  85. int libbpf_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head,
  86. int len, struct libbpf_nla_policy *policy)
  87. {
  88. struct nlattr *nla;
  89. int rem, err;
  90. memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
  91. libbpf_nla_for_each_attr(nla, head, len, rem) {
  92. int type = nla_type(nla);
  93. if (type > maxtype)
  94. continue;
  95. if (policy) {
  96. err = validate_nla(nla, maxtype, policy);
  97. if (err < 0)
  98. goto errout;
  99. }
  100. if (tb[type])
  101. pr_warn("Attribute of type %#x found multiple times in message, "
  102. "previous attribute is being ignored.\n", type);
  103. tb[type] = nla;
  104. }
  105. err = 0;
  106. errout:
  107. return err;
  108. }
  109. /**
  110. * Create attribute index based on nested attribute
  111. * @arg tb Index array to be filled (maxtype+1 elements).
  112. * @arg maxtype Maximum attribute type expected and accepted.
  113. * @arg nla Nested Attribute.
  114. * @arg policy Attribute validation policy.
  115. *
  116. * Feeds the stream of attributes nested into the specified attribute
  117. * to libbpf_nla_parse().
  118. *
  119. * @see libbpf_nla_parse
  120. * @return 0 on success or a negative error code.
  121. */
  122. int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype,
  123. struct nlattr *nla,
  124. struct libbpf_nla_policy *policy)
  125. {
  126. return libbpf_nla_parse(tb, maxtype, libbpf_nla_data(nla),
  127. libbpf_nla_len(nla), policy);
  128. }
  129. /* dump netlink extended ack error message */
  130. int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh)
  131. {
  132. struct libbpf_nla_policy extack_policy[NLMSGERR_ATTR_MAX + 1] = {
  133. [NLMSGERR_ATTR_MSG] = { .type = LIBBPF_NLA_STRING },
  134. [NLMSGERR_ATTR_OFFS] = { .type = LIBBPF_NLA_U32 },
  135. };
  136. struct nlattr *tb[NLMSGERR_ATTR_MAX + 1], *attr;
  137. struct nlmsgerr *err;
  138. char *errmsg = NULL;
  139. int hlen, alen;
  140. /* no TLVs, nothing to do here */
  141. if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
  142. return 0;
  143. err = (struct nlmsgerr *)NLMSG_DATA(nlh);
  144. hlen = sizeof(*err);
  145. /* if NLM_F_CAPPED is set then the inner err msg was capped */
  146. if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
  147. hlen += nlmsg_len(&err->msg);
  148. attr = (struct nlattr *) ((void *) err + hlen);
  149. alen = (void *)nlh + nlh->nlmsg_len - (void *)attr;
  150. if (libbpf_nla_parse(tb, NLMSGERR_ATTR_MAX, attr, alen,
  151. extack_policy) != 0) {
  152. pr_warn("Failed to parse extended error attributes\n");
  153. return 0;
  154. }
  155. if (tb[NLMSGERR_ATTR_MSG])
  156. errmsg = (char *) libbpf_nla_data(tb[NLMSGERR_ATTR_MSG]);
  157. pr_warn("Kernel error message: %s\n", errmsg);
  158. return 0;
  159. }