Skip to content

Commit

Permalink
net: dev: Convert sa_data to flexible array in struct sockaddr
Browse files Browse the repository at this point in the history
One of the worst offenders of "fake flexible arrays" is struct sockaddr,
as it is the classic example of why GCC and Clang have been traditionally
forced to treat all trailing arrays as fake flexible arrays: in the
distant misty past, sa_data became too small, and code started just
treating it as a flexible array, even though it was fixed-size. The
special case by the compiler is specifically that sizeof(sa->sa_data)
and FORTIFY_SOURCE (which uses __builtin_object_size(sa->sa_data, 1))
do not agree (14 and -1 respectively), which makes FORTIFY_SOURCE treat
it as a flexible array.

However, the coming -fstrict-flex-arrays compiler flag will remove
these special cases so that FORTIFY_SOURCE can gain coverage over all
the trailing arrays in the kernel that are _not_ supposed to be treated
as a flexible array. To deal with this change, convert sa_data to a true
flexible array. To keep the structure size the same, move sa_data into
a union with a newly introduced sa_data_min with the original size. The
result is that FORTIFY_SOURCE can continue to have no idea how large
sa_data may actually be, but anything using sizeof(sa->sa_data) must
switch to sizeof(sa->sa_data_min).

Cc: Jens Axboe <[email protected]>
Cc: Pavel Begunkov <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Dylan Yudaken <[email protected]>
Cc: Yajun Deng <[email protected]>
Cc: Petr Machata <[email protected]>
Cc: Hangbin Liu <[email protected]>
Cc: Leon Romanovsky <[email protected]>
Cc: syzbot <[email protected]>
Cc: Willem de Bruijn <[email protected]>
Cc: Pablo Neira Ayuso <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Jakub Kicinski <[email protected]>
  • Loading branch information
kees authored and kuba-moo committed Oct 25, 2022
1 parent d6dd508 commit b5f0de6
Show file tree
Hide file tree
Showing 4 changed files with 11 additions and 8 deletions.
5 changes: 4 additions & 1 deletion include/linux/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ typedef __kernel_sa_family_t sa_family_t;

struct sockaddr {
sa_family_t sa_family; /* address family, AF_xxx */
char sa_data[14]; /* 14 bytes of protocol address */
union {
char sa_data_min[14]; /* Minimum 14 bytes of protocol address */
DECLARE_FLEX_ARRAY(char, sa_data);
};
};

struct linger {
Expand Down
2 changes: 1 addition & 1 deletion net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -8822,7 +8822,7 @@ EXPORT_SYMBOL(dev_set_mac_address_user);

int dev_get_mac_address(struct sockaddr *sa, struct net *net, char *dev_name)
{
size_t size = sizeof(sa->sa_data);
size_t size = sizeof(sa->sa_data_min);
struct net_device *dev;
int ret = 0;

Expand Down
2 changes: 1 addition & 1 deletion net/core/dev_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, void __user *data,
if (ifr->ifr_hwaddr.sa_family != dev->type)
return -EINVAL;
memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data,
min(sizeof(ifr->ifr_hwaddr.sa_data),
min(sizeof(ifr->ifr_hwaddr.sa_data_min),
(size_t)dev->addr_len));
call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
return 0;
Expand Down
10 changes: 5 additions & 5 deletions net/packet/af_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -3277,7 +3277,7 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr,
int addr_len)
{
struct sock *sk = sock->sk;
char name[sizeof(uaddr->sa_data) + 1];
char name[sizeof(uaddr->sa_data_min) + 1];

/*
* Check legality
Expand All @@ -3288,8 +3288,8 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr,
/* uaddr->sa_data comes from the userspace, it's not guaranteed to be
* zero-terminated.
*/
memcpy(name, uaddr->sa_data, sizeof(uaddr->sa_data));
name[sizeof(uaddr->sa_data)] = 0;
memcpy(name, uaddr->sa_data, sizeof(uaddr->sa_data_min));
name[sizeof(uaddr->sa_data_min)] = 0;

return packet_do_bind(sk, name, 0, pkt_sk(sk)->num);
}
Expand Down Expand Up @@ -3561,11 +3561,11 @@ static int packet_getname_spkt(struct socket *sock, struct sockaddr *uaddr,
return -EOPNOTSUPP;

uaddr->sa_family = AF_PACKET;
memset(uaddr->sa_data, 0, sizeof(uaddr->sa_data));
memset(uaddr->sa_data, 0, sizeof(uaddr->sa_data_min));
rcu_read_lock();
dev = dev_get_by_index_rcu(sock_net(sk), READ_ONCE(pkt_sk(sk)->ifindex));
if (dev)
strscpy(uaddr->sa_data, dev->name, sizeof(uaddr->sa_data));
strscpy(uaddr->sa_data, dev->name, sizeof(uaddr->sa_data_min));
rcu_read_unlock();

return sizeof(*uaddr);
Expand Down

0 comments on commit b5f0de6

Please sign in to comment.