[<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