[COMMIT osv master] libc/getifaddrs: Extract and use allocate_and_add_ifaddrs
From: Benoît CanetCommitter: Nadav Har'El Branch: master libc/getifaddrs: Extract and use allocate_and_add_ifaddrs The code will need to allocate twice as much ifaddr_storage structure to be able to return mac addresses in their own ifaddrs structure. Signed-off-by: Benoît Canet Message-Id: <1477485154-13682-3-git-send-email-ben...@scylladb.com> --- diff --git a/libc/network/getifaddrs.c b/libc/network/getifaddrs.c --- a/libc/network/getifaddrs.c +++ b/libc/network/getifaddrs.c @@ -112,18 +112,27 @@ static void dealwithipv6(stor **list, stor** head) fclose(f); } +int allocate_and_add_ifaddrs(stor **list, stor **head, struct if_nameindex *ii) +{ + size_t i; + for(i = 0; ii[i].if_index || ii[i].if_name; i++) { + stor* curr = list_add(list, head, ii[i].if_name); + if(!curr) { + return 0; + } + } + return i; +} + int getifaddrs(struct ifaddrs **ifap) { stor *list = 0, *head = 0; struct if_nameindex* ii = if_nameindex(); if(!ii) return -1; size_t i; - for(i = 0; ii[i].if_index || ii[i].if_name; i++) { - stor* curr = list_add(, , ii[i].if_name); - if(!curr) { - if_freenameindex(ii); - goto err2; - } + if (!allocate_and_add_ifaddrs(, , ii)) { + if_freenameindex(ii); + goto err2; } if_freenameindex(ii); -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to osv-dev+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[COMMIT osv master] libc/getifaddrs: Also return ifaddrs with ether hw addresses
From: Benoît CanetCommitter: Nadav Har'El Branch: master libc/getifaddrs: Also return ifaddrs with ether hw addresses Before this patch, OSv's getifaddrs() returns for each network interface a single entry, with the AF_INET address family and sockaddr_in address type. Linux's getifaddrs() returns an additional entry for each interface, with the AF_PACKET address family and sockaddr_ll address type. This sockaddr_ll structure ("ll" = link level) contains the MAC address of this interface, and some code expects to find these interfaces (see issue #787). So this patch adds them, after the list of AF_INET interfaces. Fixes #787. Signed-off-by: Benoît Canet Signed-off-by: Nadav Har'El Message-Id: <1477485154-13682-4-git-send-email-ben...@scylladb.com> --- diff --git a/libc/network/getifaddrs.c b/libc/network/getifaddrs.c --- a/libc/network/getifaddrs.c +++ b/libc/network/getifaddrs.c @@ -11,10 +11,13 @@ #include /* inet_pton */ #include #include +#include +#include typedef union { struct sockaddr_in6 v6; struct sockaddr_in v4; + struct sockaddr_ll hw; } soa; typedef struct ifaddrs_storage { @@ -124,15 +127,70 @@ int allocate_and_add_ifaddrs(stor **list, stor **head, struct if_nameindex *ii) return i; } +int fill_mac_addrs(int sock, stor *list, struct if_nameindex *ii) +{ + stor *head; + size_t i; + + for(head = list, i = 0; + head; head = (stor*)(head->next)) { + struct sockaddr_ll *hw_addr = (struct sockaddr_ll *) >addr; + head->ifa.ifa_addr = (struct sockaddr*) >addr; + struct ifreq req; + int ret; + + if (!ii[i].if_name) { + continue; + } + + /* zero the ifreq structure */ + memset(, 0, sizeof(req)); + + /* fill in the interface name */ + strlcpy(req.ifr_name, ii[i].if_name, IFNAMSIZ); + + /* Get the hardware address */ + ret = ioctl(sock, SIOCGIFHWADDR, ); + if (ret == -1) { + return ret; + } + + /* Fill address, index, type, length, familly */ + memcpy(hw_addr->sll_addr, req.ifr_hwaddr.sa_data, IFHWADDRLEN); + hw_addr->sll_ifindex = ii[i].if_index; + hw_addr->sll_hatype = ARPHRD_ETHER; + hw_addr->sll_halen = IFHWADDRLEN; + hw_addr->sll_family = AF_PACKET; + + /* Get and fill the address flags */ + ret = ioctl(sock, SIOCGIFFLAGS, ); + if (ret == - 1) { + return ret; + } + head->ifa.ifa_flags = req.ifr_flags; + i++; + } + + return 0; +} + int getifaddrs(struct ifaddrs **ifap) { stor *list = 0, *head = 0; struct if_nameindex* ii = if_nameindex(); if(!ii) return -1; + int addr_count; size_t i; - if (!allocate_and_add_ifaddrs(, , ii)) { - if_freenameindex(ii); - goto err2; + // allocate and add to the list twice the number of + // interface of ifaddr storage in order to have enough + // for MAC HW addresses that require their own location. + for (i = 0; i < 2; i++) { + addr_count = + allocate_and_add_ifaddrs(, , ii); + if (!addr_count) { + if_freenameindex(ii); + goto err2; + } } if_freenameindex(ii); @@ -142,7 +200,9 @@ int getifaddrs(struct ifaddrs **ifap) struct ifconf conf = {.ifc_len = sizeof reqs, .ifc_req = reqs}; if(-1 == ioctl(sock, SIOCGIFCONF, )) goto err; size_t reqitems = conf.ifc_len / sizeof(struct ifreq); - for(head = list; head; head = (stor*)head->next) { + int j; + // loop and fill the INET addrs + for(head = list, j = 0; head && j < addr_count; head = (stor*)head->next, j++) { for(i = 0; i < reqitems; i++) { // get SIOCGIFADDR of active interfaces. if(!strcmp(reqs[i].ifr_name, head->name)) { @@ -173,6 +233,9 @@ int getifaddrs(struct ifaddrs **ifap) head->ifa.ifa_ifu.ifu_dstaddr = (struct sockaddr*) >dst; } } + if (-1 == fill_mac_addrs(sock, head, ii)) { + goto err; + } close(sock); void* last = 0; for(head = list; head; head=(stor*)head->next) last=head; -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to osv-dev+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[COMMIT osv master] uipc_socket.cc: prevent use after free bug in soisdisconnected
From: Timmons C. PlayerCommitter: Nadav Har'El Branch: master uipc_socket.cc: prevent use after free bug in soisdisconnected Simultaneously closing a socket from both the network and user space sides can trigger a use after free bug in soisdisconnected. This change uses the existing socket reference counting mechanism to prevent the socket from being freed until after this function has completed. Signed-off-by: Timmons C. Player Message-Id: <1473445171-17551-1-git-send-email-timmons.pla...@spirent.com> --- diff --git a/bsd/sys/kern/uipc_socket.cc b/bsd/sys/kern/uipc_socket.cc --- a/bsd/sys/kern/uipc_socket.cc +++ b/bsd/sys/kern/uipc_socket.cc @@ -3469,20 +3469,45 @@ void soisdisconnected(struct socket *so) { + bool do_release = false; /* * Note: This code assumes that SOCK_LOCK(so) and * SOCKBUF_LOCK(>so_rcv) are the same. */ SOCK_LOCK(so); + /* +* If user space has already closed the socket, then it's possible +* for some of these wakeups to trigger soclose. We need to prevent +* the socket from getting freed in the middle of this function, so +* bump the reference count. +*/ + soref(so); so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); so->so_state |= SS_ISDISCONNECTED; so->so_rcv.sb_state |= SBS_CANTRCVMORE; sorwakeup_locked(so); so->so_snd.sb_state |= SBS_CANTSENDMORE; sbdrop_locked(so, >so_snd, so->so_snd.sb_cc); sowwakeup_locked(so); + /* +* If we have the only reference, then we need to call sorele to +* free the socket. If not, then we just quietly drop the ref +* count ourselves to avoid taking the accept lock and possibly +* deadlocking. +*/ + if (so->so_count == 1) { + do_release = true; + } else { + so->so_count--; + } SOCK_UNLOCK(so); wakeup(>so_timeo); + + if (do_release) { + ACCEPT_LOCK(); + SOCK_LOCK(so); + sorele(so); + } } /* -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to osv-dev+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[PATCH v3 3/3] libc/getifaddrs: Also return ifaddrs with ether hw addresses
Add these structure add the end of the list after the INET and INET6 addresses are filled. Signed-off-by: Benoît Canet--- libc/network/getifaddrs.c | 71 --- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/libc/network/getifaddrs.c b/libc/network/getifaddrs.c index 7bab121..4cdf4d6 100644 --- a/libc/network/getifaddrs.c +++ b/libc/network/getifaddrs.c @@ -11,10 +11,13 @@ #include /* inet_pton */ #include #include +#include +#include typedef union { struct sockaddr_in6 v6; struct sockaddr_in v4; + struct sockaddr_ll hw; } soa; typedef struct ifaddrs_storage { @@ -124,15 +127,70 @@ int allocate_and_add_ifaddrs(stor **list, stor **head, struct if_nameindex *ii) return i; } +int fill_mac_addrs(int sock, stor *list, struct if_nameindex *ii) +{ + stor *head; + size_t i; + + for(head = list, i = 0; + head; head = (stor*)(head->next)) { + struct sockaddr_ll *hw_addr = (struct sockaddr_ll *) >addr; + head->ifa.ifa_addr = (struct sockaddr*) >addr; + struct ifreq req; + int ret; + + if (!ii[i].if_name) { + continue; + } + + /* zero the ifreq structure */ + memset(, 0, sizeof(req)); + + /* fill in the interface name */ + strlcpy(req.ifr_name, ii[i].if_name, IFNAMSIZ); + + /* Get the hardware address */ + ret = ioctl(sock, SIOCGIFHWADDR, ); + if (ret == -1) { + return ret; + } + + /* Fill address, index, type, length, familly */ + memcpy(hw_addr->sll_addr, req.ifr_hwaddr.sa_data, IFHWADDRLEN); + hw_addr->sll_ifindex = ii[i].if_index; + hw_addr->sll_hatype = ARPHRD_ETHER; + hw_addr->sll_halen = IFHWADDRLEN; + hw_addr->sll_family = AF_PACKET; + + /* Get and fill the address flags */ + ret = ioctl(sock, SIOCGIFFLAGS, ); + if (ret == - 1) { + return ret; + } + head->ifa.ifa_flags = req.ifr_flags; + i++; + } + + return 0; +} + int getifaddrs(struct ifaddrs **ifap) { stor *list = 0, *head = 0; struct if_nameindex* ii = if_nameindex(); if(!ii) return -1; + int addr_count; size_t i; - if (!allocate_and_add_ifaddrs(, , ii)) { - if_freenameindex(ii); - goto err2; + // allocate and add to the list twice the number of + // interface of ifaddr storage in order to have enough + // for MAC HW addresses that require their own location. + for (i = 0; i < 2; i++) { + addr_count = + allocate_and_add_ifaddrs(, , ii); + if (!addr_count) { + if_freenameindex(ii); + goto err2; + } } if_freenameindex(ii); @@ -142,7 +200,9 @@ int getifaddrs(struct ifaddrs **ifap) struct ifconf conf = {.ifc_len = sizeof reqs, .ifc_req = reqs}; if(-1 == ioctl(sock, SIOCGIFCONF, )) goto err; size_t reqitems = conf.ifc_len / sizeof(struct ifreq); - for(head = list; head; head = (stor*)head->next) { + int j; + // loop and fill the INET addrs + for(head = list, j = 0; head && j < addr_count; head = (stor*)head->next, j++) { for(i = 0; i < reqitems; i++) { // get SIOCGIFADDR of active interfaces. if(!strcmp(reqs[i].ifr_name, head->name)) { @@ -173,6 +233,9 @@ int getifaddrs(struct ifaddrs **ifap) head->ifa.ifa_ifu.ifu_dstaddr = (struct sockaddr*) >dst; } } + if (-1 == fill_mac_addrs(sock, head, ii)) { + goto err; + } close(sock); void* last = 0; for(head = list; head; head=(stor*)head->next) last=head; -- 2.7.4 -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to osv-dev+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [PATCH v2 3/3] libc/getifaddrs: Also return ifaddrs with ether hw addresses
On Wed, Oct 26, 2016 at 2:03 PM, Nadav Har'Elwrote: > Please add "Fixes #787" to the commit message. > > Thanks, the patch looks mostly correct, but one question below. > > On Wed, Oct 26, 2016 at 2:33 PM, Benoît Canet com> wrote: > >> Add these structure add the end of the list after the >> INET and INET6 addresses are filled. >> >> Signed-off-by: Benoît Canet >> --- >> libc/network/getifaddrs.c | 70 ++ >> ++--- >> 1 file changed, 66 insertions(+), 4 deletions(-) >> >> diff --git a/libc/network/getifaddrs.c b/libc/network/getifaddrs.c >> index 7bab121..bfce1e9 100644 >> --- a/libc/network/getifaddrs.c >> +++ b/libc/network/getifaddrs.c >> @@ -11,6 +11,8 @@ >> #include /* inet_pton */ >> #include >> #include >> +#include >> +#include >> >> typedef union { >> struct sockaddr_in6 v6; >> @@ -124,15 +126,70 @@ int allocate_and_add_ifaddrs(stor **list, stor >> **head, struct if_nameindex *ii) >> return i; >> } >> >> +int fill_mac_addrs(int sock, stor *list, struct if_nameindex *ii) >> +{ >> + stor *head; >> + size_t i; >> + >> + for(head = list, i = 0; >> + head; head = (stor*)(head->next)) { >> + struct sockaddr_ll *hw_addr = (struct sockaddr_ll *) >> >addr; >> + head->ifa.ifa_addr = (struct sockaddr*) >addr; >> + struct ifreq req; >> + int ret; >> + >> + if (!ii[i].if_name) { >> + continue; >> + } >> > > Shouldn't we also skip non-AF_INET interfaces, like loopback? > 127.0.0.1 look totally like an IPV4 address so it's AF_INET. See http://man7.org/linux/man-pages/man3/getifaddrs.3.html or man getifaddrs . So lo seems to have an AF_PACKET entry in the getifaddrs list. > > I think your code makes two copies of the loopback interface, and then > tries to find the hw address for that interface (I don't know what it > finds). Would have been nicer to have just one copy. > > Is it really necessary for you to call allocate_and_add_ifaddrs() twice? > Couldn't you fill the normal interfaces just once (as in the original > code), and then loop over them adding *additional* AF_PACKET interface for > each AF_INET interface? > It make the code manipulating the linked list simple. I think that having simple code for this is a strong selling point. > > (Another possible problem with the way you did it which I don't fully > understand how it worked for you: sockaddr_ll has a different length than > sockaddr_in. So how could you allocate the structure with the normal code > which allocated sockaddr_in, and then put a sockaddr_ll in there?) > Well spotted. I just have to put sockaddr_ll in the soa union at the begining of the file. Thanks > > >> + >> + /* zero the ifreq structure */ >> + memset(, 0, sizeof(req)); >> + >> + /* fill in the interface name */ >> + strlcpy(req.ifr_name, ii[i].if_name, IFNAMSIZ); >> + >> + /* Get the hardware address */ >> + ret = ioctl(sock, SIOCGIFHWADDR, ); >> + if (ret == -1) { >> + return ret; >> + } >> + >> + /* Fill address, index, type, length, familly */ >> + memcpy(hw_addr->sll_addr, req.ifr_hwaddr.sa_data, >> IFHWADDRLEN); >> + hw_addr->sll_ifindex = ii[i].if_index; >> + hw_addr->sll_hatype = ARPHRD_ETHER; >> + hw_addr->sll_halen = IFHWADDRLEN; >> + hw_addr->sll_family = AF_PACKET; >> + >> + /* Get and fill the address flags */ >> + ret = ioctl(sock, SIOCGIFFLAGS, ); >> + if (ret == - 1) { >> + return ret; >> + } >> + head->ifa.ifa_flags = req.ifr_flags; >> + i++; >> + } >> + >> + return 0; >> +} >> + >> int getifaddrs(struct ifaddrs **ifap) >> { >> stor *list = 0, *head = 0; >> struct if_nameindex* ii = if_nameindex(); >> if(!ii) return -1; >> + int addr_count; >> size_t i; >> - if (!allocate_and_add_ifaddrs(, , ii)) { >> - if_freenameindex(ii); >> - goto err2; >> + // allocate and add to the list twice the number of >> + // interface of ifaddr storage in order to have enough >> + // for MAC HW addresses that require their own location. >> + for (i = 0; i < 2; i++) { >> + addr_count = >> + allocate_and_add_ifaddrs(, , ii); >> + if (!addr_count) { >> + if_freenameindex(ii); >> + goto err2; >> + } >> } >> if_freenameindex(ii); >> >> @@ -142,7 +199,9 @@ int getifaddrs(struct ifaddrs **ifap) >> struct ifconf conf = {.ifc_len = sizeof reqs, .ifc_req =
[PATCH v2 1/3] libc: Move getifaddrs.c from musl to libc.
Signed-off-by: Benoît Canet--- Makefile | 2 +- libc/network/getifaddrs.c | 180 ++ 2 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 libc/network/getifaddrs.c diff --git a/Makefile b/Makefile index e294a03..03b06e2 100644 --- a/Makefile +++ b/Makefile @@ -1354,7 +1354,7 @@ musl += network/getservbyname_r.o musl += network/getservbyname.o musl += network/getservbyport_r.o musl += network/getservbyport.o -musl += network/getifaddrs.o +libc += network/getifaddrs.o libc += network/if_nameindex.o musl += network/if_freenameindex.o diff --git a/libc/network/getifaddrs.c b/libc/network/getifaddrs.c new file mode 100644 index 000..a14ac1b --- /dev/null +++ b/libc/network/getifaddrs.c @@ -0,0 +1,180 @@ +/* (C) 2013 John Spencer. released under musl's standard MIT license. */ +#undef _GNU_SOURCE +#define _GNU_SOURCE +#include +#include +#include /* IFNAMSIZ, ifreq, ifconf */ +#include +#include +#include +#include +#include /* inet_pton */ +#include +#include + +typedef union { + struct sockaddr_in6 v6; + struct sockaddr_in v4; +} soa; + +typedef struct ifaddrs_storage { + struct ifaddrs ifa; + soa addr; + soa netmask; + soa dst; + char name[IFNAMSIZ+1]; +} stor; +#define next ifa.ifa_next + +static stor* list_add(stor** list, stor** head, char* ifname) +{ + stor* curr = calloc(1, sizeof(stor)); + if(curr) { + strcpy(curr->name, ifname); + curr->ifa.ifa_name = curr->name; + if(*head) (*head)->next = (struct ifaddrs*) curr; + *head = curr; + if(!*list) *list = curr; + } + return curr; +} + +void freeifaddrs(struct ifaddrs *ifp) +{ + stor *head = (stor *) ifp; + while(head) { + void *p = head; + head = (stor *) head->next; + free(p); + } +} + +static void ipv6netmask(unsigned prefix_length, struct sockaddr_in6 *sa) +{ + unsigned char* hb = sa->sin6_addr.s6_addr; + unsigned onebytes = prefix_length / 8; + unsigned bits = prefix_length % 8; + unsigned nullbytes = 16 - onebytes; + memset(hb, -1, onebytes); + memset(hb+onebytes, 0, nullbytes); + if(bits) { + unsigned char x = -1; + x <<= 8 - bits; + hb[onebytes] = x; + } +} + +static void dealwithipv6(stor **list, stor** head) +{ + FILE* f = fopen("/proc/net/if_inet6", "r"); + /* 0001 01 80 10 80 lo + AB C D E F + all numbers in hex + A = addr B=netlink device#, C=prefix length, + D = scope value (ipv6.h) E = interface flags (rnetlink.h, addrconf.c) + F = if name */ + char v6conv[32 + 7 + 1], *v6; + char *line, linebuf[512]; + if(!f) return; + while((line = fgets(linebuf, sizeof linebuf, f))) { + v6 = v6conv; + size_t i = 0; + for(; i < 8; i++) { + memcpy(v6, line, 4); + v6+=4; + *v6++=':'; + line+=4; + } + --v6; *v6 = 0; + line++; + unsigned b, c, d, e; + char name[IFNAMSIZ+1]; + if(5 == sscanf(line, "%x %x %x %x %s", , , , , name)) { + struct sockaddr_in6 sa = {0}; + if(1 == inet_pton(AF_INET6, v6conv, _addr)) { + sa.sin6_family = AF_INET6; + stor* curr = list_add(list, head, name); + if(!curr) goto out; + curr->addr.v6 = sa; + curr->ifa.ifa_addr = (struct sockaddr*) >addr; + ipv6netmask(c, ); + curr->netmask.v6 = sa; + curr->ifa.ifa_netmask = (struct sockaddr*) >netmask; + /* find ipv4 struct with the same interface name to copy flags */ + stor* scan = *list; + for(;scan && strcmp(name, scan->name);scan=(stor*)scan->next); + if(scan) curr->ifa.ifa_flags = scan->ifa.ifa_flags; + else curr->ifa.ifa_flags = 0; + } else errno = 0; + } + } + out: + fclose(f); +} + +int getifaddrs(struct ifaddrs **ifap) +{ + stor *list = 0, *head = 0; + struct if_nameindex* ii = if_nameindex(); + if(!ii) return -1; + size_t i; + for(i = 0; ii[i].if_index || ii[i].if_name; i++) { + stor* curr = list_add(, , ii[i].if_name); + if(!curr) { + if_freenameindex(ii); +