CVE-2015-6520 (C, published 2015-09-01T14:59Z)
Description: value: IPPUSBXD before 1.22 listens on all interfaces, which allows remote attackers to obtain access to USB connected printers via a direct request.
Severity: HIGH (CVSS v3 base score: )
Weakness: CWE-264 \u2014 Permissions, Privileges, and Access Controls
Weaknesses in this category are related to the management of permissions, privileges, and other security features that are used to perform access control.
Repository: https://github.com/tillkamppeter/ippusbxd
Files changed:
src/ippusbxd.c
src/tcp.c
src/tcp.h
Commit message: SECURITY FIX: Actually restrict the access to the printer to localhost

Before, any machine in any network connected by any of the interfaces (as
listed by "ifconfig") could access to an IPP-over-USB printer on the assigned
port, allowing users on remote machines to print and to access the web
configuration interface of a IPP-over-USB printer in contrary to conventional
USB printers which are only accessible locally.


Vulnerable code:
	struct tcp_sock_t *tcp_socket;
	while ((tcp_socket = tcp_open(desired_port)) == NULL &&
	       g_options.only_desired_port == 0) {
	if (tcp_socket == NULL)
	uint16_t real_port = tcp_port_number_get(tcp_socket);
		args->tcp = tcp_conn_accept(tcp_socket);
		ERR("callocing this failed");
		ERR("sockect open failed");
	addr.sin6_addr = in6addr_any;
			ERR("Bind on port failed. "
		ERR("listen failed on socket");
struct tcp_conn_t *tcp_conn_accept(struct tcp_sock_t *sock)
	conn->sd = accept(sock->sd, NULL, NULL);

struct tcp_conn_t *tcp_conn_accept(struct tcp_sock_t *);

Fixed code:
	struct tcp_sock_t *tcp_socket = NULL, *tcp6_socket = NULL;
	for (;;) {
		tcp_socket = tcp_open(desired_port);
		tcp6_socket = tcp6_open(desired_port);
		if (tcp_socket || tcp6_socket || g_options.only_desired_port)
			break;
		NOTE("Access to desired port failed, trying alternative port %d", desired_port);
	if (tcp_socket == NULL && tcp6_socket == NULL)
	uint16_t real_port;
	if (tcp_socket)
	  real_port = tcp_port_number_get(tcp_socket);
	else
	  real_port = tcp_port_number_get(tcp6_socket);
	NOTE("Port: %d, IPv4 %savailable, IPv6 %savailable",
	     real_port, tcp_socket ? "" : "not ", tcp6_socket ? "" : "not ");


		// For each request/response round we use the socket (IPv4 or
		// IPv6) which receives data first
		args->tcp = tcp_conn_select(tcp_socket, tcp6_socket);
	if (tcp6_socket!= NULL)
		tcp_close(tcp6_socket);
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
		ERR("IPv4: callocing this failed");
		goto error;
	}

	// Open [S]ocket [D]escriptor
	this->sd = -1;
	this->sd = socket(AF_INET, SOCK_STREAM, 0);
	if (this->sd < 0) {
		ERR("IPv4 socket open failed");
		goto error;
	}

	// Configure socket params
	struct sockaddr_in addr;
	memset(&addr, 0, sizeof addr);
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = htonl(0x7F000001);

	// Bind to localhost
	if (bind(this->sd,
	        (struct sockaddr *)&addr,
	        sizeof addr) < 0) {
		if (g_options.only_desired_port == 1)
			ERR("IPv4 bind on port failed. "
			    "Requested port may be taken or require root permissions.");
		goto error;
	}

	// Let kernel over-accept max number of connections
	if (listen(this->sd, HTTP_MAX_PENDING_CONNS) < 0) {
		ERR("IPv4 listen failed on socket");
		goto error;
	}

	return this;

error:
	if (this != NULL) {
		if (this->sd != -1) {
			close(this->sd);
		}
		free(this);
	}
	return NULL;
}

struct tcp_sock_t *tcp6_open(uint16_t port)
{
	struct tcp_sock_t *this = calloc(1, sizeof *this);
	if (this == NULL) {
		ERR("IPv6: callocing this failed");
		ERR("Ipv6 socket open failed");
	addr.sin6_addr = in6addr_loopback;
			ERR("IPv6 bind on port failed. "
		ERR("IPv6 listen failed on socket");
struct tcp_conn_t *tcp_conn_select(struct tcp_sock_t *sock,
				   struct tcp_sock_t *sock6)
	fd_set rfds;
	struct timeval tv;
	int retval = 0;
	int nfds = 0;
	while (retval == 0) {
		FD_ZERO(&rfds);
		if (sock) {
			FD_SET(sock->sd, &rfds);
			nfds = sock->sd;
		}
		if (sock6) {
			FD_SET(sock6->sd, &rfds);
			if (sock6->sd > nfds)
				nfds = sock6->sd;
		}
		if (nfds == 0) {
			ERR("No valid TCP socket supplied.");
			goto error;
		}
		nfds += 1;
		/* Wait up to five seconds. */
		tv.tv_sec = 5;
		tv.tv_usec = 0;
		retval = select(nfds, &rfds, NULL, NULL, &tv);
		if (retval == -1) {
			ERR("Failed to open tcp connection");
			goto error;
		}
	}
	if (sock && FD_ISSET(sock->sd, &rfds)) {
		conn->sd = accept(sock->sd, NULL, NULL);
		NOTE ("Using IPv4");
	} else if (sock6 && FD_ISSET(sock6->sd, &rfds)) {
		conn->sd = accept(sock6->sd, NULL, NULL);
		NOTE ("Using IPv6");
	} else {
		ERR("select failed");
		goto error;
	}
struct tcp_sock_t *tcp6_open(uint16_t);
struct tcp_conn_t *tcp_conn_select(struct tcp_sock_t *sock,
				   struct tcp_sock_t *sock6);