public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] tcp: fix tcp_md5_hash_skb_data()
@ 2013-05-14  7:25 Eric Dumazet
  2013-05-14 17:58 ` Eric Dumazet
  2013-05-14 18:33 ` David Miller
  0 siblings, 2 replies; 3+ messages in thread
From: Eric Dumazet @ 2013-05-14  7:25 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Matt Schnall, Bernhard Beck

From: Eric Dumazet <edumazet@google.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()

[1] Failure is giving following messages.

huh, entered softirq 3 NET_RX ffffffff806ad230 preempt_count 00000100,
exited with 00000101?

[2] mlx4 driver uses order-2 pages to allocate RX frags

Reported-by: Matt Schnall <mischnal@google.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Bernhard Beck <bbeck@google.com>
---
 net/ipv4/tcp.c |    7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index dcb116d..10c9393 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -3269,8 +3269,11 @@ int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *hp,
 
 	for (i = 0; i < shi->nr_frags; ++i) {
 		const struct skb_frag_struct *f = &shi->frags[i];
-		struct page *page = skb_frag_page(f);
-		sg_set_page(&sg, page, skb_frag_size(f), f->page_offset);
+		unsigned int offset = f->page_offset;
+		struct page *page = skb_frag_page(f) + (offset >> PAGE_SHIFT);
+
+		sg_set_page(&sg, page, skb_frag_size(f),
+			    offset_in_page(offset));
 		if (crypto_hash_update(desc, &sg, skb_frag_size(f)))
 			return 1;
 	}

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] tcp: fix tcp_md5_hash_skb_data()
  2013-05-14  7:25 [PATCH] tcp: fix tcp_md5_hash_skb_data() Eric Dumazet
@ 2013-05-14 17:58 ` Eric Dumazet
  2013-05-14 18:33 ` David Miller
  1 sibling, 0 replies; 3+ messages in thread
From: Eric Dumazet @ 2013-05-14 17:58 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Matt Schnall, Bernhard Beck

On Tue, 2013-05-14 at 00:25 -0700, Eric Dumazet wrote:
> From: Eric Dumazet <edumazet@google.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@google.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);
}

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] tcp: fix tcp_md5_hash_skb_data()
  2013-05-14  7:25 [PATCH] tcp: fix tcp_md5_hash_skb_data() Eric Dumazet
  2013-05-14 17:58 ` Eric Dumazet
@ 2013-05-14 18:33 ` David Miller
  1 sibling, 0 replies; 3+ messages in thread
From: David Miller @ 2013-05-14 18:33 UTC (permalink / raw)
  To: eric.dumazet; +Cc: netdev, mischnal, bbeck

From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Tue, 14 May 2013 00:25:52 -0700

> From: Eric Dumazet <edumazet@google.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()
> 
> [1] Failure is giving following messages.
> 
> huh, entered softirq 3 NET_RX ffffffff806ad230 preempt_count 00000100,
> exited with 00000101?
> 
> [2] mlx4 driver uses order-2 pages to allocate RX frags
> 
> Reported-by: Matt Schnall <mischnal@google.com>
> Signed-off-by: Eric Dumazet <edumazet@google.com>

Applied.

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2013-05-14 18:33 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-05-14  7:25 [PATCH] tcp: fix tcp_md5_hash_skb_data() Eric Dumazet
2013-05-14 17:58 ` Eric Dumazet
2013-05-14 18:33 ` David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox