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 netlink_policy_dump_state { |
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[] __counted_by(n_alloc); |
25 | }; |
26 | |
27 | static int add_policy(struct netlink_policy_dump_state **statep, |
28 | const struct nla_policy *policy, |
29 | unsigned int maxtype) |
30 | { |
31 | struct netlink_policy_dump_state *state = *statep; |
32 | unsigned int old_n_alloc, 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 | state->policies[i].maxtype == maxtype) |
40 | return 0; |
41 | |
42 | if (!state->policies[i].policy) { |
43 | state->policies[i].policy = policy; |
44 | state->policies[i].maxtype = maxtype; |
45 | return 0; |
46 | } |
47 | } |
48 | |
49 | n_alloc = state->n_alloc + INITIAL_POLICIES_ALLOC; |
50 | state = krealloc(objp: state, struct_size(state, policies, n_alloc), |
51 | GFP_KERNEL); |
52 | if (!state) |
53 | return -ENOMEM; |
54 | |
55 | old_n_alloc = state->n_alloc; |
56 | state->n_alloc = n_alloc; |
57 | memset(&state->policies[old_n_alloc], 0, |
58 | flex_array_size(state, policies, n_alloc - old_n_alloc)); |
59 | |
60 | state->policies[old_n_alloc].policy = policy; |
61 | state->policies[old_n_alloc].maxtype = maxtype; |
62 | *statep = state; |
63 | |
64 | return 0; |
65 | } |
66 | |
67 | /** |
68 | * netlink_policy_dump_get_policy_idx - retrieve policy index |
69 | * @state: the policy dump state |
70 | * @policy: the policy to find |
71 | * @maxtype: the policy's maxattr |
72 | * |
73 | * Returns: the index of the given policy in the dump state |
74 | * |
75 | * Call this to find a policy index when you've added multiple and e.g. |
76 | * need to tell userspace which command has which policy (by index). |
77 | * |
78 | * Note: this will WARN and return 0 if the policy isn't found, which |
79 | * means it wasn't added in the first place, which would be an |
80 | * internal consistency bug. |
81 | */ |
82 | int netlink_policy_dump_get_policy_idx(struct netlink_policy_dump_state *state, |
83 | const struct nla_policy *policy, |
84 | unsigned int maxtype) |
85 | { |
86 | unsigned int i; |
87 | |
88 | if (WARN_ON(!policy || !maxtype)) |
89 | return 0; |
90 | |
91 | for (i = 0; i < state->n_alloc; i++) { |
92 | if (state->policies[i].policy == policy && |
93 | state->policies[i].maxtype == maxtype) |
94 | return i; |
95 | } |
96 | |
97 | WARN_ON(1); |
98 | return 0; |
99 | } |
100 | |
101 | static struct netlink_policy_dump_state *alloc_state(void) |
102 | { |
103 | struct netlink_policy_dump_state *state; |
104 | |
105 | state = kzalloc(struct_size(state, policies, INITIAL_POLICIES_ALLOC), |
106 | GFP_KERNEL); |
107 | if (!state) |
108 | return ERR_PTR(error: -ENOMEM); |
109 | state->n_alloc = INITIAL_POLICIES_ALLOC; |
110 | |
111 | return state; |
112 | } |
113 | |
114 | /** |
115 | * netlink_policy_dump_add_policy - add a policy to the dump |
116 | * @pstate: state to add to, may be reallocated, must be %NULL the first time |
117 | * @policy: the new policy to add to the dump |
118 | * @maxtype: the new policy's max attr type |
119 | * |
120 | * Returns: 0 on success, a negative error code otherwise. |
121 | * |
122 | * Call this to allocate a policy dump state, and to add policies to it. This |
123 | * should be called from the dump start() callback. |
124 | * |
125 | * Note: on failures, any previously allocated state is freed. |
126 | */ |
127 | int netlink_policy_dump_add_policy(struct netlink_policy_dump_state **pstate, |
128 | const struct nla_policy *policy, |
129 | unsigned int maxtype) |
130 | { |
131 | struct netlink_policy_dump_state *state = *pstate; |
132 | unsigned int policy_idx; |
133 | int err; |
134 | |
135 | if (!state) { |
136 | state = alloc_state(); |
137 | if (IS_ERR(ptr: state)) |
138 | return PTR_ERR(ptr: state); |
139 | } |
140 | |
141 | /* |
142 | * walk the policies and nested ones first, and build |
143 | * a linear list of them. |
144 | */ |
145 | |
146 | err = add_policy(statep: &state, policy, maxtype); |
147 | if (err) |
148 | goto err_try_undo; |
149 | |
150 | for (policy_idx = 0; |
151 | policy_idx < state->n_alloc && state->policies[policy_idx].policy; |
152 | policy_idx++) { |
153 | const struct nla_policy *policy; |
154 | unsigned int type; |
155 | |
156 | policy = state->policies[policy_idx].policy; |
157 | |
158 | for (type = 0; |
159 | type <= state->policies[policy_idx].maxtype; |
160 | type++) { |
161 | switch (policy[type].type) { |
162 | case NLA_NESTED: |
163 | case NLA_NESTED_ARRAY: |
164 | err = add_policy(statep: &state, |
165 | policy: policy[type].nested_policy, |
166 | maxtype: policy[type].len); |
167 | if (err) |
168 | goto err_try_undo; |
169 | break; |
170 | default: |
171 | break; |
172 | } |
173 | } |
174 | } |
175 | |
176 | *pstate = state; |
177 | return 0; |
178 | |
179 | err_try_undo: |
180 | /* Try to preserve reasonable unwind semantics - if we're starting from |
181 | * scratch clean up fully, otherwise record what we got and caller will. |
182 | */ |
183 | if (!*pstate) |
184 | netlink_policy_dump_free(state); |
185 | else |
186 | *pstate = state; |
187 | return err; |
188 | } |
189 | |
190 | static bool |
191 | netlink_policy_dump_finished(struct netlink_policy_dump_state *state) |
192 | { |
193 | return state->policy_idx >= state->n_alloc || |
194 | !state->policies[state->policy_idx].policy; |
195 | } |
196 | |
197 | /** |
198 | * netlink_policy_dump_loop - dumping loop indicator |
199 | * @state: the policy dump state |
200 | * |
201 | * Returns: %true if the dump continues, %false otherwise |
202 | * |
203 | * Note: this frees the dump state when finishing |
204 | */ |
205 | bool netlink_policy_dump_loop(struct netlink_policy_dump_state *state) |
206 | { |
207 | return !netlink_policy_dump_finished(state); |
208 | } |
209 | |
210 | int netlink_policy_dump_attr_size_estimate(const struct nla_policy *pt) |
211 | { |
212 | /* nested + type */ |
213 | int common = 2 * nla_attr_size(payload: sizeof(u32)); |
214 | |
215 | switch (pt->type) { |
216 | case NLA_UNSPEC: |
217 | case NLA_REJECT: |
218 | /* these actually don't need any space */ |
219 | return 0; |
220 | case NLA_NESTED: |
221 | case NLA_NESTED_ARRAY: |
222 | /* common, policy idx, policy maxattr */ |
223 | return common + 2 * nla_attr_size(payload: sizeof(u32)); |
224 | case NLA_U8: |
225 | case NLA_U16: |
226 | case NLA_U32: |
227 | case NLA_U64: |
228 | case NLA_MSECS: |
229 | case NLA_S8: |
230 | case NLA_S16: |
231 | case NLA_S32: |
232 | case NLA_S64: |
233 | case NLA_SINT: |
234 | case NLA_UINT: |
235 | /* maximum is common, u64 min/max with padding */ |
236 | return common + |
237 | 2 * (nla_attr_size(payload: 0) + nla_attr_size(payload: sizeof(u64))); |
238 | case NLA_BITFIELD32: |
239 | return common + nla_attr_size(payload: sizeof(u32)); |
240 | case NLA_STRING: |
241 | case NLA_NUL_STRING: |
242 | case NLA_BINARY: |
243 | /* maximum is common, u32 min-length/max-length */ |
244 | return common + 2 * nla_attr_size(payload: sizeof(u32)); |
245 | case NLA_FLAG: |
246 | return common; |
247 | } |
248 | |
249 | /* this should then cause a warning later */ |
250 | return 0; |
251 | } |
252 | |
253 | static int |
254 | __netlink_policy_dump_write_attr(struct netlink_policy_dump_state *state, |
255 | struct sk_buff *skb, |
256 | const struct nla_policy *pt, |
257 | int nestattr) |
258 | { |
259 | int estimate = netlink_policy_dump_attr_size_estimate(pt); |
260 | enum netlink_attribute_type type; |
261 | struct nlattr *attr; |
262 | |
263 | attr = nla_nest_start(skb, attrtype: nestattr); |
264 | if (!attr) |
265 | return -ENOBUFS; |
266 | |
267 | switch (pt->type) { |
268 | default: |
269 | case NLA_UNSPEC: |
270 | case NLA_REJECT: |
271 | /* skip - use NLA_MIN_LEN to advertise such */ |
272 | nla_nest_cancel(skb, start: attr); |
273 | return -ENODATA; |
274 | case NLA_NESTED: |
275 | type = NL_ATTR_TYPE_NESTED; |
276 | fallthrough; |
277 | case NLA_NESTED_ARRAY: |
278 | if (pt->type == NLA_NESTED_ARRAY) |
279 | type = NL_ATTR_TYPE_NESTED_ARRAY; |
280 | if (state && pt->nested_policy && pt->len && |
281 | (nla_put_u32(skb, attrtype: NL_POLICY_TYPE_ATTR_POLICY_IDX, |
282 | value: netlink_policy_dump_get_policy_idx(state, |
283 | policy: pt->nested_policy, |
284 | maxtype: pt->len)) || |
285 | nla_put_u32(skb, attrtype: NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE, |
286 | value: pt->len))) |
287 | goto nla_put_failure; |
288 | break; |
289 | case NLA_U8: |
290 | case NLA_U16: |
291 | case NLA_U32: |
292 | case NLA_U64: |
293 | case NLA_UINT: |
294 | case NLA_MSECS: { |
295 | struct netlink_range_validation range; |
296 | |
297 | if (pt->type == NLA_U8) |
298 | type = NL_ATTR_TYPE_U8; |
299 | else if (pt->type == NLA_U16) |
300 | type = NL_ATTR_TYPE_U16; |
301 | else if (pt->type == NLA_U32) |
302 | type = NL_ATTR_TYPE_U32; |
303 | else if (pt->type == NLA_U64) |
304 | type = NL_ATTR_TYPE_U64; |
305 | else |
306 | type = NL_ATTR_TYPE_UINT; |
307 | |
308 | if (pt->validation_type == NLA_VALIDATE_MASK) { |
309 | if (nla_put_u64_64bit(skb, attrtype: NL_POLICY_TYPE_ATTR_MASK, |
310 | value: pt->mask, |
311 | padattr: NL_POLICY_TYPE_ATTR_PAD)) |
312 | goto nla_put_failure; |
313 | break; |
314 | } |
315 | |
316 | nla_get_range_unsigned(pt, range: &range); |
317 | |
318 | if (nla_put_u64_64bit(skb, attrtype: NL_POLICY_TYPE_ATTR_MIN_VALUE_U, |
319 | value: range.min, padattr: NL_POLICY_TYPE_ATTR_PAD) || |
320 | nla_put_u64_64bit(skb, attrtype: NL_POLICY_TYPE_ATTR_MAX_VALUE_U, |
321 | value: range.max, padattr: NL_POLICY_TYPE_ATTR_PAD)) |
322 | goto nla_put_failure; |
323 | break; |
324 | } |
325 | case NLA_S8: |
326 | case NLA_S16: |
327 | case NLA_S32: |
328 | case NLA_S64: |
329 | case NLA_SINT: { |
330 | struct netlink_range_validation_signed range; |
331 | |
332 | if (pt->type == NLA_S8) |
333 | type = NL_ATTR_TYPE_S8; |
334 | else if (pt->type == NLA_S16) |
335 | type = NL_ATTR_TYPE_S16; |
336 | else if (pt->type == NLA_S32) |
337 | type = NL_ATTR_TYPE_S32; |
338 | else if (pt->type == NLA_S64) |
339 | type = NL_ATTR_TYPE_S64; |
340 | else |
341 | type = NL_ATTR_TYPE_SINT; |
342 | |
343 | nla_get_range_signed(pt, range: &range); |
344 | |
345 | if (nla_put_s64(skb, attrtype: NL_POLICY_TYPE_ATTR_MIN_VALUE_S, |
346 | value: range.min, padattr: NL_POLICY_TYPE_ATTR_PAD) || |
347 | nla_put_s64(skb, attrtype: NL_POLICY_TYPE_ATTR_MAX_VALUE_S, |
348 | value: range.max, padattr: NL_POLICY_TYPE_ATTR_PAD)) |
349 | goto nla_put_failure; |
350 | break; |
351 | } |
352 | case NLA_BITFIELD32: |
353 | type = NL_ATTR_TYPE_BITFIELD32; |
354 | if (nla_put_u32(skb, attrtype: NL_POLICY_TYPE_ATTR_BITFIELD32_MASK, |
355 | value: pt->bitfield32_valid)) |
356 | goto nla_put_failure; |
357 | break; |
358 | case NLA_STRING: |
359 | case NLA_NUL_STRING: |
360 | case NLA_BINARY: |
361 | if (pt->type == NLA_STRING) |
362 | type = NL_ATTR_TYPE_STRING; |
363 | else if (pt->type == NLA_NUL_STRING) |
364 | type = NL_ATTR_TYPE_NUL_STRING; |
365 | else |
366 | type = NL_ATTR_TYPE_BINARY; |
367 | |
368 | if (pt->validation_type == NLA_VALIDATE_RANGE || |
369 | pt->validation_type == NLA_VALIDATE_RANGE_WARN_TOO_LONG) { |
370 | struct netlink_range_validation range; |
371 | |
372 | nla_get_range_unsigned(pt, range: &range); |
373 | |
374 | if (range.min && |
375 | nla_put_u32(skb, attrtype: NL_POLICY_TYPE_ATTR_MIN_LENGTH, |
376 | value: range.min)) |
377 | goto nla_put_failure; |
378 | |
379 | if (range.max < U16_MAX && |
380 | nla_put_u32(skb, attrtype: NL_POLICY_TYPE_ATTR_MAX_LENGTH, |
381 | value: range.max)) |
382 | goto nla_put_failure; |
383 | } else if (pt->len && |
384 | nla_put_u32(skb, attrtype: NL_POLICY_TYPE_ATTR_MAX_LENGTH, |
385 | value: pt->len)) { |
386 | goto nla_put_failure; |
387 | } |
388 | break; |
389 | case NLA_FLAG: |
390 | type = NL_ATTR_TYPE_FLAG; |
391 | break; |
392 | } |
393 | |
394 | if (nla_put_u32(skb, attrtype: NL_POLICY_TYPE_ATTR_TYPE, value: type)) |
395 | goto nla_put_failure; |
396 | |
397 | nla_nest_end(skb, start: attr); |
398 | WARN_ON(attr->nla_len > estimate); |
399 | |
400 | return 0; |
401 | nla_put_failure: |
402 | nla_nest_cancel(skb, start: attr); |
403 | return -ENOBUFS; |
404 | } |
405 | |
406 | /** |
407 | * netlink_policy_dump_write_attr - write a given attribute policy |
408 | * @skb: the message skb to write to |
409 | * @pt: the attribute's policy |
410 | * @nestattr: the nested attribute ID to use |
411 | * |
412 | * Returns: 0 on success, an error code otherwise; -%ENODATA is |
413 | * special, indicating that there's no policy data and |
414 | * the attribute is generally rejected. |
415 | */ |
416 | int netlink_policy_dump_write_attr(struct sk_buff *skb, |
417 | const struct nla_policy *pt, |
418 | int nestattr) |
419 | { |
420 | return __netlink_policy_dump_write_attr(NULL, skb, pt, nestattr); |
421 | } |
422 | |
423 | /** |
424 | * netlink_policy_dump_write - write current policy dump attributes |
425 | * @skb: the message skb to write to |
426 | * @state: the policy dump state |
427 | * |
428 | * Returns: 0 on success, an error code otherwise |
429 | */ |
430 | int netlink_policy_dump_write(struct sk_buff *skb, |
431 | struct netlink_policy_dump_state *state) |
432 | { |
433 | const struct nla_policy *pt; |
434 | struct nlattr *policy; |
435 | bool again; |
436 | int err; |
437 | |
438 | send_attribute: |
439 | again = false; |
440 | |
441 | pt = &state->policies[state->policy_idx].policy[state->attr_idx]; |
442 | |
443 | policy = nla_nest_start(skb, attrtype: state->policy_idx); |
444 | if (!policy) |
445 | return -ENOBUFS; |
446 | |
447 | err = __netlink_policy_dump_write_attr(state, skb, pt, nestattr: state->attr_idx); |
448 | if (err == -ENODATA) { |
449 | nla_nest_cancel(skb, start: policy); |
450 | again = true; |
451 | goto next; |
452 | } else if (err) { |
453 | goto nla_put_failure; |
454 | } |
455 | |
456 | /* finish and move state to next attribute */ |
457 | nla_nest_end(skb, start: policy); |
458 | |
459 | next: |
460 | state->attr_idx += 1; |
461 | if (state->attr_idx > state->policies[state->policy_idx].maxtype) { |
462 | state->attr_idx = 0; |
463 | state->policy_idx++; |
464 | } |
465 | |
466 | if (again) { |
467 | if (netlink_policy_dump_finished(state)) |
468 | return -ENODATA; |
469 | goto send_attribute; |
470 | } |
471 | |
472 | return 0; |
473 | |
474 | nla_put_failure: |
475 | nla_nest_cancel(skb, start: policy); |
476 | return -ENOBUFS; |
477 | } |
478 | |
479 | /** |
480 | * netlink_policy_dump_free - free policy dump state |
481 | * @state: the policy dump state to free |
482 | * |
483 | * Call this from the done() method to ensure dump state is freed. |
484 | */ |
485 | void netlink_policy_dump_free(struct netlink_policy_dump_state *state) |
486 | { |
487 | kfree(objp: state); |
488 | } |
489 | |