aboutsummaryrefslogtreecommitdiffstats
path: root/lib/nlattr.c
diff options
context:
space:
mode:
authorDavid S. Miller <[email protected]>2018-10-02 06:05:32 +0000
committerDavid S. Miller <[email protected]>2018-10-02 06:05:32 +0000
commita1fa80802cb02cb043fd61b87bc81c06a38b4bb1 (patch)
treebd3980a02a9896a5a1d60936b451ce40efc44349 /lib/nlattr.c
parentMerge branch 'Support-of-Flow-Director-in-HNS3-Ethernet-Driver-for-HiP08-Rev2... (diff)
parentnetlink: add validation function to policy (diff)
downloadkernel-a1fa80802cb02cb043fd61b87bc81c06a38b4bb1.tar.gz
kernel-a1fa80802cb02cb043fd61b87bc81c06a38b4bb1.zip
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 <[email protected]>
Diffstat (limited to 'lib/nlattr.c')
-rw-r--r--lib/nlattr.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/lib/nlattr.c b/lib/nlattr.c
index 2f8feff669a7..1e900bb414ef 100644
--- a/lib/nlattr.c
+++ b/lib/nlattr.c
@@ -95,6 +95,64 @@ static int nla_validate_array(const struct nlattr *head, int len, int maxtype,
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,
const struct nla_policy *policy,
struct netlink_ext_ack *extack)
@@ -230,6 +288,27 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
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;
out_err:
NL_SET_ERR_MSG_ATTR(extack, nla, "Attribute failed policy validation");