Skip to content

Commit 2dc3606

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

File tree

1 file changed

+63
-32
lines changed

1 file changed

+63
-32
lines changed

options/posix/generic/lookup.cpp

Lines changed: 63 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -20,30 +20,43 @@ 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+
2933
uint8_t offset = ((code & 0x3F) << 8) | *it++;
34+
if(offset >= buf_size)
35+
return frg::null_opt;
36+
3037
auto offset_it = buf + offset;
31-
return res + read_dns_name(buf, offset_it);
32-
} else if (!(code & 0xC0)) {
38+
auto sub_name = read_dns_name(buf, buf_size, offset_it);
39+
if(!sub_name)
40+
return frg::null_opt;
41+
42+
return res + *sub_name;
43+
} else if(!(code & 0xC0)) {
3344
if (!code)
34-
break;
45+
return res;
46+
else if(it + code > buf + buf_size)
47+
return frg::null_opt;
3548

3649
for (int i = 0; i < code; i++)
3750
res += (*it++);
3851

39-
if (*it)
52+
if (it < buf + buf_size && *it)
4053
res += '.';
4154
} else {
42-
break;
55+
return frg::null_opt;
4356
}
4457
}
4558

46-
return res;
59+
return frg::null_opt;
4760
}
4861

4962
int lookup_name_dns(struct lookup_result &buf, const char *name,
@@ -105,10 +118,10 @@ int lookup_name_dns(struct lookup_result &buf, const char *name,
105118
return -EAI_SYSTEM;
106119
}
107120

108-
char response[256];
121+
uint8_t response[1500];
109122
ssize_t rlen;
110123
int num_ans = 0;
111-
while ((rlen = recvfrom(fd, response, 256, 0, NULL, NULL)) >= 0) {
124+
while ((rlen = recvfrom(fd, response, sizeof(response), 0, NULL, NULL)) >= 0) {
112125
if ((size_t)rlen < sizeof(struct dns_header))
113126
continue;
114127
auto response_header = reinterpret_cast<struct dns_header*>(response);
@@ -117,33 +130,44 @@ int lookup_name_dns(struct lookup_result &buf, const char *name,
117130

118131
auto it = response + sizeof(struct dns_header);
119132
for (int i = 0; i < ntohs(response_header->no_q); i++) {
120-
auto dns_name = read_dns_name(response, it);
121-
(void) dns_name;
133+
auto dns_name = read_dns_name(response, sizeof(response), it);
134+
if(!dns_name)
135+
return -EAI_FAIL;
122136
it += 4;
123137
}
124138

125139
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);
140+
auto dns_name = read_dns_name(response, sizeof(response), it);
141+
if(!dns_name)
142+
return -EAI_FAIL;
143+
if(it + 10 > response + rlen)
144+
return -EAI_FAIL;
128145

129146
uint16_t rr_type = (it[0] << 8) | it[1];
130147
uint16_t rr_class = (it[2] << 8) | it[3];
131148
uint16_t rr_length = (it[8] << 8) | it[9];
132149
it += 10;
133150
(void)rr_class;
151+
if(it + rr_length > response + rlen)
152+
return -EAI_FAIL;
134153

154+
struct dns_addr_buf buffer;
135155
switch (rr_type) {
136156
case RECORD_A:
137157
memcpy(buffer.addr, it, rr_length);
138158
it += rr_length;
139159
buffer.family = AF_INET;
140-
buffer.name = std::move(dns_name);
160+
buffer.name = std::move(*dns_name);
141161
buf.buf.push(std::move(buffer));
142162
break;
143-
case RECORD_CNAME:
144-
canon_name = read_dns_name(response, it);
145-
buf.aliases.push(std::move(dns_name));
163+
case RECORD_CNAME: {
164+
auto cname = read_dns_name(response, sizeof(response), it);
165+
if(!cname)
166+
return -EAI_FAIL;
167+
canon_name = std::move(*cname);
168+
buf.aliases.push(std::move(*dns_name));
146169
break;
170+
}
147171
default:
148172
mlibc::infoLogger() << "lookup_name_dns: unknown rr type "
149173
<< rr_type << frg::endlog;
@@ -234,10 +258,10 @@ int lookup_addr_dns(frg::span<char> name, frg::array<uint8_t, 16> &addr, int fam
234258
return -EAI_SYSTEM;
235259
}
236260

237-
char response[256];
261+
uint8_t response[1500];
238262
ssize_t rlen;
239263
int num_ans = 0;
240-
while ((rlen = recvfrom(fd, response, 256, 0, NULL, NULL)) >= 0) {
264+
while ((rlen = recvfrom(fd, response, sizeof(response), 0, NULL, NULL)) >= 0) {
241265
if ((size_t)rlen < sizeof(struct dns_header))
242266
continue;
243267
auto response_header = reinterpret_cast<struct dns_header*>(response);
@@ -246,31 +270,38 @@ int lookup_addr_dns(frg::span<char> name, frg::array<uint8_t, 16> &addr, int fam
246270

247271
auto it = response + sizeof(struct dns_header);
248272
for (int i = 0; i < ntohs(response_header->no_q); i++) {
249-
auto dns_name = read_dns_name(response, it);
250-
(void) dns_name;
273+
auto dns_name = read_dns_name(response, sizeof(response), it);
274+
if(!dns_name)
275+
return -EAI_FAIL;
251276
it += 4;
252277
}
253278

254279
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);
280+
auto dns_name = read_dns_name(response, sizeof(response), it);
281+
if(!dns_name)
282+
return -EAI_FAIL;
283+
if(it + 10 > response + rlen)
284+
return -EAI_FAIL;
257285

258286
uint16_t rr_type = (it[0] << 8) | it[1];
259287
uint16_t rr_class = (it[2] << 8) | it[3];
260288
uint16_t rr_length = (it[8] << 8) | it[9];
261289
it += 10;
262290
(void)rr_class;
263-
(void)rr_length;
264291

265-
(void)dns_name;
292+
if(it + rr_length > response + rlen)
293+
return -EAI_FAIL;
266294

295+
struct dns_addr_buf buffer;
267296
switch (rr_type) {
268297
case RECORD_PTR: {
269-
auto ptr_name = read_dns_name(response, it);
270-
if (ptr_name.size() >= name.size())
298+
auto ptr_name = read_dns_name(response, sizeof(response), it);
299+
if(!ptr_name)
300+
return -EAI_FAIL;
301+
else if(ptr_name->size() >= name.size())
271302
return -EAI_OVERFLOW;
272-
std::copy(ptr_name.begin(), ptr_name.end(), name.data());
273-
name.data()[ptr_name.size()] = '\0';
303+
std::copy(ptr_name->begin(), ptr_name->end(), name.data());
304+
name.data()[ptr_name->size()] = '\0';
274305
return 1;
275306
}
276307
default:

0 commit comments

Comments
 (0)