Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755034AbXJBHfh (ORCPT ); Tue, 2 Oct 2007 03:35:37 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1751433AbXJBHf2 (ORCPT ); Tue, 2 Oct 2007 03:35:28 -0400 Received: from ms0.nttdata.co.jp ([163.135.193.231]:33508 "EHLO ms0.nttdata.co.jp" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751596AbXJBHf1 (ORCPT ); Tue, 2 Oct 2007 03:35:27 -0400 Message-ID: <4701F4B4.3080507@nttdata.co.jp> Date: Tue, 02 Oct 2007 16:35:16 +0900 From: Kentaro Takeda User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.8.1.6) Gecko/20070728 Thunderbird/2.0.0.6 Mnenhy/0.7.5.0 MIME-Version: 1.0 To: linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org CC: chrisw@sous-sol.org Subject: [TOMOYO 08/15](repost) Argv[0] access control functions. References: <4701F285.5000206@nttdata.co.jp> In-Reply-To: <4701F285.5000206@nttdata.co.jp> Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-OriginalArrivalTime: 02 Oct 2007 07:35:17.0301 (UTC) FILETIME=[C740D650:01C804C6] Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 6048 Lines: 245 argv[0] check functions for TOMOYO Linux. If the executed program name and argv[0] is different, TOMOYO Linux checks permission. Each permission can be automatically accumulated into the policy of each domain using 'learning mode'. Signed-off-by: Kentaro Takeda Signed-off-by: Tetsuo Handa --- security/tomoyo/exec.c | 222 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 222 insertions(+) --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6/security/tomoyo/exec.c 2007-10-02 11:26:22.000000000 +0900 @@ -0,0 +1,222 @@ +/* + * security/tomoyo/exec.c + * + * Argv0 access control functions for TOMOYO Linux. + */ + +#include "tomoyo.h" +#include "realpath.h" + +/************************* AUDIT FUNCTIONS *************************/ + +static int tmy_audit_argv0_log(const struct path_info *filename, + const char *argv0, + 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 = filename->total_len + strlen(argv0) + 8; + buf = tmy_init_audit_log(&len); + + if (!buf) + return -ENOMEM; + + snprintf(buf + strlen(buf), + len - strlen(buf) - 1, + TMY_ALLOW_ARGV0 "%s %s", + filename->name, + argv0); + + return tmy_write_audit_log(buf, is_granted, is_enforce); +} + +/************************* ARGV0 MISMATCH HANDLER *************************/ + +static int tmy_add_argv0_entry(const char *filename, + const char *argv0, + struct domain_info *domain, + const struct condition_list *cond, + const u8 is_delete) +{ + struct acl_info *ptr; + const struct path_info *saved_filename; + const struct path_info *saved_argv0; + int error = -ENOMEM; + + if (!tmy_correct_path(filename, 1, 0, -1, __FUNCTION__) || + !tmy_correct_path(argv0, -1, 0, -1, __FUNCTION__) || + strchr(argv0, '/')) + return -EINVAL; + + saved_filename = tmy_save_name(filename); + saved_argv0 = tmy_save_name(argv0); + if (!saved_filename || !saved_argv0) + return -ENOMEM; + + down(&domain_acl_lock); + + if (is_delete) + goto remove; + + ptr = domain->first_acl_ptr; + if (!ptr) + goto first_entry; + while (1) { + struct argv0_acl *acl = (struct argv0_acl *) ptr; + + if (ptr->type == TMY_TYPE_ARGV0_ACL && ptr->cond == cond && + acl->filename == saved_filename && + acl->argv0 == saved_argv0) { + 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_ARGV0_ACL; + acl->head.cond = cond; + acl->filename = saved_filename; + acl->argv0 = saved_argv0; + 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 argv0_acl *acl = (struct argv0_acl *) ptr; + + if (ptr->type != TMY_TYPE_ARGV0_ACL || + ptr->cond != cond || ptr->is_deleted || + acl->filename != saved_filename || + acl->argv0 != saved_argv0) + continue; + + error = tmy_del_acl(ptr); + break; + } +ok: ; + up(&domain_acl_lock); + + return error; +} + +static int tmy_argv0_acl(const struct path_info *filename, + const char *argv0_) +{ + const struct domain_info *domain = TMY_SECURITY->domain; + int error = -EPERM; + struct acl_info *ptr; + struct path_info argv0; + + if (!tmy_flags(TMY_MAC_FOR_ARGV0)) + return 0; + + argv0.name = argv0_; + tmy_fill_path_info(&argv0); + + for (ptr = domain->first_acl_ptr; ptr; ptr = ptr->next) { + struct argv0_acl *acl = (struct argv0_acl *) ptr; + + if (ptr->type == TMY_TYPE_ARGV0_ACL && + ptr->is_deleted == 0 && + tmy_check_condition(ptr->cond, NULL) == 0 && + tmy_path_match(filename, acl->filename) && + tmy_path_match(&argv0, acl->argv0)) { + error = 0; + break; + } + } + + return error; +} + +/** + * tmy_argv0_perm - check for argv[0] permission. + * @filename: pointer to filename. + * @argv0: pointer to basename of argv[0]. + * + * Returns zero if permission granted. + * Returns nonzero if permission denied. + */ +int tmy_argv0_perm(const struct path_info *filename, const char *argv0) +{ + int error = 0; + const u8 is_enforce = tmy_enforce(TMY_MAC_FOR_ARGV0); + + if (!tmy_flags(TMY_MAC_FOR_ARGV0)) + return 0; + if (!filename || !argv0 || !*argv0) + return 0; + + error = tmy_argv0_acl(filename, argv0); + + tmy_audit_argv0_log(filename, argv0, !error, is_enforce); + + if (error) { + struct domain_info * const domain = TMY_SECURITY->domain; + + if (is_enforce) + error = tmy_supervisor("%s\n" TMY_ALLOW_ARGV0 "%s %s\n", + domain->domainname->name, + filename->name, argv0); + + else if (tmy_accept(TMY_MAC_FOR_ARGV0, domain)) + tmy_add_argv0_entry(filename->name, argv0, domain, + NULL, 0); + + if (!is_enforce) + error = 0; + } + + return error; +} + +/** + * tmy_add_argv0_policy - add or delete argv[0] 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_argv0_policy(char *data, + struct domain_info *domain, + const struct condition_list *cond, + const u8 is_delete) +{ + char *argv0 = strchr(data, ' '); + + if (!argv0) + return -EINVAL; + + *argv0++ = '\0'; + + return tmy_add_argv0_entry(data, argv0, domain, cond, + is_delete); +} - 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/