Skip to content

Commit 28b1f11

Browse files
committed
options/posix: add bound checks for dns response parsing
1 parent b115980 commit 28b1f11

File tree

1 file changed

+79
-35
lines changed

1 file changed

+79
-35
lines changed

options/posix/generic/lookup.cpp

Lines changed: 79 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -20,30 +20,49 @@ namespace {
2020
constexpr unsigned int RECORD_PTR = 12;
2121
}
2222

23-
static frg::string<MemoryAllocator> read_dns_name(char *buf, char *&it) {
23+
static frg::optional<frg::string<MemoryAllocator>> read_dns_name(uint8_t *buf,
24+
size_t buf_size, uint8_t *&it) {
2425
frg::string<MemoryAllocator> res{getAllocator()};
25-
while (true) {
26-
char code = *it++;
27-
if ((code & 0xC0) == 0xC0) {
26+
while(it < buf + buf_size) {
27+
uint8_t code = *it++;
28+
if((code & 0xC0) == 0xC0) {
2829
// pointer
30+
if(it + 1 > buf + buf_size) {
31+
return frg::null_opt;
32+
}
33+
2934
uint8_t offset = ((code & 0x3F) << 8) | *it++;
35+
if(offset >= buf_size) {
36+
return frg::null_opt;
37+
}
38+
3039
auto offset_it = buf + offset;
31-
return res + read_dns_name(buf, offset_it);
32-
} else if (!(code & 0xC0)) {
33-
if (!code)
34-
break;
40+
auto sub_name = read_dns_name(buf, buf_size, offset_it);
41+
if(!sub_name) {
42+
return frg::null_opt;
43+
}
44+
45+
return res + *sub_name;
46+
} else if(!(code & 0xC0)) {
47+
if (!code) {
48+
return res;
49+
} else if(it + code > buf + buf_size) {
50+
return frg::null_opt;
51+
}
3552

36-
for (int i = 0; i < code; i++)
53+
for (int i = 0; i < code; i++) {
3754
res += (*it++);
55+
}
3856

39-
if (*it)
57+
if (it < buf + buf_size && *it) {
4058
res += '.';
59+
}
4160
} else {
42-
break;
61+
return frg::null_opt;
4362
}
4463
}
4564

46-
return res;
65+
return frg::null_opt;
4766
}
4867

4968
int lookup_name_dns(struct lookup_result &buf, const char *name,
@@ -105,10 +124,10 @@ int lookup_name_dns(struct lookup_result &buf, const char *name,
105124
return -EAI_SYSTEM;
106125
}
107126

108-
char response[256];
127+
uint8_t response[1500];
109128
ssize_t rlen;
110129
int num_ans = 0;
111-
while ((rlen = recvfrom(fd, response, 256, 0, NULL, NULL)) >= 0) {
130+
while ((rlen = recvfrom(fd, response, sizeof(response), 0, NULL, NULL)) >= 0) {
112131
if ((size_t)rlen < sizeof(struct dns_header))
113132
continue;
114133
auto response_header = reinterpret_cast<struct dns_header*>(response);
@@ -117,33 +136,48 @@ int lookup_name_dns(struct lookup_result &buf, const char *name,
117136

118137
auto it = response + sizeof(struct dns_header);
119138
for (int i = 0; i < ntohs(response_header->no_q); i++) {
120-
auto dns_name = read_dns_name(response, it);
121-
(void) dns_name;
139+
auto dns_name = read_dns_name(response, sizeof(response), it);
140+
if(!dns_name) {
141+
return -EAI_FAIL;
142+
}
122143
it += 4;
123144
}
124145

125146
for (int i = 0; i < ntohs(response_header->no_ans); i++) {
126-
struct dns_addr_buf buffer;
127-
auto dns_name = read_dns_name(response, it);
147+
auto dns_name = read_dns_name(response, sizeof(response), it);
148+
if(!dns_name) {
149+
return -EAI_FAIL;
150+
} else if(it + 10 > response + rlen) {
151+
return -EAI_FAIL;
152+
}
128153

129154
uint16_t rr_type = (it[0] << 8) | it[1];
130155
uint16_t rr_class = (it[2] << 8) | it[3];
131156
uint16_t rr_length = (it[8] << 8) | it[9];
132157
it += 10;
133158
(void)rr_class;
159+
if(it + rr_length > response + rlen) {
160+
return -EAI_FAIL;
161+
}
134162

163+
struct dns_addr_buf buffer;
135164
switch (rr_type) {
136165
case RECORD_A:
137166
memcpy(buffer.addr, it, rr_length);
138167
it += rr_length;
139168
buffer.family = AF_INET;
140-
buffer.name = std::move(dns_name);
169+
buffer.name = std::move(*dns_name);
141170
buf.buf.push(std::move(buffer));
142171
break;
143-
case RECORD_CNAME:
144-
canon_name = read_dns_name(response, it);
145-
buf.aliases.push(std::move(dns_name));
172+
case RECORD_CNAME: {
173+
auto cname = read_dns_name(response, sizeof(response), it);
174+
if(!cname) {
175+
return -EAI_FAIL;
176+
}
177+
canon_name = std::move(*cname);
178+
buf.aliases.push(std::move(*dns_name));
146179
break;
180+
}
147181
default:
148182
mlibc::infoLogger() << "lookup_name_dns: unknown rr type "
149183
<< rr_type << frg::endlog;
@@ -234,10 +268,10 @@ int lookup_addr_dns(frg::span<char> name, frg::array<uint8_t, 16> &addr, int fam
234268
return -EAI_SYSTEM;
235269
}
236270

237-
char response[256];
271+
uint8_t response[1500];
238272
ssize_t rlen;
239273
int num_ans = 0;
240-
while ((rlen = recvfrom(fd, response, 256, 0, NULL, NULL)) >= 0) {
274+
while ((rlen = recvfrom(fd, response, sizeof(response), 0, NULL, NULL)) >= 0) {
241275
if ((size_t)rlen < sizeof(struct dns_header))
242276
continue;
243277
auto response_header = reinterpret_cast<struct dns_header*>(response);
@@ -246,31 +280,41 @@ int lookup_addr_dns(frg::span<char> name, frg::array<uint8_t, 16> &addr, int fam
246280

247281
auto it = response + sizeof(struct dns_header);
248282
for (int i = 0; i < ntohs(response_header->no_q); i++) {
249-
auto dns_name = read_dns_name(response, it);
250-
(void) dns_name;
283+
auto dns_name = read_dns_name(response, sizeof(response), it);
284+
if(!dns_name) {
285+
return -EAI_FAIL;
286+
}
251287
it += 4;
252288
}
253289

254290
for (int i = 0; i < ntohs(response_header->no_ans); i++) {
255-
struct dns_addr_buf buffer;
256-
auto dns_name = read_dns_name(response, it);
291+
auto dns_name = read_dns_name(response, sizeof(response), it);
292+
if(!dns_name) {
293+
return -EAI_FAIL;
294+
} else if(it + 10 > response + rlen) {
295+
return -EAI_FAIL;
296+
}
257297

258298
uint16_t rr_type = (it[0] << 8) | it[1];
259299
uint16_t rr_class = (it[2] << 8) | it[3];
260300
uint16_t rr_length = (it[8] << 8) | it[9];
261301
it += 10;
262302
(void)rr_class;
263-
(void)rr_length;
264-
265-
(void)dns_name;
303+
if(it + rr_length > response + rlen) {
304+
return -EAI_FAIL;
305+
}
266306

307+
struct dns_addr_buf buffer;
267308
switch (rr_type) {
268309
case RECORD_PTR: {
269-
auto ptr_name = read_dns_name(response, it);
270-
if (ptr_name.size() >= name.size())
310+
auto ptr_name = read_dns_name(response, sizeof(response), it);
311+
if(!ptr_name) {
312+
return -EAI_FAIL;
313+
} else if(ptr_name->size() >= name.size()) {
271314
return -EAI_OVERFLOW;
272-
std::copy(ptr_name.begin(), ptr_name.end(), name.data());
273-
name.data()[ptr_name.size()] = '\0';
315+
}
316+
std::copy(ptr_name->begin(), ptr_name->end(), name.data());
317+
name.data()[ptr_name->size()] = '\0';
274318
return 1;
275319
}
276320
default:

0 commit comments

Comments
 (0)