From patchwork Sun Apr 9 10:42:08 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Djalal Harouni X-Patchwork-Id: 9671501 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 38D7C601EB for ; Sun, 9 Apr 2017 10:43:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 15A712847A for ; Sun, 9 Apr 2017 10:43:56 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0A5EB284D3; Sun, 9 Apr 2017 10:43:56 +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.3 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID autolearn=ham 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 6F73C2847A for ; Sun, 9 Apr 2017 10:43:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752391AbdDIKnx (ORCPT ); Sun, 9 Apr 2017 06:43:53 -0400 Received: from mail-wm0-f65.google.com ([74.125.82.65]:33729 "EHLO mail-wm0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751961AbdDIKn1 (ORCPT ); Sun, 9 Apr 2017 06:43:27 -0400 Received: by mail-wm0-f65.google.com with SMTP id o81so5053098wmb.0; Sun, 09 Apr 2017 03:43:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=PMm9pFRu/MhAuIigsHPMJmnrO7knEOvOkjhp0O/ozi8=; b=MjuRuzebvj6ZV3EdB1NduaVoLzxymoaRieUM3qVXL5/ap4cQxsvm23M1DT9VZInk4b UbmqGmAxzflp8c9QwYKQIi9kOyx6YHCjRJQmXXOpT7r2IhbjrL/YJMFOIyhGPNZ/SWJK 4gK75mLR1ENA5J2u5Cx9Xe8q0qZYD9ftwPnYJolwix+uDa/bQHtq4wt4ozFnZIYIxDgM bF983VFlk6rPc9RGpROaekdkfF012e7ksN0J5wSY0jquNyEX9R1/o5Ia9q/vAK4MIguZ FO9JEtg6b+Kbku1+Z0NOpYspldz4Xih3PqqRWOeCAWZ0g6LHAxmP4ICOxUbmJQCjayBA EpAA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=PMm9pFRu/MhAuIigsHPMJmnrO7knEOvOkjhp0O/ozi8=; b=Lgvq5Zh75MDtoxGGDqQpfi5isJxe/2f3Toi/Fh/Rp8PCafiD/EKD1CS8EYkCi0ky4w v7EiTgebTdC18jHbSBd6hdvoNFltcJdMeIIgmcCqDZkJ6tqcuAhWyq5i/o40xq4uACVZ fAMytHZFQB45y7FHPMShWlRWL8GjfISYaEzycVADA2Cg9HbhBUeH+PpxOzdggnowNB6o axyql+t9dQxYmZdtJPF33ANp8aRU4jJOI08w9FurowwCULXaOebtS7e3LVCtgygHYqcn VCoECfL+EY1RHqAOL/iBNiGi3ZJm+rGjJsHSxamcgj5hmhKoK5zJh3MeGmqYYTpecbjo hJNA== X-Gm-Message-State: AN3rC/6YQpXWP4MzAVJaUgpT2IbalZ7aVC0gaGXG5dsTZYpkBfIVxsnL d8NL3gO8pvW+ZA== X-Received: by 10.28.29.138 with SMTP id d132mr4021432wmd.40.1491734605977; Sun, 09 Apr 2017 03:43:25 -0700 (PDT) Received: from dztty2.Speedport_W723_V_Typ_A_1_01_018 (p5DDB52B0.dip0.t-ipconnect.de. [93.219.82.176]) by smtp.gmail.com with ESMTPSA id v29sm13053611wrv.66.2017.04.09.03.43.24 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 09 Apr 2017 03:43:25 -0700 (PDT) From: Djalal Harouni To: Linux Kernel Mailing List , Andy Lutomirski , Kees Cook , Andrew Morton , kernel-hardening@lists.openwall.com, linux-security-module@vger.kernel.org Cc: Linux API , Dongsu Park , Casey Schaufler , James Morris , , Paul Moore , Tetsuo Handa , Greg Kroah-Hartman , Djalal Harouni Subject: [PATCH RFC v2 1/3] LSM: Allow per LSM module per "struct task_struct" blob. Date: Sun, 9 Apr 2017 12:42:08 +0200 Message-Id: <1491734530-25002-2-git-send-email-tixxdz@gmail.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1491734530-25002-1-git-send-email-tixxdz@gmail.com> References: <1491734530-25002-1-git-send-email-tixxdz@gmail.com> Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP From: Tetsuo Handa Since several modules are planning to use per "struct task_struct" blob, we need a layer for isolating it. Therefore, this patch introduces per LSM module per "struct task_struct" blob. It would be possible to remember location in security_hook_heads.task_alloc list and undo up to the corresponding security_hook_heads.task_free list when task_alloc hook failed. But this patch calls all task_free hooks without checking whether the corresponding task_alloc hook was called since most modules should be able to handle this correctly. How to calculate amount of needed bytes and allocate memory for initial task is a chicken-or-egg syndrome. We need to know how many bytes needs to be allocated for initial task's security blobs before security_init() is called. But security_reserve_task_blob_index() which calculates amount of needed bytes is called from security_init(). We will need to split module registration into three steps. The first step is call security_reserve_task_blob_index() on all modules which should be activated. The second step is allocate memory for the initial task's security blob. The third step is actually activate all modules which should be activated. Signed-off-by: Djalal Harouni Signed-off-by: Tetsuo Handa --- include/linux/lsm_hooks.h | 36 +++++++++++++++++++++++++++++++++++- security/security.c | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 080f34e..ca19cdb 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -27,6 +27,7 @@ #include #include #include +#include /* "struct task_struct" */ /** * Security hooks for program execution operations. @@ -536,7 +537,10 @@ * @task_alloc: * @task task being allocated. * @clone_flags contains the flags indicating what should be shared. - * Handle allocation of task-related resources. + * Handle allocation of task-related resources. Note that task_free is + * called even if task_alloc failed. This means that all task_free users + * have to be prepared for task_free being called without corresponding + * task_alloc call. * Returns a zero on success, negative values on failure. * @task_free: * @task task about to be freed. @@ -1947,4 +1951,34 @@ void __init loadpin_add_hooks(void); static inline void loadpin_add_hooks(void) { }; #endif +/* + * Per "struct task_struct" security blob is managed using index numbers. + * + * Any user who wants to use per "struct task_struct" security blob reserves an + * index number using security_reserve_task_blob_index() before calling + * security_add_hooks(). + * + * security_reserve_task_blob_index() returns an index number which has to be + * passed to task_security() by that user when fetching security blob of given + * "struct task_struct" for that user. + * + * Security blob for newly allocated "struct task_struct" is allocated and + * initialized with 0 inside security_task_alloc(), before calling each user's + * task_alloc hook. Be careful with task_free hook, for security_task_free() + * can be called when calling each user's task_alloc hook failed. + * + * Note that security_reserve_task_blob_index() uses "u16". It is not a good + * idea to directly reserve large amount. Sum of reserved amount by all users + * should be less than PAGE_SIZE bytes, for per "struct task_struct" security + * blob is allocated for each "struct task_struct" using kcalloc(). + */ +extern u16 __init security_reserve_task_blob_index(const u16 size); +static inline void *task_security(const struct task_struct *task, + const u16 index) +{ + unsigned long *p = task->security; + + return p + index; +} + #endif /* ! __LINUX_LSM_HOOKS_H */ diff --git a/security/security.c b/security/security.c index 549bddc..4dc6bca 100644 --- a/security/security.c +++ b/security/security.c @@ -32,6 +32,7 @@ /* Maximum number of letters for an LSM name string */ #define SECURITY_NAME_MAX 10 +static u16 lsm_max_per_task_blob_index __ro_after_init; struct security_hook_heads security_hook_heads __lsm_ro_after_init; char *lsm_names; /* Boot-time LSM user choice */ @@ -75,6 +76,15 @@ int __init security_init(void) */ do_security_initcalls(); + /* + * Allocate per "struct task_struct" blob for initial task. + * Initialization is done later by each module which needs it. + */ + if (lsm_max_per_task_blob_index) + current->security = kcalloc(lsm_max_per_task_blob_index, + sizeof(unsigned long), + GFP_KERNEL | __GFP_NOFAIL); + return 0; } @@ -86,6 +96,15 @@ static int __init choose_lsm(char *str) } __setup("security=", choose_lsm); +u16 __init security_reserve_task_blob_index(const u16 size) +{ + const u16 index = lsm_max_per_task_blob_index; + u16 requested = DIV_ROUND_UP(size, sizeof(unsigned long)); + + lsm_max_per_task_blob_index += requested; + return index; +} + static int lsm_append(char *new, char **result) { char *cp; @@ -939,12 +958,28 @@ int security_task_create(unsigned long clone_flags) int security_task_alloc(struct task_struct *task, unsigned long clone_flags) { - return call_int_hook(task_alloc, 0, task, clone_flags); + int rc; + const unsigned long index = lsm_max_per_task_blob_index; + + if (index) { + task->security = kcalloc(index, sizeof(unsigned long), + GFP_KERNEL); + if (unlikely(!task->security)) + return -ENOMEM; + } + rc = call_int_hook(task_alloc, 0, task, clone_flags); + if (unlikely(rc)) + security_task_free(task); + return rc; } void security_task_free(struct task_struct *task) { call_void_hook(task_free, task); + if (lsm_max_per_task_blob_index) { + kfree(task->security); + task->security = NULL; + } } int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)