VYPR
Unrated severityNVD Advisory· Published Oct 26, 2018· Updated Jun 9, 2025

Out-of-Bounds write in systemd-networkd dhcpv6 option handling

CVE-2018-15688

Description

A buffer overflow vulnerability in the dhcp6 client of systemd allows a malicious dhcp6 server to overwrite heap memory in systemd-networkd. Affected releases are systemd: versions up to and including 239.

Affected products

1

Patches

1
5ec1fca41e5c

Merge pull request #10518 from poettering/dhcp6-size-fixes

https://github.com/systemd/systemdLennart PoetteringOct 25, 2018via osv
2 files changed · +27 24
  • src/libsystemd-network/dhcp6-internal.h+2 2 modified
    @@ -84,8 +84,8 @@ typedef struct DHCP6IA DHCP6IA;
     
     int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
                             size_t optlen, const void *optval);
    -int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia);
    -int dhcp6_option_append_pd(uint8_t *buf, size_t len, DHCP6IA *pd);
    +int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia);
    +int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd);
     int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn);
     int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode,
                            size_t *optlen, uint8_t **optvalue);
    
  • src/libsystemd-network/dhcp6-option.c+25 22 modified
    @@ -37,9 +37,9 @@ typedef struct DHCP6PDPrefixOption {
             uint8_t options[];
     } _packed_ DHCP6PDPrefixOption;
     
    -#define DHCP6_OPTION_IA_NA_LEN                  (sizeof(struct ia_na))
    -#define DHCP6_OPTION_IA_PD_LEN                  (sizeof(struct ia_pd))
    -#define DHCP6_OPTION_IA_TA_LEN                  (sizeof(struct ia_ta))
    +#define DHCP6_OPTION_IA_NA_LEN (sizeof(struct ia_na))
    +#define DHCP6_OPTION_IA_PD_LEN (sizeof(struct ia_pd))
    +#define DHCP6_OPTION_IA_TA_LEN (sizeof(struct ia_ta))
     
     static int option_append_hdr(uint8_t **buf, size_t *buflen, uint16_t optcode,
                                  size_t optlen) {
    @@ -49,14 +49,14 @@ static int option_append_hdr(uint8_t **buf, size_t *buflen, uint16_t optcode,
             assert_return(*buf, -EINVAL);
             assert_return(buflen, -EINVAL);
     
    -        if (optlen > 0xffff || *buflen < optlen + sizeof(DHCP6Option))
    +        if (optlen > 0xffff || *buflen < optlen + offsetof(DHCP6Option, data))
                     return -ENOBUFS;
     
             option->code = htobe16(optcode);
             option->len = htobe16(optlen);
     
    -        *buf += sizeof(DHCP6Option);
    -        *buflen -= sizeof(DHCP6Option);
    +        *buf += offsetof(DHCP6Option, data);
    +        *buflen -= offsetof(DHCP6Option, data);
     
             return 0;
     }
    @@ -79,14 +79,17 @@ int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
             return 0;
     }
     
    -int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) {
    +int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia) {
             uint16_t len;
             uint8_t *ia_hdr;
             size_t iaid_offset, ia_buflen, ia_addrlen = 0;
             DHCP6Address *addr;
             int r;
     
    -        assert_return(buf && *buf && buflen && ia, -EINVAL);
    +        assert_return(buf, -EINVAL);
    +        assert_return(*buf, -EINVAL);
    +        assert_return(buflen, -EINVAL);
    +        assert_return(ia, -EINVAL);
     
             switch (ia->type) {
             case SD_DHCP6_OPTION_IA_NA:
    @@ -103,14 +106,14 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) {
                     return -EINVAL;
             }
     
    -        if (*buflen < len)
    +        if (*buflen < offsetof(DHCP6Option, data) + len)
                     return -ENOBUFS;
     
             ia_hdr = *buf;
             ia_buflen = *buflen;
     
    -        *buf += sizeof(DHCP6Option);
    -        *buflen -= sizeof(DHCP6Option);
    +        *buf += offsetof(DHCP6Option, data);
    +        *buflen -= offsetof(DHCP6Option, data);
     
             memcpy(*buf, (char*) ia + iaid_offset, len);
     
    @@ -128,7 +131,7 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) {
                     *buf += sizeof(addr->iaaddr);
                     *buflen -= sizeof(addr->iaaddr);
     
    -                ia_addrlen += sizeof(DHCP6Option) + sizeof(addr->iaaddr);
    +                ia_addrlen += offsetof(DHCP6Option, data) + sizeof(addr->iaaddr);
             }
     
             r = option_append_hdr(&ia_hdr, &ia_buflen, ia->type, len + ia_addrlen);
    @@ -165,7 +168,7 @@ int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) {
             return r;
     }
     
    -int dhcp6_option_append_pd(uint8_t *buf, size_t len, DHCP6IA *pd) {
    +int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd) {
             DHCP6Option *option = (DHCP6Option *)buf;
             size_t i = sizeof(*option) + sizeof(pd->ia_pd);
             DHCP6Address *prefix;
    @@ -210,7 +213,7 @@ static int option_parse_hdr(uint8_t **buf, size_t *buflen, uint16_t *optcode, si
             assert_return(optcode, -EINVAL);
             assert_return(optlen, -EINVAL);
     
    -        if (*buflen < sizeof(DHCP6Option))
    +        if (*buflen < offsetof(DHCP6Option, data))
                     return -ENOMSG;
     
             len = be16toh(option->len);
    @@ -251,7 +254,7 @@ int dhcp6_option_parse_status(DHCP6Option *option, size_t len) {
             DHCP6StatusOption *statusopt = (DHCP6StatusOption *)option;
     
             if (len < sizeof(DHCP6StatusOption) ||
    -            be16toh(option->len) + sizeof(DHCP6Option) < sizeof(DHCP6StatusOption))
    +            be16toh(option->len) + offsetof(DHCP6Option, data) < sizeof(DHCP6StatusOption))
                     return -ENOBUFS;
     
             return be16toh(statusopt->status);
    @@ -264,7 +267,7 @@ static int dhcp6_option_parse_address(DHCP6Option *option, DHCP6IA *ia,
             uint32_t lt_valid, lt_pref;
             int r;
     
    -        if (be16toh(option->len) + sizeof(DHCP6Option) < sizeof(*addr_option))
    +        if (be16toh(option->len) + offsetof(DHCP6Option, data) < sizeof(*addr_option))
                     return -ENOBUFS;
     
             lt_valid = be32toh(addr_option->iaaddr.lifetime_valid);
    @@ -277,8 +280,8 @@ static int dhcp6_option_parse_address(DHCP6Option *option, DHCP6IA *ia,
                     return 0;
             }
     
    -        if (be16toh(option->len) + sizeof(DHCP6Option) > sizeof(*addr_option)) {
    -                r = dhcp6_option_parse_status((DHCP6Option *)addr_option->options, be16toh(option->len) + sizeof(DHCP6Option) - sizeof(*addr_option));
    +        if (be16toh(option->len) + offsetof(DHCP6Option, data) > sizeof(*addr_option)) {
    +                r = dhcp6_option_parse_status((DHCP6Option *)addr_option->options, be16toh(option->len) + offsetof(DHCP6Option, data) - sizeof(*addr_option));
                     if (r != 0)
                             return r < 0 ? r: 0;
             }
    @@ -304,7 +307,7 @@ static int dhcp6_option_parse_pdprefix(DHCP6Option *option, DHCP6IA *ia,
             uint32_t lt_valid, lt_pref;
             int r;
     
    -        if (be16toh(option->len) + sizeof(DHCP6Option) < sizeof(*pdprefix_option))
    +        if (be16toh(option->len) + offsetof(DHCP6Option, data) < sizeof(*pdprefix_option))
                     return -ENOBUFS;
     
             lt_valid = be32toh(pdprefix_option->iapdprefix.lifetime_valid);
    @@ -317,8 +320,8 @@ static int dhcp6_option_parse_pdprefix(DHCP6Option *option, DHCP6IA *ia,
                     return 0;
             }
     
    -        if (be16toh(option->len) + sizeof(DHCP6Option) > sizeof(*pdprefix_option)) {
    -                r = dhcp6_option_parse_status((DHCP6Option *)pdprefix_option->options, be16toh(option->len) + sizeof(DHCP6Option) - sizeof(*pdprefix_option));
    +        if (be16toh(option->len) + offsetof(DHCP6Option, data) > sizeof(*pdprefix_option)) {
    +                r = dhcp6_option_parse_status((DHCP6Option *)pdprefix_option->options, be16toh(option->len) + offsetof(DHCP6Option, data) - sizeof(*pdprefix_option));
                     if (r != 0)
                             return r < 0 ? r: 0;
             }
    @@ -450,7 +453,7 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia) {
     
                     case SD_DHCP6_OPTION_STATUS_CODE:
     
    -                        status = dhcp6_option_parse_status(option, optlen + sizeof(DHCP6Option));
    +                        status = dhcp6_option_parse_status(option, optlen + offsetof(DHCP6Option, data));
                             if (status < 0)
                                     return status;
                             if (status > 0) {
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

9

News mentions

0

No linked articles in our index yet.