History

netlink: add mask validation

We don't have good validation policy for existing unsigned int attrs which serve as flags (for new ones we could use NLA_BITFIELD32). With increased use of policy dumping having the validation be expressed as part of the policy is important. Add validation policy in form of a mask of supported/valid bits. Support u64 in the uAPI to be future-proof, but really for now the embedded mask member can only hold 32 bits, so anything with bit 32+ set will always fail validation.

Jakub Kicinski committed 6 years ago

Commit bdbb4e21 parent ddcf3b74 files · +56 −0Browse files

Unified · Split

4 files
  1. include/net/netlink.h +10 −0
  2. include/uapi/linux/netlink.h +2 −0
  3. lib/nlattr.c +36 −0
  4. net/netlink/policy.c +8 −0
include/net/netlink.h+10−0
@@ -200,6 +200,7 @@ enum nla_policy_validation { · 199 unmodified lines
200 NLA_VALIDATE_RANGE_WARN_TOO_LONG,200 NLA_VALIDATE_RANGE_WARN_TOO_LONG,
201 NLA_VALIDATE_MIN,201 NLA_VALIDATE_MIN,
202 NLA_VALIDATE_MAX,202 NLA_VALIDATE_MAX,
203 NLA_VALIDATE_MASK,
203 NLA_VALIDATE_RANGE_PTR,204 NLA_VALIDATE_RANGE_PTR,
204 NLA_VALIDATE_FUNCTION,205 NLA_VALIDATE_FUNCTION,
205};206};
@@ -317,6 +318,7 @@ struct nla_policy { · 111 unmodified lines
317 u16 len;318 u16 len;
318 union {319 union {
319 const u32 bitfield32_valid;320 const u32 bitfield32_valid;
321 const u32 mask;
320 const char *reject_message;322 const char *reject_message;
321 const struct nla_policy *nested_policy;323 const struct nla_policy *nested_policy;
322 struct netlink_range_validation *range;324 struct netlink_range_validation *range;
@@ -368,6 +370,8 @@ struct nla_policy { · 45 unmodified lines
368 (tp == NLA_S8 || tp == NLA_S16 || tp == NLA_S32 || tp == NLA_S64)370 (tp == NLA_S8 || tp == NLA_S16 || tp == NLA_S32 || tp == NLA_S64)
369 371
370#define __NLA_ENSURE(condition) BUILD_BUG_ON_ZERO(!(condition))372#define __NLA_ENSURE(condition) BUILD_BUG_ON_ZERO(!(condition))
373#define NLA_ENSURE_UINT_TYPE(tp) \
374 (__NLA_ENSURE(__NLA_IS_UINT_TYPE(tp)) + tp)
371#define NLA_ENSURE_UINT_OR_BINARY_TYPE(tp) \375#define NLA_ENSURE_UINT_OR_BINARY_TYPE(tp) \
372 (__NLA_ENSURE(__NLA_IS_UINT_TYPE(tp) || \376 (__NLA_ENSURE(__NLA_IS_UINT_TYPE(tp) || \
373 tp == NLA_MSECS || \377 tp == NLA_MSECS || \
@@ -416,6 +420,12 @@ struct nla_policy { · 42 unmodified lines
416 .max = _max, \420 .max = _max, \
417}421}
418 422
423#define NLA_POLICY_MASK(tp, _mask) { \
424 .type = NLA_ENSURE_UINT_TYPE(tp), \
425 .validation_type = NLA_VALIDATE_MASK, \
426 .mask = _mask, \
427}
428
419#define NLA_POLICY_VALIDATE_FN(tp, fn, ...) { \429#define NLA_POLICY_VALIDATE_FN(tp, fn, ...) { \
420 .type = NLA_ENSURE_NO_VALIDATION_PTR(tp), \430 .type = NLA_ENSURE_NO_VALIDATION_PTR(tp), \
421 .validation_type = NLA_VALIDATE_FUNCTION, \431 .validation_type = NLA_VALIDATE_FUNCTION, \
include/uapi/linux/netlink.h+2−0
@@ -331,6 +331,7 @@ enum netlink_attribute_type { · 330 unmodified lines
331 * the index, if limited inside the nesting (U32)331 * the index, if limited inside the nesting (U32)
332 * @NL_POLICY_TYPE_ATTR_BITFIELD32_MASK: valid mask for the332 * @NL_POLICY_TYPE_ATTR_BITFIELD32_MASK: valid mask for the
333 * bitfield32 type (U32)333 * bitfield32 type (U32)
334 * @NL_POLICY_TYPE_ATTR_MASK: mask of valid bits for unsigned integers (U64)
334 * @NL_POLICY_TYPE_ATTR_PAD: pad attribute for 64-bit alignment335 * @NL_POLICY_TYPE_ATTR_PAD: pad attribute for 64-bit alignment
335 */336 */
336enum netlink_policy_type_attr {337enum netlink_policy_type_attr {
@@ -346,6 +347,7 @@ enum netlink_policy_type_attr { · 9 unmodified lines
346 NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE,347 NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE,
347 NL_POLICY_TYPE_ATTR_BITFIELD32_MASK,348 NL_POLICY_TYPE_ATTR_BITFIELD32_MASK,
348 NL_POLICY_TYPE_ATTR_PAD,349 NL_POLICY_TYPE_ATTR_PAD,
350 NL_POLICY_TYPE_ATTR_MASK,
349 351
350 /* keep last */352 /* keep last */
351 __NL_POLICY_TYPE_ATTR_MAX,353 __NL_POLICY_TYPE_ATTR_MAX,
lib/nlattr.c+36−0
@@ -323,6 +323,37 @@ static int nla_validate_int_range(const struct nla_policy *pt, · 322 unmodified lines
323 }323 }
324}324}
325 325
326static int nla_validate_mask(const struct nla_policy *pt,
327 const struct nlattr *nla,
328 struct netlink_ext_ack *extack)
329{
330 u64 value;
331
332 switch (pt->type) {
333 case NLA_U8:
334 value = nla_get_u8(nla);
335 break;
336 case NLA_U16:
337 value = nla_get_u16(nla);
338 break;
339 case NLA_U32:
340 value = nla_get_u32(nla);
341 break;
342 case NLA_U64:
343 value = nla_get_u64(nla);
344 break;
345 default:
346 return -EINVAL;
347 }
348
349 if (value & ~(u64)pt->mask) {
350 NL_SET_ERR_MSG_ATTR(extack, nla, "reserved bit set");
351 return -EINVAL;
352 }
353
354 return 0;
355}
356
326static int validate_nla(const struct nlattr *nla, int maxtype,357static int validate_nla(const struct nlattr *nla, int maxtype,
327 const struct nla_policy *policy, unsigned int validate,358 const struct nla_policy *policy, unsigned int validate,
328 struct netlink_ext_ack *extack, unsigned int depth)359 struct netlink_ext_ack *extack, unsigned int depth)
@@ -503,6 +534,11 @@ static int validate_nla(const struct nlattr *nla, int maxtype, · 174 unmodified lines
503 if (err)534 if (err)
504 return err;535 return err;
505 break;536 break;
537 case NLA_VALIDATE_MASK:
538 err = nla_validate_mask(pt, nla, extack);
539 if (err)
540 return err;
541 break;
506 case NLA_VALIDATE_FUNCTION:542 case NLA_VALIDATE_FUNCTION:
507 if (pt->validate) {543 if (pt->validate) {
508 err = pt->validate(nla, extack);544 err = pt->validate(nla, extack);
net/netlink/policy.c+8−0
@@ -263,6 +263,14 @@ send_attribute: · 262 unmodified lines
263 else263 else
264 type = NL_ATTR_TYPE_U64;264 type = NL_ATTR_TYPE_U64;
265 265
266 if (pt->validation_type == NLA_VALIDATE_MASK) {
267 if (nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MASK,
268 pt->mask,
269 NL_POLICY_TYPE_ATTR_PAD))
270 goto nla_put_failure;
271 break;
272 }
273
266 nla_get_range_unsigned(pt, &range);274 nla_get_range_unsigned(pt, &range);
267 275
268 if (nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MIN_VALUE_U,276 if (nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MIN_VALUE_U,