From 3854f8557a8d47ebaa5173e44669a9e58e148128 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 10 May 2019 13:12:22 +0200 Subject: [PATCH] protocol: add security label to a client Don't pass the ucred to the client construct, just set the properties in the protocol. Use the client properties to get ucred. Add the security label to the client properties (from SO_PEERSEC) --- src/modules/module-flatpak.c | 42 ++++++++++++++++++++-------- src/modules/module-protocol-native.c | 28 ++++++++++++------- src/pipewire/client.c | 18 ------------ src/pipewire/client.h | 11 +------- src/pipewire/private.h | 2 -- 5 files changed, 49 insertions(+), 52 deletions(-) diff --git a/src/modules/module-flatpak.c b/src/modules/module-flatpak.c index 59c6f67a2..3c981201d 100644 --- a/src/modules/module-flatpak.c +++ b/src/modules/module-flatpak.c @@ -139,20 +139,25 @@ static void client_info_free(struct client_info *cinfo) static int check_sandboxed(struct pw_client *client) { char root_path[2048]; - int root_fd, info_fd, res; - const struct ucred *ucred; + int root_fd, info_fd, res, pid; + const char *str; + const struct pw_properties *props; struct stat stat_buf; - ucred = pw_client_get_ucred(client); + if ((props = pw_client_get_properties(client))) + str = pw_properties_get(props, PW_CLIENT_PROP_UCRED_PID); + else + str = NULL; - if (ucred) { - pw_log_info("client has trusted pid %d", ucred->pid); + if (str) { + pid = atoi(str); + pw_log_info("client has trusted pid %d", pid); } else { pw_log_info("no trusted pid found, assuming not sandboxed\n"); return 0; } - sprintf(root_path, "/proc/%u/root", ucred->pid); + sprintf(root_path, "/proc/%u/root", pid); root_fd = openat (AT_FDCWD, root_path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY); if (root_fd == -1) { /* Not able to open the root dir shouldn't happen. Probably the app died and @@ -182,11 +187,22 @@ static int check_sandboxed(struct pw_client *client) return 1; } +static int get_client_prop(struct pw_client *client, const char *prop) +{ + const struct pw_properties *props; + const char *str; + if ((props = pw_client_get_properties(client)) == NULL) + return -EINVAL; + if ((str = pw_properties_get(props, prop)) == NULL) + return -EINVAL; + return atoi(str); +} + static bool check_global_owner(struct pw_client *client, struct pw_global *global) { struct pw_client *owner; - const struct ucred *owner_ucred, *client_ucred; + int owner_uid, client_uid; if (global == NULL) return false; @@ -195,14 +211,14 @@ check_global_owner(struct pw_client *client, struct pw_global *global) if (owner == NULL) return false; - owner_ucred = pw_client_get_ucred(owner); - client_ucred = pw_client_get_ucred(client); + owner_uid = get_client_prop(owner, PW_CLIENT_PROP_UCRED_UID); + client_uid = get_client_prop(client, PW_CLIENT_PROP_UCRED_UID); - if (owner_ucred == NULL || client_ucred == NULL) + if (owner_uid < 0 || client_uid < 0) return false; /* same user can see eachothers objects */ - return owner_ucred->uid == client_ucred->uid; + return owner_uid == client_uid; } static int @@ -320,7 +336,9 @@ static void do_portal_check(struct client_info *cinfo) device = "camera"; - pid = pw_client_get_ucred(client)->pid; + pid = get_client_prop(client, PW_CLIENT_PROP_UCRED_PID); + if (pid < 0) + goto not_allowed; if (!dbus_message_append_args(m, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID)) goto message_failed; diff --git a/src/modules/module-protocol-native.c b/src/modules/module-protocol-native.c index 4929fc6d7..131657f61 100644 --- a/src/modules/module-protocol-native.c +++ b/src/modules/module-protocol-native.c @@ -313,24 +313,32 @@ static struct pw_client *client_new(struct server *s, int fd) struct pw_protocol *protocol = s->this.protocol; struct protocol_data *pd = protocol->user_data; socklen_t len; - struct ucred ucred, *ucredp; + struct ucred ucred; struct pw_core *core = protocol->core; struct pw_properties *props; - - len = sizeof(ucred); - if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) { - pw_log_error("no peercred: %m"); - ucredp = NULL; - } else { - ucredp = &ucred; - } + char buffer[1024]; props = pw_properties_new(PW_CLIENT_PROP_PROTOCOL, "protocol-native", NULL); if (props == NULL) goto no_props; + len = sizeof(ucred); + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) { + pw_log_error("no peercred: %m"); + } else { + pw_properties_setf(props, PW_CLIENT_PROP_UCRED_PID, "%d", ucred.pid); + pw_properties_setf(props, PW_CLIENT_PROP_UCRED_UID, "%d", ucred.uid); + pw_properties_setf(props, PW_CLIENT_PROP_UCRED_GID, "%d", ucred.gid); + } + + len = sizeof(buffer); + if (getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buffer, &len) < 0) { + pw_log_error("no peersec: %m"); + } else { + pw_properties_setf(props, PW_CLIENT_PROP_SEC_LABEL, "%s", buffer); + } + client = pw_client_new(protocol->core, - ucredp, props, sizeof(struct client_data)); if (client == NULL) diff --git a/src/pipewire/client.c b/src/pipewire/client.c index 8259db2a7..a09e3da84 100644 --- a/src/pipewire/client.c +++ b/src/pipewire/client.c @@ -150,7 +150,6 @@ static const struct pw_core_events core_events = { */ SPA_EXPORT struct pw_client *pw_client_new(struct pw_core *core, - struct ucred *ucred, struct pw_properties *properties, size_t user_data_size) { @@ -165,20 +164,12 @@ struct pw_client *pw_client_new(struct pw_core *core, pw_log_debug("client %p: new", this); this->core = core; - if ((this->ucred_valid = (ucred != NULL))) - this->ucred = *ucred; if (properties == NULL) properties = pw_properties_new(NULL, NULL); if (properties == NULL) return NULL; - if (ucred) { - pw_properties_setf(properties, PW_CLIENT_PROP_UCRED_PID, "%d", ucred->pid); - pw_properties_setf(properties, PW_CLIENT_PROP_UCRED_UID, "%d", ucred->uid); - pw_properties_setf(properties, PW_CLIENT_PROP_UCRED_GID, "%d", ucred->gid); - } - pw_array_init(&impl->permissions, 1024); this->properties = properties; @@ -273,15 +264,6 @@ const struct pw_properties *pw_client_get_properties(struct pw_client *client) return client->properties; } -SPA_EXPORT -const struct ucred *pw_client_get_ucred(struct pw_client *client) -{ - if (!client->ucred_valid) - return NULL; - - return &client->ucred; -} - SPA_EXPORT void *pw_client_get_user_data(struct pw_client *client) { diff --git a/src/pipewire/client.h b/src/pipewire/client.h index f653f93eb..a454d4a2f 100644 --- a/src/pipewire/client.h +++ b/src/pipewire/client.h @@ -24,12 +24,6 @@ extern "C" { #endif -#ifndef __USE_GNU -#define __USE_GNU -#endif - -#include - #include /** \class pw_client @@ -119,11 +113,11 @@ struct pw_client_events { #define PW_CLIENT_PROP_UCRED_PID "pipewire.ucred.pid" /**< Client pid, set by protocol */ #define PW_CLIENT_PROP_UCRED_UID "pipewire.ucred.uid" /**< Client uid, set by protocol*/ #define PW_CLIENT_PROP_UCRED_GID "pipewire.ucred.gid" /**< client gid, set by protocol*/ +#define PW_CLIENT_PROP_SEC_LABEL "pipewire.sec.label" /**< client security label, set by protocol*/ /** Create a new client. This is mainly used by protocols. */ struct pw_client * pw_client_new(struct pw_core *core, /**< the core object */ - struct ucred *ucred, /**< optional ucred */ struct pw_properties *properties, /**< client properties */ size_t user_data_size /**< extra user data size */); @@ -163,9 +157,6 @@ struct pw_resource *pw_client_find_resource(struct pw_client *client, uint32_t i /** Get the global associated with this client */ struct pw_global *pw_client_get_global(struct pw_client *client); -/** Get the ucred from a client or NULL when not specified/valid */ -const struct ucred *pw_client_get_ucred(struct pw_client *client); - /** listen to events from this client */ void pw_client_add_listener(struct pw_client *client, struct spa_hook *listener, diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 42612f1da..9e51d21a9 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -99,8 +99,6 @@ struct pw_client { struct pw_properties *properties; /**< Client properties */ struct pw_client_info info; /**< client info */ - bool ucred_valid; /**< if the ucred member is valid */ - struct ucred ucred; /**< ucred information */ struct pw_resource *core_resource; /**< core resource object */