diff mbox series

[v2,1/3] qio: add support for SO_PEERCRED for socket channel

Message ID 20231031144605.64822-2-aharivel@redhat.com
State New
Headers show
Series Add support for RAPL MSRs series | expand

Commit Message

Anthony Harivel Oct. 31, 2023, 2:46 p.m. UTC
The function qio_channel_get_peercred() returns a pointer to the
credentials of the peer process connected to this socket.

This credentials structure is defined in <sys/socket.h> as follows:

struct ucred {
	pid_t pid;    /* Process ID of the sending process */
	uid_t uid;    /* User ID of the sending process */
	gid_t gid;    /* Group ID of the sending process */
};

The use of this function is possible only for connected AF_UNIX stream
sockets and for AF_UNIX stream and datagram socket pairs.

Signed-off-by: Anthony Harivel <aharivel@redhat.com>
---
 include/io/channel.h | 20 ++++++++++++++++++++
 io/channel-socket.c  | 17 +++++++++++++++++
 io/channel.c         | 12 ++++++++++++
 3 files changed, 49 insertions(+)

Comments

Daniel P. Berrangé Nov. 1, 2023, 10:20 a.m. UTC | #1
On Tue, Oct 31, 2023 at 03:46:01PM +0100, Anthony Harivel wrote:
> The function qio_channel_get_peercred() returns a pointer to the
> credentials of the peer process connected to this socket.
> 
> This credentials structure is defined in <sys/socket.h> as follows:
> 
> struct ucred {
> 	pid_t pid;    /* Process ID of the sending process */
> 	uid_t uid;    /* User ID of the sending process */
> 	gid_t gid;    /* Group ID of the sending process */
> };
> 
> The use of this function is possible only for connected AF_UNIX stream
> sockets and for AF_UNIX stream and datagram socket pairs.
> 
> Signed-off-by: Anthony Harivel <aharivel@redhat.com>
> ---
>  include/io/channel.h | 20 ++++++++++++++++++++
>  io/channel-socket.c  | 17 +++++++++++++++++
>  io/channel.c         | 12 ++++++++++++
>  3 files changed, 49 insertions(+)
> 
> diff --git a/include/io/channel.h b/include/io/channel.h
> index 5f9dbaab65b0..99c02d61c3d9 100644
> --- a/include/io/channel.h
> +++ b/include/io/channel.h
> @@ -149,6 +149,9 @@ struct QIOChannelClass {
>                                    void *opaque);
>      int (*io_flush)(QIOChannel *ioc,
>                      Error **errp);
> +    void (*io_peercred)(QIOChannel *ioc,
> +                        struct ucred *cred,
> +                        Error **errp);

This isn't going to fly. 'struct ucred' is Linux specific, so this won't
compile on macOS, Windows, *BSD, and we don't really want a huge #ifdef
ladder in these APIs. This will need to explode the struct and return
the individual fields that are present instead, and the impl side must
compile on other OS, even if its just stubbed out to return an error.

With regards,
Daniel
Paolo Bonzini Nov. 1, 2023, 2:23 p.m. UTC | #2
On 11/1/23 11:20, Daniel P. Berrangé wrote:
> On Tue, Oct 31, 2023 at 03:46:01PM +0100, Anthony Harivel wrote:
>> The function qio_channel_get_peercred() returns a pointer to the
>> credentials of the peer process connected to this socket.
>>
>> This credentials structure is defined in <sys/socket.h> as follows:
>>
>> struct ucred {
>> 	pid_t pid;    /* Process ID of the sending process */
>> 	uid_t uid;    /* User ID of the sending process */
>> 	gid_t gid;    /* Group ID of the sending process */
>> };
>>
>> The use of this function is possible only for connected AF_UNIX stream
>> sockets and for AF_UNIX stream and datagram socket pairs.
>>
>> Signed-off-by: Anthony Harivel <aharivel@redhat.com>
>> ---
>>   include/io/channel.h | 20 ++++++++++++++++++++
>>   io/channel-socket.c  | 17 +++++++++++++++++
>>   io/channel.c         | 12 ++++++++++++
>>   3 files changed, 49 insertions(+)
>>
>> diff --git a/include/io/channel.h b/include/io/channel.h
>> index 5f9dbaab65b0..99c02d61c3d9 100644
>> --- a/include/io/channel.h
>> +++ b/include/io/channel.h
>> @@ -149,6 +149,9 @@ struct QIOChannelClass {
>>                                     void *opaque);
>>       int (*io_flush)(QIOChannel *ioc,
>>                       Error **errp);
>> +    void (*io_peercred)(QIOChannel *ioc,
>> +                        struct ucred *cred,
>> +                        Error **errp);
> 
> This isn't going to fly. 'struct ucred' is Linux specific, so this won't
> compile on macOS, Windows, *BSD, and we don't really want a huge #ifdef
> ladder in these APIs. This will need to explode the struct and return
> the individual fields that are present instead, and the impl side must
> compile on other OS, even if its just stubbed out to return an error.

I would further reduce it to to io_peerpid, because the BSDs can only 
provide the peer uid and gid.

Paolo
diff mbox series

Patch

diff --git a/include/io/channel.h b/include/io/channel.h
index 5f9dbaab65b0..99c02d61c3d9 100644
--- a/include/io/channel.h
+++ b/include/io/channel.h
@@ -149,6 +149,9 @@  struct QIOChannelClass {
                                   void *opaque);
     int (*io_flush)(QIOChannel *ioc,
                     Error **errp);
+    void (*io_peercred)(QIOChannel *ioc,
+                        struct ucred *cred,
+                        Error **errp);
 };
 
 /* General I/O handling functions */
@@ -898,4 +901,21 @@  int coroutine_mixed_fn qio_channel_writev_full_all(QIOChannel *ioc,
 int qio_channel_flush(QIOChannel *ioc,
                       Error **errp);
 
+/**
+ * qio_channel_get_peercred:
+ * @ioc: the channel object
+ * @cred: pointer to ucred struct
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * Returns the credentials of the peer process connected to this socket.
+ *
+ * The use of this function is possible only for connected
+ * AF_UNIX stream sockets and for AF_UNIX stream and datagra
+ * socket pairs.
+ *
+ */
+void qio_channel_get_peercred(QIOChannel *ioc,
+                              struct ucred *cred,
+                              Error **errp);
+
 #endif /* QIO_CHANNEL_H */
diff --git a/io/channel-socket.c b/io/channel-socket.c
index 02ffb51e9957..b8285eb8ae49 100644
--- a/io/channel-socket.c
+++ b/io/channel-socket.c
@@ -836,6 +836,22 @@  qio_channel_socket_set_cork(QIOChannel *ioc,
     socket_set_cork(sioc->fd, v);
 }
 
+static void
+qio_channel_socket_get_peercred(QIOChannel *ioc,
+                                struct ucred *cred,
+                                Error **errp)
+{
+    QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
+    socklen_t len = sizeof(struct ucred);
+    Error *err = NULL;
+
+    if (getsockopt(sioc->fd,
+               SOL_SOCKET, SO_PEERCRED,
+               cred, &len) == -1) {
+        error_setg_errno(&err, errno, "Unable to get peer credentials");
+        error_propagate(errp, err);
+    }
+}
 
 static int
 qio_channel_socket_close(QIOChannel *ioc,
@@ -933,6 +949,7 @@  static void qio_channel_socket_class_init(ObjectClass *klass,
 #ifdef QEMU_MSG_ZEROCOPY
     ioc_klass->io_flush = qio_channel_socket_flush;
 #endif
+    ioc_klass->io_peercred = qio_channel_socket_get_peercred;
 }
 
 static const TypeInfo qio_channel_socket_info = {
diff --git a/io/channel.c b/io/channel.c
index 86c5834510ff..6dccccba5242 100644
--- a/io/channel.c
+++ b/io/channel.c
@@ -490,6 +490,18 @@  void qio_channel_set_cork(QIOChannel *ioc,
     }
 }
 
+void qio_channel_get_peercred(QIOChannel *ioc,
+                              struct ucred *cred,
+                              Error **errp)
+{
+    QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
+
+    if (!klass->io_peercred) {
+        error_setg(errp, "Channel does not support random access");
+        return;
+    }
+    klass->io_peercred(ioc, cred, errp);
+}
 
 off_t qio_channel_io_seek(QIOChannel *ioc,
                           off_t offset,