mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-27 00:51:35 +00:00
Merge branch 'netlink-extended-attribute-validation'
Johannes Berg says: ==================== netlink: extended attribute validation This adds further netlink attribute validation: * min/max/range validation * validation through a custom function pointer This is useful to * reduce boilerplate code in command handling code, if attributes are used commonly across different commands * get more extended ACK error messages/attribute pointers * ensure attributes are valid even when ignored (though this might be a problem when converting existing code) Changes since v1: * split off validate_type from type and use that for min/max/range and function; this is better because the range is limited to the range of s16 and so things like "u16 with minimum value 1" couldn't be expressed earlier * add macros for this, e.g. NLA_POLICY_MIN(NLA_U16, 1) for the case mentioned in the previous bullet Using this pretty much in all places where applicable in nl80211 reduces the code size there by about 1.8KiB, with just a minimal code increase in lib/nlattr.o. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
a1fa80802c
2 changed files with 165 additions and 3 deletions
|
@ -188,9 +188,20 @@ enum {
|
||||||
|
|
||||||
#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1)
|
#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1)
|
||||||
|
|
||||||
|
enum nla_policy_validation {
|
||||||
|
NLA_VALIDATE_NONE,
|
||||||
|
NLA_VALIDATE_RANGE,
|
||||||
|
NLA_VALIDATE_MIN,
|
||||||
|
NLA_VALIDATE_MAX,
|
||||||
|
NLA_VALIDATE_FUNCTION,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct nla_policy - attribute validation policy
|
* struct nla_policy - attribute validation policy
|
||||||
* @type: Type of attribute or NLA_UNSPEC
|
* @type: Type of attribute or NLA_UNSPEC
|
||||||
|
* @validation_type: type of attribute validation done in addition to
|
||||||
|
* type-specific validation (e.g. range, function call), see
|
||||||
|
* &enum nla_policy_validation
|
||||||
* @len: Type specific length of payload
|
* @len: Type specific length of payload
|
||||||
*
|
*
|
||||||
* Policies are defined as arrays of this struct, the array must be
|
* Policies are defined as arrays of this struct, the array must be
|
||||||
|
@ -238,7 +249,33 @@ enum {
|
||||||
* nested attributes directly inside, while an array has
|
* nested attributes directly inside, while an array has
|
||||||
* the nested attributes at another level down and the
|
* the nested attributes at another level down and the
|
||||||
* attributes directly in the nesting don't matter.
|
* attributes directly in the nesting don't matter.
|
||||||
* All other Unused
|
* All other Unused - but note that it's a union
|
||||||
|
*
|
||||||
|
* Meaning of `min' and `max' fields, use via NLA_POLICY_MIN, NLA_POLICY_MAX
|
||||||
|
* and NLA_POLICY_RANGE:
|
||||||
|
* NLA_U8,
|
||||||
|
* NLA_U16,
|
||||||
|
* NLA_U32,
|
||||||
|
* NLA_U64,
|
||||||
|
* NLA_S8,
|
||||||
|
* NLA_S16,
|
||||||
|
* NLA_S32,
|
||||||
|
* NLA_S64 These are used depending on the validation_type
|
||||||
|
* field, if that is min/max/range then the minimum,
|
||||||
|
* maximum and both are used (respectively) to check
|
||||||
|
* the value of the integer attribute.
|
||||||
|
* Note that in the interest of code simplicity and
|
||||||
|
* struct size both limits are s16, so you cannot
|
||||||
|
* enforce a range that doesn't fall within the range
|
||||||
|
* of s16 - do that as usual in the code instead.
|
||||||
|
* All other Unused - but note that it's a union
|
||||||
|
*
|
||||||
|
* Meaning of `validate' field, use via NLA_POLICY_VALIDATE_FN:
|
||||||
|
* NLA_BINARY Validation function called for the attribute,
|
||||||
|
* not compatible with use of the validation_data
|
||||||
|
* as in NLA_BITFIELD32, NLA_REJECT, NLA_NESTED and
|
||||||
|
* NLA_NESTED_ARRAY.
|
||||||
|
* All other Unused - but note that it's a union
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* static const struct nla_policy my_policy[ATTR_MAX+1] = {
|
* static const struct nla_policy my_policy[ATTR_MAX+1] = {
|
||||||
|
@ -249,9 +286,17 @@ enum {
|
||||||
* };
|
* };
|
||||||
*/
|
*/
|
||||||
struct nla_policy {
|
struct nla_policy {
|
||||||
u16 type;
|
u8 type;
|
||||||
|
u8 validation_type;
|
||||||
u16 len;
|
u16 len;
|
||||||
const void *validation_data;
|
union {
|
||||||
|
const void *validation_data;
|
||||||
|
struct {
|
||||||
|
s16 min, max;
|
||||||
|
};
|
||||||
|
int (*validate)(const struct nlattr *attr,
|
||||||
|
struct netlink_ext_ack *extack);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NLA_POLICY_EXACT_LEN(_len) { .type = NLA_EXACT_LEN, .len = _len }
|
#define NLA_POLICY_EXACT_LEN(_len) { .type = NLA_EXACT_LEN, .len = _len }
|
||||||
|
@ -266,6 +311,44 @@ struct nla_policy {
|
||||||
#define NLA_POLICY_NESTED_ARRAY(maxattr, policy) \
|
#define NLA_POLICY_NESTED_ARRAY(maxattr, policy) \
|
||||||
{ .type = NLA_NESTED_ARRAY, .validation_data = policy, .len = maxattr }
|
{ .type = NLA_NESTED_ARRAY, .validation_data = policy, .len = maxattr }
|
||||||
|
|
||||||
|
#define __NLA_ENSURE(condition) (sizeof(char[1 - 2*!(condition)]) - 1)
|
||||||
|
#define NLA_ENSURE_INT_TYPE(tp) \
|
||||||
|
(__NLA_ENSURE(tp == NLA_S8 || tp == NLA_U8 || \
|
||||||
|
tp == NLA_S16 || tp == NLA_U16 || \
|
||||||
|
tp == NLA_S32 || tp == NLA_U32 || \
|
||||||
|
tp == NLA_S64 || tp == NLA_U64) + tp)
|
||||||
|
#define NLA_ENSURE_NO_VALIDATION_PTR(tp) \
|
||||||
|
(__NLA_ENSURE(tp != NLA_BITFIELD32 && \
|
||||||
|
tp != NLA_REJECT && \
|
||||||
|
tp != NLA_NESTED && \
|
||||||
|
tp != NLA_NESTED_ARRAY) + tp)
|
||||||
|
|
||||||
|
#define NLA_POLICY_RANGE(tp, _min, _max) { \
|
||||||
|
.type = NLA_ENSURE_INT_TYPE(tp), \
|
||||||
|
.validation_type = NLA_VALIDATE_RANGE, \
|
||||||
|
.min = _min, \
|
||||||
|
.max = _max \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NLA_POLICY_MIN(tp, _min) { \
|
||||||
|
.type = NLA_ENSURE_INT_TYPE(tp), \
|
||||||
|
.validation_type = NLA_VALIDATE_MIN, \
|
||||||
|
.min = _min, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NLA_POLICY_MAX(tp, _max) { \
|
||||||
|
.type = NLA_ENSURE_INT_TYPE(tp), \
|
||||||
|
.validation_type = NLA_VALIDATE_MAX, \
|
||||||
|
.max = _max, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NLA_POLICY_VALIDATE_FN(tp, fn, ...) { \
|
||||||
|
.type = NLA_ENSURE_NO_VALIDATION_PTR(tp), \
|
||||||
|
.validation_type = NLA_VALIDATE_FUNCTION, \
|
||||||
|
.validate = fn, \
|
||||||
|
.len = __VA_ARGS__ + 0, \
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct nl_info - netlink source information
|
* struct nl_info - netlink source information
|
||||||
* @nlh: Netlink message header of original request
|
* @nlh: Netlink message header of original request
|
||||||
|
|
79
lib/nlattr.c
79
lib/nlattr.c
|
@ -95,6 +95,64 @@ static int nla_validate_array(const struct nlattr *head, int len, int maxtype,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int nla_validate_int_range(const struct nla_policy *pt,
|
||||||
|
const struct nlattr *nla,
|
||||||
|
struct netlink_ext_ack *extack)
|
||||||
|
{
|
||||||
|
bool validate_min, validate_max;
|
||||||
|
s64 value;
|
||||||
|
|
||||||
|
validate_min = pt->validation_type == NLA_VALIDATE_RANGE ||
|
||||||
|
pt->validation_type == NLA_VALIDATE_MIN;
|
||||||
|
validate_max = pt->validation_type == NLA_VALIDATE_RANGE ||
|
||||||
|
pt->validation_type == NLA_VALIDATE_MAX;
|
||||||
|
|
||||||
|
switch (pt->type) {
|
||||||
|
case NLA_U8:
|
||||||
|
value = nla_get_u8(nla);
|
||||||
|
break;
|
||||||
|
case NLA_U16:
|
||||||
|
value = nla_get_u16(nla);
|
||||||
|
break;
|
||||||
|
case NLA_U32:
|
||||||
|
value = nla_get_u32(nla);
|
||||||
|
break;
|
||||||
|
case NLA_S8:
|
||||||
|
value = nla_get_s8(nla);
|
||||||
|
break;
|
||||||
|
case NLA_S16:
|
||||||
|
value = nla_get_s16(nla);
|
||||||
|
break;
|
||||||
|
case NLA_S32:
|
||||||
|
value = nla_get_s32(nla);
|
||||||
|
break;
|
||||||
|
case NLA_S64:
|
||||||
|
value = nla_get_s64(nla);
|
||||||
|
break;
|
||||||
|
case NLA_U64:
|
||||||
|
/* treat this one specially, since it may not fit into s64 */
|
||||||
|
if ((validate_min && nla_get_u64(nla) < pt->min) ||
|
||||||
|
(validate_max && nla_get_u64(nla) > pt->max)) {
|
||||||
|
NL_SET_ERR_MSG_ATTR(extack, nla,
|
||||||
|
"integer out of range");
|
||||||
|
return -ERANGE;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
WARN_ON(1);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((validate_min && value < pt->min) ||
|
||||||
|
(validate_max && value > pt->max)) {
|
||||||
|
NL_SET_ERR_MSG_ATTR(extack, nla,
|
||||||
|
"integer out of range");
|
||||||
|
return -ERANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int validate_nla(const struct nlattr *nla, int maxtype,
|
static int validate_nla(const struct nlattr *nla, int maxtype,
|
||||||
const struct nla_policy *policy,
|
const struct nla_policy *policy,
|
||||||
struct netlink_ext_ack *extack)
|
struct netlink_ext_ack *extack)
|
||||||
|
@ -230,6 +288,27 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* further validation */
|
||||||
|
switch (pt->validation_type) {
|
||||||
|
case NLA_VALIDATE_NONE:
|
||||||
|
/* nothing to do */
|
||||||
|
break;
|
||||||
|
case NLA_VALIDATE_RANGE:
|
||||||
|
case NLA_VALIDATE_MIN:
|
||||||
|
case NLA_VALIDATE_MAX:
|
||||||
|
err = nla_validate_int_range(pt, nla, extack);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
break;
|
||||||
|
case NLA_VALIDATE_FUNCTION:
|
||||||
|
if (pt->validate) {
|
||||||
|
err = pt->validate(nla, extack);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
out_err:
|
out_err:
|
||||||
NL_SET_ERR_MSG_ATTR(extack, nla, "Attribute failed policy validation");
|
NL_SET_ERR_MSG_ATTR(extack, nla, "Attribute failed policy validation");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue