net/core/rtnetlink.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-)
Instead of a heap allocation use a stack allocated struct sockaddr, as
dev_set_mac_address_user() is the consumer (which uses a classic
struct sockaddr). Cap the copy to the minimum address size between
the incoming address and the traditional sa_data field itself.
Putting "sa" on the stack means it will get a reused stack slot since
it is smaller than other existing single-scope stack variables (like
the vfinfo array).
Signed-off-by: Kees Cook <kees@kernel.org>
---
Cc: Eric Dumazet <edumazet@google.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: Paolo Abeni <pabeni@redhat.com>
Cc: Ido Schimmel <idosch@nvidia.com>
Cc: Petr Machata <petrm@nvidia.com>
Cc: netdev@vger.kernel.org
---
net/core/rtnetlink.c | 22 +++++++---------------
1 file changed, 7 insertions(+), 15 deletions(-)
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index ab5f201bf0ab..6da0edc0870d 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -3048,21 +3048,13 @@ static int do_setlink(const struct sk_buff *skb, struct net_device *dev,
}
if (tb[IFLA_ADDRESS]) {
- struct sockaddr *sa;
- int len;
-
- len = sizeof(sa_family_t) + max_t(size_t, dev->addr_len,
- sizeof(*sa));
- sa = kmalloc(len, GFP_KERNEL);
- if (!sa) {
- err = -ENOMEM;
- goto errout;
- }
- sa->sa_family = dev->type;
- memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]),
- dev->addr_len);
- err = dev_set_mac_address_user(dev, sa, extack);
- kfree(sa);
+ struct sockaddr sa = { };
+
+ /* dev_set_mac_address_user() uses a true struct sockaddr. */
+ sa.sa_family = dev->type;
+ memcpy(sa.sa_data, nla_data(tb[IFLA_ADDRESS]),
+ min(dev->addr_len, sizeof(sa.sa_data_min)));
+ err = dev_set_mac_address_user(dev, &sa, extack);
if (err)
goto errout;
status |= DO_SETLINK_MODIFIED;
--
2.34.1
Le mar. 17 déc. 2024 à 03:05, Kees Cook <kees@kernel.org> a écrit :
>
> Instead of a heap allocation use a stack allocated struct sockaddr, as
> dev_set_mac_address_user() is the consumer (which uses a classic
> struct sockaddr). Cap the copy to the minimum address size between
> the incoming address and the traditional sa_data field itself.
Not sure what is a 'classic sockaddr'
>
> Putting "sa" on the stack means it will get a reused stack slot since
> it is smaller than other existing single-scope stack variables (like
> the vfinfo array).
>
> Signed-off-by: Kees Cook <kees@kernel.org>
> ---
> Cc: Eric Dumazet <edumazet@google.com>
> Cc: "David S. Miller" <davem@davemloft.net>
> Cc: Jakub Kicinski <kuba@kernel.org>
> Cc: Paolo Abeni <pabeni@redhat.com>
> Cc: Ido Schimmel <idosch@nvidia.com>
> Cc: Petr Machata <petrm@nvidia.com>
> Cc: netdev@vger.kernel.org
> ---
> net/core/rtnetlink.c | 22 +++++++---------------
> 1 file changed, 7 insertions(+), 15 deletions(-)
>
> diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
> index ab5f201bf0ab..6da0edc0870d 100644
> --- a/net/core/rtnetlink.c
> +++ b/net/core/rtnetlink.c
> @@ -3048,21 +3048,13 @@ static int do_setlink(const struct sk_buff *skb, struct net_device *dev,
> }
>
> if (tb[IFLA_ADDRESS]) {
> - struct sockaddr *sa;
> - int len;
> -
> - len = sizeof(sa_family_t) + max_t(size_t, dev->addr_len,
> - sizeof(*sa));
> - sa = kmalloc(len, GFP_KERNEL);
> - if (!sa) {
> - err = -ENOMEM;
> - goto errout;
> - }
> - sa->sa_family = dev->type;
> - memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]),
> - dev->addr_len);
> - err = dev_set_mac_address_user(dev, sa, extack);
> - kfree(sa);
> + struct sockaddr sa = { };
> +
> + /* dev_set_mac_address_user() uses a true struct sockaddr. */
> + sa.sa_family = dev->type;
> + memcpy(sa.sa_data, nla_data(tb[IFLA_ADDRESS]),
> + min(dev->addr_len, sizeof(sa.sa_data_min)));
> + err = dev_set_mac_address_user(dev, &sa, extack);
Have you added debug checks in dev_set_mac_address_user() to make sure
dev->addr_len is always smaller than 14 ?
I think we support devices with bigger addresses.
From: Kees Cook <kees@kernel.org>
Date: Mon, 16 Dec 2024 18:04:45 -0800
> Instead of a heap allocation use a stack allocated struct sockaddr, as
> dev_set_mac_address_user() is the consumer (which uses a classic
> struct sockaddr).
I remember Eric's feedback was to keep using heap instead of stack
because rtnl_newlink() path already uses too much on stack.
> Cap the copy to the minimum address size between
> the incoming address and the traditional sa_data field itself.
>
> Putting "sa" on the stack means it will get a reused stack slot since
> it is smaller than other existing single-scope stack variables (like
> the vfinfo array).
>
> Signed-off-by: Kees Cook <kees@kernel.org>
> ---
> Cc: Eric Dumazet <edumazet@google.com>
> Cc: "David S. Miller" <davem@davemloft.net>
> Cc: Jakub Kicinski <kuba@kernel.org>
> Cc: Paolo Abeni <pabeni@redhat.com>
> Cc: Ido Schimmel <idosch@nvidia.com>
> Cc: Petr Machata <petrm@nvidia.com>
> Cc: netdev@vger.kernel.org
> ---
> net/core/rtnetlink.c | 22 +++++++---------------
> 1 file changed, 7 insertions(+), 15 deletions(-)
>
> diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
> index ab5f201bf0ab..6da0edc0870d 100644
> --- a/net/core/rtnetlink.c
> +++ b/net/core/rtnetlink.c
> @@ -3048,21 +3048,13 @@ static int do_setlink(const struct sk_buff *skb, struct net_device *dev,
> }
>
> if (tb[IFLA_ADDRESS]) {
> - struct sockaddr *sa;
> - int len;
> -
> - len = sizeof(sa_family_t) + max_t(size_t, dev->addr_len,
> - sizeof(*sa));
> - sa = kmalloc(len, GFP_KERNEL);
> - if (!sa) {
> - err = -ENOMEM;
> - goto errout;
> - }
> - sa->sa_family = dev->type;
> - memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]),
> - dev->addr_len);
> - err = dev_set_mac_address_user(dev, sa, extack);
> - kfree(sa);
> + struct sockaddr sa = { };
> +
> + /* dev_set_mac_address_user() uses a true struct sockaddr. */
> + sa.sa_family = dev->type;
> + memcpy(sa.sa_data, nla_data(tb[IFLA_ADDRESS]),
> + min(dev->addr_len, sizeof(sa.sa_data_min)));
> + err = dev_set_mac_address_user(dev, &sa, extack);
> if (err)
> goto errout;
> status |= DO_SETLINK_MODIFIED;
> --
> 2.34.1
On December 16, 2024 6:41:56 PM PST, Kuniyuki Iwashima <kuniyu@amazon.com> wrote:
>From: Kees Cook <kees@kernel.org>
>Date: Mon, 16 Dec 2024 18:04:45 -0800
>> Instead of a heap allocation use a stack allocated struct sockaddr, as
>> dev_set_mac_address_user() is the consumer (which uses a classic
>> struct sockaddr).
>
>I remember Eric's feedback was to keep using heap instead of stack
>because rtnl_newlink() path already uses too much on stack.
See below...
>
>
>> Cap the copy to the minimum address size between
>> the incoming address and the traditional sa_data field itself.
>>
>> Putting "sa" on the stack means it will get a reused stack slot since
>> it is smaller than other existing single-scope stack variables (like
>> the vfinfo array).
That's why I included the rationale above. (I.e. stack usage does not grow with this patch.)
-Kees
>>
>> Signed-off-by: Kees Cook <kees@kernel.org>
>> ---
>> Cc: Eric Dumazet <edumazet@google.com>
>> Cc: "David S. Miller" <davem@davemloft.net>
>> Cc: Jakub Kicinski <kuba@kernel.org>
>> Cc: Paolo Abeni <pabeni@redhat.com>
>> Cc: Ido Schimmel <idosch@nvidia.com>
>> Cc: Petr Machata <petrm@nvidia.com>
>> Cc: netdev@vger.kernel.org
>> ---
>> net/core/rtnetlink.c | 22 +++++++---------------
>> 1 file changed, 7 insertions(+), 15 deletions(-)
>>
>> diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
>> index ab5f201bf0ab..6da0edc0870d 100644
>> --- a/net/core/rtnetlink.c
>> +++ b/net/core/rtnetlink.c
>> @@ -3048,21 +3048,13 @@ static int do_setlink(const struct sk_buff *skb, struct net_device *dev,
>> }
>>
>> if (tb[IFLA_ADDRESS]) {
>> - struct sockaddr *sa;
>> - int len;
>> -
>> - len = sizeof(sa_family_t) + max_t(size_t, dev->addr_len,
>> - sizeof(*sa));
>> - sa = kmalloc(len, GFP_KERNEL);
>> - if (!sa) {
>> - err = -ENOMEM;
>> - goto errout;
>> - }
>> - sa->sa_family = dev->type;
>> - memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]),
>> - dev->addr_len);
>> - err = dev_set_mac_address_user(dev, sa, extack);
>> - kfree(sa);
>> + struct sockaddr sa = { };
>> +
>> + /* dev_set_mac_address_user() uses a true struct sockaddr. */
>> + sa.sa_family = dev->type;
>> + memcpy(sa.sa_data, nla_data(tb[IFLA_ADDRESS]),
>> + min(dev->addr_len, sizeof(sa.sa_data_min)));
>> + err = dev_set_mac_address_user(dev, &sa, extack);
>> if (err)
>> goto errout;
>> status |= DO_SETLINK_MODIFIED;
>> --
>> 2.34.1
>
--
Kees Cook
From: Kees Cook <kees@kernel.org>
Date: Mon, 16 Dec 2024 23:53:46 -0800
> On December 16, 2024 6:41:56 PM PST, Kuniyuki Iwashima <kuniyu@amazon.com> wrote:
> >From: Kees Cook <kees@kernel.org>
> >Date: Mon, 16 Dec 2024 18:04:45 -0800
> >> Instead of a heap allocation use a stack allocated struct sockaddr, as
> >> dev_set_mac_address_user() is the consumer (which uses a classic
> >> struct sockaddr).
> >
> >I remember Eric's feedback was to keep using heap instead of stack
> >because rtnl_newlink() path already uses too much on stack.
>
> See below...
>
> >
> >
> >> Cap the copy to the minimum address size between
> >> the incoming address and the traditional sa_data field itself.
> >>
> >> Putting "sa" on the stack means it will get a reused stack slot since
> >> it is smaller than other existing single-scope stack variables (like
> >> the vfinfo array).
>
> That's why I included the rationale above. (I.e. stack usage does not grow with this patch.)
Ah okay, but I think we can't cap the address size to 14
bytes. MAX_ADDR_LEN is 32.
Also, dev_set_mac_address_user() still uses dev->addr_len.
>
> -Kees
>
> >>
> >> Signed-off-by: Kees Cook <kees@kernel.org>
> >> ---
> >> Cc: Eric Dumazet <edumazet@google.com>
> >> Cc: "David S. Miller" <davem@davemloft.net>
> >> Cc: Jakub Kicinski <kuba@kernel.org>
> >> Cc: Paolo Abeni <pabeni@redhat.com>
> >> Cc: Ido Schimmel <idosch@nvidia.com>
> >> Cc: Petr Machata <petrm@nvidia.com>
> >> Cc: netdev@vger.kernel.org
> >> ---
> >> net/core/rtnetlink.c | 22 +++++++---------------
> >> 1 file changed, 7 insertions(+), 15 deletions(-)
> >>
> >> diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
> >> index ab5f201bf0ab..6da0edc0870d 100644
> >> --- a/net/core/rtnetlink.c
> >> +++ b/net/core/rtnetlink.c
> >> @@ -3048,21 +3048,13 @@ static int do_setlink(const struct sk_buff *skb, struct net_device *dev,
> >> }
> >>
> >> if (tb[IFLA_ADDRESS]) {
> >> - struct sockaddr *sa;
> >> - int len;
> >> -
> >> - len = sizeof(sa_family_t) + max_t(size_t, dev->addr_len,
> >> - sizeof(*sa));
> >> - sa = kmalloc(len, GFP_KERNEL);
> >> - if (!sa) {
> >> - err = -ENOMEM;
> >> - goto errout;
> >> - }
> >> - sa->sa_family = dev->type;
> >> - memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]),
> >> - dev->addr_len);
> >> - err = dev_set_mac_address_user(dev, sa, extack);
> >> - kfree(sa);
> >> + struct sockaddr sa = { };
> >> +
> >> + /* dev_set_mac_address_user() uses a true struct sockaddr. */
> >> + sa.sa_family = dev->type;
> >> + memcpy(sa.sa_data, nla_data(tb[IFLA_ADDRESS]),
> >> + min(dev->addr_len, sizeof(sa.sa_data_min)));
> >> + err = dev_set_mac_address_user(dev, &sa, extack);
> >> if (err)
> >> goto errout;
> >> status |= DO_SETLINK_MODIFIED;
> >> --
> >> 2.34.1
> >
>
> --
> Kees Cook
On December 17, 2024 12:03:35 AM PST, Kuniyuki Iwashima <kuniyu@amazon.com> wrote:
>From: Kees Cook <kees@kernel.org>
>Date: Mon, 16 Dec 2024 23:53:46 -0800
>> On December 16, 2024 6:41:56 PM PST, Kuniyuki Iwashima <kuniyu@amazon.com> wrote:
>> >From: Kees Cook <kees@kernel.org>
>> >Date: Mon, 16 Dec 2024 18:04:45 -0800
>> >> Instead of a heap allocation use a stack allocated struct sockaddr, as
>> >> dev_set_mac_address_user() is the consumer (which uses a classic
>> >> struct sockaddr).
>> >
>> >I remember Eric's feedback was to keep using heap instead of stack
>> >because rtnl_newlink() path already uses too much on stack.
>>
>> See below...
>>
>> >
>> >
>> >> Cap the copy to the minimum address size between
>> >> the incoming address and the traditional sa_data field itself.
>> >>
>> >> Putting "sa" on the stack means it will get a reused stack slot since
>> >> it is smaller than other existing single-scope stack variables (like
>> >> the vfinfo array).
>>
>> That's why I included the rationale above. (I.e. stack usage does not grow with this patch.)
>
>Ah okay, but I think we can't cap the address size to 14
>bytes. MAX_ADDR_LEN is 32.
>
>Also, dev_set_mac_address_user() still uses dev->addr_len.
Oh, hrm, yes, that's true. I had audited callers of dev_set_mac_address(), but I think I must have missed callers of dev_set_mac_address_user(). Ugh. :( Let me take another look at this...
-Kees
>
>
>>
>> -Kees
>>
>> >>
>> >> Signed-off-by: Kees Cook <kees@kernel.org>
>> >> ---
>> >> Cc: Eric Dumazet <edumazet@google.com>
>> >> Cc: "David S. Miller" <davem@davemloft.net>
>> >> Cc: Jakub Kicinski <kuba@kernel.org>
>> >> Cc: Paolo Abeni <pabeni@redhat.com>
>> >> Cc: Ido Schimmel <idosch@nvidia.com>
>> >> Cc: Petr Machata <petrm@nvidia.com>
>> >> Cc: netdev@vger.kernel.org
>> >> ---
>> >> net/core/rtnetlink.c | 22 +++++++---------------
>> >> 1 file changed, 7 insertions(+), 15 deletions(-)
>> >>
>> >> diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
>> >> index ab5f201bf0ab..6da0edc0870d 100644
>> >> --- a/net/core/rtnetlink.c
>> >> +++ b/net/core/rtnetlink.c
>> >> @@ -3048,21 +3048,13 @@ static int do_setlink(const struct sk_buff *skb, struct net_device *dev,
>> >> }
>> >>
>> >> if (tb[IFLA_ADDRESS]) {
>> >> - struct sockaddr *sa;
>> >> - int len;
>> >> -
>> >> - len = sizeof(sa_family_t) + max_t(size_t, dev->addr_len,
>> >> - sizeof(*sa));
>> >> - sa = kmalloc(len, GFP_KERNEL);
>> >> - if (!sa) {
>> >> - err = -ENOMEM;
>> >> - goto errout;
>> >> - }
>> >> - sa->sa_family = dev->type;
>> >> - memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]),
>> >> - dev->addr_len);
>> >> - err = dev_set_mac_address_user(dev, sa, extack);
>> >> - kfree(sa);
>> >> + struct sockaddr sa = { };
>> >> +
>> >> + /* dev_set_mac_address_user() uses a true struct sockaddr. */
>> >> + sa.sa_family = dev->type;
>> >> + memcpy(sa.sa_data, nla_data(tb[IFLA_ADDRESS]),
>> >> + min(dev->addr_len, sizeof(sa.sa_data_min)));
>> >> + err = dev_set_mac_address_user(dev, &sa, extack);
>> >> if (err)
>> >> goto errout;
>> >> status |= DO_SETLINK_MODIFIED;
>> >> --
>> >> 2.34.1
>> >
>>
>> --
>> Kees Cook
--
Kees Cook
© 2016 - 2025 Red Hat, Inc.