From b594651fc7ce543682cdff841215d010d5028793 Mon Sep 17 00:00:00 2001
From: Paul Osmialowski
Date: Tue, 26 May 2015 12:00:33 +0200
Subject: [PATCH] kdbus: use LSM hooks in kdbus code
Originates from:
https://github.com/lmctl/kdbus.git (branch: kdbus-lsm-v4.for-systemd-v212)
commit: aa0885489d19be92fa41c6f0a71df28763228a40
Change-Id: Ibcba82b35d22846c2593a42a0c66feda6a115a0f
Signed-off-by: Karol Lewandowski
Signed-off-by: Paul Osmialowski
---
ipc/kdbus/bus.c | 11 +++++++++-
ipc/kdbus/bus.h | 5 +++++
ipc/kdbus/connection.c | 48 ++++++++++++++++++++++++++++++++++++++++++
ipc/kdbus/connection.h | 6 ++++++
ipc/kdbus/domain.c | 8 +++++++
ipc/kdbus/domain.h | 4 ++++
ipc/kdbus/endpoint.c | 10 +++++++++
ipc/kdbus/names.c | 10 +++++++++
ipc/kdbus/queue.c | 30 +++++++++++++++++---------
9 files changed, 121 insertions(+), 11 deletions(-)
diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c
index 9d0679eb59f6..b73efea7e76f 100644
--- a/ipc/kdbus/bus.c
+++ b/ipc/kdbus/bus.c
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
#include "bus.h"
#include "notify.h"
@@ -51,6 +52,7 @@ static void kdbus_bus_free(struct kdbus_node *node)
kdbus_domain_unref(bus->domain);
kdbus_policy_db_clear(&bus->policy_db);
kdbus_meta_proc_unref(bus->creator_meta);
+ security_kdbus_bus_free(bus);
kfree(bus);
}
@@ -161,6 +163,11 @@ static struct kdbus_bus *kdbus_bus_new(struct kdbus_domain *domain,
goto exit_unref;
}
+ ret = security_kdbus_bus_alloc(b);
+ if (ret) {
+ goto exit_unref;
+ }
+
/*
* Bus-limits of the creator are accounted on its real UID, just like
* all other per-user limits.
@@ -169,11 +176,13 @@ static struct kdbus_bus *kdbus_bus_new(struct kdbus_domain *domain,
if (IS_ERR(b->creator)) {
ret = PTR_ERR(b->creator);
b->creator = NULL;
- goto exit_unref;
+ goto exit_free_security;
}
return b;
+exit_free_security:
+ security_kdbus_bus_free(b);
exit_unref:
kdbus_node_deactivate(&b->node);
kdbus_node_unref(&b->node);
diff --git a/ipc/kdbus/bus.h b/ipc/kdbus/bus.h
index 5bea5ef768f1..521e69264b8c 100644
--- a/ipc/kdbus/bus.h
+++ b/ipc/kdbus/bus.h
@@ -53,6 +53,7 @@ struct kdbus_user;
* @notify_list: List of pending kernel-generated messages
* @notify_lock: Notification list lock
* @notify_flush_lock: Notification flushing lock
+ * @security: LSM security blob
*/
struct kdbus_bus {
struct kdbus_node node;
@@ -81,6 +82,10 @@ struct kdbus_bus {
struct list_head notify_list;
spinlock_t notify_lock;
struct mutex notify_flush_lock;
+
+#ifdef CONFIG_SECURITY
+ void *security;
+#endif
};
struct kdbus_bus *kdbus_bus_ref(struct kdbus_bus *bus);
diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
index ab476fa9ccca..f262fa00f421 100644
--- a/ipc/kdbus/connection.c
+++ b/ipc/kdbus/connection.c
@@ -31,6 +31,7 @@
#include
#include
#include
+#include
#include "bus.h"
#include "connection.h"
@@ -73,6 +74,8 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged,
bool is_activator;
bool is_monitor;
struct kvec kvec;
+ u32 sid, len;
+ char *label;
int ret;
struct {
@@ -222,6 +225,13 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged,
}
}
+ security_task_getsecid(current, &sid);
+ security_secid_to_secctx(sid, &label, &len);
+ ret = security_kdbus_connect(conn, label, len);
+ if (ret) {
+ goto exit_unref;
+ }
+
if (atomic_inc_return(&conn->user->connections) > KDBUS_USER_MAX_CONN) {
/* decremented by destructor as conn->user is valid */
ret = -EMFILE;
@@ -276,6 +286,7 @@ static void __kdbus_conn_free(struct kref *kref)
kdbus_pool_free(conn->pool);
kdbus_ep_unref(conn->ep);
put_cred(conn->cred);
+ security_kdbus_conn_free(conn);
kfree(conn->description);
kfree(conn->quota);
kfree(conn);
@@ -1115,6 +1126,11 @@ static int kdbus_conn_reply(struct kdbus_conn *src, struct kdbus_kmsg *kmsg)
if (ret < 0)
goto exit;
+ ret = security_kdbus_talk(src, dst);
+ if (ret) {
+ goto exit;
+ }
+
mutex_lock(&dst->lock);
reply = kdbus_reply_find(src, dst, kmsg->msg.cookie_reply);
if (reply) {
@@ -1204,6 +1220,11 @@ static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src,
if (ret < 0)
goto exit;
+ ret = security_kdbus_talk(src, dst);
+ if (ret) {
+ goto exit;
+ }
+
if (!kdbus_conn_policy_talk(src, current_cred(), dst)) {
ret = -EPERM;
goto exit;
@@ -1274,6 +1295,11 @@ static int kdbus_conn_unicast(struct kdbus_conn *src, struct kdbus_kmsg *kmsg)
if (ret < 0)
goto exit;
+ ret = security_kdbus_talk(src, dst);
+ if (ret) {
+ goto exit;
+ }
+
if (is_signal) {
/* like broadcasts we eavesdrop even if the msg is dropped */
kdbus_bus_eavesdrop(bus, src, kmsg);
@@ -1675,6 +1701,11 @@ struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, bool privileged,
if (ret < 0)
goto exit;
+ ret = security_kdbus_ep_setpolicy(c->ep->bus);
+ if (ret) {
+ goto exit;
+ }
+
ret = kdbus_policy_set(&c->ep->bus->policy_db, args.items,
args.items_size, 1,
kdbus_conn_is_policy_holder(c), c);
@@ -1768,6 +1799,10 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp)
if (ret != 0)
return ret;
+ ret = security_kdbus_conn_info(conn);
+ if (ret)
+ return ret;
+
/* registry must be held throughout lookup *and* collecting data */
down_read(&bus->name_registry->rwlock);
@@ -1941,6 +1976,11 @@ int kdbus_cmd_update(struct kdbus_conn *conn, void __user *argp)
/* now that we verified the input, update the connection */
if (item_policy) {
+ ret = security_kdbus_ep_setpolicy(conn->ep->bus);
+ if (ret) {
+ goto exit;
+ }
+
ret = kdbus_policy_set(&conn->ep->bus->policy_db, cmd->items,
KDBUS_ITEMS_SIZE(cmd, items),
1, true, conn);
@@ -1984,6 +2024,10 @@ int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp)
.argc = ARRAY_SIZE(argv),
};
+ ret = security_kdbus_send(conn, conn->ep->bus);
+ if (ret)
+ return ret;
+
if (!kdbus_conn_is_ordinary(conn))
return -EOPNOTSUPP;
@@ -2080,6 +2124,10 @@ int kdbus_cmd_recv(struct kdbus_conn *conn, void __user *argp)
.argc = ARRAY_SIZE(argv),
};
+ ret = security_kdbus_recv(conn, conn->ep->bus);
+ if (ret)
+ return ret;
+
if (!kdbus_conn_is_ordinary(conn) &&
!kdbus_conn_is_monitor(conn) &&
!kdbus_conn_is_activator(conn))
diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h
index d1ffe909cb31..951f9b0c915d 100644
--- a/ipc/kdbus/connection.h
+++ b/ipc/kdbus/connection.h
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include "limits.h"
#include "metadata.h"
@@ -73,6 +74,7 @@ struct kdbus_kmsg;
* @names_queue_list: Well-known names this connection waits for
* @privileged: Whether this connection is privileged on the bus
* @faked_meta: Whether the metadata was faked on HELLO
+ * @security: LSM security blob
*/
struct kdbus_conn {
struct kref kref;
@@ -113,6 +115,10 @@ struct kdbus_conn {
bool privileged:1;
bool faked_meta:1;
+
+#ifdef CONFIG_SECURITY
+ void *security;
+#endif
};
struct kdbus_conn *kdbus_conn_ref(struct kdbus_conn *conn);
diff --git a/ipc/kdbus/domain.c b/ipc/kdbus/domain.c
index ac9f760c150d..55202fe42fac 100644
--- a/ipc/kdbus/domain.c
+++ b/ipc/kdbus/domain.c
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
#include "bus.h"
#include "domain.h"
@@ -73,6 +74,7 @@ static void kdbus_domain_free(struct kdbus_node *node)
put_user_ns(domain->user_namespace);
ida_destroy(&domain->user_ida);
idr_destroy(&domain->user_idr);
+ security_kdbus_domain_free(domain);
kfree(domain);
}
@@ -104,6 +106,10 @@ struct kdbus_domain *kdbus_domain_new(unsigned int access)
idr_init(&d->user_idr);
ida_init(&d->user_ida);
+ ret = security_kdbus_domain_alloc(d);
+ if (ret)
+ return ERR_PTR(ret);
+
/* Pin user namespace so we can guarantee domain-unique bus * names. */
d->user_namespace = get_user_ns(current_user_ns());
@@ -116,6 +122,7 @@ struct kdbus_domain *kdbus_domain_new(unsigned int access)
exit_unref:
kdbus_node_deactivate(&d->node);
kdbus_node_unref(&d->node);
+ security_kdbus_domain_free(d);
return ERR_PTR(ret);
}
@@ -265,6 +272,7 @@ static void __kdbus_user_free(struct kref *kref)
idr_remove(&user->domain->user_idr, __kuid_val(user->uid));
mutex_unlock(&user->domain->lock);
+ security_kdbus_domain_free(user->domain);
kdbus_domain_unref(user->domain);
kfree(user);
}
diff --git a/ipc/kdbus/domain.h b/ipc/kdbus/domain.h
index 447a2bd4d972..4a935aaf0f2d 100644
--- a/ipc/kdbus/domain.h
+++ b/ipc/kdbus/domain.h
@@ -31,6 +31,7 @@
* @user_ida: Set of all users to compute small indices
* @user_namespace: User namespace, pinned at creation time
* @dentry: Root dentry of VFS mount (don't use outside of kdbusfs)
+ * @security: LSM security blob
*/
struct kdbus_domain {
struct kdbus_node node;
@@ -40,6 +41,9 @@ struct kdbus_domain {
struct ida user_ida;
struct user_namespace *user_namespace;
struct dentry *dentry;
+#ifdef CONFIG_SECURITY
+ void *security;
+#endif
};
/**
diff --git a/ipc/kdbus/endpoint.c b/ipc/kdbus/endpoint.c
index 174d274b113e..2b664635282b 100644
--- a/ipc/kdbus/endpoint.c
+++ b/ipc/kdbus/endpoint.c
@@ -21,6 +21,7 @@
#include
#include
#include
+#include
#include "bus.h"
#include "connection.h"
@@ -122,6 +123,11 @@ struct kdbus_ep *kdbus_ep_new(struct kdbus_bus *bus, const char *name,
kdbus_policy_db_init(&e->policy_db);
e->bus = kdbus_bus_ref(bus);
+ ret = security_kdbus_ep_create(bus);
+ if (ret) {
+ goto exit_unref;
+ }
+
ret = kdbus_node_link(&e->node, &bus->node, name);
if (ret < 0)
goto exit_unref;
@@ -265,6 +271,10 @@ int kdbus_cmd_ep_update(struct kdbus_ep *ep, void __user *argp)
.argc = ARRAY_SIZE(argv),
};
+ ret = security_kdbus_ep_setpolicy(ep->bus);
+ if (ret)
+ return ret;
+
ret = kdbus_args_parse(&args, argp, &cmd);
if (ret != 0)
return ret;
diff --git a/ipc/kdbus/names.c b/ipc/kdbus/names.c
index df99e4df815b..918a90d98a01 100644
--- a/ipc/kdbus/names.c
+++ b/ipc/kdbus/names.c
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include "bus.h"
#include "connection.h"
@@ -517,6 +518,11 @@ int kdbus_cmd_name_acquire(struct kdbus_conn *conn, void __user *argp)
goto exit;
}
+ ret = security_kdbus_name_acquire(conn, item_name);
+ if (ret) {
+ goto exit;
+ }
+
/*
* Do atomic_inc_return here to reserve our slot, then decrement
* it before returning.
@@ -740,6 +746,10 @@ int kdbus_cmd_list(struct kdbus_conn *conn, void __user *argp)
if (ret != 0)
return ret;
+ ret = security_kdbus_name_list(conn->ep->bus);
+ if (ret)
+ return ret;
+
/* lock order: domain -> bus -> ep -> names -> conn */
down_read(®->rwlock);
down_read(&conn->ep->bus->conn_rwlock);
diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c
index a449464a3975..e04aee6786fc 100644
--- a/ipc/kdbus/queue.c
+++ b/ipc/kdbus/queue.c
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#include "util.h"
#include "domain.h"
@@ -514,12 +515,17 @@ int kdbus_queue_entry_install(struct kdbus_queue_entry *entry,
for (i = 0; i < res->fds_count; i++) {
if (install_fds) {
- fds[i] = get_unused_fd_flags(O_CLOEXEC);
- if (fds[i] >= 0)
- fd_install(fds[i],
- get_file(res->fds[i]));
- else
+ if (security_file_receive(res->fds[i])) {
+ fds[i] = -1;
incomplete_fds = true;
+ } else {
+ fds[i] = get_unused_fd_flags(O_CLOEXEC);
+ if (fds[i] >= 0)
+ fd_install(fds[i],
+ get_file(res->fds[i]));
+ else
+ incomplete_fds = true;
+ }
} else {
fds[i] = -1;
}
@@ -557,13 +563,17 @@ int kdbus_queue_entry_install(struct kdbus_queue_entry *entry,
m.fd = -1;
if (install_fds) {
- m.fd = get_unused_fd_flags(O_CLOEXEC);
- if (m.fd < 0) {
- m.fd = -1;
+ if (security_file_receive(d->memfd.file)) {
incomplete_fds = true;
} else {
- fd_install(m.fd,
- get_file(d->memfd.file));
+ m.fd = get_unused_fd_flags(O_CLOEXEC);
+ if (m.fd < 0) {
+ m.fd = -1;
+ incomplete_fds = true;
+ } else {
+ fd_install(m.fd,
+ get_file(d->memfd.file));
+ }
}
}
--
2.34.1