summaryrefslogtreecommitdiff
path: root/src/libsystemd-network/dhcp6-option.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsystemd-network/dhcp6-option.c')
-rw-r--r--src/libsystemd-network/dhcp6-option.c82
1 files changed, 44 insertions, 38 deletions
diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c
index d258c9aafa..0b8393ca2c 100644
--- a/src/libsystemd-network/dhcp6-option.c
+++ b/src/libsystemd-network/dhcp6-option.c
@@ -211,26 +211,30 @@ bool dhcp6_option_can_request(uint16_t option) {
}
}
-static int option_append_hdr(uint8_t **buf, size_t *buflen, uint16_t optcode, size_t optlen) {
+static int option_append_hdr(uint8_t **buf, size_t *offset, uint16_t optcode, size_t optlen) {
assert(buf);
assert(*buf);
- assert(buflen);
+ assert(offset);
+
+ if (optlen > 0xffff)
+ return -ENOBUFS;
- if (optlen > 0xffff || *buflen < optlen + offsetof(DHCP6Option, data))
+ if (optlen + offsetof(DHCP6Option, data) > SIZE_MAX - *offset)
return -ENOBUFS;
- unaligned_write_be16(*buf + offsetof(DHCP6Option, code), optcode);
- unaligned_write_be16(*buf + offsetof(DHCP6Option, len), optlen);
+ if (!GREEDY_REALLOC(*buf, *offset + optlen + offsetof(DHCP6Option, data)))
+ return -ENOMEM;
- *buf += offsetof(DHCP6Option, data);
- *buflen -= offsetof(DHCP6Option, data);
+ unaligned_write_be16(*buf + *offset + offsetof(DHCP6Option, code), optcode);
+ unaligned_write_be16(*buf + *offset + offsetof(DHCP6Option, len), optlen);
+ *offset += offsetof(DHCP6Option, data);
return 0;
}
int dhcp6_option_append(
uint8_t **buf,
- size_t *buflen,
+ size_t *offset,
uint16_t code,
size_t optlen,
const void *optval) {
@@ -239,23 +243,23 @@ int dhcp6_option_append(
assert(optval || optlen == 0);
- r = option_append_hdr(buf, buflen, code, optlen);
+ r = option_append_hdr(buf, offset, code, optlen);
if (r < 0)
return r;
- *buf = mempcpy_safe(*buf, optval, optlen);
- *buflen -= optlen;
+ memcpy_safe(*buf + *offset, optval, optlen);
+ *offset += optlen;
return 0;
}
-int dhcp6_option_append_vendor_option(uint8_t **buf, size_t *buflen, OrderedSet *vendor_options) {
+int dhcp6_option_append_vendor_option(uint8_t **buf, size_t *offset, OrderedSet *vendor_options) {
sd_dhcp6_option *options;
int r;
assert(buf);
assert(*buf);
- assert(buflen);
+ assert(offset);
ORDERED_SET_FOREACH(options, vendor_options) {
_cleanup_free_ uint8_t *p = NULL;
@@ -272,7 +276,7 @@ int dhcp6_option_append_vendor_option(uint8_t **buf, size_t *buflen, OrderedSet
unaligned_write_be16(p + 6, options->length);
memcpy(p + 8, options->data, options->length);
- r = dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_VENDOR_OPTS, total, p);
+ r = dhcp6_option_append(buf, offset, SD_DHCP6_OPTION_VENDOR_OPTS, total, p);
if (r < 0)
return r;
}
@@ -280,12 +284,12 @@ int dhcp6_option_append_vendor_option(uint8_t **buf, size_t *buflen, OrderedSet
return 0;
}
-static int option_append_ia_address(uint8_t **buf, size_t *buflen, const struct iaaddr *address) {
+static int option_append_ia_address(uint8_t **buf, size_t *offset, const struct iaaddr *address) {
struct iaaddr a;
assert(buf);
assert(*buf);
- assert(buflen);
+ assert(offset);
assert(address);
/* Do not append T1 and T2. */
@@ -293,15 +297,15 @@ static int option_append_ia_address(uint8_t **buf, size_t *buflen, const struct
.address = address->address,
};
- return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_IAADDR, sizeof(struct iaaddr), &a);
+ return dhcp6_option_append(buf, offset, SD_DHCP6_OPTION_IAADDR, sizeof(struct iaaddr), &a);
}
-static int option_append_pd_prefix(uint8_t **buf, size_t *buflen, const struct iapdprefix *prefix) {
+static int option_append_pd_prefix(uint8_t **buf, size_t *offset, const struct iapdprefix *prefix) {
struct iapdprefix p;
assert(buf);
assert(*buf);
- assert(buflen);
+ assert(offset);
assert(prefix);
if (prefix->prefixlen == 0)
@@ -313,18 +317,18 @@ static int option_append_pd_prefix(uint8_t **buf, size_t *buflen, const struct i
.address = prefix->address,
};
- return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_IA_PD_PREFIX, sizeof(struct iapdprefix), &p);
+ return dhcp6_option_append(buf, offset, SD_DHCP6_OPTION_IA_PD_PREFIX, sizeof(struct iapdprefix), &p);
}
-int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia) {
+int dhcp6_option_append_ia(uint8_t **buf, size_t *offset, const DHCP6IA *ia) {
+ _cleanup_free_ uint8_t *data = NULL;
struct ia_header header;
- uint8_t data[512], *p;
- size_t len, size;
+ size_t len;
int r;
assert(buf);
assert(*buf);
- assert(buflen);
+ assert(offset);
assert(ia);
/* client should not send set T1 and T2. See, RFC 8415, and issue #18090. */
@@ -349,28 +353,30 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia) {
assert_not_reached();
}
- p = mempcpy(data, &header, len);
- size = sizeof(data) - len;
+ if (!GREEDY_REALLOC(data, len))
+ return -ENOMEM;
+
+ memcpy(data, &header, len);
LIST_FOREACH(addresses, addr, ia->addresses) {
if (ia->type == SD_DHCP6_OPTION_IA_PD)
- r = option_append_pd_prefix(&p, &size, &addr->iapdprefix);
+ r = option_append_pd_prefix(&data, &len, &addr->iapdprefix);
else
- r = option_append_ia_address(&p, &size, &addr->iaaddr);
+ r = option_append_ia_address(&data, &len, &addr->iaaddr);
if (r < 0)
return r;
}
- return dhcp6_option_append(buf, buflen, ia->type, p - data, data);
+ return dhcp6_option_append(buf, offset, ia->type, len, data);
}
-int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) {
+int dhcp6_option_append_fqdn(uint8_t **buf, size_t *offset, const char *fqdn) {
uint8_t buffer[1 + DNS_WIRE_FORMAT_HOSTNAME_MAX];
int r;
assert(buf);
assert(*buf);
- assert(buflen);
+ assert(offset);
if (isempty(fqdn))
return 0;
@@ -391,16 +397,16 @@ int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) {
if (dns_name_is_single_label(fqdn))
r--;
- return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_CLIENT_FQDN, 1 + r, buffer);
+ return dhcp6_option_append(buf, offset, SD_DHCP6_OPTION_CLIENT_FQDN, 1 + r, buffer);
}
-int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char * const *user_class) {
+int dhcp6_option_append_user_class(uint8_t **buf, size_t *offset, char * const *user_class) {
_cleanup_free_ uint8_t *p = NULL;
size_t n = 0;
assert(buf);
assert(*buf);
- assert(buflen);
+ assert(offset);
if (strv_isempty(user_class))
return 0;
@@ -419,16 +425,16 @@ int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char * const *
n += len + 2;
}
- return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_USER_CLASS, n, p);
+ return dhcp6_option_append(buf, offset, SD_DHCP6_OPTION_USER_CLASS, n, p);
}
-int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char * const *vendor_class) {
+int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *offset, char * const *vendor_class) {
_cleanup_free_ uint8_t *p = NULL;
size_t n = 0;
assert(buf);
assert(*buf);
- assert(buflen);
+ assert(offset);
if (strv_isempty(vendor_class))
return 0;
@@ -454,7 +460,7 @@ int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char * const
n += len + 2;
}
- return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_VENDOR_CLASS, n, p);
+ return dhcp6_option_append(buf, offset, SD_DHCP6_OPTION_VENDOR_CLASS, n, p);
}
int dhcp6_option_parse(