Signal control functions for TOMOYO Linux.
TOMOYO Linux checks sending signal by signal number and
the domain of target process. In order to check signal
permission, LSM expansion patch [TOMOYO 14/15] is needed.

Each permission can be automatically accumulated into
the policy of each domain using 'learning mode'.

Signed-off-by: Kentaro Takeda <[EMAIL PROTECTED]>
Signed-off-by: Tetsuo Handa <[EMAIL PROTECTED]>
---
 security/tomoyo/signal.c |  229 +++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 229 insertions(+)

--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/security/tomoyo/signal.c  2007-10-02 11:26:22.000000000 +0900
@@ -0,0 +1,229 @@
+/*
+ * security/tomoyo/signal.c
+ *
+ * Signal access contol functions for TOMOYO Linux.
+ */
+
+#include "tomoyo.h"
+#include "realpath.h"
+
+/*************************  AUDIT FUNCTIONS  *************************/
+
+static int tmy_audit_signal_log(const int signal,
+                               const struct path_info *dest_domain,
+                               const u8 is_granted,
+                               const u8 is_enforce)
+{
+       char *buf;
+       int len;
+
+       if (is_granted) {
+               if (!tmy_audit_grant())
+                       return 0;
+       } else {
+               if (!tmy_audit_reject())
+                       return 0;
+       }
+
+       len = dest_domain->total_len;
+       buf = tmy_init_audit_log(&len);
+
+       if (!buf)
+               return -ENOMEM;
+
+       snprintf(buf + strlen(buf),
+                len - strlen(buf) - 1,
+                "%s%d %s",
+                TMY_ALLOW_SIGNAL, signal, dest_domain->name);
+
+       return tmy_write_audit_log(buf, is_granted, is_enforce);
+}
+
+/*************************  SIGNAL ACL HANDLER  *************************/
+
+static int tmy_add_signal_entry(const u16 sig, const char *dest_pattern,
+                               struct domain_info *domain,
+                               const struct condition_list *cond,
+                               const u8 is_delete)
+{
+       struct acl_info *ptr;
+       const struct path_info *saved_dest_pattern;
+       int error = -ENOMEM;
+
+       if (!domain)
+               return -EINVAL;
+       if (!dest_pattern ||
+           !tmy_is_correct_domain(dest_pattern, __FUNCTION__))
+               return -EINVAL;
+
+       saved_dest_pattern = tmy_save_name(dest_pattern);
+       if (!saved_dest_pattern)
+               return -ENOMEM;
+
+       down(&domain_acl_lock);
+
+       if (is_delete)
+               goto remove;
+
+       ptr = domain->first_acl_ptr;
+       if (!ptr)
+               goto first_entry;
+
+       while (1) {
+               struct signal_acl *acl = (struct signal_acl *) ptr;
+
+               if (ptr->type == TMY_TYPE_SIGNAL_ACL && acl->sig == sig
+                   && ptr->cond == cond
+                   && !tmy_pathcmp(acl->domainname, saved_dest_pattern)) {
+                       ptr->is_deleted = 0;
+                       /* Found. Nothing to do. */
+                       error = 0;
+                       break;
+               }
+
+               if (ptr->next) {
+                       ptr = ptr->next;
+                       continue;
+               }
+
+first_entry: ;
+               /* Not found. Append it to the tail. */
+               acl = tmy_alloc_element(sizeof(*acl));
+               if (!acl)
+                       break;
+
+               acl->head.type = TMY_TYPE_SIGNAL_ACL;
+               acl->head.cond = cond;
+               acl->sig = sig;
+               acl->domainname = saved_dest_pattern;
+               error = tmy_add_acl(ptr, domain, (struct acl_info *) acl);
+               break;
+       }
+       goto ok;
+remove: ;
+       error = -ENOENT;
+       for (ptr = domain->first_acl_ptr; ptr; ptr = ptr->next) {
+               struct signal_acl *acl = (struct signal_acl *) ptr;
+               if (ptr->type != TMY_TYPE_SIGNAL_ACL || ptr->cond != cond ||
+                   ptr->is_deleted || acl->sig != sig ||
+                   tmy_pathcmp(acl->domainname, saved_dest_pattern))
+                       continue;
+               error = tmy_del_acl(ptr);
+               break;
+       }
+
+ok: ;
+       up(&domain_acl_lock);
+
+       return error;
+}
+
+/**
+ * tmy_signal_acl - check permission for kill(2)/tkill(2)/tgkill(2).
+ * @sig:  signal number.
+ * @pid:  pid of destination process.
+ *
+ * Returns zero if permission granted.
+ * Returns nonzero if permission denied.
+ */
+int tmy_signal_acl(const int sig, const int pid)
+{
+       struct domain_info *domain = TMY_SECURITY->domain;
+       struct domain_info *dest = NULL;
+       const char *dest_pattern;
+       struct acl_info *ptr;
+       const u16 hash = sig;
+       const u8 is_enforce = tmy_enforce(TMY_MAC_FOR_SIGNAL);
+
+       if (!tmy_flags(TMY_MAC_FOR_SIGNAL))
+               return 0;
+       if (!sig)
+               return 0; /* No check for NULL signal. */
+       if (current->pid == pid) {
+               tmy_audit_signal_log(sig, domain->domainname, 1, is_enforce);
+               return 0; /* No check for self. */
+       }
+
+       { /* Simplified checking. */
+               struct task_struct *p = NULL;
+               read_lock(&tasklist_lock);
+               if (pid > 0)
+                       p = find_task_by_pid((pid_t) pid);
+               else if (pid == 0)
+                       p = current;
+               else if (pid == -1)
+                       dest = &KERNEL_DOMAIN;
+               else
+                       p = find_task_by_pid((pid_t) -pid);
+               if (p)
+                       /* "struct task_struct"->security is not NULL. */
+                       dest = ((struct tmy_security *) p->security)->domain;
+               read_unlock(&tasklist_lock);
+               if (!dest)
+                       return 0; /* I can't find destinatioin. */
+       }
+
+       if (domain == dest) {
+               tmy_audit_signal_log(sig, dest->domainname, 1, is_enforce);
+               return 0;
+       }
+
+       dest_pattern = dest->domainname->name;
+       for (ptr = domain->first_acl_ptr; ptr; ptr = ptr->next) {
+               struct signal_acl *acl = (struct signal_acl *) ptr;
+
+               if (ptr->type == TMY_TYPE_SIGNAL_ACL && ptr->is_deleted == 0
+                   && acl->sig == hash &&
+                   tmy_check_condition(ptr->cond, NULL) == 0) {
+                       const int len = acl->domainname->total_len;
+
+                       if (strncmp(acl->domainname->name,
+                                   dest_pattern, len) == 0
+                           && (dest_pattern[len] == ' ' ||
+                               dest_pattern[len] == '\0'))
+                               break;
+
+               }
+       }
+
+       if (ptr) {
+               tmy_audit_signal_log(sig, dest->domainname, 1, is_enforce);
+               return 0;
+       }
+
+       tmy_audit_signal_log(sig, dest->domainname, 0, is_enforce);
+       if (is_enforce)
+               return tmy_supervisor("%s\n" TMY_ALLOW_SIGNAL "%d %s\n",
+                                     domain->domainname->name,
+                                     sig, dest_pattern);
+       if (tmy_accept(TMY_MAC_FOR_SIGNAL, domain))
+               tmy_add_signal_entry(sig, dest_pattern, domain, NULL, 0);
+
+       return 0;
+}
+
+/**
+ * tmy_add_signal_policy - add or delete signal policy.
+ * @data:      a line to parse.
+ * @domain:    pointer to "struct domain_info".
+ * @cond:      pointer to "struct condition_list". May be NULL.
+ * @is_delete: is this delete request?
+ *
+ * Returns zero on success.
+ * Returns nonzero on failure.
+ */
+int tmy_add_signal_policy(char *data,
+                         struct domain_info *domain,
+                         const struct condition_list *cond,
+                         const u8 is_delete)
+{
+       int sig;
+       char *domainname = strchr(data, ' ');
+
+       if (sscanf(data, "%d", &sig) == 1 && domainname &&
+           tmy_is_domain_def(domainname + 1))
+               return tmy_add_signal_entry(sig, domainname + 1, domain,
+                                           cond, is_delete);
+
+       return -EINVAL;
+}


-
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