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