diff options
author | Andrew Ayer <agwa@andrewayer.name> | 2014-07-09 13:23:02 -0700 |
---|---|---|
committer | Jiri Pirko <jiri@resnulli.us> | 2014-07-29 15:16:06 +0200 |
commit | e93d565950129a31ac1141b6589afc4e35d1cde3 (patch) | |
tree | 0445b6614164e1e21c9d851df8998d49adcff494 | |
parent | d438bc9c4c01b12f3a50d869f87565b6e3f17531 (diff) | |
download | libndp-e93d565950129a31ac1141b6589afc4e35d1cde3.tar.gz |
libndp: fix buffer overflow in ndp_msg_opt_dnssl_domain()
The buf array would overflow when processing a malformed DNSSL option
containing a domain name whose labels' combined length exceeded 255 bytes.
To facilitate the bounds checking, the code has been restructured slightly
to be simpler and avoid repeated calls to strlen and strcat.
Signed-off-by: Andrew Ayer <agwa@andrewayer.name>
Signed-off-by: Jiri Pirko <jiri@resnulli.us>
-rw-r--r-- | libndp/libndp.c | 15 |
1 files changed, 9 insertions, 6 deletions
diff --git a/libndp/libndp.c b/libndp/libndp.c index e510e2e..cd67356 100644 --- a/libndp/libndp.c +++ b/libndp/libndp.c @@ -1527,7 +1527,7 @@ char *ndp_msg_opt_dnssl_domain(struct ndp_msg *msg, int offset, i = 0; while (len > 0) { - *buf = '\0'; + size_t buf_len = 0; while (len > 0) { uint8_t dom_len = *ptr; @@ -1539,15 +1539,18 @@ char *ndp_msg_opt_dnssl_domain(struct ndp_msg *msg, int offset, if (dom_len > len) return NULL; - if (strlen(buf)) - strcat(buf, "."); - buf[strlen(buf) + dom_len] = '\0'; - memcpy(buf + strlen(buf), ptr, dom_len); + if (buf_len + dom_len + 1 > sizeof(buf)) + return NULL; + + memcpy(buf + buf_len, ptr, dom_len); + buf[buf_len + dom_len] = '.'; ptr += dom_len; len -= dom_len; + buf_len += dom_len + 1; } - if (!strlen(buf)) + if (!buf_len) break; + buf[buf_len - 1] = '\0'; /* overwrite final '.' */ if (i++ == domain_index) return buf; } |