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 } 309