From 5ed36d2b44106f361c04e6dd56c298db632aa7e3 Mon Sep 17 00:00:00 2001 From: Rahul Sandhu Date: Sun, 23 Feb 2025 20:29:31 +0000 Subject: [PATCH] server: wl_client: introduce method for getting client security context Introduces a function wl_client_get_security_context for obtaining the security context of a connected client by using SO_PEERSEC on supported systems. Returns NULL for unsupported systems (inline with behaviour of e.g. Linux attempting to get a security context for a client that does not exist, which is a valid state). Signed-off-by: Rahul Sandhu --- src/wayland-os.c | 30 ++++++++++++++++++++++++++++++ src/wayland-os.h | 3 +++ src/wayland-server-core.h | 4 ++++ src/wayland-server.c | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+) diff --git a/src/wayland-os.c b/src/wayland-os.c index f00ead4b..6bf8543e 100644 --- a/src/wayland-os.c +++ b/src/wayland-os.c @@ -27,6 +27,8 @@ #include "../config.h" +#include +#include #include #include #include @@ -129,6 +131,34 @@ wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid) #error "Don't know how to read ucred on this platform" #endif +int +wl_os_socket_peersec(int sockfd, char **security_context) +{ +#if defined(SO_PEERSEC) + socklen_t len = NAME_MAX; + char *context = NULL; + int r; + + do { + char *new_context = realloc(context, len); + if (!new_context) { + free(context); + return -1; + } + context = new_context; + + r = getsockopt(sockfd, SOL_SOCKET, SO_PEERSEC, context, &len); + if (r < 0 && errno != ERANGE) { + free(context); + return -1; + } + } while (r < 0 && errno == ERANGE); + + *security_context = context; +#endif + return 0; +} + int wl_os_dupfd_cloexec(int fd, int minfd) { diff --git a/src/wayland-os.h b/src/wayland-os.h index 068fd2fe..3d9aeab4 100644 --- a/src/wayland-os.h +++ b/src/wayland-os.h @@ -35,6 +35,9 @@ wl_os_socket_cloexec(int domain, int type, int protocol); int wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid); +int +wl_os_socket_peersec(int sockfd, char **security_context); + int wl_os_dupfd_cloexec(int fd, int minfd); diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 15c3b762..4b498bc8 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -327,6 +327,10 @@ void wl_client_get_credentials(const struct wl_client *client, pid_t *pid, uid_t *uid, gid_t *gid); +void +wl_client_get_security_context(struct wl_client *client, + char **security_context); + int wl_client_get_fd(struct wl_client *client); diff --git a/src/wayland-server.c b/src/wayland-server.c index e5805669..4d62ada4 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -82,6 +82,7 @@ struct wl_client { pid_t pid; uid_t uid; gid_t gid; + char *security_context; bool error; struct wl_priv_signal resource_created_signal; void *data; @@ -630,6 +631,40 @@ wl_client_get_credentials(const struct wl_client *client, *gid = client->gid; } +/** Return Security context for the client + * + * \param client The display object + * \param security_context Returns the security_context, or NULL if + * a security context could not be obtained. + * + * This function returns the security context for the given client. + * The credentials come from getsockopt() with SO_PEERSEC, on the + * client socket fd. + * + * Be aware that for clients that a compositor forks and execs and + * then connects using socketpair(), this function will return the + * security context for the compositor. The security context for + * the socketpair are set at creation time in the compositor. + * + * \memberof wl_client + */ +WL_EXPORT void +wl_client_get_security_context(struct wl_client *client, + char **security_context) +{ + // Only initalise the security context if we have to + // so we don't waste heap space. + if (!client->security_context) { + if (wl_os_socket_peersec(wl_connection_get_fd(client->connection), + &client->security_context) != 0) { + *security_context = NULL; + return; + } + } + + *security_context = client->security_context; +} + /** Get the file descriptor for the client * * \param client The display object @@ -981,6 +1016,8 @@ wl_client_destroy(struct wl_client *client) wl_priv_signal_final_emit(&client->destroy_late_signal, client); + free(client->security_context); + wl_list_remove(&client->resource_created_signal.listener_list); if (client->data_dtor)