lkml.org 
[lkml]   [2007]   [Nov]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[TOMOYO #5 13/18] Signal control functions.
    TOMOYO Linux checks sending signal by signal number and
    the domain of target process. In order to check signal
    permission, LSM expansion patch [TOMOYO 18/18] is needed.

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

    Signed-off-by: Kentaro Takeda <takedakn@nttdata.co.jp>
    Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
    security/tomoyo/signal.c | 227 +++++++++++++++++++++++++++++++++++++++++++++++
    1 file changed, 227 insertions(+)

    --- /dev/null 1970-01-01 00:00:00.000000000 +0000
    +++ linux-2.6-mm/security/tomoyo/signal.c 2007-11-14 15:15:44.000000000 +0900
    @@ -0,0 +1,227 @@
    +/*
    + * 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 bool is_granted,
    + const u8 profile,
    + const unsigned int mode)
    +{
    + 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, profile, mode);
    +
    + if (!buf)
    + return -ENOMEM;
    +
    + snprintf(buf + strlen(buf),
    + len - strlen(buf) - 1,
    + "%s%d %s\n",
    + TMY_ALLOW_SIGNAL, signal, dest_domain->name);
    +
    + return tmy_write_audit_log(buf, is_granted);
    +}
    +
    +/************************* 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 bool is_delete)
    +{
    + struct acl_info *ptr;
    + struct signal_acl *acl;
    + 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;
    +
    + mutex_lock(&domain_acl_lock);
    +
    + if (is_delete)
    + goto remove;
    +
    + list_for_each_entry(ptr, &domain->acl_info_list, list) {
    + 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;
    + goto ok;
    + }
    + }
    + /* Not found. Append it to the tail. */
    + acl = tmy_alloc_element(sizeof(*acl));
    + if (!acl)
    + goto ok;
    +
    + acl->head.type = TMY_TYPE_SIGNAL_ACL;
    + acl->head.cond = cond;
    + acl->sig = sig;
    + acl->domainname = saved_dest_pattern;
    + error = tmy_add_acl(domain, (struct acl_info *) acl);
    + goto ok;
    +remove: ;
    + error = -ENOENT;
    + list_for_each_entry(ptr, &domain->acl_info_list, list) {
    + 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: ;
    + mutex_unlock(&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 profile = domain->profile;
    + const unsigned int mode = tmy_flags(TMY_MAC_FOR_SIGNAL);
    + const bool is_enforce = (mode == 3);
    + bool found = 0;
    +
    + if (!mode)
    + return 0;
    + if (!sig)
    + return 0; /* No check for NULL signal. */
    + if (current->pid == pid) {
    + tmy_audit_signal_log(sig, domain->domainname, 1, profile, mode);
    + 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, profile, mode);
    + return 0;
    + }
    +
    + dest_pattern = dest->domainname->name;
    + list_for_each_entry(ptr, &domain->acl_info_list, list) {
    + 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')) {
    + found = 1;
    + break;
    + }
    + }
    + }
    +
    + tmy_audit_signal_log(sig, dest->domainname, found, profile, mode);
    +
    + if (found)
    + return 0;
    +
    + if (tmy_flags(TMY_VERBOSE))
    + tmy_audit("TOMOYO-%s: Signal %d to %s denied for %s\n",
    + tmy_getmsg(is_enforce), sig,
    + tmy_lastname(dest), tmy_lastname(domain));
    +
    + if (is_enforce)
    + return tmy_supervisor("%s\n" TMY_ALLOW_SIGNAL "%d %s\n",
    + domain->domainname->name,
    + sig, dest_pattern);
    + if (mode == 1 && tmy_quota())
    + 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 bool 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-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2007-11-16 18:47    [W:0.040 / U:210.140 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site