Hi,
This RFC aims to implement some support for SO_PEERCRED with AF_VSOCK,
so vsock servers & clients can lookup the basic peer credentials.
(further support for SO_PEERSEC could also be useful)
This is pretty straightforward for loopback transport, where both ends
are on the same host.
For vhost transport, the host will set the peer credentials associated with
the process who called VHOST_SET_OWNER (ex QEMU).
For virtio transport, the credentials are cleared upon connect, as
providing foreign credentials wouldn't make much sense.
I haven't looked at other transports. What do you think of this approach?
Note: I think it would be a better to set the peer credentials when we
actually can provide them, rather than at creation time, but I haven't
found a way yet. Help welcome!
Marc-André Lureau (10):
sock: move sock_init_peercred() from af_unix
sock: move sock_copy_peercred() from af_unix
vsock: owner field is specific to VMCI
sock: add sock_swap_peercred
virtio/vsock: add copy_peercred() to virtio_transport
vsock: set socket peercred
vsock/loopback: implement copy_peercred()
vhost/vsock: save owner pid & creds
vhost/vsock: implement copy_peercred
vsock/virtio: clear peer creds on connect
drivers/vhost/vsock.c | 46 +++++++++++++++++
include/linux/virtio_vsock.h | 2 +
include/net/af_vsock.h | 2 +
include/net/sock.h | 9 ++++
net/core/sock.c | 66 +++++++++++++++++++++++++
net/unix/af_unix.c | 50 ++-----------------
net/vmw_vsock/af_vsock.c | 8 +++
net/vmw_vsock/virtio_transport.c | 22 ++++++++-
net/vmw_vsock/virtio_transport_common.c | 9 ++++
net/vmw_vsock/vsock_loopback.c | 7 +++
10 files changed, 175 insertions(+), 46 deletions(-)
base-commit: e0bfcf9c77d9b2c11d2767f0c747f7721ae0cc51
--
2.33.0.721.g106298f7f9
SO_PEERCRED can be made to work with other kind of sockets.
Signed-off-by: Marc-André Lureau <redacted>
---
include/net/sock.h | 3 +++
net/core/sock.c | 17 +++++++++++++++++
net/unix/af_unix.c | 24 ++++--------------------
3 files changed, 24 insertions(+), 20 deletions(-)
@@ -666,7 +650,7 @@ static int unix_listen(struct socket *sock, int backlog)sk->sk_max_ack_backlog=backlog;sk->sk_state=TCP_LISTEN;/* set credentials so connect can copy them */-init_peercred(sk);+sock_init_peercred(sk);err=0;out_unlock:
SO_PEERCRED can be made to work with other kind of sockets.
Signed-off-by: Marc-André Lureau <redacted>
---
include/net/sock.h | 3 +++
net/core/sock.c | 25 +++++++++++++++++++++++++
net/unix/af_unix.c | 26 +-------------------------
3 files changed, 29 insertions(+), 25 deletions(-)
This field isn't used by other transports.
Signed-off-by: Marc-André Lureau <redacted>
---
include/net/af_vsock.h | 2 ++
net/vmw_vsock/af_vsock.c | 6 ++++++
2 files changed, 8 insertions(+)
@@ -41,7 +41,9 @@ struct vsock_sock {*cachedpeer?*/u32cached_peer;/* Context ID of last dgram destination check. */+#if IS_ENABLED(CONFIG_VMWARE_VMCI_VSOCKETS)conststructcred*owner;+#endif/* Rest are SOCK_STREAM only. */longconnect_timeout;/* Listening socket that this came from. */
@@ -69,6 +69,8 @@ struct virtio_transport {/* Takes ownership of the packet */int(*send_pkt)(structvirtio_vsock_pkt*pkt);+/* Set peercreds on socket created after listen recv */+void(*copy_peercred)(structsock*sk,structvirtio_vsock_pkt*pkt);};ssize_t
When AF_VSOCK socket is created, the peercreds are set to the current
process values.
This is how AF_UNIX listen work too, but unconnected AF_UNIX sockets
return pid:0 & uid/gid:-1.
Signed-off-by: Marc-André Lureau <redacted>
---
net/vmw_vsock/af_vsock.c | 2 ++
1 file changed, 2 insertions(+)
@@ -41,6 +41,12 @@ static int vsock_loopback_send_pkt(struct virtio_vsock_pkt *pkt)returnlen;}+staticvoidvsock_loopback_copy_peercred(structsock*sk,structvirtio_vsock_pkt*pkt)+{+/* on vsock loopback, set both peers by swaping the creds */+sock_swap_peercred(sk,sk_vsock(pkt->vsk));+}+staticintvsock_loopback_cancel_pkt(structvsock_sock*vsk){structvsock_loopback*vsock=&the_vsock_loopback;
Since providing foreign creds wouldn't make much sense over VIRTIO,
let's clear the socket peer credentials on connect.
Signed-off-by: Marc-André Lureau <redacted>
---
net/vmw_vsock/virtio_transport.c | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
Hi,
On Thu, Oct 21, 2021 at 04:37:04PM +0400, Marc-André Lureau wrote:
Hi,
This RFC aims to implement some support for SO_PEERCRED with AF_VSOCK,
so vsock servers & clients can lookup the basic peer credentials.
(further support for SO_PEERSEC could also be useful)
Thanks for this RFC! Just had a quick look, Monday I hope to give you
better feedback :-)
This is pretty straightforward for loopback transport, where both ends
are on the same host.
For vhost transport, the host will set the peer credentials associated with
the process who called VHOST_SET_OWNER (ex QEMU).
For virtio transport, the credentials are cleared upon connect, as
providing foreign credentials wouldn't make much sense.
I haven't looked at other transports. What do you think of this
approach?
So IIUC, SO_PEERCRED will make sense only in the host and will return
the credentials of the VMM (e.g. QEMU) that manages the VM of the peer
to which we are connected.
So the features should be supported by the following type of transports:
- VSOCK_TRANSPORT_F_LOCAL (vsock_loopback)
- VSOCK_TRANSPORT_F_H2G (vhost-vsock, vmci)
Note: I think it would be a better to set the peer credentials when we
actually can provide them, rather than at creation time, but I haven't
found a way yet. Help welcome!
Yep, I agree, cleaning credentials after connecting in the guest seems a
bit strange.
As you also said, would be better to set them only after a successful
connect(), which should be similar to what AF_UNIX does.
Maybe we can add an helper in af_vsock.c that will be called from the
transports that support this feature at the end the connection setup.
I'll think better of it and get back to you.
Thanks,
Stefano
@@ -41,7 +41,9 @@ struct vsock_sock {*cachedpeer?*/u32cached_peer;/* Context ID of last dgram destination check. */+#if IS_ENABLED(CONFIG_VMWARE_VMCI_VSOCKETS)conststructcred*owner;+#endif/* Rest are SOCK_STREAM only. */longconnect_timeout;/* Listening socket that this came from. */
/* Takes ownership of the packet */
int (*send_pkt)(struct virtio_vsock_pkt *pkt);
+ /* Set peercreds on socket created after listen recv */
+ void (*copy_peercred)(struct sock *sk, struct virtio_vsock_pkt *pkt);
};
ssize_t
Should we do the same also on the other side?
I mean in virtio_transport_recv_connecting() when
VIRTIO_VSOCK_OP_RESPONSE is received.
I think we can add an helper and call it every time we call
vsock_insert_connected().
Even better if we can do it in the core, but maybe this can be a next
step.
Thanks,
Stefano
On Thu, Oct 21, 2021 at 04:37:10PM +0400, Marc-André Lureau wrote:
quoted hunk
When AF_VSOCK socket is created, the peercreds are set to the current
process values.
This is how AF_UNIX listen work too, but unconnected AF_UNIX sockets
return pid:0 & uid/gid:-1.
Signed-off-by: Marc-André Lureau <redacted>
---
net/vmw_vsock/af_vsock.c | 2 ++
1 file changed, 2 insertions(+)
IIUC in AF_UNIX the sock_init_peercred() is called only when the
connection is established, so I think we should do the same.
In the single transports or in some way in the core when the transports
call vsock_insert_connected().
Thanks,
Stefano
@@ -41,6 +41,12 @@ static int vsock_loopback_send_pkt(struct virtio_vsock_pkt *pkt)returnlen;
}
+static void vsock_loopback_copy_peercred(struct sock *sk, struct virtio_vsock_pkt *pkt)
+{
+ /* on vsock loopback, set both peers by swaping the creds */
+ sock_swap_peercred(sk, sk_vsock(pkt->vsk));
+}
+
It's a bit hacky set also the cred of `pkt->vsk`. I think here we should
only copy the cred of the remote peer.
Addind the call to t->copy_peercred() in the
virtio_transport_recv_connecting() will set the other side.
Thanks,
Stefano
On 26 Oct 2021, at 13:16, Stefano Garzarella [off-list ref] wrote:
CCing Jorgen.
On Thu, Oct 21, 2021 at 04:37:07PM +0400, Marc-André Lureau wrote:
quoted
This field isn't used by other transports.
If the field is used only in the VMCI transport, maybe it's better to
move the field and the code in that transport.
If the transport needs initialize these fields, that should happen when we
call vsock_assign_transport. So we would need to validate that
get_current_cred() gets the right credentials and that the parent of a
socket has an Initialised owner field at that point in time.
sock_assign_transport may be called when processing an
incoming packet when a remote connects to a listening socket,
and in that case, the owner will be based on the parent socket.
If the parent socket hasn’t been assigned a transport (and as I
remember it, that isn’t the case for a listening socket), then it
isn’t possible to initialize the owner field at this point using
the value from the parent. So the initialisation of the fields
probably have to stay in af_vsock.c as part of the generic structure.
Is there a particular reason to do this change as part of this series
of patches?
Thanks,
Jorgen
@@ -41,7 +41,9 @@ struct vsock_sock {*cachedpeer?*/u32cached_peer;/* Context ID of last dgram destination check. */+#if IS_ENABLED(CONFIG_VMWARE_VMCI_VSOCKETS)conststructcred*owner;+#endif/* Rest are SOCK_STREAM only. */longconnect_timeout;/* Listening socket that this came from. */
Hi
On Wed, Oct 27, 2021 at 12:13 PM Jorgen Hansen [off-list ref] wrote:
quoted
On 26 Oct 2021, at 13:16, Stefano Garzarella [off-list ref] wrote:
CCing Jorgen.
On Thu, Oct 21, 2021 at 04:37:07PM +0400, Marc-André Lureau wrote:
quoted
This field isn't used by other transports.
If the field is used only in the VMCI transport, maybe it's better to
move the field and the code in that transport.
If the transport needs initialize these fields, that should happen when we
call vsock_assign_transport. So we would need to validate that
get_current_cred() gets the right credentials and that the parent of a
socket has an Initialised owner field at that point in time.
sock_assign_transport may be called when processing an
incoming packet when a remote connects to a listening socket,
and in that case, the owner will be based on the parent socket.
If the parent socket hasn’t been assigned a transport (and as I
remember it, that isn’t the case for a listening socket), then it
isn’t possible to initialize the owner field at this point using
the value from the parent. So the initialisation of the fields
probably have to stay in af_vsock.c as part of the generic structure.
Is there a particular reason to do this change as part of this series
of patches?
No particular reason, it was just related code.
thanks
@@ -41,7 +41,9 @@ struct vsock_sock {*cachedpeer?*/u32cached_peer;/* Context ID of last dgram destination check. */+#if IS_ENABLED(CONFIG_VMWARE_VMCI_VSOCKETS)conststructcred*owner;+#endif/* Rest are SOCK_STREAM only. */longconnect_timeout;/* Listening socket that this came from. */