A nice simple vulnerability today: CVE-2011-1938. I’m amazed I didn’t see this the first time around?
The vulnerability describes a buffer overflow within the PHP ‘socket_connect()’ function. The source file for this function can be found at /ext/sockets/sockets.c and the problem was with the way that PHP handled AF_UNIX connections.
PHP_FUNCTION(socket_getpeername)
{
zval *arg1, *arg2, *arg3 = NULL;
php_sockaddr_storage sa_storage;
php_socket *php_sock;
struct sockaddr *sa;
struct sockaddr_in *sin;
#if HAVE_IPV6
struct sockaddr_in6 *sin6;
char addr6[INET6_ADDRSTRLEN+1];
#endif
struct sockaddr_un *s_un;
char *addr_string;
socklen_t salen = sizeof(php_sockaddr_storage);
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|z", &arg1, &arg2, &arg3) == FAILURE) {
return;
}
...
case AF_UNIX:
memset(&s_un, 0, sizeof(struct sockaddr_un));
s_un.sun_family = AF_UNIX;
memcpy(&s_un.sun_path, addr, addr_len);
retval = connect(php_sock->bsd_socket, (struct sockaddr *) &s_un, (socklen_t) XtOffsetOf(struct sockaddr_un, sun_path) + addr_len);
break;
As you can see, the memcpy() function copies the user supplied path into “s_un.sun_path”, a mere 108 bytes (default on Linux systems) worth of space allocated for the path. The inevitable happens and we are able to overflow the buffer and take over the function return address.
The PHP development team have since patched this problem, by simply adding bounds checking to the user supplied buffer:
case AF_UNIX:
if (addr_len >= sizeof(s_un.sun_path)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Path too long", php_sock->type);
RETURN_FALSE;
}
memset(&s_un, 0, sizeof(struct sockaddr_un));
s_un.sun_family = AF_UNIX;
memcpy(&s_un.sun_path, addr, addr_len);
retval = connect(php_sock->bsd_socket, (struct sockaddr *) &s_un, (socklen_t) XtOffsetOf(struct sockaddr_un, sun_path) + addr_len);
break;