git: 2fe5a79425c7 - main - Fix dst/netmask handling in routing socket code.

Kristof Provost kp at FreeBSD.org
Fri Feb 19 16:11:34 UTC 2021


On 19 Feb 2021, at 16:24, Kristof Provost wrote:
> On 16 Feb 2021, at 21:31, Alexander V. Chernikov wrote:
>> The branch main has been updated by melifaro:
>>
>> URL: 
>> https://cgit.FreeBSD.org/src/commit/?id=2fe5a79425c79f7b828acd91da66d97230925fc8
>>
>> commit 2fe5a79425c79f7b828acd91da66d97230925fc8
>> Author:     Alexander V. Chernikov <melifaro at FreeBSD.org>
>> AuthorDate: 2021-02-16 20:30:04 +0000
>> Commit:     Alexander V. Chernikov <melifaro at FreeBSD.org>
>> CommitDate: 2021-02-16 20:30:04 +0000
>>
>>     Fix dst/netmask handling in routing socket code.
>>
>>     Traditionally routing socket code did almost zero checks on
>>      the input message except for the most basic size checks.
>>
>>     This resulted in the unclear KPI boundary for the routing system 
>> code
>>      (`rtrequest*` and now `rib_action()`) w.r.t message validness.
>>
>>     Multiple potential problems and nuances exists:
>>     * Host bits in RTAX_DST sockaddr. Existing applications do send 
>> prefixes
>>      with hostbits uncleared. Even `route(8)` does this, as they hope 
>> the kernel
>>      would do the job of fixing it. Code inside `rib_action()` needs 
>> to handle
>>      it on its own (see `rt_maskedcopy()` ugly hack).
>>     * There are multiple way of adding the host route: it can be DST 
>> without
>>      netmask or DST with /32(/128) netmask. Also, RTF_HOST has to be 
>> set correspondingly.
>>      Currently, these 2 options create 2 DIFFERENT routes in the 
>> kernel.
>>     * no sockaddr length/content checking for the "secondary" fields 
>> exists: nothing
>>      stops rtsock application to send sockaddr_in with length of 25 
>> (instead of 16).
>>      Kernel will accept it, install to RIB as is and propagate to all 
>> rtsock consumers,
>>      potentially triggering bugs in their code. Same goes for 
>> sin_port, sin_zero, etc.
>>
>>     The goal of this change is to make rtsock verify all sockaddr and 
>> prefix consistency.
>>     Said differently, `rib_action()` or internals should NOT require 
>> to change any of the
>>      sockaddrs supplied by `rt_addrinfo` structure due to 
>> incorrectness.
>>
>>     To be more specific, this change implements the following:
>>     * sockaddr cleanup/validation check is added immediately after 
>> getting sockaddrs from rtm.
>>     * Per-family dst/netmask checks clears host bits in dst and zeros 
>> all dst/netmask "secondary" fields.
>>     * The same netmask checking code converts /32(/128) netmasks to 
>> "host" route case
>>      (NULL netmask, RTF_HOST), removing the dualism.
>>     * Instead of allowing ANY "known" sockaddr families 
>> (0<..<AF_MAX), allow only actually
>>      supported ones (inet, inet6, link).
>>     * Automatically convert `sockaddr_sdl` (AF_LINK) gateways to
>>       `sockaddr_sdl_short`.
>>
>>     Reported by:    Guy Yur <guyyur at gmail.com>
>>     Reviewed By:    donner
>>     Differential Revision: https://reviews.freebsd.org/D28668
>>     MFC after:      3 days
>> ---
>>  sys/net/rtsock.c                      | 201 
>> +++++++++++++++++++++++++++++++++-
>>  tests/sys/net/routing/rtsock_common.h |   4 -
>>  2 files changed, 195 insertions(+), 10 deletions(-)
>>
>
>> +static int
>> +cleanup_xaddrs_inet(struct rt_addrinfo *info)
>> +{
>> +	struct sockaddr_in *dst_sa, *mask_sa;
>> +
>> +	/* Check & fixup dst/netmask combination first */
>> +	dst_sa = (struct sockaddr_in *)info->rti_info[RTAX_DST];
>> +	mask_sa = (struct sockaddr_in *)info->rti_info[RTAX_NETMASK];
>> +
>> +	struct in_addr mask = {
>> +		.s_addr = mask_sa ? mask_sa->sin_addr.s_addr : INADDR_BROADCAST,
>> +	};
>> +	struct in_addr dst = {
>> +		.s_addr = htonl(ntohl(dst_sa->sin_addr.s_addr) & 
>> ntohl(mask.s_addr))
>> +	};
>> +
> This breaks things like `arp -d 10.0.2.1`. It always masks off the 
> network address, which is the right thing to do in the routing table, 
> but not in the arp table.
>
> I’ve worked around it for now with this hack:
>
> 	diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
> 	index 3c1fea497af6..533076db99a5 100644
> 	--- a/sys/net/rtsock.c
> 	+++ b/sys/net/rtsock.c
> 	@@ -638,9 +638,12 @@ fill_addrinfo(struct rt_msghdr *rtm, int len, 
> u_int fibnum, struct rt_addrinfo *
> 	                return (EINVAL);
>
> 	        info->rti_flags = rtm->rtm_flags;
> 	-       error = cleanup_xaddrs(info);
> 	-       if (error != 0)
> 	-               return (error);
> 	+       /* XXX HACK */
> 	+       if (! (rtm->rtm_flags & RTF_LLDATA)) {
> 	+               error = cleanup_xaddrs(info);
> 	+               if (error != 0)
> 	+                       return (error);
> 	+       }
> 	        saf = info->rti_info[RTAX_DST]->sa_family;
> 	        /*
> 	         * Verify that the caller has the appropriate privilege; 
> RTM_GET
>
> But I’m not totally happy with this, obviously.

This may be a bit more reasonable:

	diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
	index 3c1fea497af6..5147b92e95d5 100644
	--- a/sys/net/rtsock.c
	+++ b/sys/net/rtsock.c
	@@ -1393,6 +1393,10 @@ cleanup_xaddrs_inet(struct rt_addrinfo *info)
	                .s_addr = htonl(ntohl(dst_sa->sin_addr.s_addr) & 
ntohl(mask.s_addr))
	        };

	+       /* Keep the address if we're LL */
	+       if (info->rti_flags & RTF_LLDATA)
	+               dst.s_addr = dst_sa->sin_addr.s_addr;
	+
	        if (dst_sa->sin_len < sizeof(struct sockaddr_in)) {
	                printf("dst sin_len too small\n");
	                return (EINVAL);
	@@ -1431,7 +1435,10 @@ cleanup_xaddrs_inet6(struct rt_addrinfo *info)
	        mask_sa = (struct sockaddr_in6 *)info->rti_info[RTAX_NETMASK];

	        mask = mask_sa ? mask_sa->sin6_addr : in6mask128;
	-       IN6_MASK_ADDR(&dst_sa->sin6_addr, &mask);
	+
	+       /* Keep the address if we're LL */
	+       if (! (info->rti_flags & RTF_LLDATA))
	+               IN6_MASK_ADDR(&dst_sa->sin6_addr, &mask);

	        if (dst_sa->sin6_len < sizeof(struct sockaddr_in6)) {
	                printf("dst sin6_len too small\n");

Best regards,
Kristof


More information about the dev-commits-src-main mailing list