Blame SOURCES/1021-device-fix-dhcp-client-id-for-infiniband-1-rh1658057.patch

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