Hi again.
This time I have a little bit more controversal patches. But I think
still useful. They fixes memory leaks that might occur in some cases.
Most dnsmasq errors is fatal, so it does not matter. But some are not.
Some parts are reloaded on SIGHUP signal, so it might leak more than once.
Some example when it changes the failures. Use dhcp-options file with
this content:
tag:error,vendor:redhat
option:ntp-server,1.2.3.4.5
option6:ntp-server,[:::]
Is not fatal and dnsmasq will start. On each reload command, it would
leak some memory. I validated it using valgrind --leak-check=full
dnsmasq -d. This patch fixes it. It introduces something that might be
considered constructor and destructor of selected structures. What do
you think of it?
Comments are welcome.
Cheers,
Petr
--
Petr Menšík
Software Engineer
Red Hat, http://www.redhat.com/
email: pemen...@redhat.com PGP: 65C6C973
From 55ecb0728dbd19ef3412be2dc70d2ed9dd6ecc5e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?=
Date: Thu, 16 Aug 2018 15:48:00 +0200
Subject: [PATCH 1/2] More fixes free options
Free resources on failed config file parsing.
Make sure one_opt will free allocated memory on failed parsing.
All unsaved memory is freed on syntax error in options.
---
src/option.c | 360 ++-
1 file changed, 257 insertions(+), 103 deletions(-)
diff --git a/src/option.c b/src/option.c
index 56ef945..547d36e 100644
--- a/src/option.c
+++ b/src/option.c
@@ -759,6 +759,7 @@ static void do_usage(void)
}
#define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0)
+#define ret_err_free(x,m) do { strcpy(errstr, (x)); free((m)); return 0; } while (0)
static char *parse_mysockaddr(char *arg, union mysockaddr *addr)
{
@@ -904,6 +905,8 @@ static struct server *add_rev4(struct in_addr addr, int msize)
p += sprintf(p, "%d.", (a >> 24) & 0xff);
break;
default:
+ free(serv->domain);
+ free(serv);
return NULL;
}
@@ -1069,7 +1072,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
if (is6)
{
if (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))
- ret_err(_("unsupported encapsulation for IPv6 option"));
+ ret_err_free(_("unsupported encapsulation for IPv6 option"), new);
if (opt_len == 0 &&
!(new->flags & DHOPT_RFC3925))
@@ -1083,7 +1086,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
/* option may be missing with rfc3925 match */
if (!option_ok)
-ret_err(_("bad dhcp-option"));
+ret_err_free(_("bad dhcp-option"), new);
if (comma)
{
@@ -1151,10 +1154,10 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
is_string = is_dec = is_hex = 0;
if (!is6 && (!is_addr || dots == 0))
- ret_err(_("bad IP address"));
+ ret_err_free(_("bad IP address"), new);
if (is6 && !is_addr6)
- ret_err(_("bad IPv6 address"));
+ ret_err_free(_("bad IPv6 address"), new);
}
/* or names */
else if (opt_len & (OT_NAME | OT_RFC1035_NAME | OT_CSTRING))
@@ -1247,7 +1250,10 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
comma = split(cp);
slash = split_chr(cp, '/');
if (!inet_pton(AF_INET, cp, &in))
- ret_err(_("bad IPv4 address"));
+{
+ free(new->val);
+ ret_err_free(_("bad IPv4 address"), new);
+}
if (!slash)
{
memcpy(op, &in, INADDRSZ);
@@ -1292,8 +1298,9 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
op += IN6ADDRSZ;
continue;
}
-
- ret_err(_("bad IPv6 address"));
+
+ free(new->val);
+ ret_err_free(_("bad IPv6 address"), new);
}
new->len = op - new->val;
}
@@ -1320,7 +1327,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
if (strcmp (arg, ".") != 0)
{
if (!(dom = canonicalise_opt(arg)))
- ret_err(_("bad domain in dhcp-option"));
+ ret_err_free(_("bad domain in dhcp-option"), new);
domlen = strlen(dom) + 2;
}
@@ -1414,7 +1421,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
{
char *dom = canonicalise_opt(arg);
if (!dom)
- ret_err(_("bad domain in dhcp-option"));
+ ret_err_free(_("bad domain in dhcp-option"), new);
newp = opt_malloc(len + strlen(dom) + 2);
@@ -1452,14 +1459,14 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
((new->len > 255) ||
(new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))) ||
(new->len > 250 && (new->flags & DHOPT_RFC3925
-ret_err(_("dhcp-option too long"));
+ret_err_free(_("dhcp-option too long"), new);
if (flags == DHOPT_MATCH)
{
if ((new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)) ||
!new->netid ||
new->netid->next)
- ret_err(_("illegal dhcp-match"));
+ ret_err_free(_("illegal dh