From patchwork Fri Oct 21 12:49:04 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tetsuo Handa X-Patchwork-Id: 9388915 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 8FE66607F0 for ; Fri, 21 Oct 2016 12:53:07 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8182729195 for ; Fri, 21 Oct 2016 12:53:07 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 75F1B2A183; Fri, 21 Oct 2016 12:53:07 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DF41B29195 for ; Fri, 21 Oct 2016 12:53:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933712AbcJUMuz (ORCPT ); Fri, 21 Oct 2016 08:50:55 -0400 Received: from www262.sakura.ne.jp ([202.181.97.72]:39023 "EHLO www262.sakura.ne.jp" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933532AbcJUMth (ORCPT ); Fri, 21 Oct 2016 08:49:37 -0400 Received: from fsav301.sakura.ne.jp (fsav301.sakura.ne.jp [153.120.85.132]) by www262.sakura.ne.jp (8.14.5/8.14.5) with ESMTP id u9LCnTLb029086; Fri, 21 Oct 2016 21:49:29 +0900 (JST) (envelope-from penguin-kernel@I-love.SAKURA.ne.jp) Received: from www262.sakura.ne.jp (202.181.97.72) by fsav301.sakura.ne.jp (F-Secure/fsigk_smtp/530/fsav301.sakura.ne.jp); Fri, 21 Oct 2016 21:49:29 +0900 (JST) X-Virus-Status: clean(F-Secure/fsigk_smtp/530/fsav301.sakura.ne.jp) Received: from ccsecurity.localdomain (softbank126227147111.bbtec.net [126.227.147.111]) (authenticated bits=0) by www262.sakura.ne.jp (8.14.5/8.14.5) with ESMTP id u9LCnMFm029053 (version=TLSv1/SSLv3 cipher=DHE-RSA-CAMELLIA256-SHA bits=256 verify=NO); Fri, 21 Oct 2016 21:49:29 +0900 (JST) (envelope-from penguin-kernel@I-love.SAKURA.ne.jp) From: Tetsuo Handa To: linux-security-module@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Tetsuo Handa Subject: [PATCH 2/8] CaitSith: Add pathname calculation functions. Date: Fri, 21 Oct 2016 21:49:04 +0900 Message-Id: <1477054150-4772-3-git-send-email-penguin-kernel@I-love.SAKURA.ne.jp> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1477054150-4772-1-git-send-email-penguin-kernel@I-love.SAKURA.ne.jp> References: <1477054150-4772-1-git-send-email-penguin-kernel@I-love.SAKURA.ne.jp> Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP This is a simplified version of security/tomoyo/realpath.c , except two changes listed below. A "\" character (0x5C) in TOMOYO is represented as "\\" while it in CaitSith is represented as "\134". This allows us to tell whether a "\" character at any position is a literal "\" character without scanning from the beginning of the string. A "/" character (0x2F) is appended in TOMOYO in order to represent a directory while it is not appended in CaitSith. In CaitSith, path.type variable which will be implemented after this version is accepted will allow us to tell whether a pathname represents a directory without appending a "/" character. Signed-off-by: Tetsuo Handa --- security/caitsith/realpath.c | 227 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 security/caitsith/realpath.c diff --git a/security/caitsith/realpath.c b/security/caitsith/realpath.c new file mode 100644 index 0000000..f62d843 --- /dev/null +++ b/security/caitsith/realpath.c @@ -0,0 +1,227 @@ +/* + * security/caitsith/realpath.c + * + * Copyright (C) 2005-2012 NTT DATA CORPORATION + */ + +#include "caitsith.h" + +/** + * cs_realpath - Returns realpath(3) of the given pathname but ignores chroot'ed root. + * + * @path: Pointer to "struct path". + * + * Returns the realpath of the given @path on success, NULL otherwise. + * + * This function uses kzalloc(), so caller must kfree() if this function + * didn't return NULL. + */ +char *cs_realpath(const struct path *path) +{ + char *buf = NULL; + char *name = NULL; + unsigned int buf_len = PAGE_SIZE / 2; + struct dentry *dentry = path->dentry; + struct super_block *sb; + + if (!dentry) + return NULL; + sb = dentry->d_sb; + while (1) { + char *pos; + + buf_len <<= 1; + kfree(buf); + buf = kmalloc(buf_len, GFP_NOFS); + if (!buf) + break; + /* To make sure that pos is '\0' terminated. */ + buf[buf_len - 1] = '\0'; + /* For "pipe:[\$]". */ + if (dentry->d_op && dentry->d_op->d_dname) + pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1); + else + pos = d_absolute_path(path, buf, buf_len); + if (IS_ERR(pos)) + continue; + name = cs_encode(pos); + break; + } + kfree(buf); + if (!name) + cs_warn_oom(__func__); + return name; +} + +/** + * cs_encode2 - Encode binary string to ascii string. + * + * @str: String in binary format. Maybe NULL. + * @str_len: Size of @str in byte. + * + * Returns pointer to @str in ascii format on success, NULL otherwise. + * + * This function uses kzalloc(), so caller must kfree() if this function + * didn't return NULL. + */ +static char *cs_encode2(const char *str, int str_len) +{ + int i; + int len; + const char *p = str; + char *cp; + char *cp0; + + if (!p) + return NULL; + len = str_len; + for (i = 0; i < str_len; i++) { + const unsigned char c = p[i]; + + if (!(c > ' ' && c < 127 && c != '\\')) + len += 3; + } + len++; + cp = kzalloc(len, GFP_NOFS); + if (!cp) + return NULL; + cp0 = cp; + p = str; + for (i = 0; i < str_len; i++) { + const unsigned char c = p[i]; + + if (c > ' ' && c < 127 && c != '\\') { + *cp++ = c; + } else { + *cp++ = '\\'; + *cp++ = (c >> 6) + '0'; + *cp++ = ((c >> 3) & 7) + '0'; + *cp++ = (c & 7) + '0'; + } + } + return cp0; +} + +/** + * cs_encode - Encode binary string to ascii string. + * + * @str: String in binary format. Maybe NULL. + * + * Returns pointer to @str in ascii format on success, NULL otherwise. + * + * This function uses kzalloc(), so caller must kfree() if this function + * didn't return NULL. + */ +char *cs_encode(const char *str) +{ + return str ? cs_encode2(str, strlen(str)) : NULL; +} + +/** + * cs_const_part_length - Evaluate the initial length without a pattern in a token. + * + * @filename: The string to evaluate. Maybe NULL. + * + * Returns the initial length without a pattern in @filename. + */ +static int cs_const_part_length(const char *filename) +{ + char c; + int len = 0; + + if (!filename) + return 0; + while (1) { + c = *filename++; + if (!c) + break; + if (c != '\\') { + len++; + continue; + } + c = *filename++; + switch (c) { + case '0': /* "\ooo" */ + case '1': + case '2': + case '3': + c = *filename++; + if (c < '0' || c > '7') + break; + c = *filename++; + if (c < '0' || c > '7') + break; + len += 4; + continue; + } + break; + } + return len; +} + +/** + * cs_fill_path_info - Fill in "struct cs_path_info" members. + * + * @ptr: Pointer to "struct cs_path_info" to fill in. + * + * Returns nothing. + * + * The caller sets "struct cs_path_info"->name. + */ +void cs_fill_path_info(struct cs_path_info *ptr) +{ + const char *name = ptr->name; + const int len = strlen(name); + + ptr->total_len = len; + ptr->const_len = cs_const_part_length(name); + ptr->hash = full_name_hash(NULL, name, len); +} + +/** + * cs_get_exe - Get cs_realpath() of current process. + * + * Returns the cs_realpath() of current process on success, NULL otherwise. + * + * This function uses kzalloc(), so the caller must kfree() + * if this function didn't return NULL. + */ +char *cs_get_exe(void) +{ + struct mm_struct *mm = current->mm; + char *cp; + struct file *exe_file; + + if (current->flags & PF_KTHREAD) + return kstrdup("", GFP_NOFS); + if (!mm) + goto task_has_no_mm; + exe_file = get_mm_exe_file(mm); + if (!exe_file) + goto task_has_no_mm; + cp = cs_realpath(&exe_file->f_path); + fput(exe_file); + return cp; +task_has_no_mm: + return kstrdup("", GFP_NOFS); +} + +/** + * cs_get_exename - Get cs_realpath() of current process. + * + * @buf: Pointer to "struct cs_path_info". + * + * Returns true on success, false otherwise. + * + * This function uses kzalloc(), so the caller must kfree() + * if this function returned true. + */ +bool cs_get_exename(struct cs_path_info *buf) +{ + buf->name = cs_get_exe(); + if (buf->name) { + cs_fill_path_info(buf); + return true; + } + return false; +}