]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - net/netlink/policy.c
Merge tag 'omap-for-v5.8/fixes-merge-window-signed' of git://git.kernel.org/pub/scm...
[mirror_ubuntu-jammy-kernel.git] / net / netlink / policy.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * NETLINK Policy advertisement to userspace
4 *
5 * Authors: Johannes Berg <johannes@sipsolutions.net>
6 *
7 * Copyright 2019 Intel Corporation
8 */
9
10 #include <linux/kernel.h>
11 #include <linux/errno.h>
12 #include <linux/types.h>
13 #include <net/netlink.h>
14
15 #define INITIAL_POLICIES_ALLOC 10
16
17 struct nl_policy_dump {
18 unsigned int policy_idx;
19 unsigned int attr_idx;
20 unsigned int n_alloc;
21 struct {
22 const struct nla_policy *policy;
23 unsigned int maxtype;
24 } policies[];
25 };
26
27 static int add_policy(struct nl_policy_dump **statep,
28 const struct nla_policy *policy,
29 unsigned int maxtype)
30 {
31 struct nl_policy_dump *state = *statep;
32 unsigned int n_alloc, i;
33
34 if (!policy || !maxtype)
35 return 0;
36
37 for (i = 0; i < state->n_alloc; i++) {
38 if (state->policies[i].policy == policy)
39 return 0;
40
41 if (!state->policies[i].policy) {
42 state->policies[i].policy = policy;
43 state->policies[i].maxtype = maxtype;
44 return 0;
45 }
46 }
47
48 n_alloc = state->n_alloc + INITIAL_POLICIES_ALLOC;
49 state = krealloc(state, struct_size(state, policies, n_alloc),
50 GFP_KERNEL);
51 if (!state)
52 return -ENOMEM;
53
54 state->policies[state->n_alloc].policy = policy;
55 state->policies[state->n_alloc].maxtype = maxtype;
56 state->n_alloc = n_alloc;
57 *statep = state;
58
59 return 0;
60 }
61
62 static unsigned int get_policy_idx(struct nl_policy_dump *state,
63 const struct nla_policy *policy)
64 {
65 unsigned int i;
66
67 for (i = 0; i < state->n_alloc; i++) {
68 if (state->policies[i].policy == policy)
69 return i;
70 }
71
72 WARN_ON_ONCE(1);
73 return -1;
74 }
75
76 int netlink_policy_dump_start(const struct nla_policy *policy,
77 unsigned int maxtype,
78 unsigned long *_state)
79 {
80 struct nl_policy_dump *state;
81 unsigned int policy_idx;
82 int err;
83
84 /* also returns 0 if "*_state" is our ERR_PTR() end marker */
85 if (*_state)
86 return 0;
87
88 /*
89 * walk the policies and nested ones first, and build
90 * a linear list of them.
91 */
92
93 state = kzalloc(struct_size(state, policies, INITIAL_POLICIES_ALLOC),
94 GFP_KERNEL);
95 if (!state)
96 return -ENOMEM;
97 state->n_alloc = INITIAL_POLICIES_ALLOC;
98
99 err = add_policy(&state, policy, maxtype);
100 if (err)
101 return err;
102
103 for (policy_idx = 0;
104 policy_idx < state->n_alloc && state->policies[policy_idx].policy;
105 policy_idx++) {
106 const struct nla_policy *policy;
107 unsigned int type;
108
109 policy = state->policies[policy_idx].policy;
110
111 for (type = 0;
112 type <= state->policies[policy_idx].maxtype;
113 type++) {
114 switch (policy[type].type) {
115 case NLA_NESTED:
116 case NLA_NESTED_ARRAY:
117 err = add_policy(&state,
118 policy[type].nested_policy,
119 policy[type].len);
120 if (err)
121 return err;
122 break;
123 default:
124 break;
125 }
126 }
127 }
128
129 *_state = (unsigned long)state;
130
131 return 0;
132 }
133
134 static bool netlink_policy_dump_finished(struct nl_policy_dump *state)
135 {
136 return state->policy_idx >= state->n_alloc ||
137 !state->policies[state->policy_idx].policy;
138 }
139
140 bool netlink_policy_dump_loop(unsigned long *_state)
141 {
142 struct nl_policy_dump *state = (void *)*_state;
143
144 if (IS_ERR(state))
145 return false;
146
147 if (netlink_policy_dump_finished(state)) {
148 kfree(state);
149 /* store end marker instead of freed state */
150 *_state = (unsigned long)ERR_PTR(-ENOENT);
151 return false;
152 }
153
154 return true;
155 }
156
157 int netlink_policy_dump_write(struct sk_buff *skb, unsigned long _state)
158 {
159 struct nl_policy_dump *state = (void *)_state;
160 const struct nla_policy *pt;
161 struct nlattr *policy, *attr;
162 enum netlink_attribute_type type;
163 bool again;
164
165 send_attribute:
166 again = false;
167
168 pt = &state->policies[state->policy_idx].policy[state->attr_idx];
169
170 policy = nla_nest_start(skb, state->policy_idx);
171 if (!policy)
172 return -ENOBUFS;
173
174 attr = nla_nest_start(skb, state->attr_idx);
175 if (!attr)
176 goto nla_put_failure;
177
178 switch (pt->type) {
179 default:
180 case NLA_UNSPEC:
181 case NLA_REJECT:
182 /* skip - use NLA_MIN_LEN to advertise such */
183 nla_nest_cancel(skb, policy);
184 again = true;
185 goto next;
186 case NLA_NESTED:
187 type = NL_ATTR_TYPE_NESTED;
188 /* fall through */
189 case NLA_NESTED_ARRAY:
190 if (pt->type == NLA_NESTED_ARRAY)
191 type = NL_ATTR_TYPE_NESTED_ARRAY;
192 if (pt->nested_policy && pt->len &&
193 (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_POLICY_IDX,
194 get_policy_idx(state, pt->nested_policy)) ||
195 nla_put_u32(skb, NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE,
196 pt->len)))
197 goto nla_put_failure;
198 break;
199 case NLA_U8:
200 case NLA_U16:
201 case NLA_U32:
202 case NLA_U64:
203 case NLA_MSECS: {
204 struct netlink_range_validation range;
205
206 if (pt->type == NLA_U8)
207 type = NL_ATTR_TYPE_U8;
208 else if (pt->type == NLA_U16)
209 type = NL_ATTR_TYPE_U16;
210 else if (pt->type == NLA_U32)
211 type = NL_ATTR_TYPE_U32;
212 else
213 type = NL_ATTR_TYPE_U64;
214
215 nla_get_range_unsigned(pt, &range);
216
217 if (nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MIN_VALUE_U,
218 range.min, NL_POLICY_TYPE_ATTR_PAD) ||
219 nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MAX_VALUE_U,
220 range.max, NL_POLICY_TYPE_ATTR_PAD))
221 goto nla_put_failure;
222 break;
223 }
224 case NLA_S8:
225 case NLA_S16:
226 case NLA_S32:
227 case NLA_S64: {
228 struct netlink_range_validation_signed range;
229
230 if (pt->type == NLA_S8)
231 type = NL_ATTR_TYPE_S8;
232 else if (pt->type == NLA_S16)
233 type = NL_ATTR_TYPE_S16;
234 else if (pt->type == NLA_S32)
235 type = NL_ATTR_TYPE_S32;
236 else
237 type = NL_ATTR_TYPE_S64;
238
239 nla_get_range_signed(pt, &range);
240
241 if (nla_put_s64(skb, NL_POLICY_TYPE_ATTR_MIN_VALUE_S,
242 range.min, NL_POLICY_TYPE_ATTR_PAD) ||
243 nla_put_s64(skb, NL_POLICY_TYPE_ATTR_MAX_VALUE_S,
244 range.max, NL_POLICY_TYPE_ATTR_PAD))
245 goto nla_put_failure;
246 break;
247 }
248 case NLA_BITFIELD32:
249 type = NL_ATTR_TYPE_BITFIELD32;
250 if (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_BITFIELD32_MASK,
251 pt->bitfield32_valid))
252 goto nla_put_failure;
253 break;
254 case NLA_EXACT_LEN:
255 type = NL_ATTR_TYPE_BINARY;
256 if (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_MIN_LENGTH, pt->len) ||
257 nla_put_u32(skb, NL_POLICY_TYPE_ATTR_MAX_LENGTH, pt->len))
258 goto nla_put_failure;
259 break;
260 case NLA_STRING:
261 case NLA_NUL_STRING:
262 case NLA_BINARY:
263 if (pt->type == NLA_STRING)
264 type = NL_ATTR_TYPE_STRING;
265 else if (pt->type == NLA_NUL_STRING)
266 type = NL_ATTR_TYPE_NUL_STRING;
267 else
268 type = NL_ATTR_TYPE_BINARY;
269 if (pt->len && nla_put_u32(skb, NL_POLICY_TYPE_ATTR_MAX_LENGTH,
270 pt->len))
271 goto nla_put_failure;
272 break;
273 case NLA_MIN_LEN:
274 type = NL_ATTR_TYPE_BINARY;
275 if (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_MIN_LENGTH, pt->len))
276 goto nla_put_failure;
277 break;
278 case NLA_FLAG:
279 type = NL_ATTR_TYPE_FLAG;
280 break;
281 }
282
283 if (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_TYPE, type))
284 goto nla_put_failure;
285
286 /* finish and move state to next attribute */
287 nla_nest_end(skb, attr);
288 nla_nest_end(skb, policy);
289
290 next:
291 state->attr_idx += 1;
292 if (state->attr_idx > state->policies[state->policy_idx].maxtype) {
293 state->attr_idx = 0;
294 state->policy_idx++;
295 }
296
297 if (again) {
298 if (netlink_policy_dump_finished(state))
299 return -ENODATA;
300 goto send_attribute;
301 }
302
303 return 0;
304
305 nla_put_failure:
306 nla_nest_cancel(skb, policy);
307 return -ENOBUFS;
308 }