1 | // Test that ASan detects buffer overflow on read from socket via recvfrom. |
2 | // |
3 | // RUN: %clangxx_asan %s -DRECVFROM -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-RECVFROM |
4 | // RUN: %clangxx_asan %s -DSENDTO -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-SENDTO |
5 | // RUN: %clangxx_asan %s -DSENDTO -o %t && %env_asan_opts=intercept_send=0 %run %t 2>&1 |
6 | // |
7 | // This will try to fast unwind on Arm Thumb, where fast unwinding does not work. |
8 | // UNSUPPORTED: android, !fast-unwinder-works |
9 | |
10 | #include <stdio.h> |
11 | #include <unistd.h> |
12 | #include <stdlib.h> |
13 | #include <string.h> |
14 | #include <netdb.h> |
15 | #include <sys/types.h> |
16 | #include <sys/socket.h> |
17 | #include <pthread.h> |
18 | |
19 | #define CHECK_ERROR(p, m) \ |
20 | do { \ |
21 | if (p) { \ |
22 | fprintf(stderr, "ERROR " m "\n"); \ |
23 | exit(1); \ |
24 | } \ |
25 | } while (0) |
26 | |
27 | const int kBufSize = 10; |
28 | int sockfd; |
29 | |
30 | static void *client_thread_udp(void *data) { |
31 | #ifdef SENDTO |
32 | const char buf[kBufSize / 2] = {0, }; |
33 | #else |
34 | const char buf[kBufSize] = {0, }; |
35 | #endif |
36 | struct sockaddr_in serveraddr; |
37 | socklen_t addrlen = sizeof(serveraddr); |
38 | |
39 | int succeeded = getsockname(fd: sockfd, addr: (struct sockaddr *)&serveraddr, len: &addrlen); |
40 | CHECK_ERROR(succeeded < 0, "in getsockname" ); |
41 | |
42 | succeeded = sendto(fd: sockfd, buf: buf, n: kBufSize, flags: 0, addr: (struct sockaddr *)&serveraddr, |
43 | addr_len: sizeof(serveraddr)); |
44 | // CHECK-SENDTO: {{READ of size 10 at 0x.* thread T1}} |
45 | // CHECK-SENDTO: {{ #1 0x.* in client_thread_udp.*recvfrom.cpp:}}[[@LINE-3]] |
46 | CHECK_ERROR(succeeded < 0, "in sending message" ); |
47 | return NULL; |
48 | } |
49 | |
50 | int main() { |
51 | #ifdef RECVFROM |
52 | char buf[kBufSize / 2]; |
53 | #else |
54 | char buf[kBufSize]; |
55 | #endif |
56 | pthread_t client_thread; |
57 | struct sockaddr_in serveraddr; |
58 | |
59 | sockfd = socket(AF_INET, SOCK_DGRAM, protocol: 0); |
60 | CHECK_ERROR(sockfd < 0, "opening socket" ); |
61 | |
62 | memset(s: &serveraddr, c: 0, n: sizeof(serveraddr)); |
63 | serveraddr.sin_family = AF_INET; |
64 | serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); |
65 | serveraddr.sin_port = 0; |
66 | |
67 | int bound = bind(fd: sockfd, addr: (struct sockaddr *)&serveraddr, len: sizeof(serveraddr)); |
68 | CHECK_ERROR(bound < 0, "on binding" ); |
69 | |
70 | int succeeded = |
71 | pthread_create(newthread: &client_thread, NULL, start_routine: client_thread_udp, arg: &serveraddr); |
72 | CHECK_ERROR(succeeded, "creating thread" ); |
73 | |
74 | recvfrom(fd: sockfd, buf: buf, n: kBufSize, flags: 0, NULL, NULL); // BOOM |
75 | // CHECK-RECVFROM: {{WRITE of size 10 at 0x.* thread T0}} |
76 | // CHECK-RECVFROM: {{ #1 0x.* in main.*recvfrom.cpp:}}[[@LINE-2]] |
77 | // CHECK-RECVFROM: {{Address 0x.* is located in stack of thread T0 at offset}} |
78 | // CHECK-RECVFROM-NEXT: in{{.*}}main{{.*}}recvfrom.cpp |
79 | succeeded = pthread_join(th: client_thread, NULL); |
80 | CHECK_ERROR(succeeded, "joining thread" ); |
81 | return 0; |
82 | } |
83 | |