|
|
f86c11 |
From 158163f248631f5f2b51b7a1ff00c3eb2c096400 Mon Sep 17 00:00:00 2001
|
|
|
f86c11 |
From: Thomas Haller <thaller@redhat.com>
|
|
|
f86c11 |
Date: Thu, 20 Dec 2018 13:05:13 +0100
|
|
|
f86c11 |
Subject: [PATCH 1/3] dhcp: fix sd_dhcp_client_set_client_id() for infiniband
|
|
|
f86c11 |
addresses
|
|
|
f86c11 |
|
|
|
f86c11 |
Infiniband addresses are 20 bytes (INFINIBAND_ALEN), but only the last
|
|
|
f86c11 |
8 bytes are suitable for putting into the client-id.
|
|
|
f86c11 |
|
|
|
f86c11 |
This bug had no effect for networkd, because sd_dhcp_client_set_client_id()
|
|
|
f86c11 |
has only one caller which always uses ARPHRD_ETHER type.
|
|
|
f86c11 |
|
|
|
f86c11 |
I was unable to find good references for why this is correct ([1]). Fedora/RHEL
|
|
|
f86c11 |
has patches for ISC dhclient that also only use the last 8 bytes ([2], [3]).
|
|
|
f86c11 |
RFC 4390 (Dynamic Host Configuration Protocol (DHCP) over InfiniBand) [4] does
|
|
|
f86c11 |
not discuss the content of the client-id either.
|
|
|
f86c11 |
|
|
|
f86c11 |
[1] https://bugzilla.redhat.com/show_bug.cgi?id=1658057#c29
|
|
|
f86c11 |
[2] https://bugzilla.redhat.com/show_bug.cgi?id=660681
|
|
|
f86c11 |
[3] https://src.fedoraproject.org/rpms/dhcp/blob/3ccf3c8d815df4b8e11e1a04850975f099273d5d/f/dhcp-lpf-ib.patch
|
|
|
f86c11 |
[4] https://tools.ietf.org/html/rfc4390
|
|
|
f86c11 |
|
|
|
f86c11 |
https://github.com/systemd/systemd/commit/b9d80714583bf40e354ad0fc364ebfb35a0b3d76
|
|
|
f86c11 |
(cherry picked from commit 24a62f90c764c4c84fc95c654b76842dcf48118e)
|
|
|
f86c11 |
(cherry picked from commit 56f5edcbd31b91b9d0fd23f9b70d3de04ab70d1a)
|
|
|
f86c11 |
---
|
|
|
f86c11 |
src/systemd/src/libsystemd-network/sd-dhcp-client.c | 4 +++-
|
|
|
f86c11 |
1 file changed, 3 insertions(+), 1 deletion(-)
|
|
|
f86c11 |
|
|
|
f86c11 |
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
|
|
|
f86c11 |
index 915894537..ceb1709d1 100644
|
|
|
f86c11 |
--- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c
|
|
|
f86c11 |
+++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
|
|
|
f86c11 |
@@ -309,7 +309,9 @@ int sd_dhcp_client_set_client_id(
|
|
|
f86c11 |
break;
|
|
|
f86c11 |
|
|
|
f86c11 |
case ARPHRD_INFINIBAND:
|
|
|
f86c11 |
- if (data_len != INFINIBAND_ALEN)
|
|
|
f86c11 |
+ /* Infiniband addresses are 20 bytes (INFINIBAND_ALEN), however only
|
|
|
f86c11 |
+ * the last 8 bytes are stable and suitable for putting into the client-id. */
|
|
|
f86c11 |
+ if (data_len != 8)
|
|
|
f86c11 |
return -EINVAL;
|
|
|
f86c11 |
break;
|
|
|
f86c11 |
|
|
|
f86c11 |
--
|
|
|
f86c11 |
2.20.1
|
|
|
f86c11 |
|
|
|
f86c11 |
|
|
|
f86c11 |
From 68aa4fe865ea76bc4d03194d3eb9a5e6c09b08d9 Mon Sep 17 00:00:00 2001
|
|
|
f86c11 |
From: Thomas Haller <thaller@redhat.com>
|
|
|
f86c11 |
Date: Wed, 19 Dec 2018 10:05:37 +0100
|
|
|
f86c11 |
Subject: [PATCH 2/3] dhcp: don't enforce hardware address length for
|
|
|
f86c11 |
sd_dhcp_client_set_client_id()
|
|
|
f86c11 |
|
|
|
f86c11 |
sd_dhcp_client_set_client_id() is the only API for setting a raw client-id.
|
|
|
f86c11 |
All other setters are more restricted and only allow to set a type 255 DUID.
|
|
|
f86c11 |
|
|
|
f86c11 |
Also, dhcp4_set_client_identifier() is the only caller, which already
|
|
|
f86c11 |
does:
|
|
|
f86c11 |
|
|
|
f86c11 |
r = sd_dhcp_client_set_client_id(link->dhcp_client,
|
|
|
f86c11 |
ARPHRD_ETHER,
|
|
|
f86c11 |
(const uint8_t *) &link->mac,
|
|
|
f86c11 |
sizeof(link->mac));
|
|
|
f86c11 |
|
|
|
f86c11 |
and hence ensures that the data length is indeed ETH_ALEN.
|
|
|
f86c11 |
|
|
|
f86c11 |
Drop additional input validation from sd_dhcp_client_set_client_id(). The client-id
|
|
|
f86c11 |
is an opaque blob, and if a caller wishes to set type 1 (ethernet) or type 32
|
|
|
f86c11 |
(infiniband) with unexpected address length, it should be allowed. The actual
|
|
|
f86c11 |
client-id is not relevant to the DHCP client, and it's the responsibility of the
|
|
|
f86c11 |
caller to generate a suitable client-id.
|
|
|
f86c11 |
|
|
|
f86c11 |
For example, in NetworkManager you can configure all the bytes of the
|
|
|
f86c11 |
client-id, including such _invalid_ settings. I think it makes sense,
|
|
|
f86c11 |
to allow the user to fully configure the identifier. Even if such configuration
|
|
|
f86c11 |
would be rejected, it would be the responsibility of the higher layers (including
|
|
|
f86c11 |
a sensible error message to the user) and not fail later during
|
|
|
f86c11 |
sd_dhcp_client_set_client_id().
|
|
|
f86c11 |
|
|
|
f86c11 |
Still log a debug message if the length is unexpected.
|
|
|
f86c11 |
|
|
|
f86c11 |
https://github.com/systemd/systemd/commit/bfda0d0f09666e2476c9abd0280c4b9fa82b968c
|
|
|
f86c11 |
(cherry picked from commit 0d5fec574117a59c6aa9767a1948a5e3d1a70531)
|
|
|
f86c11 |
(cherry picked from commit a46745a36a825d0b14dc13d276ed192df44e0ca0)
|
|
|
f86c11 |
---
|
|
|
f86c11 |
.../src/libsystemd-network/sd-dhcp-client.c | 29 +++++++------------
|
|
|
f86c11 |
1 file changed, 11 insertions(+), 18 deletions(-)
|
|
|
f86c11 |
|
|
|
f86c11 |
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
|
|
|
f86c11 |
index ceb1709d1..94ee88e36 100644
|
|
|
f86c11 |
--- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c
|
|
|
f86c11 |
+++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
|
|
|
f86c11 |
@@ -301,29 +301,22 @@ int sd_dhcp_client_set_client_id(
|
|
|
f86c11 |
assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL);
|
|
|
f86c11 |
G_STATIC_ASSERT_EXPR (_NM_SD_MAX_CLIENT_ID_LEN == MAX_CLIENT_ID_LEN);
|
|
|
f86c11 |
|
|
|
f86c11 |
- switch (type) {
|
|
|
f86c11 |
-
|
|
|
f86c11 |
- case ARPHRD_ETHER:
|
|
|
f86c11 |
- if (data_len != ETH_ALEN)
|
|
|
f86c11 |
- return -EINVAL;
|
|
|
f86c11 |
- break;
|
|
|
f86c11 |
-
|
|
|
f86c11 |
- case ARPHRD_INFINIBAND:
|
|
|
f86c11 |
- /* Infiniband addresses are 20 bytes (INFINIBAND_ALEN), however only
|
|
|
f86c11 |
- * the last 8 bytes are stable and suitable for putting into the client-id. */
|
|
|
f86c11 |
- if (data_len != 8)
|
|
|
f86c11 |
- return -EINVAL;
|
|
|
f86c11 |
- break;
|
|
|
f86c11 |
-
|
|
|
f86c11 |
- default:
|
|
|
f86c11 |
- break;
|
|
|
f86c11 |
- }
|
|
|
f86c11 |
-
|
|
|
f86c11 |
if (client->client_id_len == data_len + sizeof(client->client_id.type) &&
|
|
|
f86c11 |
client->client_id.type == type &&
|
|
|
f86c11 |
memcmp(&client->client_id.raw.data, data, data_len) == 0)
|
|
|
f86c11 |
return 0;
|
|
|
f86c11 |
|
|
|
f86c11 |
+ /* For hardware types, log debug message about unexpected data length.
|
|
|
f86c11 |
+ *
|
|
|
f86c11 |
+ * Note that infiniband's INFINIBAND_ALEN is 20 bytes long, but only
|
|
|
f86c11 |
+ * last last 8 bytes of the address are stable and suitable to put into
|
|
|
f86c11 |
+ * the client-id. The caller is advised to account for that. */
|
|
|
f86c11 |
+ if ((type == ARPHRD_ETHER && data_len != ETH_ALEN) ||
|
|
|
f86c11 |
+ (type == ARPHRD_INFINIBAND && data_len != 8))
|
|
|
f86c11 |
+ log_dhcp_client(client, "Changing client ID to hardware type %u with "
|
|
|
f86c11 |
+ "unexpected address length %zu",
|
|
|
f86c11 |
+ type, data_len);
|
|
|
f86c11 |
+
|
|
|
f86c11 |
if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
|
|
|
f86c11 |
log_dhcp_client(client, "Changing client ID on running DHCP "
|
|
|
f86c11 |
"client, restarting");
|
|
|
f86c11 |
--
|
|
|
f86c11 |
2.20.1
|
|
|
f86c11 |
|
|
|
f86c11 |
|
|
|
f86c11 |
From 7bf24a0786a721619a4ab2b734d74718fbbaa793 Mon Sep 17 00:00:00 2001
|
|
|
f86c11 |
From: Thomas Haller <thaller@redhat.com>
|
|
|
f86c11 |
Date: Thu, 20 Dec 2018 11:56:02 +0100
|
|
|
f86c11 |
Subject: [PATCH 3/3] dhcp6: don't enforce DUID content for
|
|
|
f86c11 |
sd_dhcp6_client_set_duid()
|
|
|
f86c11 |
|
|
|
f86c11 |
There are various functions to set the DUID of a DHCPv6 client.
|
|
|
f86c11 |
However, none of them allows to set arbitrary data. The closest is
|
|
|
f86c11 |
sd_dhcp6_client_set_duid(), which would still do validation of the
|
|
|
f86c11 |
DUID's content via dhcp_validate_duid_len().
|
|
|
f86c11 |
|
|
|
f86c11 |
Relax the validation and only log a debug message if the DUID
|
|
|
f86c11 |
does not validate.
|
|
|
f86c11 |
|
|
|
f86c11 |
Note that dhcp_validate_duid_len() already is not very strict. For example
|
|
|
f86c11 |
with DUID_TYPE_LLT it only ensures that the length is suitable to contain
|
|
|
f86c11 |
hwtype and time. It does not further check that the length of hwaddr is non-zero
|
|
|
f86c11 |
or suitable for hwtype. Also, non-well-known DUID types are accepted for
|
|
|
f86c11 |
extensibility. Why reject certain DUIDs but allowing clearly wrong formats
|
|
|
f86c11 |
otherwise?
|
|
|
f86c11 |
|
|
|
f86c11 |
The validation and failure should happen earlier, when accepting the
|
|
|
f86c11 |
unsuitable DUID. At that point, there is more context of what is wrong,
|
|
|
f86c11 |
and a better failure reason (or warning) can be reported to the user. Rejecting
|
|
|
f86c11 |
the DUID when setting up the DHCPv6 client seems not optimal, in particular
|
|
|
f86c11 |
because the DHCPv6 client does not care about actual content of the
|
|
|
f86c11 |
DUID and treats it as opaque blob.
|
|
|
f86c11 |
|
|
|
f86c11 |
Also, NetworkManager (which uses this code) allows to configure the entire
|
|
|
f86c11 |
binary DUID in binary. It intentionally does not validate the binary
|
|
|
f86c11 |
content any further. Hence, it needs to be able to set _invalid_ DUIDs,
|
|
|
f86c11 |
provided that some basic constraints are satisfied (like the maximum length).
|
|
|
f86c11 |
|
|
|
f86c11 |
sd_dhcp6_client_set_duid() has two callers: both set the DUID obtained
|
|
|
f86c11 |
from link_get_duid(), which comes from configuration.
|
|
|
f86c11 |
`man networkd.conf` says: "The configured DHCP DUID should conform to
|
|
|
f86c11 |
the specification in RFC 3315, RFC 6355.". It does not not state that
|
|
|
f86c11 |
it MUST conform.
|
|
|
f86c11 |
|
|
|
f86c11 |
Note that dhcp_validate_duid_len() has another caller: DHCPv4's
|
|
|
f86c11 |
dhcp_client_set_iaid_duid_internal(). In this case, continue with
|
|
|
f86c11 |
strict validation, as the callers are more controlled. Also, there is
|
|
|
f86c11 |
already sd_dhcp_client_set_client_id() which can be used to bypass
|
|
|
f86c11 |
this check and set arbitrary client identifiers.
|
|
|
f86c11 |
|
|
|
f86c11 |
https://github.com/systemd/systemd/commit/ab4a88bc29e31754ec50c4a865058ee36f6284a6
|
|
|
f86c11 |
(cherry picked from commit d65ee3bb18fd27072113065c189e76d8abe16b25)
|
|
|
f86c11 |
(cherry picked from commit 87baa2678a2bb67896da1382f0ddef2f54ef585d)
|
|
|
f86c11 |
---
|
|
|
f86c11 |
src/systemd/src/libsystemd-network/dhcp-identifier.c | 8 +++++++-
|
|
|
f86c11 |
src/systemd/src/libsystemd-network/dhcp-identifier.h | 2 +-
|
|
|
f86c11 |
src/systemd/src/libsystemd-network/sd-dhcp-client.c | 2 +-
|
|
|
f86c11 |
src/systemd/src/libsystemd-network/sd-dhcp6-client.c | 10 +++++++---
|
|
|
f86c11 |
4 files changed, 16 insertions(+), 6 deletions(-)
|
|
|
f86c11 |
|
|
|
f86c11 |
diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.c b/src/systemd/src/libsystemd-network/dhcp-identifier.c
|
|
|
f86c11 |
index f18713e8d..b1afbf009 100644
|
|
|
f86c11 |
--- a/src/systemd/src/libsystemd-network/dhcp-identifier.c
|
|
|
f86c11 |
+++ b/src/systemd/src/libsystemd-network/dhcp-identifier.c
|
|
|
f86c11 |
@@ -25,13 +25,19 @@
|
|
|
f86c11 |
#define APPLICATION_ID SD_ID128_MAKE(a5,0a,d1,12,bf,60,45,77,a2,fb,74,1a,b1,95,5b,03)
|
|
|
f86c11 |
#define USEC_2000 ((usec_t) 946684800000000) /* 2000-01-01 00:00:00 UTC */
|
|
|
f86c11 |
|
|
|
f86c11 |
-int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) {
|
|
|
f86c11 |
+int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len, bool strict) {
|
|
|
f86c11 |
struct duid d;
|
|
|
f86c11 |
|
|
|
f86c11 |
assert_cc(sizeof(d.raw) >= MAX_DUID_LEN);
|
|
|
f86c11 |
if (duid_len > MAX_DUID_LEN)
|
|
|
f86c11 |
return -EINVAL;
|
|
|
f86c11 |
|
|
|
f86c11 |
+ if (!strict) {
|
|
|
f86c11 |
+ /* Strict validation is not requested. We only ensure that the
|
|
|
f86c11 |
+ * DUID is not too long. */
|
|
|
f86c11 |
+ return 0;
|
|
|
f86c11 |
+ }
|
|
|
f86c11 |
+
|
|
|
f86c11 |
switch (duid_type) {
|
|
|
f86c11 |
case DUID_TYPE_LLT:
|
|
|
f86c11 |
if (duid_len <= sizeof(d.llt))
|
|
|
f86c11 |
diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.h b/src/systemd/src/libsystemd-network/dhcp-identifier.h
|
|
|
f86c11 |
index 64315d3a3..e6834039a 100644
|
|
|
f86c11 |
--- a/src/systemd/src/libsystemd-network/dhcp-identifier.h
|
|
|
f86c11 |
+++ b/src/systemd/src/libsystemd-network/dhcp-identifier.h
|
|
|
f86c11 |
@@ -52,7 +52,7 @@ struct duid {
|
|
|
f86c11 |
};
|
|
|
f86c11 |
} _packed_;
|
|
|
f86c11 |
|
|
|
f86c11 |
-int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len);
|
|
|
f86c11 |
+int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len, bool strict);
|
|
|
f86c11 |
int dhcp_identifier_set_duid_llt(struct duid *duid, usec_t t, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len);
|
|
|
f86c11 |
int dhcp_identifier_set_duid_ll(struct duid *duid, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len);
|
|
|
f86c11 |
int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len);
|
|
|
f86c11 |
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
|
|
|
f86c11 |
index 94ee88e36..0c385a84e 100644
|
|
|
f86c11 |
--- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c
|
|
|
f86c11 |
+++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
|
|
|
f86c11 |
@@ -357,7 +357,7 @@ static int dhcp_client_set_iaid_duid_internal(
|
|
|
f86c11 |
assert_return(duid_len == 0 || duid != NULL, -EINVAL);
|
|
|
f86c11 |
|
|
|
f86c11 |
if (duid != NULL) {
|
|
|
f86c11 |
- r = dhcp_validate_duid_len(duid_type, duid_len);
|
|
|
f86c11 |
+ r = dhcp_validate_duid_len(duid_type, duid_len, true);
|
|
|
f86c11 |
if (r < 0)
|
|
|
f86c11 |
return r;
|
|
|
f86c11 |
}
|
|
|
f86c11 |
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
|
|
|
f86c11 |
index 7dfb2acee..f0cd2f977 100644
|
|
|
f86c11 |
--- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
|
|
|
f86c11 |
+++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
|
|
|
f86c11 |
@@ -197,9 +197,13 @@ static int dhcp6_client_set_duid_internal(
|
|
|
f86c11 |
assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
|
|
|
f86c11 |
|
|
|
f86c11 |
if (duid != NULL) {
|
|
|
f86c11 |
- r = dhcp_validate_duid_len(duid_type, duid_len);
|
|
|
f86c11 |
- if (r < 0)
|
|
|
f86c11 |
- return r;
|
|
|
f86c11 |
+ r = dhcp_validate_duid_len(duid_type, duid_len, true);
|
|
|
f86c11 |
+ if (r < 0) {
|
|
|
f86c11 |
+ r = dhcp_validate_duid_len(duid_type, duid_len, false);
|
|
|
f86c11 |
+ if (r < 0)
|
|
|
f86c11 |
+ return r;
|
|
|
f86c11 |
+ log_dhcp6_client(client, "Setting DUID of type %u with unexpected content", duid_type);
|
|
|
f86c11 |
+ }
|
|
|
f86c11 |
|
|
|
f86c11 |
client->duid.type = htobe16(duid_type);
|
|
|
f86c11 |
memcpy(&client->duid.raw.data, duid, duid_len);
|
|
|
f86c11 |
--
|
|
|
f86c11 |
2.20.1
|
|
|
f86c11 |
|