Skip to content

Commit e68409d

Browse files
jhsmtkuba-moo
authored andcommitted
net: sched: cls_u32: Fix match key mis-addressing
A match entry is uniquely identified with an "address" or "path" in the form of: hashtable ID(12b):bucketid(8b):nodeid(12b). When creating table match entries all of hash table id, bucket id and node (match entry id) are needed to be either specified by the user or reasonable in-kernel defaults are used. The in-kernel default for a table id is 0x800(omnipresent root table); for bucketid it is 0x0. Prior to this fix there was none for a nodeid i.e. the code assumed that the user passed the correct nodeid and if the user passes a nodeid of 0 (as Mingi Cho did) then that is what was used. But nodeid of 0 is reserved for identifying the table. This is not a problem until we dump. The dump code notices that the nodeid is zero and assumes it is referencing a table and therefore references table struct tc_u_hnode instead of what was created i.e match entry struct tc_u_knode. Ming does an equivalent of: tc filter add dev dummy0 parent 10: prio 1 handle 0x1000 \ protocol ip u32 match ip src 10.0.0.1/32 classid 10:1 action ok Essentially specifying a table id 0, bucketid 1 and nodeid of zero Tableid 0 is remapped to the default of 0x800. Bucketid 1 is ignored and defaults to 0x00. Nodeid was assumed to be what Ming passed - 0x000 dumping before fix shows: ~$ tc filter ls dev dummy0 parent 10: filter protocol ip pref 1 u32 chain 0 filter protocol ip pref 1 u32 chain 0 fh 800: ht divisor 1 filter protocol ip pref 1 u32 chain 0 fh 800: ht divisor -30591 Note that the last line reports a table instead of a match entry (you can tell this because it says "ht divisor..."). As a result of reporting the wrong data type (misinterpretting of struct tc_u_knode as being struct tc_u_hnode) the divisor is reported with value of -30591. Ming identified this as part of the heap address (physmap_base is 0xffff8880 (-30591 - 1)). The fix is to ensure that when table entry matches are added and no nodeid is specified (i.e nodeid == 0) then we get the next available nodeid from the table's pool. After the fix, this is what the dump shows: $ tc filter ls dev dummy0 parent 10: filter protocol ip pref 1 u32 chain 0 filter protocol ip pref 1 u32 chain 0 fh 800: ht divisor 1 filter protocol ip pref 1 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 flowid 10:1 not_in_hw match 0a000001/ffffffff at 12 action order 1: gact action pass random type none pass val 0 index 1 ref 1 bind 1 Reported-by: Mingi Cho <[email protected]> Fixes: 1da177e ("Linux-2.6.12-rc2") Signed-off-by: Jamal Hadi Salim <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 5416d79 commit e68409d

File tree

1 file changed

+50
-6
lines changed

1 file changed

+50
-6
lines changed

net/sched/cls_u32.c

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,18 +1024,62 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
10241024
return -EINVAL;
10251025
}
10261026

1027+
/* At this point, we need to derive the new handle that will be used to
1028+
* uniquely map the identity of this table match entry. The
1029+
* identity of the entry that we need to construct is 32 bits made of:
1030+
* htid(12b):bucketid(8b):node/entryid(12b)
1031+
*
1032+
* At this point _we have the table(ht)_ in which we will insert this
1033+
* entry. We carry the table's id in variable "htid".
1034+
* Note that earlier code picked the ht selection either by a) the user
1035+
* providing the htid specified via TCA_U32_HASH attribute or b) when
1036+
* no such attribute is passed then the root ht, is default to at ID
1037+
* 0x[800][00][000]. Rule: the root table has a single bucket with ID 0.
1038+
* If OTOH the user passed us the htid, they may also pass a bucketid of
1039+
* choice. 0 is fine. For example a user htid is 0x[600][01][000] it is
1040+
* indicating hash bucketid of 1. Rule: the entry/node ID _cannot_ be
1041+
* passed via the htid, so even if it was non-zero it will be ignored.
1042+
*
1043+
* We may also have a handle, if the user passed one. The handle also
1044+
* carries the same addressing of htid(12b):bucketid(8b):node/entryid(12b).
1045+
* Rule: the bucketid on the handle is ignored even if one was passed;
1046+
* rather the value on "htid" is always assumed to be the bucketid.
1047+
*/
10271048
if (handle) {
1049+
/* Rule: The htid from handle and tableid from htid must match */
10281050
if (TC_U32_HTID(handle) && TC_U32_HTID(handle ^ htid)) {
10291051
NL_SET_ERR_MSG_MOD(extack, "Handle specified hash table address mismatch");
10301052
return -EINVAL;
10311053
}
1032-
handle = htid | TC_U32_NODE(handle);
1033-
err = idr_alloc_u32(&ht->handle_idr, NULL, &handle, handle,
1034-
GFP_KERNEL);
1035-
if (err)
1036-
return err;
1037-
} else
1054+
/* Ok, so far we have a valid htid(12b):bucketid(8b) but we
1055+
* need to finalize the table entry identification with the last
1056+
* part - the node/entryid(12b)). Rule: Nodeid _cannot be 0_ for
1057+
* entries. Rule: nodeid of 0 is reserved only for tables(see
1058+
* earlier code which processes TC_U32_DIVISOR attribute).
1059+
* Rule: The nodeid can only be derived from the handle (and not
1060+
* htid).
1061+
* Rule: if the handle specified zero for the node id example
1062+
* 0x60000000, then pick a new nodeid from the pool of IDs
1063+
* this hash table has been allocating from.
1064+
* If OTOH it is specified (i.e for example the user passed a
1065+
* handle such as 0x60000123), then we use it generate our final
1066+
* handle which is used to uniquely identify the match entry.
1067+
*/
1068+
if (!TC_U32_NODE(handle)) {
1069+
handle = gen_new_kid(ht, htid);
1070+
} else {
1071+
handle = htid | TC_U32_NODE(handle);
1072+
err = idr_alloc_u32(&ht->handle_idr, NULL, &handle,
1073+
handle, GFP_KERNEL);
1074+
if (err)
1075+
return err;
1076+
}
1077+
} else {
1078+
/* The user did not give us a handle; lets just generate one
1079+
* from the table's pool of nodeids.
1080+
*/
10381081
handle = gen_new_kid(ht, htid);
1082+
}
10391083

10401084
if (tb[TCA_U32_SEL] == NULL) {
10411085
NL_SET_ERR_MSG_MOD(extack, "Selector not specified");

0 commit comments

Comments
 (0)