From patchwork Wed May 22 18:13:23 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10956445 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8AF8F912 for ; Wed, 22 May 2019 18:13:36 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7E5B01FE8A for ; Wed, 22 May 2019 18:13:36 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 72A291FF65; Wed, 22 May 2019 18:13:36 +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=-15.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI, USER_IN_DEF_DKIM_WL 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 0AA4D1FE8A for ; Wed, 22 May 2019 18:13:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729018AbfEVSNf (ORCPT ); Wed, 22 May 2019 14:13:35 -0400 Received: from mail-oi1-f202.google.com ([209.85.167.202]:53831 "EHLO mail-oi1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727984AbfEVSNf (ORCPT ); Wed, 22 May 2019 14:13:35 -0400 Received: by mail-oi1-f202.google.com with SMTP id k66so1259221oib.20 for ; Wed, 22 May 2019 11:13:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=6wO6oiSLtG+g/llMooqVDOP+WudURPHtf7GN76fyZzI=; b=exb8k5l8CB978GrssJJQSUDvEF5O8bh9lzG4ewE4r8MAd60F7JGj1Q4sF4R5zcD5sS Bcs7SLRaaO7JpgUjDJSSErJMPS+x+58C5blLzSWO3RpEDNyy6J3L02A1aPlyFp4M2Rj8 Z4kXt7ZbfWnQd5ewyD/8o5vp/rZFan3o0Vt97uEzWUFXQeykzNwphZCJUJBlWJ/LOlnV 6Blsr6/QajUtNgtu5oV1dQfXea8WouWBdswfOAnzsX+J9rVVKLRBopH2S7tC6rTPK3Zq YCePgWR9onlwuOfR1DsC5DycNqclfXc9VL1Z/65cJDFwvKjrszwutv31jBnNnzHFBFNa gPmA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=6wO6oiSLtG+g/llMooqVDOP+WudURPHtf7GN76fyZzI=; b=BPnnGa/HqI0DTvkviM2mGwgPfNbUw4+TW3KBbQhIRq51RAaXhz1dxx9IwNPLBcjqhU zRlhb3vTMAowwRRrlf98ikLiZ9VEpnVC5my3rfDXED5pHFL+jgaB6dodRCPuOh/L2y8R XSESA837xkMf4666/xdnYwH8gEXAmNC//B4o6JO06hPtnOAFnErSjNBm9K/2YipkHwbQ eTGoCjckVYpD1XIOoQ22emg9bSeHbF+nx8BertjCbKjZBHI4xwlKwRCSUvkngMBximbc dSx5CJ6n2c3tNyGXWeL3Of1AmpJaK0uWV9TzLpEJRrWqvvK17HYLBYZ9mWRjTGENVOfi 7Chg== X-Gm-Message-State: APjAAAUKvYW8k9HWNUzALWg+bCtK8ZulxSdN0Kugg/Mnnqv5QqsG51HL Rg6o7OM2xTPWHWHJaz6z3eE24xIHrmzF9VTIJzvRAp+/dBDnFXJFmpayURUJMlzjI+IH0hakztE GcWSnA4+xjJHEr4YQzIl/gduYW7Y5vcttuY1OLxN02IdChBjHLZKNmDdVCdnFDC+vfk2paWM4Dl bEvvZElgO2Rav4gPmOhRY= X-Google-Smtp-Source: APXvYqzSP/OiEWYntQWkldbi77heTw6ka6f05ZnI9TroTmLmU0qCosjcXD6Tg0HMe5qxojPOICMM03TCBJnpNK8F0+uS+Q== X-Received: by 2002:aca:c6c2:: with SMTP id w185mr801882oif.104.1558548814728; Wed, 22 May 2019 11:13:34 -0700 (PDT) Date: Wed, 22 May 2019 11:13:23 -0700 In-Reply-To: <20190522181327.71980-1-matthewgarrett@google.com> Message-Id: <20190522181327.71980-2-matthewgarrett@google.com> Mime-Version: 1.0 References: <20190522181327.71980-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.21.0.1020.gf2820cf01a-goog Subject: [PATCH V4 1/5] VFS: Add a call to obtain a file's hash From: Matthew Garrett To: linux-integrity@vger.kernel.org Cc: zohar@linux.vnet.ibm.com, dmitry.kasatkin@gmail.com, miklos@szeredi.hu, linux-fsdevel@vger.kernel.org, viro@zeniv.linux.org.uk, Matthew Garrett Sender: linux-integrity-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Matthew Garrett IMA wants to know what the hash of a file is, and currently does so by reading the entire file and generating the hash. Some filesystems may have the ability to store the hash in a secure manner resistant to offline attacks (eg, filesystem-level file signing), and in that case it's a performance win for IMA to be able to use that rather than having to re-hash everything. This patch simply adds VFS-level support for calling down to filesystems. Signed-off-by: Matthew Garrett --- fs/read_write.c | 24 ++++++++++++++++++++++++ include/linux/fs.h | 6 +++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/fs/read_write.c b/fs/read_write.c index c543d965e288..34c939b4d05f 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -2178,3 +2178,27 @@ int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same) return ret; } EXPORT_SYMBOL(vfs_dedupe_file_range); + +/** + * vfs_gethash - obtain a file's hash + * @file: file structure in question + * @hash_algo: the hash algorithm requested + * @buf: buffer to return the hash in + * @size: size allocated for the buffer by the caller + * + * This function allows filesystems that support securely storing the hash + * of a file to return it rather than forcing the kernel to recalculate it. + * Filesystems that cannot provide guarantees about the hash being resistant + * to offline attack should not implement this functionality. + * + * Returns 0 on success, -EOPNOTSUPP if the filesystem doesn't support it. + */ +int vfs_get_hash(struct file *file, enum hash_algo hash, uint8_t *buf, + size_t size) +{ + if (!file->f_op->get_hash) + return -EOPNOTSUPP; + + return file->f_op->get_hash(file, hash, buf, size); +} +EXPORT_SYMBOL(vfs_get_hash); diff --git a/include/linux/fs.h b/include/linux/fs.h index f7fdfe93e25d..9e9f927ac2fc 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -43,6 +43,7 @@ #include #include +#include struct backing_dev_info; struct bdi_writeback; @@ -1828,6 +1829,8 @@ struct file_operations { struct file *file_out, loff_t pos_out, loff_t len, unsigned int remap_flags); int (*fadvise)(struct file *, loff_t, loff_t, int); + int (*get_hash)(struct file *, enum hash_algo hash, uint8_t *buf, + size_t size); } __randomize_layout; struct inode_operations { @@ -1904,7 +1907,8 @@ extern int vfs_dedupe_file_range(struct file *file, extern loff_t vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos, struct file *dst_file, loff_t dst_pos, loff_t len, unsigned int remap_flags); - +extern int vfs_get_hash(struct file *file, enum hash_algo hash, uint8_t *buf, + size_t size); struct super_operations { struct inode *(*alloc_inode)(struct super_block *sb); From patchwork Wed May 22 18:13:24 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10956449 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 37601912 for ; Wed, 22 May 2019 18:13:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2AD661FF40 for ; Wed, 22 May 2019 18:13:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1F1841FF7F; Wed, 22 May 2019 18:13:39 +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=-15.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI, USER_IN_DEF_DKIM_WL 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 A517F1FF40 for ; Wed, 22 May 2019 18:13:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729454AbfEVSNi (ORCPT ); Wed, 22 May 2019 14:13:38 -0400 Received: from mail-qk1-f202.google.com ([209.85.222.202]:43848 "EHLO mail-qk1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727984AbfEVSNi (ORCPT ); Wed, 22 May 2019 14:13:38 -0400 Received: by mail-qk1-f202.google.com with SMTP id p190so3020699qke.10 for ; Wed, 22 May 2019 11:13:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=kDtuSdPuZMfh9jp8My/vbwyi1T6nRo1X8LH0Nx8sUW0=; b=kpOsJ+uujV1C3fFII9KudyrzxcdcyDJPJT+Ra2CIB6ikvgsCVzfo+a4mvaVs8sl4jm 4ReNg2od1dc61vZ7p4O3osQwaoNtSg9KuNiQ5f2j3ZTMQ2SgiDZFJFBYGOaKHUjKT5Us Q6OGl2zhN2ZGrDrkzf00xi2Stq6V0Ug8wdeji1KzKRnEC/lWUbQI7kdwnhT2pOKFzNX2 MxbXic1sFn6VMRFN/U9ZkFVuauT24FNVaor2HeIUlf15z0cEfj3PwrkeVnSJNpjQiZCo SaIGoiB85mtZoE4qYrKaSgX+NlmOlSJWt5XKpwk6Xvnq3OBWVV48//axafuZAgKB5iLe Q3lw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=kDtuSdPuZMfh9jp8My/vbwyi1T6nRo1X8LH0Nx8sUW0=; b=kNaQXwTOLtQrUW/uB2S3gOYBwXUKx2DtQQoyYveqBAtVARbF/6uzEcwjNSyOnQR78U ylO2W/RGqW2ygEiR2k6947Ohwlz+vVx6BPTwBdY+VaRjJbWYOUPgksPqSr4Qne7M3QrE kZKF7tB2fnlJK+hapG62x+WRNTHaOH3LQdZuup6nO0mtJ9rDe5YoEuJMkLQBjGy2GaYt zlJtu62u1Fehpq1RpKthJt696s+9Qz+dxKzPN/TMV/xdzBDSQhB9YG87F+DZubxQvak1 zJg+0cTgeJHIFxBAPfFEFr3ftoDGXuJlzVWs5ZMLHBFaJe/AgIU90wqude6R1+iglXY7 GQ7w== X-Gm-Message-State: APjAAAVQ3o1dVnjdgY2PXQ7gP6t9bihIpuo/iahQkfqxRulvW1Xl13jo WLtaKZnWjK16X1MCTpvMuJF1yNVfKJafU3WRPDTUHRxItwqaSG8ed+k9Fa5cFSUxQy5Om8wjBUX vFFb9HbP5lJnliZdYwkWYTd6mLQVwOgR4lv8diIxrVKX701vIogtdbho8tpKJoH8gEaopBHlkvH hoMnNIk4gTXFunU8JhRVs= X-Google-Smtp-Source: APXvYqxwHFScNgrqYOoyXuXus7m90y856n5PvOiRTcJgUHGB0oeT87Rbp9HT/WHIBzy+67ozEjfyLxlgjNYV/9vw+3aOvg== X-Received: by 2002:ac8:538f:: with SMTP id x15mr41161741qtp.263.1558548817161; Wed, 22 May 2019 11:13:37 -0700 (PDT) Date: Wed, 22 May 2019 11:13:24 -0700 In-Reply-To: <20190522181327.71980-1-matthewgarrett@google.com> Message-Id: <20190522181327.71980-3-matthewgarrett@google.com> Mime-Version: 1.0 References: <20190522181327.71980-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.21.0.1020.gf2820cf01a-goog Subject: [PATCH V4 2/5] IMA: Allow rule matching on filesystem subtype From: Matthew Garrett To: linux-integrity@vger.kernel.org Cc: zohar@linux.vnet.ibm.com, dmitry.kasatkin@gmail.com, miklos@szeredi.hu, linux-fsdevel@vger.kernel.org, viro@zeniv.linux.org.uk, Matthew Garrett , Matthew Garrett Sender: linux-integrity-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP IMA currently allows rules to match on the filesystem type. Certain filesystem types permit subtypes (eg, fuse). Add support to IMA to allow rules to match on subtypes as well as types. Signed-off-by: Matthew Garrett --- Documentation/ABI/testing/ima_policy | 4 +++- security/integrity/ima/ima_policy.c | 26 +++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy index 74c6702de74e..09a5def7e28a 100644 --- a/Documentation/ABI/testing/ima_policy +++ b/Documentation/ABI/testing/ima_policy @@ -21,7 +21,7 @@ Description: audit | hash | dont_hash condition:= base | lsm [option] base: [[func=] [mask=] [fsmagic=] [fsuuid=] [uid=] - [euid=] [fowner=] [fsname=]] + [euid=] [fowner=] [fsname=] [subtype=]] lsm: [[subj_user=] [subj_role=] [subj_type=] [obj_user=] [obj_role=] [obj_type=]] option: [[appraise_type=]] [permit_directio] @@ -33,6 +33,8 @@ Description: [[^]MAY_EXEC] fsmagic:= hex value fsuuid:= file system UUID (e.g 8bcbe394-4f13-4144-be8e-5aa9ea2ce2f6) + fsname:= file system type (e.g fuse) + subtype:= file system subtype (e.g ntfs3g) uid:= decimal value euid:= decimal value fowner:= decimal value diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index e0cc323f948f..bb4e265823a7 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -35,6 +35,7 @@ #define IMA_EUID 0x0080 #define IMA_PCR 0x0100 #define IMA_FSNAME 0x0200 +#define IMA_SUBTYPE 0x0400 #define UNKNOWN 0 #define MEASURE 0x0001 /* same as IMA_MEASURE */ @@ -80,6 +81,7 @@ struct ima_rule_entry { int type; /* audit type */ } lsm[MAX_LSM_RULES]; char *fsname; + char *subtype; }; /* @@ -306,6 +308,10 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode, if ((rule->flags & IMA_FSNAME) && strcmp(rule->fsname, inode->i_sb->s_type->name)) return false; + if ((rule->flags & IMA_SUBTYPE) + && (inode->i_sb->s_subtype == NULL || + strcmp(rule->subtype, inode->i_sb->s_subtype))) + return false; if ((rule->flags & IMA_FSUUID) && !uuid_equal(&rule->fsuuid, &inode->i_sb->s_uuid)) return false; @@ -670,7 +676,7 @@ enum { Opt_audit, Opt_hash, Opt_dont_hash, Opt_obj_user, Opt_obj_role, Opt_obj_type, Opt_subj_user, Opt_subj_role, Opt_subj_type, - Opt_func, Opt_mask, Opt_fsmagic, Opt_fsname, + Opt_func, Opt_mask, Opt_fsmagic, Opt_fsname, Opt_subtype, Opt_fsuuid, Opt_uid_eq, Opt_euid_eq, Opt_fowner_eq, Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt, Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt, @@ -696,6 +702,7 @@ static const match_table_t policy_tokens = { {Opt_mask, "mask=%s"}, {Opt_fsmagic, "fsmagic=%s"}, {Opt_fsname, "fsname=%s"}, + {Opt_subtype, "subtype=%s"}, {Opt_fsuuid, "fsuuid=%s"}, {Opt_uid_eq, "uid=%s"}, {Opt_euid_eq, "euid=%s"}, @@ -921,6 +928,17 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) result = 0; entry->flags |= IMA_FSNAME; break; + case Opt_subtype: + ima_log_string(ab, "subtype", args[0].from); + + entry->subtype = kstrdup(args[0].from, GFP_KERNEL); + if (!entry->subtype) { + result = -ENOMEM; + break; + } + result = 0; + entry->flags |= IMA_SUBTYPE; + break; case Opt_fsuuid: ima_log_string(ab, "fsuuid", args[0].from); @@ -1256,6 +1274,12 @@ int ima_policy_show(struct seq_file *m, void *v) seq_puts(m, " "); } + if (entry->flags & IMA_SUBTYPE) { + snprintf(tbuf, sizeof(tbuf), "%s", entry->subtype); + seq_printf(m, pt(Opt_subtype), tbuf); + seq_puts(m, " "); + } + if (entry->flags & IMA_PCR) { snprintf(tbuf, sizeof(tbuf), "%d", entry->pcr); seq_printf(m, pt(Opt_pcr), tbuf); From patchwork Wed May 22 18:13:25 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10956453 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DB45C112C for ; Wed, 22 May 2019 18:13:41 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CAE101FE8A for ; Wed, 22 May 2019 18:13:41 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BF6A41FF41; Wed, 22 May 2019 18:13:41 +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=-15.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI, USER_IN_DEF_DKIM_WL 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 10ACE1FF13 for ; Wed, 22 May 2019 18:13:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729491AbfEVSNk (ORCPT ); Wed, 22 May 2019 14:13:40 -0400 Received: from mail-yb1-f202.google.com ([209.85.219.202]:40209 "EHLO mail-yb1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727975AbfEVSNk (ORCPT ); Wed, 22 May 2019 14:13:40 -0400 Received: by mail-yb1-f202.google.com with SMTP id n7so2850342ybk.7 for ; Wed, 22 May 2019 11:13:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=W14yhZSbIYutl917bFZgD1LB9cP8MSc8qpJ30KN8/xY=; b=nshLQUz/xs28a0FBCodICoIzvpNx1PJyfnOnmdzn70d2gOdRdy7rnM8JdGkjNt3fie A28qlYr2fA+SSp7LWX8UC/l3v3YT3l7thwESJ/zj3QM0oRx/LoKlseqRtR7pr9IgeVbT CawAkF3e4TBZK/SD/qWeqw3a3DjVaq1y31i5loIHi3UwKIZqTGEL1K10Zgd5sKvojg8v lpzPZHjthq3XjJSruqoxiaePMPqHHQt5u6vE48jJLWWkQVmlThy+1TUgC0uyt2T9Xlwk HbFWynOPTcQG6Ur14E4ArgWIUqV3clymeXU7N8jVImENIJcanL/T2sPeJis9bbHNpeEP tp9Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=W14yhZSbIYutl917bFZgD1LB9cP8MSc8qpJ30KN8/xY=; b=ScyFKugUPSMMLv2fhOZDcA8rXnSvfD/lvoekZSaDbYpErb8pIdOwEnHiLrO2LR/9fW 1YV1ugCg8BakMtKCiwP9Tm6SsbLv1qA3gaXAVD/OHdC3R5cYEn89+roerPvrZW9xYqFr 5jnDwTDuVpTEl5jYMYWkp82+sRiUVXRbSZ5NajgcUi6TPKN1fcsbZLdkFR60Y5ci2HnR G1UeoL77iPDg7m6Kc5a97yg0kprQ8luoVO9bo5vtXOcjUjNbN8w4fdukorP5nU91KU1R TAhMXVroLeFGM85to1SCpvxqyPkdWzpoimeQDG+RVN9Tjj6K3QcSIqRAwFcCh4mtBhoL xZ/A== X-Gm-Message-State: APjAAAVUhVbMn7LIPtgRRb6Pv99euL4enW8u2AU2au4HYD1xxNVIQdaq j0Q45tMTTKlYyBtJKsBCyvcyZfibGMbvmZtZGketaEGJwvx0YkWvz6U/tfgGGfzXdy/SLQmKR8T 23ge3P9rOSS063DzKQ2ORBq9U+NSV4d6mMuzPV/cxed272JgXUM9HzWgtIxHuE691UTaE6b5rZ5 QJWnbXls95WLz9JiCxfqo= X-Google-Smtp-Source: APXvYqxbky+LkwRGXyhlR2YyZYaXkAJZNhVmC8tXFtPRQpXY+UO0/lGmRXaCTlVy56bqUHTgigIYoKLR44BvZN5xuiRHVw== X-Received: by 2002:a81:4d8a:: with SMTP id a132mr42404176ywb.326.1558548819594; Wed, 22 May 2019 11:13:39 -0700 (PDT) Date: Wed, 22 May 2019 11:13:25 -0700 In-Reply-To: <20190522181327.71980-1-matthewgarrett@google.com> Message-Id: <20190522181327.71980-4-matthewgarrett@google.com> Mime-Version: 1.0 References: <20190522181327.71980-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.21.0.1020.gf2820cf01a-goog Subject: [PATCH V4 3/5] IMA: Optionally make use of filesystem-provided hashes From: Matthew Garrett To: linux-integrity@vger.kernel.org Cc: zohar@linux.vnet.ibm.com, dmitry.kasatkin@gmail.com, miklos@szeredi.hu, linux-fsdevel@vger.kernel.org, viro@zeniv.linux.org.uk, Matthew Garrett Sender: linux-integrity-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Matthew Garrett Some filesystems may be able to provide hashes in an out of band manner, and allowing them to do so is a performance win. This is especially true of FUSE-based filesystems where otherwise we recalculate the hash on every measurement. Make use of this if policy says we should, but provide a parameter to force recalculation rather than trusting the filesystem. Signed-off-by: Matthew Garrett --- Documentation/ABI/testing/ima_policy | 5 +++- .../admin-guide/kernel-parameters.txt | 5 ++++ security/integrity/ima/ima.h | 3 ++- security/integrity/ima/ima_api.c | 5 +++- security/integrity/ima/ima_crypto.c | 23 ++++++++++++++++++- security/integrity/ima/ima_policy.c | 8 ++++++- security/integrity/ima/ima_template_lib.c | 2 +- security/integrity/integrity.h | 1 + 8 files changed, 46 insertions(+), 6 deletions(-) diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy index 09a5def7e28a..6a517282068d 100644 --- a/Documentation/ABI/testing/ima_policy +++ b/Documentation/ABI/testing/ima_policy @@ -24,7 +24,8 @@ Description: [euid=] [fowner=] [fsname=] [subtype=]] lsm: [[subj_user=] [subj_role=] [subj_type=] [obj_user=] [obj_role=] [obj_type=]] - option: [[appraise_type=]] [permit_directio] + option: [[appraise_type=] [permit_directio] + [trust_vfs]] base: func:= [BPRM_CHECK][MMAP_CHECK][CREDS_CHECK][FILE_CHECK][MODULE_CHECK] [FIRMWARE_CHECK] @@ -41,6 +42,8 @@ Description: lsm: are LSM specific option: appraise_type:= [imasig] pcr:= decimal value + permit_directio:= allow directio accesses + trust_vfs:= trust VFS-provided hash values default policy: # PROC_SUPER_MAGIC diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 52e6fbb042cc..cc9302b79409 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1658,6 +1658,11 @@ different crypto accelerators. This option can be used to achieve best performance for particular HW. + ima.force_hash= [IMA] Force hash calculation in IMA + Format: + Always calculate hashes rather than trusting the + filesystem to provide them to us. + init= [KNL] Format: Run specified binary instead of /sbin/init as init diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index d213e835c498..cdaffe6c8a8d 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -133,7 +133,8 @@ int ima_fs_init(void); int ima_add_template_entry(struct ima_template_entry *entry, int violation, const char *op, struct inode *inode, const unsigned char *filename); -int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash); +int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash, + bool trust_vfs); int ima_calc_buffer_hash(const void *buf, loff_t len, struct ima_digest_data *hash); int ima_calc_field_array_hash(struct ima_field_data *field_data, diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index c7505fb122d4..0def9cf43549 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -206,6 +206,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, int length; void *tmpbuf; u64 i_version; + bool trust_vfs; struct { struct ima_digest_data hdr; char digest[IMA_MAX_DIGEST_SIZE]; @@ -225,10 +226,12 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, /* Initialize hash digest to 0's in case of failure */ memset(&hash.digest, 0, sizeof(hash.digest)); + trust_vfs = iint->flags & IMA_TRUST_VFS; + if (buf) result = ima_calc_buffer_hash(buf, size, &hash.hdr); else - result = ima_calc_file_hash(file, &hash.hdr); + result = ima_calc_file_hash(file, &hash.hdr, trust_vfs); if (result && result != -EBADF && result != -EINVAL) goto out; diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index a32878e10ebc..1c83d23d21a6 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -32,6 +32,10 @@ static unsigned long ima_ahash_minsize; module_param_named(ahash_minsize, ima_ahash_minsize, ulong, 0644); MODULE_PARM_DESC(ahash_minsize, "Minimum file size for ahash use"); +static bool ima_force_hash; +module_param_named(force_hash, ima_force_hash, bool_enable_only, 0644); +MODULE_PARM_DESC(force_hash, "Always calculate hashes"); + /* default is 0 - 1 page. */ static int ima_maxorder; static unsigned int ima_bufsize = PAGE_SIZE; @@ -401,11 +405,14 @@ static int ima_calc_file_shash(struct file *file, struct ima_digest_data *hash) * shash for the hash calculation. If ahash fails, it falls back to using * shash. */ -int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) +int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash, + bool trust_vfs) { loff_t i_size; int rc; struct file *f = file; + struct dentry *dentry = file_dentry(file); + struct inode *inode = d_backing_inode(dentry); bool new_file_instance = false, modified_flags = false; /* @@ -418,6 +425,20 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) return -EINVAL; } + /* + * If policy says we should trust VFS-provided hashes, and + * we're not configured to force hashing, and if the + * filesystem is trusted, ask the VFS if it can obtain the + * hash without us having to calculate it ourself. + */ + if (trust_vfs && !ima_force_hash && + !(inode->i_sb->s_iflags & SB_I_UNTRUSTED_MOUNTER)) { + hash->length = hash_digest_size[hash->algo]; + rc = vfs_get_hash(file, hash->algo, hash->digest, hash->length); + if (!rc) + return 0; + } + /* Open a new file instance in O_RDONLY if we cannot read */ if (!(file->f_mode & FMODE_READ)) { int flags = file->f_flags & ~(O_WRONLY | O_APPEND | diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index bb4e265823a7..c293cbc6c578 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -681,7 +681,7 @@ enum { Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt, Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt, Opt_appraise_type, Opt_permit_directio, - Opt_pcr, Opt_err + Opt_pcr, Opt_trust_vfs, Opt_err }; static const match_table_t policy_tokens = { @@ -716,6 +716,7 @@ static const match_table_t policy_tokens = { {Opt_appraise_type, "appraise_type=%s"}, {Opt_permit_directio, "permit_directio"}, {Opt_pcr, "pcr=%s"}, + {Opt_trust_vfs, "trust_vfs"}, {Opt_err, NULL} }; @@ -1062,6 +1063,9 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) case Opt_permit_directio: entry->flags |= IMA_PERMIT_DIRECTIO; break; + case Opt_trust_vfs: + entry->flags |= IMA_TRUST_VFS; + break; case Opt_pcr: if (entry->action != MEASURE) { result = -EINVAL; @@ -1358,6 +1362,8 @@ int ima_policy_show(struct seq_file *m, void *v) seq_puts(m, "appraise_type=imasig "); if (entry->flags & IMA_PERMIT_DIRECTIO) seq_puts(m, "permit_directio "); + if (entry->flags & IMA_TRUST_VFS) + seq_puts(m, "trust_vfs "); rcu_read_unlock(); seq_puts(m, "\n"); return 0; diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index 513b457ae900..26f71c5805f0 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c @@ -291,7 +291,7 @@ int ima_eventdigest_init(struct ima_event_data *event_data, inode = file_inode(event_data->file); hash.hdr.algo = ima_template_hash_algo_allowed(ima_hash_algo) ? ima_hash_algo : HASH_ALGO_SHA1; - result = ima_calc_file_hash(event_data->file, &hash.hdr); + result = ima_calc_file_hash(event_data->file, &hash.hdr, false); if (result) { integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, event_data->filename, "collect_data", diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 7de59f44cba3..a03f859c1602 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -36,6 +36,7 @@ #define IMA_NEW_FILE 0x04000000 #define EVM_IMMUTABLE_DIGSIG 0x08000000 #define IMA_FAIL_UNVERIFIABLE_SIGS 0x10000000 +#define IMA_TRUST_VFS 0x20000000 #define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \ IMA_HASH | IMA_APPRAISE_SUBMASK) From patchwork Wed May 22 18:13:26 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10956457 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6E7A9912 for ; Wed, 22 May 2019 18:13:44 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 606F31FF40 for ; Wed, 22 May 2019 18:13:44 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 54D8B1FF41; Wed, 22 May 2019 18:13:44 +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=-15.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI, USER_IN_DEF_DKIM_WL 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 C988A1FF60 for ; Wed, 22 May 2019 18:13:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729509AbfEVSNn (ORCPT ); Wed, 22 May 2019 14:13:43 -0400 Received: from mail-yb1-f201.google.com ([209.85.219.201]:37567 "EHLO mail-yb1-f201.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729481AbfEVSNn (ORCPT ); Wed, 22 May 2019 14:13:43 -0400 Received: by mail-yb1-f201.google.com with SMTP id f138so2878173yba.4 for ; Wed, 22 May 2019 11:13:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=+IAS24bvoT6KCKSZJBMAHwUwLFDiYhVfFPEcOO2vYVU=; b=K+Tv4+2eWCBG6jteYwWoWD112XnDeiwE74I2pfmVgpjqDREXF/cwC08ChiXR9XB2uD n4yesW5u9RR+oRKmBKHMRhYhRe8IhgtGLjmrY0bqb+w+Ij21Ixiqs2AfHtrnB7W+2+ZY eMv7rj6gmXkO5s0hOF3gHT5VzwrVabwAlJabccJ3WmGDkvK8JNH/4FWnsO1/yIUsuXr/ 7OtOnsiih+4MLXJvIfZsmng7eK6vVQTtYpVJ7QygC/eJ15l+FpOZWp/QNEGCdKDNKVVA SYL2BaeyVb/UEUvk8bQNVrpFtNjPlfcuUxpMBUe1i2c9C0vKHl6p58a5lHr/NTzS7woI lscw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=+IAS24bvoT6KCKSZJBMAHwUwLFDiYhVfFPEcOO2vYVU=; b=fHsnbaObATiGC5aeW9pxaVrq8kCjK1YHIMarZtr7yuJRGTZxdaJWoUdLVTSEuNipiB ZYDDOB4q31rGUBzY9akc0BxzeZb3WFRmk5a3l0Nzt0QKGnxliROQ4CerWF33JENRXk2B FJI9JJSbzrSKORMvH4wbet6uZ14ZRcwyCjyzTT+Bp9QFY8cKq+RAVHQYmstL7ky3g2Qy Ua9/jVAgEmNpdaOHXfWFjUvS80rhUev41CerrVWd6ueInL7h8pA4Q8boeLq3V4AN47DX /r6b2aSwvuDt5vEyRLuzikeskRq8iDWjlOjZIBOJlCZdz1lVOShyTTMHBPLZXMUANKMY IT8A== X-Gm-Message-State: APjAAAWK1HCCY9TBomEwdaPkN30hRumMHAK6yxCjLCJaaDjZGDDfcky6 QYu9zQyuLHC+n+bMgzLreyL2riINGV7H1Qry5p60poOwB8Dfn4vZZXt94O6d/e6n4mtwMLz3i8L sgVJpEL7m9mhDegBIhfvzvttcP2RpOjgUKc3Z3HjBfY5Li/JZu+jJDp15IWsWiTgiqy5EblmR+M c7fzLjE6eY0Zqc/F7bZFM= X-Google-Smtp-Source: APXvYqwihKKb/sLg0LH6caYO15TawZZFk1N9W6Uo6d7ym4JR4ny6W0RaIpB8x69+AxEQAK0LVSYmImgu9uyVR7/CvSj7qg== X-Received: by 2002:a81:59c2:: with SMTP id n185mr41299555ywb.21.1558548822021; Wed, 22 May 2019 11:13:42 -0700 (PDT) Date: Wed, 22 May 2019 11:13:26 -0700 In-Reply-To: <20190522181327.71980-1-matthewgarrett@google.com> Message-Id: <20190522181327.71980-5-matthewgarrett@google.com> Mime-Version: 1.0 References: <20190522181327.71980-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.21.0.1020.gf2820cf01a-goog Subject: [PATCH V4 4/5] FUSE: Allow filesystems to provide gethash methods From: Matthew Garrett To: linux-integrity@vger.kernel.org Cc: zohar@linux.vnet.ibm.com, dmitry.kasatkin@gmail.com, miklos@szeredi.hu, linux-fsdevel@vger.kernel.org, viro@zeniv.linux.org.uk, Matthew Garrett Sender: linux-integrity-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Matthew Garrett FUSE implementations may have a secure way to provide file hashes (eg, they're a front-end to a remote store that ties files to their hashes). Allow filesystems to expose this information, but require an option to be provided before it can be used. This is to avoid malicious users being able to mount an unprivileged FUSE filesystem that provides incorrect hashes. A sufficiently malicious FUSE filesystem may still simply swap out its contents after the hash has been obtained - this patchset does nothing to change that, and sysadmins should have appropriate policy in place to protect against that. Signed-off-by: Matthew Garrett --- fs/fuse/file.c | 33 +++++++++++++++++++++++++++++++++ fs/fuse/fuse_i.h | 7 +++++++ fs/fuse/inode.c | 15 +++++++++++++++ include/uapi/linux/fuse.h | 6 ++++++ 4 files changed, 61 insertions(+) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 3959f08279e6..a89ace030d1c 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -3170,6 +3170,38 @@ static ssize_t fuse_copy_file_range(struct file *file_in, loff_t pos_in, inode_unlock(inode_out); + return err; +}; + +static int fuse_file_get_hash(struct file *file, enum hash_algo hash, + uint8_t *buf, size_t size) +{ + struct fuse_file *ff = file->private_data; + struct fuse_conn *fc = ff->fc; + FUSE_ARGS(args); + struct fuse_gethash_in inarg; + int err = 0; + + if (!fc->allow_gethash) + return -EOPNOTSUPP; + + memset(&inarg, 0, sizeof(inarg)); + inarg.size = size; + inarg.hash = hash; + args.in.h.opcode = FUSE_GETHASH; + args.in.h.nodeid = ff->nodeid; + args.in.numargs = 1; + args.in.args[0].size = sizeof(inarg); + args.in.args[0].value = &inarg; + args.out.numargs = 1; + args.out.args[0].size = size; + args.out.args[0].value = buf; + + err = fuse_simple_request(fc, &args); + + if (err == -ENOSYS) + err = -EOPNOTSUPP; + return err; } @@ -3191,6 +3223,7 @@ static const struct file_operations fuse_file_operations = { .poll = fuse_file_poll, .fallocate = fuse_file_fallocate, .copy_file_range = fuse_copy_file_range, + .get_hash = fuse_file_get_hash, }; static const struct address_space_operations fuse_file_aops = { diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 24dbca777775..06c8d396cc74 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -721,6 +721,13 @@ struct fuse_conn { /** Does the filesystem support copy_file_range? */ unsigned no_copy_file_range:1; + /* + * Allow the underlying filesystem to the hash of a file. This is + * used by IMA to avoid needing to calculate the hash on every + * measurement + */ + unsigned allow_gethash:1; + /** The number of requests waiting for completion */ atomic_t num_waiting; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 4bb885b0f032..ef7f408ac69c 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -70,6 +70,7 @@ struct fuse_mount_data { unsigned group_id_present:1; unsigned default_permissions:1; unsigned allow_other:1; + unsigned allow_gethash:1; unsigned max_read; unsigned blksize; }; @@ -451,6 +452,7 @@ enum { OPT_ALLOW_OTHER, OPT_MAX_READ, OPT_BLKSIZE, + OPT_ALLOW_GETHASH, OPT_ERR }; @@ -463,6 +465,7 @@ static const match_table_t tokens = { {OPT_ALLOW_OTHER, "allow_other"}, {OPT_MAX_READ, "max_read=%u"}, {OPT_BLKSIZE, "blksize=%u"}, + {OPT_ALLOW_GETHASH, "allow_gethash"}, {OPT_ERR, NULL} }; @@ -549,6 +552,15 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev, d->blksize = value; break; + case OPT_ALLOW_GETHASH: + /* + * This is relevant to security decisions made in + * the root namespace, so restrict it more strongly + */ + if (capable(CAP_SYS_ADMIN)) + d->allow_gethash = 1; + break; + default: return 0; } @@ -572,6 +584,8 @@ static int fuse_show_options(struct seq_file *m, struct dentry *root) seq_puts(m, ",default_permissions"); if (fc->allow_other) seq_puts(m, ",allow_other"); + if (fc->allow_gethash) + seq_puts(m, ",allow_gethash"); if (fc->max_read != ~0) seq_printf(m, ",max_read=%u", fc->max_read); if (sb->s_bdev && sb->s_blocksize != FUSE_DEFAULT_BLKSIZE) @@ -1164,6 +1178,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) fc->user_id = d.user_id; fc->group_id = d.group_id; fc->max_read = max_t(unsigned, 4096, d.max_read); + fc->allow_gethash = d.allow_gethash; /* Used by get_root_inode() */ sb->s_fs_info = fc; diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index 19fb55e3c73e..2487e2c3a4ba 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -417,6 +417,7 @@ enum fuse_opcode { FUSE_RENAME2 = 45, FUSE_LSEEK = 46, FUSE_COPY_FILE_RANGE = 47, + FUSE_GETHASH = 48, /* CUSE specific operations */ CUSE_INIT = 4096, @@ -840,4 +841,9 @@ struct fuse_copy_file_range_in { uint64_t flags; }; +struct fuse_gethash_in { + uint32_t size; + uint32_t hash; +}; + #endif /* _LINUX_FUSE_H */ From patchwork Wed May 22 18:13:27 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10956463 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 016E2112C for ; Wed, 22 May 2019 18:13:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E9C541FF2D for ; Wed, 22 May 2019 18:13:49 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DE5D81FF65; Wed, 22 May 2019 18:13:49 +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=-15.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI, USER_IN_DEF_DKIM_WL 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 1A73D1FF2D for ; Wed, 22 May 2019 18:13:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728734AbfEVSNs (ORCPT ); Wed, 22 May 2019 14:13:48 -0400 Received: from mail-vk1-f201.google.com ([209.85.221.201]:57200 "EHLO mail-vk1-f201.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729506AbfEVSNq (ORCPT ); Wed, 22 May 2019 14:13:46 -0400 Received: by mail-vk1-f201.google.com with SMTP id q139so1232380vkq.23 for ; Wed, 22 May 2019 11:13:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=1Alsu9xQddUZwK4MUO0Ms0F6c5A3p78CyoojTq2bN0g=; b=QeYvLb7V1IFnmx2qy7BdWOi0slKXBSnW0pOrIKUHrD0ocLNAyDL271LceAzvZmxJ01 YXO5PTdwpXkONhW3IMzwW2cDtLaijEffYUE2JHnYGFs8W+xQl0CZ6CaZjCfeS8o2FhVl vW9Y4eJkuu6j1gFcqCrPq0Ej9cKvYAjsx0lFOp63YxiSNxChkLtMPEHtuxBDj6yYt7mc I+336lhFkkd2zgwwFvuaffsWV0EiXw1rqbtd54D8o1CDw4pEadV7SUxMfj79cBzLBn7i xXwVdBAuPuNHHBj64E4AjfQR3A4BsOamTtqsHo8JCv1rWUBflMAl3QMFWPCzvFvt8IQV P4sw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=1Alsu9xQddUZwK4MUO0Ms0F6c5A3p78CyoojTq2bN0g=; b=llzhPFjBaqWy+FDDWmworWRw24Oo/OKd2p8l7Noxg3872z9DgXK0zjntAGPp5khDC5 TxjS1RYwLMMtXnIVfHoNtikKuyzyNHJgtlAeJg1VgDFmlfNR2fOfLkEq6Oh7GBfuT/hh FpVvFUsRGHgLzdsQzwjP1LDuCsWOAaZqfLDzomfTocS3d6yFf1ojQ9DCrKLhJ4vctcm5 MW7mxxBrUI7+RskeY6yzC/4uCgs2x8R1DC+zJPHJ1rO4VwIHZJ88HYq4xjlw0Z7smawA MAs8+07Ee3TJfRU77cOYGklhOi1qZgtyA8/MbdejuE5D3X+TN48qXIOWIiayqOKceWch F2Vg== X-Gm-Message-State: APjAAAVxLjqN2UgCgOteb/25GAuAOKbnp0cTMjLrxmiRLyyup4L5nl/F 4Q3MZNiJI/4WE89ZGhmLsDGYr/3QogYQ1CNorT0kjmwwTI+FGb1QRvIzVLX20lUtXZMVIoy/cLy cTXCiT52BmstdMuSoGUQi62G8xm3muwBq8HCovquwsWQja+J/Ra12sJe3NvzBGXqAJZE7SHWk1T K6omXCPOqufyVre7b0JJo= X-Google-Smtp-Source: APXvYqxZwXiXefVAFyWja8aGzYttQxCkJJ7UNJaoGUxZzb/3Dfe44mM8N/KT05DIZJ9zwmN1LsbD3C44HTLhj+s+7tAvXg== X-Received: by 2002:ab0:448:: with SMTP id 66mr21610101uav.29.1558548824430; Wed, 22 May 2019 11:13:44 -0700 (PDT) Date: Wed, 22 May 2019 11:13:27 -0700 In-Reply-To: <20190522181327.71980-1-matthewgarrett@google.com> Message-Id: <20190522181327.71980-6-matthewgarrett@google.com> Mime-Version: 1.0 References: <20190522181327.71980-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.21.0.1020.gf2820cf01a-goog Subject: [PATCH V4 5/5] IMA: Add a ima-vfs-sig measurement template From: Matthew Garrett To: linux-integrity@vger.kernel.org Cc: zohar@linux.vnet.ibm.com, dmitry.kasatkin@gmail.com, miklos@szeredi.hu, linux-fsdevel@vger.kernel.org, viro@zeniv.linux.org.uk, Matthew Garrett , Matthew Garrett Sender: linux-integrity-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Admins may wish to know whether measurements were sourced from the VFS or calculated by IMA, so we should provide an additional tag to indicate that. However, doing this by default would potentially break existing log parsing pipelines, so add a new template type rather than changing the default behaviour. Signed-off-by: Matthew Garrett --- security/integrity/ima/Kconfig | 7 ++++- security/integrity/ima/ima.h | 2 +- security/integrity/ima/ima_api.c | 6 +++- security/integrity/ima/ima_crypto.c | 7 +++-- security/integrity/ima/ima_template.c | 3 ++ security/integrity/ima/ima_template_lib.c | 37 +++++++++++++++++++++-- security/integrity/ima/ima_template_lib.h | 2 ++ security/integrity/integrity.h | 1 + 8 files changed, 57 insertions(+), 8 deletions(-) diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index a18f8c6d13b5..d2c7623d1dde 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -69,12 +69,16 @@ choice hash, defined as 20 bytes, and a null terminated pathname, limited to 255 characters. The 'ima-ng' measurement list template permits both larger hash digests and longer - pathnames. + pathnames. The 'ima-vfs-ng' measurement list template includes + an additional vfs: tag if the measurement was sourced directly + from the filesystem. config IMA_TEMPLATE bool "ima" config IMA_NG_TEMPLATE bool "ima-ng (default)" + config IMA_VFS_NG_TEMPLATE + bool "ima-vfs-ng" config IMA_SIG_TEMPLATE bool "ima-sig" endchoice @@ -85,6 +89,7 @@ config IMA_DEFAULT_TEMPLATE default "ima" if IMA_TEMPLATE default "ima-ng" if IMA_NG_TEMPLATE default "ima-sig" if IMA_SIG_TEMPLATE + default "ima-vfs-ng" if IMA_VFS_NG_TEMPLATE choice prompt "Default integrity hash algorithm" diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index cdaffe6c8a8d..d99b867bdc53 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -134,7 +134,7 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, const char *op, struct inode *inode, const unsigned char *filename); int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash, - bool trust_vfs); + bool *trust_vfs); int ima_calc_buffer_hash(const void *buf, loff_t len, struct ima_digest_data *hash); int ima_calc_field_array_hash(struct ima_field_data *field_data, diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 0def9cf43549..55bafce3d9c0 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -231,7 +231,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, if (buf) result = ima_calc_buffer_hash(buf, size, &hash.hdr); else - result = ima_calc_file_hash(file, &hash.hdr, trust_vfs); + result = ima_calc_file_hash(file, &hash.hdr, &trust_vfs); if (result && result != -EBADF && result != -EINVAL) goto out; @@ -247,6 +247,10 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, memcpy(iint->ima_hash, &hash, length); iint->version = i_version; + /* Record whether we got this measurement from the VFS or not */ + if (trust_vfs) + set_bit(IMA_TRUSTED_VFS, &iint->atomic_flags); + /* Possibly temporary failure due to type of read (eg. O_DIRECT) */ if (!result) iint->flags |= IMA_COLLECTED; diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 1c83d23d21a6..209c1bf836c1 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -406,7 +406,7 @@ static int ima_calc_file_shash(struct file *file, struct ima_digest_data *hash) * shash. */ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash, - bool trust_vfs) + bool *trust_vfs) { loff_t i_size; int rc; @@ -431,7 +431,7 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash, * filesystem is trusted, ask the VFS if it can obtain the * hash without us having to calculate it ourself. */ - if (trust_vfs && !ima_force_hash && + if (*trust_vfs == true && !ima_force_hash && !(inode->i_sb->s_iflags & SB_I_UNTRUSTED_MOUNTER)) { hash->length = hash_digest_size[hash->algo]; rc = vfs_get_hash(file, hash->algo, hash->digest, hash->length); @@ -439,6 +439,9 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash, return 0; } + /* If we're here then we're not using the VFS to obtain the hash */ + *trust_vfs = false; + /* Open a new file instance in O_RDONLY if we cannot read */ if (!(file->f_mode & FMODE_READ)) { int flags = file->f_flags & ~(O_WRONLY | O_APPEND | diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index b631b8bc7624..78bd8fea8b35 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -25,6 +25,7 @@ enum header_fields { HDR_PCR, HDR_DIGEST, HDR_TEMPLATE_NAME, static struct ima_template_desc builtin_templates[] = { {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT}, {.name = "ima-ng", .fmt = "d-ng|n-ng"}, + {.name = "ima-vfs-ng", .fmt = "d-vng|n-ng"}, {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"}, {.name = "", .fmt = ""}, /* placeholder for a custom format */ }; @@ -41,6 +42,8 @@ static const struct ima_template_field supported_fields[] = { .field_show = ima_show_template_digest_ng}, {.field_id = "n-ng", .field_init = ima_eventname_ng_init, .field_show = ima_show_template_string}, + {.field_id = "d-vng", .field_init = ima_eventdigest_vfs_ng_init, + .field_show = ima_show_template_digest_ng}, {.field_id = "sig", .field_init = ima_eventsig_init, .field_show = ima_show_template_sig}, }; diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index 26f71c5805f0..6defb0620f8d 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c @@ -224,7 +224,9 @@ int ima_parse_buf(void *bufstartp, void *bufendp, void **bufcurp, } static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo, - struct ima_field_data *field_data) + struct ima_event_data *event_data, + struct ima_field_data *field_data, + bool from_vfs) { /* * digest formats: @@ -237,6 +239,9 @@ static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo, enum data_formats fmt = DATA_FMT_DIGEST; u32 offset = 0; + if (from_vfs) + offset += snprintf(buffer, 5, "vfs:"); + if (hash_algo < HASH_ALGO__LAST) { fmt = DATA_FMT_DIGEST_WITH_ALGO; offset += snprintf(buffer, CRYPTO_MAX_ALG_NAME + 1, "%s", @@ -302,7 +307,7 @@ int ima_eventdigest_init(struct ima_event_data *event_data, cur_digestsize = hash.hdr.length; out: return ima_eventdigest_init_common(cur_digest, cur_digestsize, - HASH_ALGO__LAST, field_data); + HASH_ALGO__LAST, event_data, field_data, false); } /* @@ -323,7 +328,33 @@ int ima_eventdigest_ng_init(struct ima_event_data *event_data, hash_algo = event_data->iint->ima_hash->algo; out: return ima_eventdigest_init_common(cur_digest, cur_digestsize, - hash_algo, field_data); + hash_algo, event_data, field_data, false); +} + +/* + * This function is identical to ima_eventdigest_ng_init but tags events whose + * digest came from the VFS + */ +int ima_eventdigest_vfs_ng_init(struct ima_event_data *event_data, + struct ima_field_data *field_data) +{ + u8 *cur_digest = NULL, hash_algo = HASH_ALGO_SHA1; + u32 cur_digestsize = 0; + bool vfs = false; + + if (test_bit(IMA_TRUSTED_VFS, &event_data->iint->atomic_flags)) + vfs = true; + + if (event_data->violation) /* recording a violation. */ + goto out; + + cur_digest = event_data->iint->ima_hash->digest; + cur_digestsize = event_data->iint->ima_hash->length; + + hash_algo = event_data->iint->ima_hash->algo; +out: + return ima_eventdigest_init_common(cur_digest, cur_digestsize, + hash_algo, event_data, field_data, vfs); } static int ima_eventname_init_common(struct ima_event_data *event_data, diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h index 6a3d8b831deb..3f320299e0a0 100644 --- a/security/integrity/ima/ima_template_lib.h +++ b/security/integrity/ima/ima_template_lib.h @@ -38,6 +38,8 @@ int ima_eventname_init(struct ima_event_data *event_data, struct ima_field_data *field_data); int ima_eventdigest_ng_init(struct ima_event_data *event_data, struct ima_field_data *field_data); +int ima_eventdigest_vfs_ng_init(struct ima_event_data *event_data, + struct ima_field_data *field_data); int ima_eventname_ng_init(struct ima_event_data *event_data, struct ima_field_data *field_data); int ima_eventsig_init(struct ima_event_data *event_data, diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index a03f859c1602..9d74119bcdfd 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -68,6 +68,7 @@ #define IMA_CHANGE_ATTR 2 #define IMA_DIGSIG 3 #define IMA_MUST_MEASURE 4 +#define IMA_TRUSTED_VFS 5 enum evm_ima_xattr_type { IMA_XATTR_DIGEST = 0x01,