[PATCH 06/24] CRED: Request a credential record for a kernel service

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

 



Request a credential record for the named kernel service.  This produces a
cred struct with appropriate DAC and MAC controls for effecting that service.
It may be used to override the credentials on a task to do work on that task's
behalf.

Signed-off-by: David Howells <[email protected]>
---

 include/linux/cred.h     |    2 +
 include/linux/security.h |   43 +++++++++++++++++++++++++++++
 kernel/cred.c            |   68 ++++++++++++++++++++++++++++++++++++++++++++++
 security/dummy.c         |   13 +++++++++
 security/selinux/hooks.c |   47 ++++++++++++++++++++++++++++++++
 5 files changed, 173 insertions(+), 0 deletions(-)

diff --git a/include/linux/cred.h b/include/linux/cred.h
index 78924d5..b2d0ac9 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -51,6 +51,8 @@ extern void change_fsgid(struct cred *, gid_t);
 extern void change_groups(struct cred *, struct group_info *);
 extern void change_cap(struct cred *, kernel_cap_t);
 extern struct cred *dup_cred(const struct cred *);
+extern struct cred *get_kernel_cred(const char *, struct task_struct *);
+extern int change_create_files_as(struct cred *, struct inode *);
 
 /**
  * get_cred - Get an extra reference on a credentials record
diff --git a/include/linux/security.h b/include/linux/security.h
index 0933333..b7c06c3 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -514,6 +514,18 @@ struct request_sock;
  * @cred_destroy:
  *	Destroy the credentials attached to a cred structure.
  *	@cred points to the credentials structure that is to be destroyed.
+ * @cred_kernel_act_as:
+ *	Set the credentials for a kernel service to act as (subjective context).
+ *	@cred points to the credentials structure to be filled in.
+ *	@service names the service making the request.
+ *	@daemon: A userspace daemon to be used as a base for the context.
+ *	Return 0 if successful.
+ * @cred_create_files_as:
+ *	Set the file creation context in a credentials record to be the same as
+ *	the objective context of an inode.
+ *	@cred points to the credentials structure to be altered.
+ *	@inode points to the inode to use as a reference.
+ *	Return 0 if successful.
  *
  * Security hooks for task operations.
  *
@@ -1275,6 +1287,9 @@ struct security_operations {
 
 	int (*cred_dup)(struct cred *cred);
 	void (*cred_destroy)(struct cred *cred);
+	int (*cred_kernel_act_as)(struct cred *cred, const char *service,
+			       struct task_struct *daemon);
+	int (*cred_create_files_as)(struct cred *cred, struct inode *inode);
 
 	int (*task_create) (unsigned long clone_flags);
 	int (*task_alloc_security) (struct task_struct * p);
@@ -1894,6 +1909,21 @@ static inline void security_cred_destroy(struct cred *cred)
 	return security_ops->cred_destroy(cred);
 }
 
+static inline int security_cred_kernel_act_as(struct cred *cred,
+					   const char *service,
+					   struct task_struct *daemon)
+{
+	return security_ops->cred_kernel_act_as(cred, service, daemon);
+}
+
+static inline int security_cred_create_files_as(struct cred *cred,
+						struct inode *inode)
+{
+	if (IS_PRIVATE(inode))
+		return -EINVAL;
+	return security_ops->cred_create_files_as(cred, inode);
+}
+
 static inline int security_task_create (unsigned long clone_flags)
 {
 	return security_ops->task_create (clone_flags);
@@ -2586,6 +2616,19 @@ static inline void security_cred_destroy(struct cred *cred)
 {
 }
 
+static inline int security_cred_kernel_act_as(struct cred *cred,
+					      const char *service,
+					      struct task_struct *daemon)
+{
+	return 0;
+}
+
+static inline int security_cred_create_files_as(struct cred *cred,
+						struct inode *inode)
+{
+	return 0;
+}
+
 static inline int security_task_create (unsigned long clone_flags)
 {
 	return 0;
diff --git a/kernel/cred.c b/kernel/cred.c
index f545634..294b33a 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -210,3 +210,71 @@ void change_cap(struct cred *cred, kernel_cap_t cap)
 }
 
 EXPORT_SYMBOL(change_cap);
+
+/**
+ * get_kernel_cred - Get credentials for a named kernel service
+ * @service: The name of the service
+ * @daemon: A userspace daemon to be used as a base for the context
+ *
+ * Get a set of credentials for a specific kernel service.  These can then be
+ * used to override a task's credentials so that work can be done on behalf of
+ * that task.
+ *
+ * @daemon is used to provide a base for the security context, but can be NULL.
+ * If @deamon is supplied, then the cred's uid, gid and groups list will be
+ * derived from that; otherwise they'll be set to 0 and no groups.
+ *
+ * @daemon is also passd to the LSM module as a base from which to initialise
+ * any MAC controls.
+ *
+ * The caller may change these controls afterwards if desired.
+ */
+struct cred *get_kernel_cred(const char *service,
+			     struct task_struct *daemon)
+{
+	struct cred *cred, *dcred;
+	int ret;
+
+	cred = kzalloc(sizeof *cred, GFP_KERNEL);
+	if (!cred)
+		return ERR_PTR(-ENOMEM);
+
+	if (daemon) {
+		rcu_read_lock();
+		dcred = task_cred(daemon);
+		cred->uid = dcred->uid;
+		cred->gid = dcred->gid;
+		cred->group_info = dcred->group_info;
+		atomic_inc(&cred->group_info->usage);
+		rcu_read_unlock();
+	} else {
+		cred->group_info = &init_groups;
+		atomic_inc(&init_groups.usage);
+	}
+
+	ret = security_cred_kernel_act_as(cred, service, daemon);
+	if (ret < 0) {
+		put_cred(cred);
+		return ERR_PTR(ret);
+	}
+
+	return cred;
+}
+
+EXPORT_SYMBOL(get_kernel_cred);
+
+/**
+ * change_create_files_as - Change the file creation context in a new cred record
+ * @cred: The credential record to alter
+ * @inode: The inode to take the context from
+ *
+ * Change the file creation context in a new credentials record to be the same
+ * as the object context of the specified inode, so that the new inodes have
+ * the same MAC context as that inode.
+ */
+int change_create_files_as(struct cred *cred, struct inode *inode)
+{
+	return security_cred_create_files_as(cred, inode);
+}
+
+EXPORT_SYMBOL(change_create_files_as);
diff --git a/security/dummy.c b/security/dummy.c
index 7e52156..348c09b 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -488,6 +488,17 @@ static void dummy_cred_destroy(struct cred *cred)
 {
 }
 
+static int dummy_cred_kernel_act_as(struct cred *cred, const char *service,
+				    struct task_struct *daemon)
+{
+	return 0;
+}
+
+static int dummy_cred_create_files_as(struct cred *cred, struct inode *inode)
+{
+	return 0;
+}
+
 static int dummy_task_create (unsigned long clone_flags)
 {
 	return 0;
@@ -1064,6 +1075,8 @@ void security_fixup_ops (struct security_operations *ops)
 	set_to_dummy_if_null(ops, file_receive);
 	set_to_dummy_if_null(ops, cred_dup);
 	set_to_dummy_if_null(ops, cred_destroy);
+	set_to_dummy_if_null(ops, cred_kernel_act_as);
+	set_to_dummy_if_null(ops, cred_create_files_as);
 	set_to_dummy_if_null(ops, task_create);
 	set_to_dummy_if_null(ops, task_alloc_security);
 	set_to_dummy_if_null(ops, task_free_security);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 2ee1712..fc4e75d 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2771,6 +2771,51 @@ static void selinux_cred_destroy(struct cred *cred)
 	kfree(cred->security);
 }
 
+/*
+ * get the credentials for a kernel service, deriving the subjective context
+ * from the credentials of a userspace daemon if one supplied
+ * - all the creation contexts are set to unlabelled
+ */
+static int selinux_cred_kernel_act_as(struct cred *cred,
+				      const char *service,
+				      struct task_struct *daemon)
+{
+	struct task_security_struct *tsec;
+	struct cred_security_struct *csec;
+	u32 ksid;
+	int ret;
+
+	tsec = daemon ? daemon->security : init_task.security;
+
+	ret = security_transition_sid(tsec->victim_sid, SECINITSID_KERNEL,
+				      SECCLASS_PROCESS, &ksid);
+	if (ret < 0)
+		return ret;
+
+	csec = kzalloc(sizeof(struct cred_security_struct), GFP_KERNEL);
+	if (!csec)
+		return -ENOMEM;
+
+	csec->action_sid = ksid;
+	csec->create_sid = SECINITSID_UNLABELED;
+	csec->keycreate_sid = SECINITSID_UNLABELED;
+	csec->sockcreate_sid = SECINITSID_UNLABELED;
+	cred->security = csec;
+	return 0;
+}
+
+/*
+ * set the file creation context in a credentials record to the same as the
+ * objective context of the specified inode
+ */
+static int selinux_cred_create_files_as(struct cred *cred, struct inode *inode)
+{
+	struct cred_security_struct *csec = cred->security;
+	struct inode_security_struct *isec = inode->i_security;
+
+	csec->create_sid = isec->sid;
+	return 0;
+}
 
 /* task security operations */
 
@@ -4888,6 +4933,8 @@ static struct security_operations selinux_ops = {
 
 	.cred_dup =			selinux_cred_dup,
 	.cred_destroy =			selinux_cred_destroy,
+	.cred_kernel_act_as =		selinux_cred_kernel_act_as,
+	.cred_create_files_as =		selinux_cred_create_files_as,
 
 	.task_create =			selinux_task_create,
 	.task_alloc_security =		selinux_task_alloc_security,

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux