# HG changeset patch # User Maxim Dounin # Date 1507141173 -10800 # Node ID 83600ce25995c5c99a437b98fbe3121a2e8d5ec8 # Parent dea142ac3debf3a2b39ee52076f0aa4ba3cbaac2 Fixed buffer overread with unix sockets after accept(). Some OSes (notably macOS, NetBSD, and Solaris) allow unix socket addresses larger than struct sockaddr_un. Moreover, some of them (macOS, Solaris) return socklen of the socket address before it was truncated to fit the buffer provided. As such, on these systems socklen must not be used without additional check that it is within the buffer provided. Appropriate checks added to ngx_event_accept() (after accept()), ngx_event_recvmsg() (after recvmsg()), and ngx_set_inherited_sockets() (after getsockname()). We also obtain socket addresses via getsockname() in ngx_connection_local_sockaddr(), but it does not need any checks as it is only used for INET and INET6 sockets (as there can be no wildcard unix sockets). diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -165,6 +165,10 @@ ngx_set_inherited_sockets(ngx_cycle_t *c continue; } + if (ls[i].socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { + ls[i].socklen = sizeof(ngx_sockaddr_t); + } + switch (ls[i].sockaddr->sa_family) { #if (NGX_HAVE_INET6) diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -164,6 +164,10 @@ ngx_event_accept(ngx_event_t *ev) return; } + if (socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { + socklen = sizeof(ngx_sockaddr_t); + } + c->sockaddr = ngx_palloc(c->pool, socklen); if (c->sockaddr == NULL) { ngx_close_accepted_connection(c); @@ -440,6 +444,10 @@ ngx_event_recvmsg(ngx_event_t *ev) c->type = SOCK_DGRAM; c->socklen = msg.msg_namelen; + if (c->socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { + c->socklen = sizeof(ngx_sockaddr_t); + } + #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_active, 1); #endif