lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <1368554301.4519.20.camel@edumazet-glaptop>
Date:	Tue, 14 May 2013 10:58:21 -0700
From:	Eric Dumazet <eric.dumazet@...il.com>
To:	David Miller <davem@...emloft.net>
Cc:	netdev <netdev@...r.kernel.org>,
	Matt Schnall <mischnal@...gle.com>,
	Bernhard Beck <bbeck@...gle.com>
Subject: Re: [PATCH] tcp: fix tcp_md5_hash_skb_data()

On Tue, 2013-05-14 at 00:25 -0700, Eric Dumazet wrote:
> From: Eric Dumazet <edumazet@...gle.com>
> 
> TCP md5 communications fail [1] for some devices, because sg/crypto code
> assume page offsets are below PAGE_SIZE.
> 
> This was discovered using mlx4 driver [2], but I suspect loopback
> might trigger the same bug now we use order-3 pages in tcp_sendmsg()

Yes, I confirm I can trigger this bug on loopback, using following
program :

./tcp_md5 -s -m 127.0.0.1:somekey &
./tcp_md5 -c -m 127.0.0.1:somekey


/*
 * Copyright 2013 Google Inc. All Rights Reserved.
 * Author: edumazet@...gle.com (Eric Dumazet)
 *
 * tcp_md5
 * Usage :
 * server side : tcp_md5 -s -m ip_client:md5_key
 * client side : tcp_md5 -c -m ip_server:md5_key
 */
#include <pthread.h>
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <netdb.h>
#include <signal.h>
#include <unistd.h>
#include <time.h>
#include <netinet/tcp.h>


char *content;
size_t content_size = 4000000;

void content_init(void)
{
	size_t ui;

	content = malloc(content_size);
	if (!content) {
		perror("bind"); 
		exit(EXIT_FAILURE);
	}
	srandom(12345);
	for (ui = 0; ui < content_size; ui += sizeof(unsigned short))
		*(unsigned short *)(content + ui) = (unsigned short)random();
}



char buffer[4096];

int main(int argc, char *argv[])
{
	int fd, c;
	int sflg = 0, cflg = 0;
	char *mopt = NULL;
	struct tcp_md5sig sig;
	int one = 1;
	int port = 8080;
	struct sockaddr_in server_addr, addr;
	socklen_t len;

	while ((c = getopt(argc, argv, "scm:p:")) != -1) {
		if (c == 's') sflg++;
		else if (c == 'c') cflg++;
		else if (c == 'm') mopt = optarg;
		else if (c == 'p') port = atoi(optarg);
	}
	content_init();
  	memset(&sig, 0, sizeof(sig));
	if (mopt) {
		char *p = strchr(mopt, ':');

		if (!p) {
			fprintf(stderr, " Use -m ip:key\n");
			exit(EXIT_FAILURE);
		}
		*p++ = 0;
		sig.tcpm_keylen = strlen(p);
		memcpy(sig.tcpm_key, p, sig.tcpm_keylen);
		addr.sin_family = AF_INET;
		inet_pton(AF_INET, mopt, &addr.sin_addr);
		memcpy(&sig.tcpm_addr, &addr, sizeof(addr));
	}
	if (sflg + cflg != 1) {
		fprintf(stderr, "Use option -c or -s\n");
		exit(EXIT_FAILURE);
	}
	if (sflg) {
		int listener_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if (listener_fd == -1) {
			perror("socket");
			exit(EXIT_FAILURE);
		}
		if (setsockopt(listener_fd, SOL_SOCKET, SO_REUSEADDR,
			       &one, sizeof(one)) == -1) {
			perror("setsockopt");
			exit(EXIT_FAILURE);
		}
		memset(&server_addr, 0, sizeof(server_addr));
		server_addr.sin_family = AF_INET;
		server_addr.sin_port = htons(port);
		if (bind(listener_fd, (struct sockaddr *)&server_addr, sizeof(server_addr))) {
			perror("bind"); 
			exit(EXIT_FAILURE);
		}
		if (setsockopt(listener_fd, SOL_TCP,  TCP_MD5SIG, &sig, sizeof(sig)) == -1) {
			perror("TCP_MD5SIG");
			exit(EXIT_FAILURE);
		}
		if (listen(listener_fd, 255) == -1) {
			perror("listen");
			exit(EXIT_FAILURE);
		}
		while (1) {
			pid_t pid;
			off_t off;
			len = sizeof(addr);
			fd = accept(listener_fd, (struct sockaddr *)&addr, &len);
			if (fd == -1) {
				perror("accept");
				exit(EXIT_FAILURE); 
			}
			signal(SIGCLD, SIG_IGN);
			pid = fork();
			if (pid == -1) {
				close(fd);
				continue;
			}
			if (pid)
				continue;
//			sleep(1);
			for (off = 0; ;) {
				int lu = read(fd, buffer, 4096);
				if (lu <= 0) break;
				if (memcmp(content + off, buffer, lu)) {
					fprintf(stderr, "Mismatch at off %llu\n", (unsigned long long)off);
					break;
				}
				off += lu;
			}
			printf("read %llu bytes\n", (unsigned long long)off);
			close(fd);
			exit( off == content_size ? 0 : EXIT_FAILURE);
		}
	}
	if (cflg) {
		int fd1 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		int fd2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if (fd1 == -1) {
			perror("socket");
			exit(EXIT_FAILURE);
		}
		if (setsockopt(fd1, SOL_SOCKET, SO_REUSEADDR,
			       &one, sizeof(one)) == -1) {
			perror("setsockopt");
			exit(EXIT_FAILURE);
		}
		
		addr.sin_port = htons(port);
		if (setsockopt(fd1, SOL_TCP, TCP_MD5SIG,
			       &sig, sizeof(sig)) == -1) {
			perror("TCP_MD5SIG");
			exit(EXIT_FAILURE);
		}
		if (connect(fd1, (struct sockaddr *)&addr,
			    sizeof(addr))) {
			perror("connect"); 
			exit(EXIT_FAILURE);
		}
		if (fd2 == -1) {
			perror("socket");
			exit(EXIT_FAILURE);
		}
		if (setsockopt(fd2, SOL_SOCKET, SO_REUSEADDR,
			       &one, sizeof(one)) == -1) {
			perror("setsockopt");
			exit(EXIT_FAILURE);
		}
		
		addr.sin_port = htons(port);
		if (setsockopt(fd2, SOL_TCP, TCP_MD5SIG,
			       &sig, sizeof(sig)) == -1) {
			perror("TCP_MD5SIG");
			exit(EXIT_FAILURE);
		}
		if (connect(fd2, (struct sockaddr *)&addr,
			    sizeof(addr))) {
			perror("connect"); 
			exit(EXIT_FAILURE);
		}
		if (1) {
			size_t off1 = 0;
			size_t off2 = 0;
			srandom(12345);
			while (1) {
				if (off1 < content_size) {
					int res;
					int amount = random() % 10000;
					if (amount > content_size - off1)
						amount = content_size - off1;
					res = write(fd1, content + off1, amount);
					if (res == -1) {
						perror("write");
						exit(EXIT_FAILURE);
					}
					off1 += res;
				}
				if (off2 < content_size) {
					int res;
					int amount = random() % 10000;
					if (amount > content_size - off2)
						amount = content_size - off2;
					res = write(fd2, content + off2, amount);
					if (res == -1) {
						perror("write");
						exit(EXIT_FAILURE);
					}
					off2 += res;
				}
			if (off1 == content_size && off2 == content_size)
				break;
			}
		}
		close(fd1);
		close(fd2);
	}
	exit(0);
}



--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ