[sanitizer] Move recvmsg and recv interceptors to sanitizer_common.

This patch moves recv and recvfrom interceptors from MSan and TSan to
sanitizer_common to enable them in ASan.

Differential Revision: http://reviews.llvm.org/D17479

llvm-svn: 261841
This commit is contained in:
Maxim Ostapenko 2016-02-25 08:44:25 +00:00
parent 12737b7f72
commit 7389936f57
5 changed files with 118 additions and 38 deletions

View File

@ -978,30 +978,6 @@ INTERCEPTOR(int, epoll_pwait, int epfd, void *events, int maxevents,
#define MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT
#endif
INTERCEPTOR(SSIZE_T, recv, int fd, void *buf, SIZE_T len, int flags) {
ENSURE_MSAN_INITED();
SSIZE_T res = REAL(recv)(fd, buf, len, flags);
if (res > 0)
__msan_unpoison(buf, res);
return res;
}
INTERCEPTOR(SSIZE_T, recvfrom, int fd, void *buf, SIZE_T len, int flags,
void *srcaddr, int *addrlen) {
ENSURE_MSAN_INITED();
SIZE_T srcaddr_sz;
if (srcaddr) srcaddr_sz = *addrlen;
SSIZE_T res = REAL(recvfrom)(fd, buf, len, flags, srcaddr, addrlen);
if (res > 0) {
__msan_unpoison(buf, res);
if (srcaddr) {
SIZE_T sz = *addrlen;
__msan_unpoison(srcaddr, Min(sz, srcaddr_sz));
}
}
return res;
}
INTERCEPTOR(void *, calloc, SIZE_T nmemb, SIZE_T size) {
GET_MALLOC_STACK_TRACE;
if (UNLIKELY(!msan_inited)) {
@ -1647,8 +1623,6 @@ void InitializeInterceptors() {
INTERCEPT_FUNCTION(gethostname);
MSAN_MAYBE_INTERCEPT_EPOLL_WAIT;
MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT;
INTERCEPT_FUNCTION(recv);
INTERCEPT_FUNCTION(recvfrom);
INTERCEPT_FUNCTION(dladdr);
INTERCEPT_FUNCTION(dlerror);
INTERCEPT_FUNCTION(dl_iterate_phdr);

View File

@ -5333,6 +5333,43 @@ INTERCEPTOR(char *, ctermid_r, char *s) {
#define INIT_CTERMID_R
#endif
#if SANITIZER_INTERCEPT_RECV_RECVFROM
INTERCEPTOR(SSIZE_T, recv, int fd, void *buf, SIZE_T len, int flags) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, recv, fd, buf, len, flags);
COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
SSIZE_T res = REAL(recv)(fd, buf, len, flags);
if (res > 0) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, len);
}
if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
return res;
}
INTERCEPTOR(SSIZE_T, recvfrom, int fd, void *buf, SIZE_T len, int flags,
void *srcaddr, int *addrlen) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, recvfrom, fd, buf, len, flags, srcaddr,
addrlen);
COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
SIZE_T srcaddr_sz;
if (srcaddr) srcaddr_sz = *addrlen;
SSIZE_T res = REAL(recvfrom)(fd, buf, len, flags, srcaddr, addrlen);
if (res > 0) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, len);
if (srcaddr)
COMMON_INTERCEPTOR_INITIALIZE_RANGE(srcaddr,
Min((SIZE_T)*addrlen, srcaddr_sz));
}
return res;
}
#define INIT_RECV_RECVFROM \
COMMON_INTERCEPT_FUNCTION(recv); \
COMMON_INTERCEPT_FUNCTION(recvfrom);
#else
#define INIT_RECV_RECVFROM
#endif
static void InitializeCommonInterceptors() {
static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1];
interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap();
@ -5509,4 +5546,5 @@ static void InitializeCommonInterceptors() {
INIT_PROCESS_VM_READV;
INIT_CTERMID;
INIT_CTERMID_R;
INIT_RECV_RECVFROM;
}

View File

@ -272,5 +272,6 @@
#define SANITIZER_INTERCEPT_CTERMID_R SI_MAC || SI_FREEBSD
#define SANITIZER_INTERCEPTOR_HOOKS SI_LINUX
#define SANITIZER_INTERCEPT_RECV_RECVFROM 1
#endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H

View File

@ -1814,17 +1814,6 @@ TSAN_INTERCEPTOR(long_t, sendmsg, int fd, void *msg, int flags) {
return res;
}
TSAN_INTERCEPTOR(long_t, recv, int fd, void *buf, long_t len, int flags) {
SCOPED_TSAN_INTERCEPTOR(recv, fd, buf, len, flags);
if (fd >= 0)
FdAccess(thr, pc, fd);
int res = REAL(recv)(fd, buf, len, flags);
if (res >= 0 && fd >= 0) {
FdAcquire(thr, pc, fd);
}
return res;
}
TSAN_INTERCEPTOR(int, unlink, char *path) {
SCOPED_TSAN_INTERCEPTOR(unlink, path);
Release(thr, pc, File2addr(path));
@ -2716,7 +2705,6 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(send);
TSAN_INTERCEPT(sendmsg);
TSAN_INTERCEPT(recv);
TSAN_INTERCEPT(unlink);
TSAN_INTERCEPT(tmpfile);

View File

@ -0,0 +1,79 @@
// Test that ASan detects buffer overflow on read from socket via recvfrom.
//
// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s
// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s
// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
const int kPortNum = 1234;
const int kBufSize = 10;
static void *server_thread_udp(void *data) {
char buf[kBufSize / 2];
struct sockaddr_in serveraddr; // server's addr
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
fprintf(stderr, "ERROR opening socket\n");
memset((char *) &serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(kPortNum);
if (bind(sockfd, (struct sockaddr *) &serveraddr, sizeof(serveraddr)) < 0)
fprintf(stderr, "ERROR on binding\n");
recvfrom(sockfd, buf, kBufSize, 0, NULL, NULL); // BOOM
// CHECK: {{WRITE of size 10 at 0x.* thread T1}}
// CHECK: {{ #1 0x.* in server_thread_udp.*recvfrom.cc:}}[[@LINE-2]]
// CHECK: {{Address 0x.* is located in stack of thread T1 at offset}}
// CHECK-NEXT: in{{.*}}server_thread_udp{{.*}}recvfrom.cc
return NULL;
}
int main() {
char buf[kBufSize] = "123456789";
struct sockaddr_in serveraddr; // server's addr
pthread_t server_thread;
if (pthread_create(&server_thread, NULL, server_thread_udp, NULL)) {
fprintf(stderr, "Error creating thread\n");
exit(1);
}
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
struct hostent *server;
char hostname[] = "localhost";
if (sockfd < 0)
fprintf(stderr, "ERROR opening socket\n");
server = gethostbyname(hostname);
if (!server) {
fprintf(stderr,"ERROR, no such host as %s\n", hostname);
exit(1);
}
memset((char *) &serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
memcpy((char *)&serveraddr.sin_addr.s_addr, (char *)server->h_addr,
server->h_length);
serveraddr.sin_port = htons(kPortNum);
sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *) &serveraddr,
sizeof(serveraddr));
if (pthread_join(server_thread, NULL)) {
fprintf(stderr, "Error joining thread\n");
exit(1);
}
return 0;
}