Commit eecc1152 authored by David Goulet's avatar David Goulet
Browse files

Add recvmsg() FD passing check



Signed-off-by: default avatarDavid Goulet <dgoulet@ev0ke.net>
parent 0c7ad6d9
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
Version 2.0
-----------
* Support res_* API
* Get sendmsg FD passing on Unix socket and for TCP socket, clean exit
* Check recvmmsg() FD passing on Unix socket and for TCP socket, clean exit
* Deny ICMP
* Support the complete list of dangerous syscall number with syscall()

+1 −1
Original line number Diff line number Diff line
@@ -12,7 +12,7 @@ lib_LTLIBRARIES = libtorsocks.la

libtorsocks_la_SOURCES = torsocks.c torsocks.h \
                         connect.c gethostbyname.c getaddrinfo.c close.c \
                         getpeername.c socket.c syscall.c socketpair.c
                         getpeername.c socket.c syscall.c socketpair.c recv.c

libtorsocks_la_LIBADD = \
		$(top_builddir)/src/common/libcommon.la \

src/lib/recv.c

0 → 100644
+100 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2013 - David Goulet <dgoulet@ev0ke.net>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License, version 2 only, as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 51
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <assert.h>
#include <stdlib.h>

#include <common/log.h>

#include "torsocks.h"

/*
 * Torsocks call for recvmsg(2)
 *
 * We only hijack this call to handle the FD passing between process on Unix
 * socket. If an INET/INET6 socket is recevied, we stop everything because at
 * that point we can't guarantee traffic going through Tor.
 */
LIBC_RECVMSG_RET_TYPE tsocks_recvmsg(LIBC_RECVMSG_SIG)
{
	int fd;
	ssize_t ret = 0;
	char dummy, recv_fd[CMSG_SPACE(sizeof(fd))];
	struct iovec iov[1];
	struct cmsghdr *cmsg;
	struct msghdr msg;

	memset(&msg, 0, sizeof(msg));

	/* Prepare to receive the structures */
	iov[0].iov_base = &dummy;
	iov[0].iov_len = 1;
	msg.msg_iov = iov;
	msg.msg_iovlen = 1;
	msg.msg_control = recv_fd;
	msg.msg_controllen = sizeof(recv_fd);

	do {
		/* Just peek the data to inspect the payload for fd. */
		ret = tsocks_libc_recvmsg(__sockfd, &msg, MSG_PEEK);
	} while (ret < 0 && errno == EINTR);

	cmsg = CMSG_FIRSTHDR(&msg);
	if (!cmsg) {
		goto end;
	}

	/*
	 * Detecting FD passing, the next snippet of code will check if we get a
	 * inet/inet6 socket. If so, everything stops immediately before going
	 * further.
	 */
	if (cmsg->cmsg_type == SCM_RIGHTS || cmsg->cmsg_level == SOL_SOCKET) {
		socklen_t optlen;
		int sock_dom;

		memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd));

		/* Get socket domain. */
		optlen = sizeof(sock_dom);
		ret = getsockopt(fd, SOL_SOCKET, SO_DOMAIN, &sock_dom, &optlen);
		if (ret < 0) {
			/* Use the getsockopt() errno value. */
			goto end;
		}

		if (sock_dom == AF_INET || sock_dom == AF_INET6) {
			ERR("[recvmsg] Inet socket passing detected. Aborting everything! "
					"A non Tor socket could be used thus leaking information.");
			exit(EXIT_FAILURE);
		}
	}

end:
	return tsocks_libc_recvmsg(LIBC_RECVMSG_ARGS);
}

/*
 * Libc hijacked symbol recvmsg(2).
 */
LIBC_RECVMSG_DECL
{
	/* Find symbol if not already set. Exit if not found. */
	tsocks_libc_recvmsg = tsocks_find_libc_symbol(LIBC_RECVMSG_NAME_STR,
			TSOCKS_SYM_EXIT_NOT_FOUND);
	return tsocks_recvmsg(LIBC_RECVMSG_ARGS);
}
+13 −0
Original line number Diff line number Diff line
@@ -161,6 +161,14 @@ struct hostent **__result, int *__h_errnop
	int __sockfd, struct sockaddr *__addr, socklen_t *__addrlen
#define LIBC_GETPEERNAME_ARGS  __sockfd, __addr, __addrlen

#define LIBC_RECVMSG_NAME recvmsg
#define LIBC_RECVMSG_NAME_STR XSTR(LIBC_RECVMSG_NAME)
#define LIBC_RECVMSG_RET_TYPE ssize_t
#define LIBC_RECVMSG_SIG \
	int __sockfd, struct msghdr *__msg, int __flags
#define LIBC_RECVMSG_ARGS \
	__sockfd, __msg, __flags

#else
#error "OS not supported."
#endif /* __linux__ , __FreeBSD__, __darwin__ */
@@ -191,6 +199,11 @@ TSOCKS_DECL(connect, LIBC_CONNECT_RET_TYPE, LIBC_CONNECT_SIG)
#define LIBC_CONNECT_DECL \
	LIBC_CONNECT_RET_TYPE LIBC_CONNECT_NAME(LIBC_CONNECT_SIG)

/* recvmsg(2) */
TSOCKS_LIBC_DECL(recvmsg, LIBC_RECVMSG_RET_TYPE, LIBC_RECVMSG_SIG)
#define LIBC_RECVMSG_DECL \
		LIBC_RECVMSG_RET_TYPE LIBC_RECVMSG_NAME(LIBC_RECVMSG_SIG)

/* socket(2) */
TSOCKS_LIBC_DECL(socket, LIBC_SOCKET_RET_TYPE, LIBC_SOCKET_SIG)
TSOCKS_DECL(socket, LIBC_SOCKET_RET_TYPE, LIBC_SOCKET_SIG)