The code doing addition in that commit is + switch (cmd) { + case TCA_PEDIT_KEY_EX_CMD_SET: + val = tkey->val; + break; + case TCA_PEDIT_KEY_EX_CMD_ADD: + val = (*ptr + tkey->val) & ~tkey->mask; + break; + default: + pr_info("tc filter pedit bad command (%d)\n", + cmd); + goto bad; + } + + *ptr = ((*ptr & tkey->mask) ^ val);
Any net-endian field wider than an octet will have the carry between octets handled wrong on little-endian hosts. Should we at least verify that ~mask fits into one octet? As it is, consider e.g. an attempt to subtract 1 from a 16bit field at offset 2 in a word. We want {0,0,0,1} (0x10000000 from host POV) to turn into 0, so the value to add would be 0xff000000. Except that {0, 0, 1, 0} would turn into {0, 0, 1, 0xff} that way, not the expected {0, 0, 0, 0xff}. Granted, there's not a lot of wider-than-octet fields where arithmetics would've made sense, but we probably ought to refuse allowing such operations. Especially since on big-endian hosts they will work just fine until you try to move that over to a little-endian box... Alternatively, we could do something like val = htonl(be32_to_cpup(ptr) + ntohl(tkey->val)) & ~tkey->mask; but I'm not sure if that's worth doing. It's not as if there would be a major overhead, but still... Comments?