[SLOF] [PATCH 1/5] ipv6: Fix possible NULL-pointer dereference in send_ipv6()
Andrew Jones
drjones at redhat.com
Tue May 3 15:11:06 AEST 2016
On Mon, May 02, 2016 at 09:55:27PM +0200, Thomas Huth wrote:
> The "struct neighbor *n" pointer in send_ipv6() can be NULL, e.g.
> when we're sending to multicast addresses or to a server that sits
> behind a router (since we do not have an entry in the neighbor cache
> in this case).
> However, the final code in send_ipv6() is always using n->eth_frame
> to assemble the ethernet packet, and thus silently writes the data
> into the low memory (which happens unnoticed because SLOF does not
> use the MMU for memory protection).
> This issue is now fixed by using a separate buffer for assembling
> those ethernet packets instead. The block for using the router's
> MAC address is also moved out of the block that is supposed to handle
> the unicast transfers, so that we do not accidentially end up in the
> neighbour solicitation code here (which also relies on n != NULL).
>
> Reported-by: Andrew Jones <drjones at redhat.com>
> Signed-off-by: Thomas Huth <thuth at redhat.com>
> ---
> clients/net-snk/app/netlib/ipv6.c | 32 ++++++++++++++++----------------
> 1 file changed, 16 insertions(+), 16 deletions(-)
Reviewed-by: Andrew Jones <drjones at redhat.com>
>
> diff --git a/clients/net-snk/app/netlib/ipv6.c b/clients/net-snk/app/netlib/ipv6.c
> index dfa16b3..6c041d6 100644
> --- a/clients/net-snk/app/netlib/ipv6.c
> +++ b/clients/net-snk/app/netlib/ipv6.c
> @@ -488,12 +488,12 @@ static unsigned short ip6_checksum(struct ip6hdr *ip6h, unsigned short *packet,
> */
> int send_ipv6(int fd, void* buffer, int len)
> {
> - struct neighbor *n;
> struct ip6hdr *ip6h;
> struct udphdr *udph;
> struct icmp6hdr *icmp6h;
> ip6_addr_t ip_dst;
> uint8_t *mac_addr, mc_mac[6];
> + static uint8_t ethframe[ETH_MTU_SIZE];
>
> mac_addr = null_mac;
>
> @@ -524,21 +524,20 @@ int send_ipv6(int fd, void* buffer, int len)
> (unsigned short *) icmp6h,
> ip6h->pl >> 1);
>
> - n = find_neighbor (&ip_dst);
> -
> - // If address is a multicast address, create a proper mac address
> if (ip6_is_multicast (&ip_dst)) {
> + /* If multicast, then create a proper multicast mac address */
> mac_addr = ip6_to_multicast_mac (&ip_dst, mc_mac);
> - }
> - else {
> - // Check if the MAC address is already cached
> - if (n) {
> + } else if (!is_ip6addr_in_my_net(&ip_dst)) {
> + /* If server is not in same subnet, user MAC of the router */
> + struct router *gw;
> + gw = ipv6_get_default_router(&ip6h->src);
> + mac_addr = gw ? gw->mac : null_mac;
> + } else {
> + /* Normal unicast, so use neighbor cache to look up MAC */
> + struct neighbor *n = find_neighbor (&ip_dst);
> + if (n) { /* Already cached ? */
> if (memcmp(n->mac, null_mac, ETH_ALEN) != 0)
> mac_addr = n->mac; /* found it */
> - } else if (!is_ip6addr_in_my_net(&ip_dst)) {
> - struct router *gw;
> - gw = ipv6_get_default_router(&ip6h->src);
> - mac_addr = gw ? gw->mac : null_mac;
> } else {
> mac_addr = null_mac;
> n = malloc(sizeof(struct neighbor));
> @@ -575,10 +574,11 @@ int send_ipv6(int fd, void* buffer, int len)
> if (mac_addr == null_mac)
> return -1;
>
> - fill_ethhdr (n->eth_frame, htons(ETHERTYPE_IPv6), get_mac_address(),
> - mac_addr);
> - memcpy (&(n->eth_frame[sizeof(struct ethhdr)]), buffer, len);
> - return send_ether (fd, n->eth_frame, len + sizeof(struct ethhdr));
> + fill_ethhdr(ethframe, htons(ETHERTYPE_IPv6), get_mac_address(),
> + mac_addr);
> + memcpy(ðframe[sizeof(struct ethhdr)], buffer, len);
> +
> + return send_ether(fd, ethframe, len + sizeof(struct ethhdr));
> }
>
> static int check_colons(const char *str)
> --
> 1.8.3.1
>
More information about the SLOF
mailing list