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)
This commit is contained in:
Wim Taymans 2019-05-10 13:12:22 +02:00
parent e0eeedc369
commit 3854f8557a
5 changed files with 49 additions and 52 deletions

View file

@ -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;

View file

@ -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)

View file

@ -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)
{

View file

@ -24,12 +24,6 @@
extern "C" {
#endif
#ifndef __USE_GNU
#define __USE_GNU
#endif
#include <sys/socket.h>
#include <spa/utils/hook.h>
/** \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,

View file

@ -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 */