From 4b555091e42ec5e9d9568abead5011dea6c0be9b Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Fri, 17 Dec 2010 17:26:58 -0600 Subject: [PATCH] Fix memory corruption with unnamed AF_UNIX sockets. AF_UNIX sockets can have a pathname, be unnamed, or abstract (Linux only). If an unnamed socket is returned by getsockname, getpeername, or accept, sun_path should not be inspected. --- src/node_net.cc | 70 +++++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/src/node_net.cc b/src/node_net.cc index 72312ed718..12c162af61 100644 --- a/src/node_net.cc +++ b/src/node_net.cc @@ -372,34 +372,52 @@ static Handle Connect(const Arguments& args) { return Undefined(); } -#define ADDRESS_TO_JS(info, address_storage) \ +#define ADDRESS_TO_JS(info, address_storage, addrlen) \ do { \ char ip[INET6_ADDRSTRLEN]; \ int port; \ struct sockaddr_in *a4; \ struct sockaddr_in6 *a6; \ struct sockaddr_un *au; \ - switch ((address_storage).ss_family) { \ - case AF_INET6: \ - a6 = (struct sockaddr_in6*)&(address_storage); \ - inet_ntop(AF_INET6, &(a6->sin6_addr), ip, INET6_ADDRSTRLEN); \ - port = ntohs(a6->sin6_port); \ - (info)->Set(address_symbol, String::New(ip)); \ - (info)->Set(port_symbol, Integer::New(port)); \ - break; \ - case AF_INET: \ - a4 = (struct sockaddr_in*)&(address_storage); \ - inet_ntop(AF_INET, &(a4->sin_addr), ip, INET6_ADDRSTRLEN); \ - port = ntohs(a4->sin_port); \ - (info)->Set(address_symbol, String::New(ip)); \ - (info)->Set(port_symbol, Integer::New(port)); \ - break; \ - case AF_UNIX: \ - au = (struct sockaddr_un*)&(address_storage); \ - (info)->Set(address_symbol, String::New(au->sun_path)); \ - break; \ - default: \ - (info)->Set(address_symbol, String::Empty()); \ + if (addrlen == 0) { \ + (info)->Set(address_symbol, String::Empty()); \ + } else { \ + switch ((address_storage).ss_family) { \ + case AF_INET6: \ + a6 = (struct sockaddr_in6*)&(address_storage); \ + inet_ntop(AF_INET6, &(a6->sin6_addr), ip, INET6_ADDRSTRLEN); \ + port = ntohs(a6->sin6_port); \ + (info)->Set(address_symbol, String::New(ip)); \ + (info)->Set(port_symbol, Integer::New(port)); \ + break; \ + case AF_INET: \ + a4 = (struct sockaddr_in*)&(address_storage); \ + inet_ntop(AF_INET, &(a4->sin_addr), ip, INET6_ADDRSTRLEN); \ + port = ntohs(a4->sin_port); \ + (info)->Set(address_symbol, String::New(ip)); \ + (info)->Set(port_symbol, Integer::New(port)); \ + break; \ + case AF_UNIX: \ + /* + * Three types of addresses (see man 7 unix): + * * unnamed: sizeof(sa_family_t) (sun_path should not be used) + * * abstract (Linux extension): sizeof(struct sockaddr_un) + * * pathname: sizeof(sa_family_t) + strlen(sun_path) + 1 + */ \ + au = (struct sockaddr_un*)&(address_storage); \ + if (addrlen == sizeof(sa_family_t)) { \ + (info)->Set(address_symbol, String::Empty()); \ + } else if (addrlen == sizeof(struct sockaddr_un)) { \ + /* first byte is '\0' and all remaining bytes are name; + * it is not NUL-terminated and may contain embedded NULs */ \ + (info)->Set(address_symbol, String::New(au->sun_path + 1, sizeof(au->sun_path - 1))); \ + } else { \ + (info)->Set(address_symbol, String::New(au->sun_path)); \ + } \ + break; \ + default: \ + (info)->Set(address_symbol, String::Empty()); \ + } \ } \ } while (0) @@ -420,7 +438,7 @@ static Handle GetSockName(const Arguments& args) { Local info = Object::New(); - ADDRESS_TO_JS(info, address_storage); + ADDRESS_TO_JS(info, address_storage, len); return scope.Close(info); } @@ -442,7 +460,7 @@ static Handle GetPeerName(const Arguments& args) { Local info = Object::New(); - ADDRESS_TO_JS(info, address_storage); + ADDRESS_TO_JS(info, address_storage, len); return scope.Close(info); } @@ -498,7 +516,7 @@ static Handle Accept(const Arguments& args) { peer_info->Set(fd_symbol, Integer::New(peer_fd)); - ADDRESS_TO_JS(peer_info, address_storage); + ADDRESS_TO_JS(peer_info, address_storage, len); return scope.Close(peer_info); } @@ -619,7 +637,7 @@ static Handle RecvFrom(const Arguments& args) { info->Set(size_symbol, Integer::New(bytes_read)); - ADDRESS_TO_JS(info, address_storage); + ADDRESS_TO_JS(info, address_storage, addrlen); return scope.Close(info); }