Users reported stack clash detected when using --get-phy-tunable on
ppc64le. Problem is caused by local variable ds of type struct
ethtool_tunable which has last member "void *data[0]". Accessing data[0]
(as do_get_phy_tunable() does) or adding requested value at the end (which
is what kernel ioctl does) writes past allocated space for the variable.

Make ds part of an anonymous structure to make sure there is enough space
for tunable value and drop the (pointless) access to ds.data[0]. The same
problem also exists in do_set_phy_tunable().

Fixes: b0fe96dec90f ("Ethtool: Implements 
ETHTOOL_PHY_GTUNABLE/ETHTOOL_PHY_STUNABLE and PHY downshift")
Signed-off-by: Michal Kubecek <mkube...@suse.cz>
---
 ethtool.c | 39 +++++++++++++++++++++------------------
 1 file changed, 21 insertions(+), 18 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index 3289e0f6e8ec..2e873848eb4e 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -4740,20 +4740,22 @@ static int do_get_phy_tunable(struct cmd_context *ctx)
        }
 
        if (downshift_changed) {
-               struct ethtool_tunable ds;
+               struct {
+                       struct ethtool_tunable ds;
+                       u8 __count;
+               } cont;
                u8 count = 0;
 
-               ds.cmd = ETHTOOL_PHY_GTUNABLE;
-               ds.id = ETHTOOL_PHY_DOWNSHIFT;
-               ds.type_id = ETHTOOL_TUNABLE_U8;
-               ds.len = 1;
-               ds.data[0] = &count;
-               err = send_ioctl(ctx, &ds);
+               cont.ds.cmd = ETHTOOL_PHY_GTUNABLE;
+               cont.ds.id = ETHTOOL_PHY_DOWNSHIFT;
+               cont.ds.type_id = ETHTOOL_TUNABLE_U8;
+               cont.ds.len = 1;
+               err = send_ioctl(ctx, &cont.ds);
                if (err < 0) {
                        perror("Cannot Get PHY downshift count");
                        return 87;
                }
-               count = *((u8 *)&ds.data[0]);
+               count = *((u8 *)&cont.ds.data[0]);
                if (count)
                        fprintf(stdout, "Downshift count: %d\n", count);
                else
@@ -4931,16 +4933,17 @@ static int do_set_phy_tunable(struct cmd_context *ctx)
 
        /* Do it */
        if (ds_changed) {
-               struct ethtool_tunable ds;
-               u8 count;
-
-               ds.cmd = ETHTOOL_PHY_STUNABLE;
-               ds.id = ETHTOOL_PHY_DOWNSHIFT;
-               ds.type_id = ETHTOOL_TUNABLE_U8;
-               ds.len = 1;
-               ds.data[0] = &count;
-               *((u8 *)&ds.data[0]) = ds_cnt;
-               err = send_ioctl(ctx, &ds);
+               struct {
+                       struct ethtool_tunable ds;
+                       u8 __count;
+               } cont;
+
+               cont.ds.cmd = ETHTOOL_PHY_STUNABLE;
+               cont.ds.id = ETHTOOL_PHY_DOWNSHIFT;
+               cont.ds.type_id = ETHTOOL_TUNABLE_U8;
+               cont.ds.len = 1;
+               *((u8 *)&cont.ds.data[0]) = ds_cnt;
+               err = send_ioctl(ctx, &cont.ds);
                if (err < 0) {
                        perror("Cannot Set PHY downshift count");
                        err = 87;
-- 
2.16.3

Reply via email to