mbox series

[0/7] netlink recursive policy validation

Message ID 20180919120900.28708-1-johannes@sipsolutions.net (mailing list archive)
Headers show
Series netlink recursive policy validation | expand

Message

Johannes Berg Sept. 19, 2018, 12:08 p.m. UTC
This series adds recursive policy validation, allowing you to specify
complex policies involving nested attributes, both
 * attributes that directly contain new nested attributes
   (NLA_NESTED)
 * attributes that have nested attributes used as an array, where the
   type of each inner attribute is irrelevant/ignored but each of them
   yet again contains nested attributes that should conform to a given
   policy (the new NLA_NESTED_ARRAY)

This is useful for a more compact representation of the policy for the
attributes, which - among other benefits - makes it more easily seen
when reading the code, requiring reading just the policy instead of
digging into all the usage/nested validation code.

In terms of code benefits, it means possibly some validation code can
be removed.

One thing to be aware of: retrofitting this to existing policies may
in fact break userspace - it might have been sending broken but ignored
attributes, which global enforcement of the (nested) policy would now
prevent.

johannes

Comments

Johannes Berg Sept. 19, 2018, 12:15 p.m. UTC | #1
Below is an example of a policy I just built using this.

This may seem rather complex, but that's because the problem is complex
- we want to be able to measure multiple different things (currently
only FTM though) with different peers, and some attributes are shared
(like channel, MAC address) whereas others are method-specific...

I'm sticking all of the measurement request into a single top-level
nl80211 attribute (NL80211_ATTR_PEER_MEASUREMENTS), then in there you
specify global parameters (elided) as well as an array of peers.

Each peer again contains some method-independent parameters (only "CHAN"
shown), as well as request data, which has some parts that are common
and some that are method dependent (yet another nesting level).

All of this gets validated - with the channel data exception in the
comment below - entirely without ever writing another line of code for
it. Yes, we'll still have to write some code to actually use it, but
then we need to worry much less about formatting there.

johannes


static const struct nla_policy
nl80211_pmsr_ftm_req_attr_policy[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1] = {
/* ... */
};

static const struct nla_policy
nl80211_pmsr_req_data_policy[NL80211_PMSR_TYPE_MAX + 1] = {
	[NL80211_PMSR_TYPE_FTM] =
		NLA_POLICY_NESTED(NL80211_PMSR_FTM_REQ_ATTR_MAX,
				  nl80211_pmsr_ftm_req_attr_policy),
};

static const struct nla_policy
nl80211_pmsr_req_attr_policy[NL80211_PMSR_REQ_ATTR_MAX + 1] = {
	[NL80211_PMSR_REQ_ATTR_DATA] =
		NLA_POLICY_NESTED(NL80211_PMSR_TYPE_MAX,
				  nl80211_pmsr_req_data_policy),
/* ... */
};

static const struct nla_policy
nl80211_psmr_peer_attr_policy[NL80211_PMSR_PEER_ATTR_MAX + 1] = {
	/*
	 * we could specify this again to be the top-level policy,
	 * but that would open us up to recursion problems ...
	 */
	[NL80211_PMSR_PEER_ATTR_CHAN] = { .type = NLA_NESTED },
	[NL80211_PMSR_PEER_ATTR_REQ] =
		NLA_POLICY_NESTED(NL80211_PMSR_REQ_ATTR_MAX,
				  nl80211_pmsr_req_attr_policy),
/* ... */
};

static const struct nla_policy
nl80211_pmsr_attr_policy[NL80211_PMSR_ATTR_MAX + 1] = {
	[NL80211_PMSR_ATTR_PEERS] =
		NLA_POLICY_NESTED_ARRAY(NL80211_PMSR_PEER_ATTR_MAX,
					nl80211_psmr_peer_attr_policy),
/* ... */
};

static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
/* ... */
	[NL80211_ATTR_PEER_MEASUREMENTS] =
		NLA_POLICY_NESTED(NL80211_PMSR_FTM_REQ_ATTR_MAX,
				  nl80211_pmsr_attr_policy),
};