netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net-next v2 0/2] tuntap: correctly initialize socket uid
@ 2023-02-03 14:30 Pietro Borrello
  2023-02-03 14:30 ` [PATCH net-next v2 1/2] tun: tun_chr_open(): " Pietro Borrello
  2023-02-03 14:30 ` [PATCH net-next v2 2/2] tap: tap_open(): " Pietro Borrello
  0 siblings, 2 replies; 5+ messages in thread
From: Pietro Borrello @ 2023-02-03 14:30 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Lorenzo Colitti
  Cc: Stephen Hemminger, Cristiano Giuffrida, Bos, H.J.,
	Jakob Koschel, netdev, linux-kernel, Pietro Borrello

sock_init_data() assumes that the `struct socket` passed in input is
contained in a `struct socket_alloc` allocated with sock_alloc().
However, tap_open() and tun_chr_open() pass a `struct socket` embedded
in a `struct tap_queue` and `struct tun_file` respectively, both
allocated with sk_alloc().
This causes a type confusion when issuing a container_of() with
SOCK_INODE() in sock_init_data() which results in assigning a wrong
sk_uid to the `struct sock` in input.

Due to the type confusion, both sockets happen to have their uid set
to 0, i.e. root.
While it will be often correct, as tuntap devices require
CAP_NET_ADMIN, it may not always be the case.
Not sure how widespread is the impact of this, it seems the socket uid
may be used for network filtering and routing, thus tuntap sockets may
be incorrectly managed.
Additionally, it seems a socket with an incorrect uid may be returned
to the vhost driver when issuing a get_socket() on a tuntap device in
vhost_net_set_backend().

The proposed fix may not be the cleanest one, as it simply overrides
the incorrect uid after the type confusion in sock_init_data()
happens.
While minimal, this may not be solid in case more logic relying on
SOCK_INODE() is added to sock_init_data().
The alternative fix would be to pass a NULL sock, and manually perform
the assignments after the sock_init_data() call:
```
sk_set_socket(sk, sock);
// and
sk->sk_type	=	sock->type;
RCU_INIT_POINTER(sk->sk_wq, &sock->wq);
sock->sk	=	sk;
sk->sk_uid	=	SOCK_INODE(sock)->i_uid;
```

Signed-off-by: Pietro Borrello <borrello@diag.uniroma1.it>
---
Changes in v2:
- Shorten and format comments
- Link to v1: https://lore.kernel.org/r/20230131-tuntap-sk-uid-v1-0-af4f9f40979d@diag.uniroma1.it

---
Pietro Borrello (2):
      tun: tun_chr_open(): correctly initialize socket uid
      tap: tap_open(): correctly initialize socket uid

 drivers/net/tap.c | 4 ++++
 drivers/net/tun.c | 5 +++++
 2 files changed, 9 insertions(+)
---
base-commit: 6d796c50f84ca79f1722bb131799e5a5710c4700
change-id: 20230131-tuntap-sk-uid-78efc80f4b82

Best regards,
-- 
Pietro Borrello <borrello@diag.uniroma1.it>


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH net-next v2 1/2] tun: tun_chr_open(): correctly initialize socket uid
  2023-02-03 14:30 [PATCH net-next v2 0/2] tuntap: correctly initialize socket uid Pietro Borrello
@ 2023-02-03 14:30 ` Pietro Borrello
  2023-02-03 14:58   ` Eric Dumazet
  2023-02-03 14:30 ` [PATCH net-next v2 2/2] tap: tap_open(): " Pietro Borrello
  1 sibling, 1 reply; 5+ messages in thread
From: Pietro Borrello @ 2023-02-03 14:30 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Lorenzo Colitti
  Cc: Stephen Hemminger, Cristiano Giuffrida, Bos, H.J.,
	Jakob Koschel, netdev, linux-kernel, Pietro Borrello

sock_init_data() assumes that the `struct socket` passed in input is
contained in a `struct socket_alloc` allocated with sock_alloc().
However, tun_chr_open() passes a `struct socket` embedded in a `struct
tun_file` allocated with sk_alloc().
This causes a type confusion when issuing a container_of() with
SOCK_INODE() in sock_init_data() which results in assigning a wrong
sk_uid to the `struct sock` in input.
On default configuration, the type confused field overlaps with the
high 4 bytes of `struct tun_struct __rcu *tun` of `struct tun_file`,
NULL at the time of call, which makes the uid of all tun sockets 0,
i.e., the root one.  Fix the assignment by overriding it with the
correct uid.

Fixes: 86741ec25462 ("net: core: Add a UID field to struct sock.")
Signed-off-by: Pietro Borrello <borrello@diag.uniroma1.it>
---
 drivers/net/tun.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index a7d17c680f4a..ccffbc439c95 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -3450,6 +3450,11 @@ static int tun_chr_open(struct inode *inode, struct file * file)
 
 	sock_init_data(&tfile->socket, &tfile->sk);
 
+	/* Assign sk_uid from the inode argument, since tfile->socket
+	 * passed to sock_init_data() has no corresponding inode
+	 */
+	tfile->sk.sk_uid = inode->i_uid;
+
 	tfile->sk.sk_write_space = tun_sock_write_space;
 	tfile->sk.sk_sndbuf = INT_MAX;
 

-- 
2.25.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH net-next v2 2/2] tap: tap_open(): correctly initialize socket uid
  2023-02-03 14:30 [PATCH net-next v2 0/2] tuntap: correctly initialize socket uid Pietro Borrello
  2023-02-03 14:30 ` [PATCH net-next v2 1/2] tun: tun_chr_open(): " Pietro Borrello
@ 2023-02-03 14:30 ` Pietro Borrello
  1 sibling, 0 replies; 5+ messages in thread
From: Pietro Borrello @ 2023-02-03 14:30 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Lorenzo Colitti
  Cc: Stephen Hemminger, Cristiano Giuffrida, Bos, H.J.,
	Jakob Koschel, netdev, linux-kernel, Pietro Borrello

sock_init_data() assumes that the `struct socket` passed in input is
contained in a `struct socket_alloc` allocated with sock_alloc().
However, tap_open() passes a `struct socket` embedded in a `struct
tap_queue` allocated with sk_alloc().
This causes a type confusion when issuing a container_of() with
SOCK_INODE() in sock_init_data() which results in assigning a wrong
sk_uid to the `struct sock` in input.
On default configuration, the type confused field overlaps with
padding bytes between `int vnet_hdr_sz` and `struct tap_dev __rcu
*tap` in `struct tap_queue`, which makes the uid of all tap sockets 0,
i.e., the root one.  Fix the assignment by overriding it with the
correct uid.

Fixes: 86741ec25462 ("net: core: Add a UID field to struct sock.")
Signed-off-by: Pietro Borrello <borrello@diag.uniroma1.it>
---
 drivers/net/tap.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/tap.c b/drivers/net/tap.c
index a2be1994b389..145c3f84fac4 100644
--- a/drivers/net/tap.c
+++ b/drivers/net/tap.c
@@ -538,6 +538,10 @@ static int tap_open(struct inode *inode, struct file *file)
 	q->sk.sk_destruct = tap_sock_destruct;
 	q->flags = IFF_VNET_HDR | IFF_NO_PI | IFF_TAP;
 	q->vnet_hdr_sz = sizeof(struct virtio_net_hdr);
+	/* Assign sk_uid from the inode argument, since q->sock
+	 * passed to sock_init_data() has no corresponding inode
+	 */
+	q->sk.sk_uid = inode->i_uid;
 
 	/*
 	 * so far only KVM virtio_net uses tap, enable zero copy between

-- 
2.25.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH net-next v2 1/2] tun: tun_chr_open(): correctly initialize socket uid
  2023-02-03 14:30 ` [PATCH net-next v2 1/2] tun: tun_chr_open(): " Pietro Borrello
@ 2023-02-03 14:58   ` Eric Dumazet
  2023-02-03 15:12     ` Pietro Borrello
  0 siblings, 1 reply; 5+ messages in thread
From: Eric Dumazet @ 2023-02-03 14:58 UTC (permalink / raw)
  To: Pietro Borrello
  Cc: David S. Miller, Jakub Kicinski, Paolo Abeni, Lorenzo Colitti,
	Stephen Hemminger, Cristiano Giuffrida, Bos, H.J.,
	Jakob Koschel, netdev, linux-kernel

On Fri, Feb 3, 2023 at 3:30 PM Pietro Borrello
<borrello@diag.uniroma1.it> wrote:
>
> sock_init_data() assumes that the `struct socket` passed in input is
> contained in a `struct socket_alloc` allocated with sock_alloc().
> However, tun_chr_open() passes a `struct socket` embedded in a `struct
> tun_file` allocated with sk_alloc().
> This causes a type confusion when issuing a container_of() with
> SOCK_INODE() in sock_init_data() which results in assigning a wrong
> sk_uid to the `struct sock` in input.
> On default configuration, the type confused field overlaps with the
> high 4 bytes of `struct tun_struct __rcu *tun` of `struct tun_file`,
> NULL at the time of call, which makes the uid of all tun sockets 0,
> i.e., the root one.  Fix the assignment by overriding it with the
> correct uid.
>
> Fixes: 86741ec25462 ("net: core: Add a UID field to struct sock.")
> Signed-off-by: Pietro Borrello <borrello@diag.uniroma1.it>
> ---
>  drivers/net/tun.c | 5 +++++
>  1 file changed, 5 insertions(+)
>
> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> index a7d17c680f4a..ccffbc439c95 100644
> --- a/drivers/net/tun.c
> +++ b/drivers/net/tun.c
> @@ -3450,6 +3450,11 @@ static int tun_chr_open(struct inode *inode, struct file * file)
>
>         sock_init_data(&tfile->socket, &tfile->sk);
>
> +       /* Assign sk_uid from the inode argument, since tfile->socket
> +        * passed to sock_init_data() has no corresponding inode
> +        */
> +       tfile->sk.sk_uid = inode->i_uid;
> +
>         tfile->sk.sk_write_space = tun_sock_write_space;
>         tfile->sk.sk_sndbuf = INT_MAX;
>


This seems very fragile...
"struct inode" could be made bigger, and __randomize_layout could move i_uid
at the end of it.

KASAN could then detect an out-of-bound access in sock_init_data()

I would rather add a wrapper like this [1], then change tun/tap to use
sock_init_data_uid()

diff --git a/include/net/sock.h b/include/net/sock.h
index 9e464f6409a7175cef5f8ec22e70cade19df5e60..a7e1396d1b778c8a7ed664d149bd6c82cf2ae422
100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1946,6 +1946,8 @@ void sk_common_release(struct sock *sk);
  */

 /* Initialise core socket variables */
+void sock_init_data_uid(struct socket *sock, struct sock *sk, kuid_t uid);
+
 void sock_init_data(struct socket *sock, struct sock *sk);

 /*
diff --git a/net/core/sock.c b/net/core/sock.c
index a3ba0358c77c0e44db1cfbaeb420f8b80ad7cf98..d811cd0d204f37b1791ae94ccfe95114a2286caf
100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -3357,7 +3357,7 @@ void sk_stop_timer_sync(struct sock *sk, struct
timer_list *timer)
 }
 EXPORT_SYMBOL(sk_stop_timer_sync);

-void sock_init_data(struct socket *sock, struct sock *sk)
+void sock_init_data_uid(struct socket *sock, struct sock *sk, kuid_t uid)
 {
        sk_init_common(sk);
        sk->sk_send_head        =       NULL;
@@ -3376,11 +3376,10 @@ void sock_init_data(struct socket *sock,
struct sock *sk)
                sk->sk_type     =       sock->type;
                RCU_INIT_POINTER(sk->sk_wq, &sock->wq);
                sock->sk        =       sk;
-               sk->sk_uid      =       SOCK_INODE(sock)->i_uid;
        } else {
                RCU_INIT_POINTER(sk->sk_wq, NULL);
-               sk->sk_uid      =       make_kuid(sock_net(sk)->user_ns, 0);
        }
+       sk->sk_uid      =       uid;

        rwlock_init(&sk->sk_callback_lock);
        if (sk->sk_kern_sock)
@@ -3439,6 +3438,16 @@ void sock_init_data(struct socket *sock, struct sock *sk)
        refcount_set(&sk->sk_refcnt, 1);
        atomic_set(&sk->sk_drops, 0);
 }
+EXPORT_SYMBOL(sock_init_data_uid);
+
+void sock_init_data(struct socket *sock, struct sock *sk)
+{
+       kuid_t uid = sock ?
+               SOCK_INODE(sock)->i_uid :
+               make_kuid(sock_net(sk)->user_ns, 0);
+
+       sock_init_data_uid(sock, sk, uid);
+}
 EXPORT_SYMBOL(sock_init_data);

 void lock_sock_nested(struct sock *sk, int subclass)

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH net-next v2 1/2] tun: tun_chr_open(): correctly initialize socket uid
  2023-02-03 14:58   ` Eric Dumazet
@ 2023-02-03 15:12     ` Pietro Borrello
  0 siblings, 0 replies; 5+ messages in thread
From: Pietro Borrello @ 2023-02-03 15:12 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: David S. Miller, Jakub Kicinski, Paolo Abeni, Lorenzo Colitti,
	Stephen Hemminger, Cristiano Giuffrida, Bos, H.J.,
	Jakob Koschel, netdev, linux-kernel

On Fri, 3 Feb 2023 at 15:58, Eric Dumazet <edumazet@google.com> wrote:
>
> This seems very fragile...
> "struct inode" could be made bigger, and __randomize_layout could move i_uid
> at the end of it.
>
> KASAN could then detect an out-of-bound access in sock_init_data()
>
> I would rather add a wrapper like this [1], then change tun/tap to use
> sock_init_data_uid()
>

I agree this is a much cleaner solution.
I'll wait the usual 24h for further comments, and send a patch like this in v3.

Best regards,
Pietro

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2023-02-03 15:17 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-03 14:30 [PATCH net-next v2 0/2] tuntap: correctly initialize socket uid Pietro Borrello
2023-02-03 14:30 ` [PATCH net-next v2 1/2] tun: tun_chr_open(): " Pietro Borrello
2023-02-03 14:58   ` Eric Dumazet
2023-02-03 15:12     ` Pietro Borrello
2023-02-03 14:30 ` [PATCH net-next v2 2/2] tap: tap_open(): " Pietro Borrello

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).