Commit e1201bc7 authored by Pedro Tammela's avatar Pedro Tammela Committed by David S. Miller
Browse files

net/sched: act_pedit: check static offsets a priori



Static key offsets should always be on 32 bit boundaries. Validate them on
create/update time for static offsets and move the datapath validation
for runtime offsets only.

iproute2 already errors out if a given offset and data size cannot be
packed to a 32 bit boundary. This change will make sure users which
create/update pedit instances directly via netlink also error out,
instead of finding out when packets are traversing.

Reviewed-by: default avatarJamal Hadi Salim <jhs@mojatatu.com>
Reviewed-by: default avatarSimon Horman <simon.horman@corigine.com>
Signed-off-by: default avatarPedro Tammela <pctammela@mojatatu.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0c83c521
Loading
Loading
Loading
Loading
+14 −6
Original line number Diff line number Diff line
@@ -251,8 +251,16 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
	memcpy(nparms->tcfp_keys, parm->keys, ksize);

	for (i = 0; i < nparms->tcfp_nkeys; ++i) {
		u32 offmask = nparms->tcfp_keys[i].offmask;
		u32 cur = nparms->tcfp_keys[i].off;

		/* The AT option can be added to static offsets in the datapath */
		if (!offmask && cur % 4) {
			NL_SET_ERR_MSG_MOD(extack, "Offsets must be on 32bit boundaries");
			ret = -EINVAL;
			goto put_chain;
		}

		/* sanitize the shift value for any later use */
		nparms->tcfp_keys[i].shift = min_t(size_t,
						   BITS_PER_TYPE(int) - 1,
@@ -261,7 +269,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
		/* The AT option can read a single byte, we can bound the actual
		 * value with uchar max.
		 */
		cur += (0xff & nparms->tcfp_keys[i].offmask) >> nparms->tcfp_keys[i].shift;
		cur += (0xff & offmask) >> nparms->tcfp_keys[i].shift;

		/* Each key touches 4 bytes starting from the computed offset */
		nparms->tcfp_off_max_hint =
@@ -411,13 +419,13 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb,
					       sizeof(_d), &_d);
			if (!d)
				goto bad;
			offset += (*d & tkey->offmask) >> tkey->shift;
		}

			offset += (*d & tkey->offmask) >> tkey->shift;
			if (offset % 4) {
				pr_info("tc action pedit offset must be on 32 bit boundaries\n");
				goto bad;
			}
		}

		if (!offset_valid(skb, hoffset + offset)) {
			pr_info("tc action pedit offset %d out of bounds\n",