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-security-module" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to