]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
ethtool: do not embed struct with flexible array into another struct
authorYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 3 Apr 2025 16:17:36 +0000 (01:17 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 4 Apr 2025 11:54:53 +0000 (20:54 +0900)
To allow compile ethtool-util.c with -Werror=flex-array-member-not-at-end.

src/shared/ethtool-util.c
src/shared/ethtool-util.h

index b29d2641ef2af1f1390d06a9623489b78e5d47fb..70066b6104aaa010eff7bff9f602381572374621 100644 (file)
@@ -254,9 +254,9 @@ int ethtool_get_link_info(
 
 int ethtool_get_permanent_hw_addr(int *ethtool_fd, const char *ifname, struct hw_addr_data *ret) {
         _cleanup_close_ int fd = -EBADF;
-        struct {
+        union {
                 struct ethtool_perm_addr addr;
-                uint8_t space[HW_ADDR_MAX_SIZE];
+                uint8_t buf[offsetof(struct ethtool_perm_addr, data) + HW_ADDR_MAX_SIZE];
         } epaddr = {
                 .addr.cmd = ETHTOOL_GPERMADDR,
                 .addr.size = HW_ADDR_MAX_SIZE,
@@ -429,15 +429,9 @@ int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, const netde
 
 static int get_stringset(int ethtool_fd, const char *ifname, enum ethtool_stringset stringset_id, struct ethtool_gstrings **ret) {
         _cleanup_free_ struct ethtool_gstrings *strings = NULL;
-        struct {
-                struct ethtool_sset_info info;
-                uint32_t space;
-        } buffer = {
-                .info.cmd = ETHTOOL_GSSET_INFO,
-                .info.sset_mask = UINT64_C(1) << stringset_id,
-        };
+        uint8_t buffer[offsetof(struct ethtool_sset_info, data) + sizeof(uint32_t)] = {};
         struct ifreq ifr = {
-                .ifr_data = (void*) &buffer,
+                .ifr_data = (void*) buffer,
         };
         uint32_t len;
 
@@ -445,17 +439,18 @@ static int get_stringset(int ethtool_fd, const char *ifname, enum ethtool_string
         assert(ifname);
         assert(ret);
 
+        struct ethtool_sset_info *info = (struct ethtool_sset_info*) buffer;
+        info->cmd = ETHTOOL_GSSET_INFO;
+        info->sset_mask = UINT64_C(1) << stringset_id;
         strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname);
 
         if (ioctl(ethtool_fd, SIOCETHTOOL, &ifr) < 0)
                 return -errno;
 
-        if (buffer.info.sset_mask == 0)
+        if (info->sset_mask == 0)
                 return -EOPNOTSUPP;
 
-        DISABLE_WARNING_ZERO_LENGTH_BOUNDS;
-        len = buffer.info.data[0];
-        REENABLE_WARNING;
+        len = *info->data;
         if (len == 0)
                 return -EOPNOTSUPP;
 
@@ -652,15 +647,10 @@ int ethtool_set_features(int *ethtool_fd, const char *ifname, const int features
         return 0;
 }
 
-static int get_glinksettings(int fd, struct ifreq *ifr, struct ethtool_link_usettings **ret) {
-        struct ecmd {
-                struct ethtool_link_settings req;
-                uint32_t link_mode_data[3 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32];
-        } ecmd = {
-                .req.cmd = ETHTOOL_GLINKSETTINGS,
+static int get_glinksettings(int fd, struct ifreq *ifr, union ethtool_link_usettings **ret) {
+        union ethtool_link_usettings ecmd = {
+                .base.cmd = ETHTOOL_GLINKSETTINGS,
         };
-        struct ethtool_link_usettings *u;
-        unsigned offset;
 
         assert(fd >= 0);
         assert(ifr);
@@ -674,48 +664,33 @@ static int get_glinksettings(int fd, struct ifreq *ifr, struct ethtool_link_uset
            https://github.com/torvalds/linux/commit/3f1ac7a700d039c61d8d8b99f28d605d489a60cf
         */
 
-        ifr->ifr_data = (void *) &ecmd;
+        ifr->ifr_data = (void*) &ecmd;
 
         if (ioctl(fd, SIOCETHTOOL, ifr) < 0)
                 return -errno;
 
-        if (ecmd.req.link_mode_masks_nwords >= 0 || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS)
+        if (ecmd.base.link_mode_masks_nwords >= 0 || ecmd.base.cmd != ETHTOOL_GLINKSETTINGS)
                 return -EOPNOTSUPP;
 
-        ecmd.req.link_mode_masks_nwords = -ecmd.req.link_mode_masks_nwords;
+        ecmd.base.link_mode_masks_nwords = -ecmd.base.link_mode_masks_nwords;
 
         ifr->ifr_data = (void *) &ecmd;
 
         if (ioctl(fd, SIOCETHTOOL, ifr) < 0)
                 return -errno;
 
-        if (ecmd.req.link_mode_masks_nwords <= 0 || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS)
+        if (ecmd.base.link_mode_masks_nwords <= 0 || ecmd.base.cmd != ETHTOOL_GLINKSETTINGS)
                 return -EOPNOTSUPP;
 
-        u = new(struct ethtool_link_usettings, 1);
+        union ethtool_link_usettings *u = newdup(union ethtool_link_usettings, &ecmd, 1);
         if (!u)
                 return -ENOMEM;
 
-        *u = (struct ethtool_link_usettings) {
-                .base = ecmd.req,
-        };
-
-        offset = 0;
-        memcpy(u->link_modes.supported, &ecmd.link_mode_data[offset], 4 * ecmd.req.link_mode_masks_nwords);
-
-        offset += ecmd.req.link_mode_masks_nwords;
-        memcpy(u->link_modes.advertising, &ecmd.link_mode_data[offset], 4 * ecmd.req.link_mode_masks_nwords);
-
-        offset += ecmd.req.link_mode_masks_nwords;
-        memcpy(u->link_modes.lp_advertising, &ecmd.link_mode_data[offset], 4 * ecmd.req.link_mode_masks_nwords);
-
         *ret = u;
-
         return 0;
 }
 
-static int get_gset(int fd, struct ifreq *ifr, struct ethtool_link_usettings **ret) {
-        struct ethtool_link_usettings *e;
+static int get_gset(int fd, struct ifreq *ifr, union ethtool_link_usettings **ret) {
         struct ethtool_cmd ecmd = {
                 .cmd = ETHTOOL_GSET,
         };
@@ -729,11 +704,11 @@ static int get_gset(int fd, struct ifreq *ifr, struct ethtool_link_usettings **r
         if (ioctl(fd, SIOCETHTOOL, ifr) < 0)
                 return -errno;
 
-        e = new(struct ethtool_link_usettings, 1);
-        if (!e)
+        union ethtool_link_usettings *u = new(union ethtool_link_usettings, 1);
+        if (!u)
                 return -ENOMEM;
 
-        *e = (struct ethtool_link_usettings) {
+        *u = (union ethtool_link_usettings) {
                 .base.cmd = ETHTOOL_GSET,
                 .base.link_mode_masks_nwords = 1,
                 .base.speed = ethtool_cmd_speed(&ecmd),
@@ -744,24 +719,17 @@ static int get_gset(int fd, struct ifreq *ifr, struct ethtool_link_usettings **r
                 .base.mdio_support = ecmd.mdio_support,
                 .base.eth_tp_mdix = ecmd.eth_tp_mdix,
                 .base.eth_tp_mdix_ctrl = ecmd.eth_tp_mdix_ctrl,
-
-                .link_modes.supported[0] = ecmd.supported,
-                .link_modes.advertising[0] = ecmd.advertising,
-                .link_modes.lp_advertising[0] = ecmd.lp_advertising,
         };
 
-        *ret = e;
+        u->link_modes.supported[0] = ecmd.supported;
+        u->link_modes.advertising[0] = ecmd.advertising;
+        u->link_modes.lp_advertising[0] = ecmd.lp_advertising;
 
+        *ret = u;
         return 0;
 }
 
-static int set_slinksettings(int fd, struct ifreq *ifr, const struct ethtool_link_usettings *u) {
-        struct {
-                struct ethtool_link_settings req;
-                uint32_t link_mode_data[3 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32];
-        } ecmd = {};
-        unsigned offset;
-
+static int set_slinksettings(int fd, struct ifreq *ifr, const union ethtool_link_usettings *u) {
         assert(fd >= 0);
         assert(ifr);
         assert(u);
@@ -769,23 +737,14 @@ static int set_slinksettings(int fd, struct ifreq *ifr, const struct ethtool_lin
         if (u->base.cmd != ETHTOOL_GLINKSETTINGS || u->base.link_mode_masks_nwords <= 0)
                 return -EINVAL;
 
-        ecmd.req = u->base;
-        ecmd.req.cmd = ETHTOOL_SLINKSETTINGS;
-        offset = 0;
-        memcpy(&ecmd.link_mode_data[offset], u->link_modes.supported, 4 * ecmd.req.link_mode_masks_nwords);
-
-        offset += ecmd.req.link_mode_masks_nwords;
-        memcpy(&ecmd.link_mode_data[offset], u->link_modes.advertising, 4 * ecmd.req.link_mode_masks_nwords);
-
-        offset += ecmd.req.link_mode_masks_nwords;
-        memcpy(&ecmd.link_mode_data[offset], u->link_modes.lp_advertising, 4 * ecmd.req.link_mode_masks_nwords);
-
+        union ethtool_link_usettings ecmd = *u;
+        ecmd.base.cmd = ETHTOOL_SLINKSETTINGS;
         ifr->ifr_data = (void *) &ecmd;
 
         return RET_NERRNO(ioctl(fd, SIOCETHTOOL, ifr));
 }
 
-static int set_sset(int fd, struct ifreq *ifr, const struct ethtool_link_usettings *u) {
+static int set_sset(int fd, struct ifreq *ifr, const union ethtool_link_usettings *u) {
         struct ethtool_cmd ecmd = {
                 .cmd = ETHTOOL_SSET,
         };
@@ -826,7 +785,7 @@ int ethtool_set_glinksettings(
                 NetDevPort port,
                 uint8_t mdi) {
 
-        _cleanup_free_ struct ethtool_link_usettings *u = NULL;
+        _cleanup_free_ union ethtool_link_usettings *u = NULL;
         struct ifreq ifr = {};
         bool changed = false;
         int r;
index 9aa36da227a838a65c533443f8b5f325798f3d3f..8f67e6e2b6094d9d0e5dc1c4d28e1dc10a034106 100644 (file)
@@ -107,10 +107,11 @@ typedef enum NetDevPort {
 #define ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBYTES  (4 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32)
 
 /* layout of the struct passed from/to userland */
-struct ethtool_link_usettings {
+union ethtool_link_usettings {
         struct ethtool_link_settings base;
 
         struct {
+                uint8_t header[offsetof(struct ethtool_link_settings, link_mode_masks)];
                 uint32_t supported[ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32];
                 uint32_t advertising[ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32];
                 uint32_t lp_advertising[ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32];