[Dnsmasq-discuss] Heap Overflow in "read_file" function

Kyle Zeng jkjh1jkjh1 at gmail.com
Fri Sep 13 18:36:11 BST 2019


There is a heap overflow in "read_file". It can be triggered if the file it wants to read is not a valid conf file and it has very long name. Notice that it can also be trigger through function "clear_cache_and_reload" which is called in some event handlers. So it might be able to be triggered remotely(do not have a poc).

poc(target: git://thekelleys.org.uk/dnsmasq.git (https://link.getmailspring.com/link/FC759E02-CF53-4055-ABFC-17B29107897F@getmailspring.com/0?redirect=git%3A%2F%2Fthekelleys.org.uk%2Fdnsmasq.git&recipient=ZG5zbWFzcS1kaXNjdXNzQGxpc3RzLnRoZWtlbGxleXMub3JnLnVr), commit: e24abf28a29574069717af78c1d3e0ede64388ff, compilation command: CC="clang -fsanitize=address" make):
folder=$(python -c "print(('B'*100+'/')*10)"); mkdir -p $folder && echo "111" > $folder/config && ./dnsmasq -p 8333 -C $folder/config -d

The bug is in line 4586 of options.c.
Here is the snippet :
-------
oops:
if (errmess)
strcpy(daemon->namebuff, errmess);

if (errmess || !one_opt(option, arg, daemon->namebuff, _("error"), 0, hard_opt == LOPT_REV_SERV))
{
sprintf(daemon->namebuff + strlen(daemon->namebuff), _(" at line %d of %s"), lineno, file);
if (hard_opt != 0)
my_syslog(LOG_ERR, "%s", daemon->namebuff);
else
die("%s", daemon->namebuff, EC_BADCONF);
}
--------
Analysis:
If oops is triggered, an error message will be copied into the daemon->namebuff. And then a sprintf will be triggered to append a detailed error message.
However, the namebuff is of length MAXDNAME and file is also of length MAXDNAME. So, overflow happens.

Suggested fix:
------
diff --git a/src/option.c b/src/option.c
index 83d57a6..24e77e4 100644
--- a/src/option.c
+++ b/src/option.c
@@ -4583,7 +4583,8 @@ static void read_file(char *file, FILE *f, int hard_opt)

if (errmess || !one_opt(option, arg, daemon->namebuff, _("error"), 0, hard_opt == LOPT_REV_SERV))
{
- sprintf(daemon->namebuff + strlen(daemon->namebuff), _(" at line %d of %s"), lineno, file);
+ size_t buf_len = strlen(daemon->namebuff);
+ snprintf(daemon->namebuff + buf_len, MAXDNAME-buf_len, _(" at line %d of %s"), lineno, file);
if (hard_opt != 0)
my_syslog(LOG_ERR, "%s", daemon->namebuff);
else
------

Yihui Zeng
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/attachments/20190913/90973ca0/attachment.html>


More information about the Dnsmasq-discuss mailing list