svn commit: r337776 - head/sys/netinet6
Bjoern A. Zeeb
bzeeb-lists at lists.zabbadoz.net
Thu Aug 30 22:07:52 UTC 2018
On 30 Aug 2018, at 22:00, Kristof Provost wrote:
> On 14 Aug 2018, at 19:17, Jonathan T. Looney wrote:
>> Author: jtl
>> Date: Tue Aug 14 17:17:37 2018
>> New Revision: 337776
>> URL: https://svnweb.freebsd.org/changeset/base/337776
>>
>> Log:
>> Improve IPv6 reassembly performance by hashing fragments into
>> buckets.
>>
>> Currently, all IPv6 fragment reassembly queues are kept in a flat
>> linked list. This has a number of implications. Two significant
>> implications are: all reassembly operations share a common lock,
>> and it is possible for the linked list to grow quite large.
>>
>> Improve IPv6 reassembly performance by hashing fragments into
>> buckets,
>> each of which has its own lock. Calculate the hash key using a
>> Jenkins
>> hash with a random seed.
>>
>> Reviewed by: jhb
>> Security: FreeBSD-SA-18:10.ip
>> Security: CVE-2018-6923
>>
>> Modified:
>> head/sys/netinet6/frag6.c
>>
>> Modified: head/sys/netinet6/frag6.c
>> ==============================================================================
>> --- head/sys/netinet6/frag6.c Tue Aug 14 17:15:47 2018 (r337775)
>> +++ head/sys/netinet6/frag6.c Tue Aug 14 17:17:37 2018 (r337776)
>> @@ -157,12 +176,13 @@ frag6_input(struct mbuf **mp, int *offp, int
>> proto)
>> struct mbuf *m = *mp, *t;
>> struct ip6_hdr *ip6;
>> struct ip6_frag *ip6f;
>> - struct ip6q *q6;
>> + struct ip6q *head, *q6;
>> struct ip6asfrag *af6, *ip6af, *af6dwn;
>> struct in6_ifaddr *ia;
>> int offset = *offp, nxt, i, next;
>> int first_frag = 0;
>> int fragoff, frgpartlen; /* must be larger than u_int16_t */
>> + uint32_t hash, hashkey[sizeof(struct in6_addr) * 2 + 1], *hashkeyp;
>
> I’m pretty sure you didn’t mean for the hashkey to be 1028 bytes
> long.
>
>> struct ifnet *dstifp;
>> u_int8_t ecn, ecn0;
>> #ifdef RSS
>> @@ -231,7 +251,16 @@ frag6_input(struct mbuf **mp, int *offp, int
>> proto)
>> return (ip6f->ip6f_nxt);
>> }
>>
>> - IP6Q_LOCK();
>> + hashkeyp = hashkey;
>> + memcpy(hashkeyp, &ip6->ip6_src, sizeof(struct in6_addr));
>> + hashkeyp += sizeof(struct in6_addr) / sizeof(*hashkeyp);
>> + memcpy(hashkeyp, &ip6->ip6_dst, sizeof(struct in6_addr));
>> + hashkeyp += sizeof(struct in6_addr) / sizeof(*hashkeyp);
>> + *hashkeyp = ip6f->ip6f_ident;
>> + hash = jenkins_hash32(hashkey, nitems(hashkey), V_ip6q_hashseed);
>
> Especially combined with this, because it means we hash a lot more
> than the src/dst dress and ident.
> We end up hashing random stack garbage, so the hash isn’t guaranteed
> to be the same every time.
> So we end up not always being able to reassemble the packet.
>
> It’s especially fun when you consider that a Dtrace fbt:::entry
> probe will leave a consistent stack state, so when you try to probe
> frag6_input() the problem magically goes away.
>
> This broke the sys.netpfil.pf.fragmentation.v6 test.
>
> I’ve done this, which fixes the problem:
>
> diff --git a/sys/netinet6/frag6.c b/sys/netinet6/frag6.c
> index 0f30801540a..e1f2b3f5842 100644
> --- a/sys/netinet6/frag6.c
> +++ b/sys/netinet6/frag6.c
> @@ -218,7 +218,9 @@ frag6_input(struct mbuf **mp, int *offp, int
> proto)
> int offset = *offp, nxt, i, next;
> int first_frag = 0;
> int fragoff, frgpartlen; /* must be larger than
> u_int16_t */
> - uint32_t hash, hashkey[sizeof(struct in6_addr) * 2 + 1],
> *hashkeyp;
> + uint32_t hashkey[(sizeof(struct in6_addr) * 2 +
> sizeof(u_int32_t)) /
Can we actually make it the size of the field rather than uint32_t (not
u_int32_t)? I guess not easily but at least change the type spelling
and leave a comment what it is?
> + sizeof(uint32_t)];
> + uint32_t hash, *hashkeyp;
> struct ifnet *dstifp;
> u_int8_t ecn, ecn0;
> #ifdef RSS
>
> Regards,
> Kristof
More information about the svn-src-head
mailing list