[RFC 5/8] kdbus: use LSM hooks in kdbus code

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Originates from:

https://github.com/lmctl/kdbus.git (branch: kdbus-lsm-v4.for-systemd-v212)
commit: aa0885489d19be92fa41c6f0a71df28763228a40

Signed-off-by: Karol Lewandowski <k.lewandowsk@xxxxxxxxxxx>
Signed-off-by: Paul Osmialowski <p.osmialowsk@xxxxxxxxxxx>
---
 ipc/kdbus/bus.c        | 12 ++++++++++-
 ipc/kdbus/bus.h        |  3 +++
 ipc/kdbus/connection.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++
 ipc/kdbus/connection.h |  4 ++++
 ipc/kdbus/domain.c     |  9 ++++++++-
 ipc/kdbus/domain.h     |  2 ++
 ipc/kdbus/endpoint.c   | 11 ++++++++++
 ipc/kdbus/names.c      | 11 ++++++++++
 ipc/kdbus/queue.c      | 30 ++++++++++++++++++----------
 9 files changed, 124 insertions(+), 12 deletions(-)

diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c
index bbdf0f2..9894895 100644
--- a/ipc/kdbus/bus.c
+++ b/ipc/kdbus/bus.c
@@ -22,6 +22,7 @@
 #include <linux/slab.h>
 #include <linux/uaccess.h>
 #include <linux/uio.h>
+#include <linux/security.h>
 
 #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,12 @@ static struct kdbus_bus *kdbus_bus_new(struct kdbus_domain *domain,
 		goto exit_unref;
 	}
 
+	ret = security_kdbus_bus_alloc(b);
+	if (ret) {
+		ret = -EPERM;
+		goto exit_unref;
+	}
+
 	/*
 	 * Bus-limits of the creator are accounted on its real UID, just like
 	 * all other per-user limits.
@@ -169,11 +177,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 5bea5ef..03e4a54 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,8 @@ struct kdbus_bus {
 	struct list_head notify_list;
 	spinlock_t notify_lock;
 	struct mutex notify_flush_lock;
+
+	void *security;
 };
 
 struct kdbus_bus *kdbus_bus_ref(struct kdbus_bus *bus);
diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
index 9993753..b85cdc7 100644
--- a/ipc/kdbus/connection.c
+++ b/ipc/kdbus/connection.c
@@ -31,6 +31,7 @@
 #include <linux/slab.h>
 #include <linux/syscalls.h>
 #include <linux/uio.h>
+#include <linux/security.h>
 
 #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,14 @@ 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) {
+		ret = -EPERM;
+		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 +287,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);
@@ -1107,6 +1119,12 @@ 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) {
+		ret = -EPERM;
+		goto exit;
+	}
+
 	mutex_lock(&dst->lock);
 	reply = kdbus_reply_find(src, dst, kmsg->msg.cookie_reply);
 	if (reply) {
@@ -1187,6 +1205,12 @@ static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src,
 	if (ret < 0)
 		goto exit;
 
+	ret = security_kdbus_talk(src, dst);
+	if (ret) {
+		ret = -EPERM;
+		goto exit;
+	}
+
 	if (!kdbus_conn_policy_talk(src, current_cred(), dst)) {
 		ret = -EPERM;
 		goto exit;
@@ -1248,6 +1272,12 @@ 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) {
+		ret = -EPERM;
+		goto exit;
+	}
+
 	if (is_signal) {
 		/* like broadcasts we eavesdrop even if the msg is dropped */
 		kdbus_bus_eavesdrop(bus, src, kmsg);
@@ -1639,6 +1669,12 @@ 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) {
+			ret = -EPERM;
+			goto exit;
+		}
+
 		ret = kdbus_policy_set(&c->ep->bus->policy_db, args.items,
 				       args.items_size, 1,
 				       kdbus_conn_is_policy_holder(c), c);
@@ -1732,6 +1768,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 -EPERM;
+
 	/* registry must be held throughout lookup *and* collecting data */
 	down_read(&bus->name_registry->rwlock);
 
@@ -1905,6 +1945,12 @@ 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) {
+			ret = -EPERM;
+			goto exit;
+		}
+
 		ret = kdbus_policy_set(&conn->ep->bus->policy_db, cmd->items,
 				       KDBUS_ITEMS_SIZE(cmd, items),
 				       1, true, conn);
@@ -1948,6 +1994,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 -EPERM;
+
 	if (!kdbus_conn_is_ordinary(conn))
 		return -EOPNOTSUPP;
 
@@ -2044,6 +2094,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 -EPERM;
+
 	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 d1ffe90..1f91d39 100644
--- a/ipc/kdbus/connection.h
+++ b/ipc/kdbus/connection.h
@@ -19,6 +19,7 @@
 #include <linux/kref.h>
 #include <linux/lockdep.h>
 #include <linux/path.h>
+#include <uapi/linux/kdbus.h>
 
 #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,8 @@ struct kdbus_conn {
 
 	bool privileged:1;
 	bool faked_meta:1;
+
+	void *security;
 };
 
 struct kdbus_conn *kdbus_conn_ref(struct kdbus_conn *conn);
diff --git a/ipc/kdbus/domain.c b/ipc/kdbus/domain.c
index ac9f760..da9cdab 100644
--- a/ipc/kdbus/domain.c
+++ b/ipc/kdbus/domain.c
@@ -20,6 +20,7 @@
 #include <linux/sizes.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
+#include <linux/security.h>
 
 #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(-EPERM);
+
 	/* 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);
 }
 
@@ -264,7 +271,7 @@ static void __kdbus_user_free(struct kref *kref)
 	if (uid_valid(user->uid))
 		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 447a2bd..3db06d8 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,7 @@ struct kdbus_domain {
 	struct ida user_ida;
 	struct user_namespace *user_namespace;
 	struct dentry *dentry;
+	void *security;
 };
 
 /**
diff --git a/ipc/kdbus/endpoint.c b/ipc/kdbus/endpoint.c
index 9a95a5e..380228f 100644
--- a/ipc/kdbus/endpoint.c
+++ b/ipc/kdbus/endpoint.c
@@ -21,6 +21,7 @@
 #include <linux/slab.h>
 #include <linux/uaccess.h>
 #include <linux/uio.h>
+#include <linux/security.h>
 
 #include "bus.h"
 #include "connection.h"
@@ -122,6 +123,12 @@ 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) {
+		ret = -EPERM;
+		goto exit_unref;
+	}
+
 	ret = kdbus_node_link(&e->node, &bus->node, name);
 	if (ret < 0)
 		goto exit_unref;
@@ -265,6 +272,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 -EPERM;
+
 	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 d77ee08..dd20bea 100644
--- a/ipc/kdbus/names.c
+++ b/ipc/kdbus/names.c
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/uaccess.h>
 #include <linux/uio.h>
+#include <linux/security.h>
 
 #include "bus.h"
 #include "connection.h"
@@ -503,6 +504,12 @@ int kdbus_cmd_name_acquire(struct kdbus_conn *conn, void __user *argp)
 		goto exit;
 	}
 
+	ret = security_kdbus_name_acquire(conn, item_name);
+	if (ret) {
+		ret = -EPERM;
+		goto exit;
+	}
+
 	/*
 	 * Do atomic_inc_return here to reserve our slot, then decrement
 	 * it before returning.
@@ -724,6 +731,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 -EPERM;
+
 	/* lock order: domain -> bus -> ep -> names -> conn */
 	down_read(&reg->rwlock);
 	down_read(&conn->ep->bus->conn_rwlock);
diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c
index 25bb3ad..9872fb4 100644
--- a/ipc/kdbus/queue.c
+++ b/ipc/kdbus/queue.c
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/syscalls.h>
 #include <linux/uio.h>
+#include <linux/security.h>
 
 #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));
+				}
 			}
 		}
 
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux