From patchwork Tue Feb 26 21:50:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10830857 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 1AED0180E for ; Tue, 26 Feb 2019 21:50:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0BF792CBDF for ; Tue, 26 Feb 2019 21:50:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 000D02D2EB; Tue, 26 Feb 2019 21:50:45 +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 934B72D2E2 for ; Tue, 26 Feb 2019 21:50:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729089AbfBZVuo (ORCPT ); Tue, 26 Feb 2019 16:50:44 -0500 Received: from mail-io1-f74.google.com ([209.85.166.74]:50664 "EHLO mail-io1-f74.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728766AbfBZVuo (ORCPT ); Tue, 26 Feb 2019 16:50:44 -0500 Received: by mail-io1-f74.google.com with SMTP id d7so11380012ios.17 for ; Tue, 26 Feb 2019 13:50:43 -0800 (PST) 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=OrLpVbFrhqHDu/nyMeqzGxF462Au6CRl2ys6e5+Fmlc=; b=M0pghNy1IQHmsn3LwD2Rcupn1ATT8/1wGNHkMW9MAWjSBSLDvTiaRdLeXMYpwV+7WD jSLN5JxVQV7bsATkpBQTv+/5fmChgvq/z1uPIRBoBLou23Fjlr6nXL6L6z1fcs3vnE+i oXR0uUWVHDs/rrMjZ7zUPmjMSDK3lTBFZCvGmiAozC9gq1IHzO4+esKKscVmTOiqFo0u fbRgYPr3rEQcvIzALTLF8MywzJJvAvgp4ZpMWI39RXnbAe1FDwKLCWnWsdU+FktpFxDo DlQ5uLlkfw8VSkg9bpX0X3dXkm15u6YVl3ezMs5qMordxE3TrTfKkkOxYTlflREAs5wr 3eQQ== 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=OrLpVbFrhqHDu/nyMeqzGxF462Au6CRl2ys6e5+Fmlc=; b=EZZ/mkbzwV9t23vjnuB4guBfB3++KJpAWS83uk9IbgEZ8vxsTtUx8zT0/CL31BJ5l3 j7jbUVOHASHlvUYqtPYA7zaETN0y+FHd7koCcMv2p6/SWGH2aeWmBHcacZ+60WWbo48+ xnG4PnIVnoT2d2rPhBUO+W9sQP282nvlEswUXWbnKIJ7kQGfgTEhtK6P+AGfem5Vm5Be xesUK4kjNNUT1BxKGbByUcp2F/VZ+yXABCHGSQQuJl/MYR7y4QG3FsDRXAhtJVoVHATr aTgWYFFiYnyyhWFhiCSpqUYdH9Gs0o3aPfsON6VBNF7y/YulUi/exIqsAv3VzVwMKoDQ 6P4g== X-Gm-Message-State: AHQUAuZqKjWcV6NMyZcPqnEBNpMG6VpDCTCaEk47ls6x9skNwwoodfQn GawRQKRAAsU6y3UHXpcOH1/UFSTZ8dVoLajYq4sSXw== X-Google-Smtp-Source: AHgI3IZbVD7NCGm3UXQ5pHDo2aRoNP9MyW1XXkOooFu5JiDCKU/A+poA+djdpw+M0YUSl/X/+PykqMmaDaCNfYuTJkaAZw== X-Received: by 2002:a24:220a:: with SMTP id o10mr3938734ito.22.1551217843625; Tue, 26 Feb 2019 13:50:43 -0800 (PST) Date: Tue, 26 Feb 2019 13:50:31 -0800 In-Reply-To: <20190226215034.68772-1-matthewgarrett@google.com> Message-Id: <20190226215034.68772-2-matthewgarrett@google.com> Mime-Version: 1.0 References: <20190226215034.68772-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.21.0.rc2.261.ga7da99ff1b-goog Subject: [PATCH V2 1/4] VFS: Add a call to obtain a file's hash From: Matthew Garrett To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, dmitry.kasatkin@gmail.com, linux-fsdevel@vger.kernel.org, miklos@szeredi.hu, Matthew Garrett Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@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 ff3c5e6f87cf..2b86f912be34 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -2150,3 +2150,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 29d8e2cfed0e..c6de2855cfdb 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -40,6 +40,7 @@ #include #include +#include struct backing_dev_info; struct bdi_writeback; @@ -1819,6 +1820,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 { @@ -1895,7 +1898,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 Tue Feb 26 21:50:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10830859 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 E03FF1390 for ; Tue, 26 Feb 2019 21:50:47 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CF8982CBDF for ; Tue, 26 Feb 2019 21:50:47 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C3A522D2EB; Tue, 26 Feb 2019 21:50:47 +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 593F52CBDF for ; Tue, 26 Feb 2019 21:50:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729115AbfBZVuq (ORCPT ); Tue, 26 Feb 2019 16:50:46 -0500 Received: from mail-pl1-f202.google.com ([209.85.214.202]:48575 "EHLO mail-pl1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728766AbfBZVuq (ORCPT ); Tue, 26 Feb 2019 16:50:46 -0500 Received: by mail-pl1-f202.google.com with SMTP id j13so10778494pll.15 for ; Tue, 26 Feb 2019 13:50:46 -0800 (PST) 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=W4AQdO0YXdQStwIqEW9eH2qaknX9pHyjHHTGGLf92pQ=; b=vt7cHQgg0rmQthW6SACNWMPRAQHMlenslKOWDe+rCF7ovBql5MKsW7NDuE3vKU1lAY YgTfFGDnN1aDKXT+Quj45t3cxjZXNE2N7wJ6DNc9Gw4cVSsZE7S79IJAtmB2daYZEu6r 0VV31zdh7/ZI8gSPu5MkX0FpWOuJzgL4NKFDoe3lG6uviBJ89deXswmo/zfbA6QmP6dX +QCuJw6JbSylCUho/LFj4AlkI13ZQ0eORzVqZgYCQuc2COnAyBrgFpZRKplFmg6H1CpD vLbYB89Gt8oB6FB0Jro3fvr/o7IJa79LaX6ezXdOvkEZc3vIML9U+zm1uP25EIvrjlzn yLeA== 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=W4AQdO0YXdQStwIqEW9eH2qaknX9pHyjHHTGGLf92pQ=; b=oOKtGhvxJTYUkQyoy7d044pYcVWtNSOR4ueKoKSX7Eo+14WVDMUgFv0+kjLq6/6wfq WQcgXQ4IZsbjT+dl8wawqPy02LnIKiygluI2g8AKrcJZMMCx/M6lWxGtBSd0gcqPnPw4 SQ6zWPxdJ1i2v1T/niVTrR/Eyi74zVP08q473XBOFuuWVzkCC/mXnT/rww2w22xPFueA 46vDTeym2Ze4AG6iFue0SYpbh6kO+MZblQ6dKPAR0edA3f5tT91uiP+PCL7Mf2B3rhLC nw7Z5Eg6ptkt3b/0s0u8JR+95HydYTy9WwDX6PNvAbljmMD+dO4AqBHVJ7vDLdCdVCKf sfvw== X-Gm-Message-State: AHQUAuZAOgSgefO0YoDEjFDlHAdlxJsMYieW3PZcals/kcOdbMZgRpM4 AT8NoiJI9I+vamOqDk0bME89Vq6Py4MkKkkCMQ9chg== X-Google-Smtp-Source: AHgI3IaguCd7CY+7KWQ8nxFIpRyRlWuQzJc7ZhQT5iZ+vP9IIupuw7K+BsVRCfqS19h76cryylU84wUOHiBc6Oh8MU/VpA== X-Received: by 2002:a62:488c:: with SMTP id q12mr2672853pfi.92.1551217845940; Tue, 26 Feb 2019 13:50:45 -0800 (PST) Date: Tue, 26 Feb 2019 13:50:32 -0800 In-Reply-To: <20190226215034.68772-1-matthewgarrett@google.com> Message-Id: <20190226215034.68772-3-matthewgarrett@google.com> Mime-Version: 1.0 References: <20190226215034.68772-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.21.0.rc2.261.ga7da99ff1b-goog Subject: [PATCH V2 2/4] IMA: Allow rule matching on filesystem subtype From: Matthew Garrett To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, dmitry.kasatkin@gmail.com, linux-fsdevel@vger.kernel.org, miklos@szeredi.hu, Matthew Garrett , Matthew Garrett Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@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 8bc8a1c8cb3f..dcecb6aae5ec 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; @@ -672,7 +678,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, @@ -698,6 +704,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"}, @@ -923,6 +930,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); @@ -1254,6 +1272,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 Tue Feb 26 21:50:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10830865 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 C35171390 for ; Tue, 26 Feb 2019 21:50:52 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B4E9D2CBDF for ; Tue, 26 Feb 2019 21:50:52 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A93EA2D2EB; Tue, 26 Feb 2019 21:50:52 +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 EA3F32CBDF for ; Tue, 26 Feb 2019 21:50:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729161AbfBZVuv (ORCPT ); Tue, 26 Feb 2019 16:50:51 -0500 Received: from mail-qt1-f201.google.com ([209.85.160.201]:42936 "EHLO mail-qt1-f201.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729129AbfBZVuv (ORCPT ); Tue, 26 Feb 2019 16:50:51 -0500 Received: by mail-qt1-f201.google.com with SMTP id o56so12090808qto.9 for ; Tue, 26 Feb 2019 13:50:49 -0800 (PST) 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=pEmqUgLDavjqt3Hyf36Pk7Q9hLue8QiyJJfaxkzgCdk=; b=HZpvwtWduOXKYQGQc+dVMlyWOv7ITnd2GtPj1DiFVy5pO92qYhoFJLSlB7cfaRe4GJ 2NL0qnExx+EqsxX9YbFvHTogiKE46+Oastn3WhI7F1hctpU0WV4lbb04SZX6gYacu1aQ enbjJpT3oC6nn/U1Yi5vU85aqiD4TVnL7aVic1mXGiN0HgL0ZdcWvDdPEt1UX//H08xX 6tpaZSR695HqW54L+/pQ+kv3XfqJ1PCxvLlwdURW22zCYqf34SxgqCZhUnpJ3SCy2UJh vd4+jCfxWiJ+arHnGEfpD385xn7xL1dtPexzf0WSFuTh+ZO9nTYqepT1d1IWb9iDoqGp 8kGw== 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=pEmqUgLDavjqt3Hyf36Pk7Q9hLue8QiyJJfaxkzgCdk=; b=SDvvqqNXHb/jHY2teFFwtCa3v2dGXldtTb65Sm/9EPg85RnUPSn5f+Ufs8CSbqOmZ3 vkQ9hT5UTpWJAjowCvXodPwSIkZAxiB8w6aBo7U52ny5NGe9dSk30xuyAN2Q121SCYzl 6G9kM6Me6fULc4KKkE55XD7E6qVmrsGzfnZRG5EqxZcjFnzom2iZg1WM87oQ6QWJ54dJ c+PbkmiTU3Jn9fuE3CIZq4kEeoMu7vnCHZMAoAYguIKM5c0G2KEJ12JcB8MFOc6WY26E Bn87Dk7VGbSHgZU2Mh81fqPnQdCYlqHoHFN90FZP2703C0Pu0DcabCbQ+BY2nyCDe4mA Ks8g== X-Gm-Message-State: AHQUAubY11gkPzP0hXK9nH7VcQPnMTsvh5XpOj3uxYPjSIhxiyThevjA cQ3bYHhdcqZUM103H60gA4k3RflrkzFer/FAJqwr4A== X-Google-Smtp-Source: AHgI3Ia+HoDcIHOndYsU5tvjeIEaGndO91XzJSFJy/L9mXLQjChKgbpTCg0l4guMZTaUFOcTMGp66S0xcvITm6927nIY9A== X-Received: by 2002:a0c:af31:: with SMTP id i46mr13935280qvc.33.1551217848640; Tue, 26 Feb 2019 13:50:48 -0800 (PST) Date: Tue, 26 Feb 2019 13:50:33 -0800 In-Reply-To: <20190226215034.68772-1-matthewgarrett@google.com> Message-Id: <20190226215034.68772-4-matthewgarrett@google.com> Mime-Version: 1.0 References: <20190226215034.68772-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.21.0.rc2.261.ga7da99ff1b-goog Subject: [PATCH V2 3/4] IMA: Optionally make use of filesystem-provided hashes From: Matthew Garrett To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, dmitry.kasatkin@gmail.com, linux-fsdevel@vger.kernel.org, miklos@szeredi.hu, Matthew Garrett Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@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 858b6c0b9a15..d3054a67e700 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1640,6 +1640,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 cc12f3449a72..24d9b3a3bfc0 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 acf2c7df7145..94105089ad41 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; @@ -402,11 +406,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; /* @@ -419,6 +426,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 dcecb6aae5ec..af632c31f856 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -683,7 +683,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 = { @@ -718,6 +718,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} }; @@ -1060,6 +1061,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; @@ -1356,6 +1360,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 43752002c222..a36cdc6651b7 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c @@ -290,7 +290,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 Tue Feb 26 21:50:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10830869 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 2D4951669 for ; Tue, 26 Feb 2019 21:50:55 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1BD672CBDF for ; Tue, 26 Feb 2019 21:50:55 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 103CD2D2EB; Tue, 26 Feb 2019 21:50:55 +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 E6D902D2E2 for ; Tue, 26 Feb 2019 21:50:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729176AbfBZVux (ORCPT ); Tue, 26 Feb 2019 16:50:53 -0500 Received: from mail-ua1-f73.google.com ([209.85.222.73]:37829 "EHLO mail-ua1-f73.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729129AbfBZVuw (ORCPT ); Tue, 26 Feb 2019 16:50:52 -0500 Received: by mail-ua1-f73.google.com with SMTP id 49so3570759ual.4 for ; Tue, 26 Feb 2019 13:50:51 -0800 (PST) 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=sTEnArxA3KhiLdOWIX5HwLoDvZHEQrk/7qv7T+h1Kus=; b=SARWUUNyP4ZaYFzfPqHmYTwCKaxhu5iosYKf5IGzgNAmQGmtXypdLpbbTsYmiwT0o2 QW3yhqMRm8JamXNRu/UhU54O0T2pNlrukk9R0wRJfcw7StJD3QEUX5sfu4Fll5ph+LAp fqQij50oSfM847bVrbiLhw0EAzbrsG1dY4DG4hpZaoKr+LxxhwbVyeRETqwmtsMuIGZI jzVWm91kgTKXGsgnSqPehGp0ZjpagJ40E8g4Mb+3jYOzocNjTvW8+WBfC0uNfBc5ufJo yfS6bGCMYs3A0iyBVf+IG3gf7jy4nf7Z31rzhnN2xadZPCa8wdmkSPi9PStrnZ1P8irY Q0vw== 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=sTEnArxA3KhiLdOWIX5HwLoDvZHEQrk/7qv7T+h1Kus=; b=IHP0ZEGYzG1MGnvAXurt8wYEBdvrPXdcc56yGaKyKa1X5cQHxFI+fUTuz0t9+btvrS mUcc/4q+JQiioP1wdyW6o3BdVlNrwivh0OPIS7oFzA9IflZ6VPqn15gQcmzIO0JMh/IU cGtes9hSO/hBpK8GW6iYYEAsHds19QbL9Hlm0vQJq9LYC4muVuMYH59Ewgxh+0eDYhLi lPqfK45BhC5iXrJmgouSfINQZdX4tl8hg2ok2BggmQOO3Dzngsx6dzOyaCLeCbDKE0un d8X9BAMTnCWJFRW5MfoRZQklMAS2ncuCBTDaKn+5+QgOZdBPUPIfcQB3qWXBJdkKXmwT R4aA== X-Gm-Message-State: AHQUAubxETCGIxRzoEDucuPraX9qYEEafP2Z7nmhNDn9bsKyWEwcKtRN mm503mPbcdu8PSl/oKcJmYR6LcVLejZyfa/0x/9SgA== X-Google-Smtp-Source: AHgI3IbZwX/5sJf1k67SLWD48J8TgNVLpbdFCmviXknsx2gGdVMTt+DtmDxgrOeOZT/9kQH7dv5dcdoU9TGOwjBUmkXGjw== X-Received: by 2002:a1f:1b82:: with SMTP id b124mr12503445vkb.11.1551217851266; Tue, 26 Feb 2019 13:50:51 -0800 (PST) Date: Tue, 26 Feb 2019 13:50:34 -0800 In-Reply-To: <20190226215034.68772-1-matthewgarrett@google.com> Message-Id: <20190226215034.68772-5-matthewgarrett@google.com> Mime-Version: 1.0 References: <20190226215034.68772-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.21.0.rc2.261.ga7da99ff1b-goog Subject: [PATCH V2 4/4] FUSE: Allow filesystems to provide gethash methods From: Matthew Garrett To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, dmitry.kasatkin@gmail.com, linux-fsdevel@vger.kernel.org, miklos@szeredi.hu, Matthew Garrett Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@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 | 34 ++++++++++++++++++++++++++++++++++ fs/fuse/fuse_i.h | 7 +++++++ fs/fuse/inode.c | 15 +++++++++++++++ include/uapi/linux/fuse.h | 6 ++++++ 4 files changed, 62 insertions(+) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index a59c16bd90ac..a791d69385de 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -3099,6 +3099,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; } @@ -3119,6 +3151,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 file_operations fuse_direct_io_file_operations = { @@ -3136,6 +3169,7 @@ static const struct file_operations fuse_direct_io_file_operations = { .compat_ioctl = fuse_file_compat_ioctl, .poll = fuse_file_poll, .fallocate = fuse_file_fallocate, + .get_hash = fuse_file_get_hash, /* no splice_read */ }; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 2f2c92e6f8cb..f63920ebce85 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -705,6 +705,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 c2d4099429be..d0d4177fb099 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; }; @@ -453,6 +454,7 @@ enum { OPT_ALLOW_OTHER, OPT_MAX_READ, OPT_BLKSIZE, + OPT_ALLOW_GETHASH, OPT_ERR }; @@ -465,6 +467,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} }; @@ -551,6 +554,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; } @@ -574,6 +586,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) @@ -1163,6 +1177,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 b4967d48bfda..d106ea3e52f3 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -394,6 +394,7 @@ enum fuse_opcode { FUSE_RENAME2 = 45, FUSE_LSEEK = 46, FUSE_COPY_FILE_RANGE = 47, + FUSE_GETHASH = 48, /* CUSE specific operations */ CUSE_INIT = 4096, @@ -817,4 +818,9 @@ struct fuse_copy_file_range_in { uint64_t flags; }; +struct fuse_gethash_in { + uint32_t size; + uint32_t hash; +}; + #endif /* _LINUX_FUSE_H */