Re: [PATCH] nfs: fix host_reliable_addrinfo (try #2)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Thanks.

This is a security problem, but I don't want to lose sight of the original cause of this bug, which was my lack of understanding of the function of the old code and the API contract (return only _one_ address).

For extra credit, we might check if statd has a similar issue when it matches addresses.

On Jun 22, 2011, at 9:35 AM, Jeff Layton wrote:

> According to Neil Brown:
> 
>    The point of the word 'reliable' is to check that the name we get
>    really does belong to the host in question - ie that both the
>    forward and reverse maps agree.
> 
>    But the new code doesn't do that check at all.  Rather it simply
>    maps the address to a name, then discards the address and maps the
>    name back to a list of addresses and uses that list of addresses as
>    "where the request came from" for permission checking.
> 
> This bug is exploitable via the following scenario and could allow an
> attacker access to data that they shouldn't be able to access.
> 
>    Suppose you export a filesystem to some subnet or FQDN and also to a
>    wildcard or netgroup, and I know the details of this (maybe
>    showmount -e tells me) Suppose further that I can get IP packets to
>    your server..
> 
>    Then I create a reverse mapping for my ipaddress to a domain that I
>    own, say "black.hat.org", and a forward mapping from that domain to
>    my IP address, and one of your IP addresses.
> 
>    Then I try to mount your filesystem.  The IP address gets correctly
>    mapped to "black.hat.org" and then mapped to both my IP address and
>    your IP address.
> 
>    Then you search through all of your exports and find that one of the
>    addresses: yours - is allowed to access the filesystem.
> 
>    So you create an export based on the addrinfo you have which allows
>    my IP address the same access as your IP address.
> 
> Fix this by instead using the forward lookup of the hostname just to
> verify that the original address is in the list. Then do a numeric
> lookup using the address and stick the hostname in the ai_canonname.
> 
> Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx>
> Reviewed-by: NeilBrown <neilb@xxxxxxx>
> ---
> support/export/hostname.c |   36 ++++++++++++++++++++++++++++++------
> 1 files changed, 30 insertions(+), 6 deletions(-)
> 
> diff --git a/support/export/hostname.c b/support/export/hostname.c
> index efcb75c..3e949a1 100644
> --- a/support/export/hostname.c
> +++ b/support/export/hostname.c
> @@ -258,17 +258,19 @@ host_canonname(const struct sockaddr *sap)
>  * @sap: pointer to socket address to look up
>  *
>  * Reverse and forward lookups are performed to ensure the address has
> - * proper forward and reverse mappings.
> + * matching forward and reverse mappings.
>  *
> - * Returns address info structure with ai_canonname filled in, or NULL
> - * if no information is available for @sap.  Caller must free the returned
> - * structure with freeaddrinfo(3).
> + * Returns addrinfo structure with just the provided address with
> + * ai_canonname filled in. If there is a problem with resolution or
> + * the resolved records don't match up properly then it returns NULL
> + *
> + * Caller must free the returned structure with freeaddrinfo(3).
>  */
> __attribute_malloc__
> struct addrinfo *
> host_reliable_addrinfo(const struct sockaddr *sap)
> {
> -	struct addrinfo *ai;
> +	struct addrinfo *ai, *a;
> 	char *hostname;
> 
> 	hostname = host_canonname(sap);
> @@ -276,9 +278,31 @@ host_reliable_addrinfo(const struct sockaddr *sap)
> 		return NULL;
> 
> 	ai = host_addrinfo(hostname);
> +	if (!ai)
> +		goto out_free_hostname;
> 
> -	free(hostname);
> +	/* make sure there's a matching address in the list */
> +	for (a = ai; a; a = a->ai_next)
> +		if (nfs_compare_sockaddr(a->ai_addr, sap))
> +			break;
> +
> +	freeaddrinfo(ai);
> +	if (!a)
> +		goto out_free_hostname;
> +
> +	/* get addrinfo with just the original address */
> +	ai = host_numeric_addrinfo(sap);
> +	if (!ai)
> +		goto out_free_hostname;
> +
> +	/* and populate its ai_canonname field */
> +	free(ai->ai_canonname);
> +	ai->ai_canonname = hostname;
> 	return ai;
> +
> +out_free_hostname:
> +	free(hostname);
> +	return NULL;
> }
> 
> /**
> -- 
> 1.7.5.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com



--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux