net_new() creates a struct net_connection and calls arp_request()
to resolve unicast addresses. On success, arp_request() will
populate a buffer within the net_connection with the destination MAC
address.

If arp_request() aborts due to an error, it will leave the global
pending_arp.ether pointing at the buffer, which is promptly freed
leading to a dangling pointer and a use-after-free if we happen to get
an ARP response just after the error occurred.

Fix this memory safety issue by always clearing all of  pending_arp once
we are done with it, including error cases.

Reported-by: Sohaib Mohamed <[email protected]>
Signed-off-by: Ahmad Fatoum <[email protected]>
Link: https://lore.barebox.org/[email protected]
Signed-off-by: Sascha Hauer <[email protected]>
(cherry picked from commit effaa57f9a9476ecc5d07be92255769631ecb624)
Signed-off-by: Ahmad Fatoum <[email protected]>
---
 net/net.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/net/net.c b/net/net.c
index 795afed159aa..9c5999604b67 100644
--- a/net/net.c
+++ b/net/net.c
@@ -220,24 +220,28 @@ static int arp_request(struct eth_device *edev, IPaddr_t 
dest, unsigned char *et
 
        ret = eth_send(edev, arp_packet, ETHER_HDR_SIZE + ARP_HDR_SIZE);
        if (ret)
-               return ret;
+               goto out;
        arp_start = get_time_ns();
 
        while (pending_arp.ip) {
-               if (ctrlc())
-                       return -EINTR;
+               if (ctrlc()) {
+                       ret = -EINTR;
+                       goto out;
+               }
 
                if (is_timeout(arp_start, 3 * SECOND)) {
                        printf("T ");
                        arp_start = get_time_ns();
                        ret = eth_send(edev, arp_packet, ETHER_HDR_SIZE + 
ARP_HDR_SIZE);
                        if (ret)
-                               return ret;
+                               goto out;
                        retries++;
                }
 
-               if (retries > PKT_NUM_RETRIES)
-                       return -ETIMEDOUT;
+               if (retries > PKT_NUM_RETRIES) {
+                       ret = -ETIMEDOUT;
+                       goto out;
+               }
 
                net_poll();
        }
@@ -245,7 +249,11 @@ static int arp_request(struct eth_device *edev, IPaddr_t 
dest, unsigned char *et
        pr_debug("Got ARP REPLY for %pI4: %02x:%02x:%02x:%02x:%02x:%02x\n",
                 &dest, ether[0], ether[1], ether[2], ether[3], ether[4],
                 ether[5]);
-       return 0;
+
+out:
+       pending_arp.ip = 0;
+       pending_arp.ether = NULL;
+       return ret;
 }
 
 void net_poll(void)
-- 
2.47.3


Reply via email to