From patchwork Fri May 17 21:24:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10948621 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 DDAD5933 for ; Fri, 17 May 2019 21:24:58 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CBF2D2847D for ; Fri, 17 May 2019 21:24:58 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BD5782847A; Fri, 17 May 2019 21:24:58 +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 414B12847A for ; Fri, 17 May 2019 21:24:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727816AbfEQVY6 (ORCPT ); Fri, 17 May 2019 17:24:58 -0400 Received: from mail-yb1-f202.google.com ([209.85.219.202]:33892 "EHLO mail-yb1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727474AbfEQVY5 (ORCPT ); Fri, 17 May 2019 17:24:57 -0400 Received: by mail-yb1-f202.google.com with SMTP id b82so7372075yba.1 for ; Fri, 17 May 2019 14:24:57 -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=APRT6LEPqixBvHano+viVPqM6dMjKu1ogq3RkP5nfIs=; b=aQGynE/2Ct9KNtAZ5iXBB7Jw62upUkAAyczhhJA2F2czqiQLh5wh9ZmTZ5mdlePYNW 7Q2l38wyOVWIApdmBcxAMtIrAymD+NglINpMls/Kdy0g5QIlyE8eSjjdDcnZFhgq967e Fy2OWQajtivBBaDPOHJOu1hVM5zn38CSqqq/wtOqyPLhTlCHffHTk5yB/O8qMLjnfiDj tneN6ddq1ojgYtZPEs34VwLam+ZAeHQV5/+rVb2RvxpDlHs6E95TpD1GltdHSms2k08y tGJ9EcZT40MUmHTOE7+C+psQM8srkuGOYH+1esnAYAtmwgChEZqTpGueKDGXdRQ46EIN RD5Q== 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=APRT6LEPqixBvHano+viVPqM6dMjKu1ogq3RkP5nfIs=; b=fnB+VHMejPJtCs+MTQr4s5vV1bKp4gKoCXwUObWTdMKS1Ti18DaFdLImekLzjys00Z c6Rddh3nzx7mnxDxFDrBElgIk/iAPLXDd5wm8awqXejFIjdkA+YJrfTxXy7i8p7HPKx8 VFzvQ+/JNPcrcXtPd2m3zs3BSnN3DD+LzFruNz8C/NWQjnblKfiWe9VPp+ElICOo5mfm MYLkjoRMsXovIWYXLHUhOsDd9IJoP52sKnBs4aWngg2CEuIwmONF/Dl+4XD8Wr58IEv5 +yANBjplxnqwUZNC9oRWQ2UwxOnURJ0grMO4vWNMkjPtaEMLgnNrc/RLtLomjuk+Hkq5 1VeA== X-Gm-Message-State: APjAAAUQsfMhn1EVHuyECSufGtv/vns4OdbSo8CYfmIywUsHxZ20w6Dz rV/qanDAuOFlkbWpN/XAtZdc/CFENMk4RwofRM8xpnWKb6cwbn8TxLTw3bKf1l1PHLjHPzBUHH3 lcj17wrfEi/ELuST6TzGPg66fZY5cSEgnYoHaKvdnq17nC7inxfzgBBck78upvktYyQP3zJ2Mwd 5a0AfCqQIDIsC6Y/wPVos= X-Google-Smtp-Source: APXvYqz8FZKK/R4raVavRFrW36HXdCWJ+9zF2vh1ttYxP1/usjMDW20DfxgQgYrPzK6jQWhBLwEqmk7fErV5wuX5TcKCNw== X-Received: by 2002:a81:2717:: with SMTP id n23mr29712693ywn.511.1558128297020; Fri, 17 May 2019 14:24:57 -0700 (PDT) Date: Fri, 17 May 2019 14:24:43 -0700 In-Reply-To: <20190517212448.14256-1-matthewgarrett@google.com> Message-Id: <20190517212448.14256-2-matthewgarrett@google.com> Mime-Version: 1.0 References: <20190517212448.14256-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.21.0.1020.gf2820cf01a-goog Subject: [PATCH V3 1/6] 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 61b43ad7608e..3ba7038ba9a9 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -2157,3 +2157,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 dd28e7679089..211f0e214953 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; @@ -1822,6 +1823,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 { @@ -1898,7 +1901,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 Fri May 17 21:24:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10948625 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 ABC63912 for ; Fri, 17 May 2019 21:25:01 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 971F62847A for ; Fri, 17 May 2019 21:25:01 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 88DD12847F; Fri, 17 May 2019 21:25:01 +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 F33252847A for ; Fri, 17 May 2019 21:25:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728551AbfEQVZA (ORCPT ); Fri, 17 May 2019 17:25:00 -0400 Received: from mail-pl1-f202.google.com ([209.85.214.202]:37113 "EHLO mail-pl1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728164AbfEQVZA (ORCPT ); Fri, 17 May 2019 17:25:00 -0400 Received: by mail-pl1-f202.google.com with SMTP id p12so4928461plk.4 for ; Fri, 17 May 2019 14:24:59 -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=2s+WtHt0xVYSES8yQsV6/RNZ+qrsDxexZPBb8+//cQ8=; b=qhWHzJsakiKjFraRvn973QzeDsH0PgsqRUAi2bbGjU1G48Npxz35o70nSQ0PrpO3Em i99hzLUtO0DkehOa8ldTXHCoaN7DIgwldadkwd2MkfUr7AV9WfgorAf5yDZb+IP/uIMV BzlZoVPkMcyWdoC9MU+SJZo282uydDZS8c3qxk4KQjcA3FtLbb6LyleQtfEjLG6XoRZ9 BSClrnkIjksUmBOWBhdAAjmMJmlaP/lp2iUuSnunoRtBIznZdtsVHN9W55pWeGyhWUR1 khMvcJdO1WGkBo5j9vmG7/IWqP4qDpbYJ8qvaeU1mgsYD86SCuE0P7r6+XVTYUNwdUqM Aobg== 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=2s+WtHt0xVYSES8yQsV6/RNZ+qrsDxexZPBb8+//cQ8=; b=kBYqCPcnmv3CMj816ug4hPoz/O5IadCri2gQmTFSK25kdmgMywD+6De3NgMHiLk04T joB7cJVMZN92Pm0Hssy3X1Sdy6DQLGJL8HXREtrZiQRf+RTgPW/tLqYvtgnYo1S9jH8s J4zOMCPxcAykUFCgxWJexmL5LN0pB+TNwOwjr129QCXjv71OmH+6G7/OmSKTKjWnS/4Y diba+qpLvsmjmSBzu6UPM9M69k8b3YQf3gAVarPagI//K/Fg4lOVEJOUwkuW6WRePmkw 4uz/JpKSA7tARvx5vRTwu8/DXAHbBmr2z0WRhLW/Dii712wiwnvq/vv8fvqga/Tqs6Op OW3w== X-Gm-Message-State: APjAAAVXDmvEx4X6s+qozsLZcwOr0ROZRL1NBwqhxJSFXUzv5YpXtzkj XJ6a8+uQJcFrxeBLgqZiC0iyuC4dwzuRysaS30h6mDPKChtwV025ObimNY3A3iOkM2Z4ylbsyeI 8lqhE+616D1LuFqqnSIGelC8sdOCpsQ0eh1pINE4kg/a8SYd2quUbHtbVmaDCDH+yog4QXP4kBn OlETx9U+0xX1gisNSFu7k= X-Google-Smtp-Source: APXvYqwPf2+O0p+dSfTpp5u79tgKSV9op63b3cr5zHPIY6Z7Qo46V24Lsfk2ye858N9iXgG32j6T4ReODfabQ+zKRrzLEw== X-Received: by 2002:a65:42ca:: with SMTP id l10mr6451745pgp.181.1558128299252; Fri, 17 May 2019 14:24:59 -0700 (PDT) Date: Fri, 17 May 2019 14:24:44 -0700 In-Reply-To: <20190517212448.14256-1-matthewgarrett@google.com> Message-Id: <20190517212448.14256-3-matthewgarrett@google.com> Mime-Version: 1.0 References: <20190517212448.14256-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.21.0.1020.gf2820cf01a-goog Subject: [PATCH V3 2/6] 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 06096b60f1df..cf73c1712333 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -3156,6 +3156,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; } @@ -3177,6 +3209,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 0920c0c032a0..7e796eaebe38 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -714,6 +714,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 ec5d9953dfb6..845e6c48a6f4 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; }; @@ -456,6 +457,7 @@ enum { OPT_ALLOW_OTHER, OPT_MAX_READ, OPT_BLKSIZE, + OPT_ALLOW_GETHASH, OPT_ERR }; @@ -468,6 +470,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} }; @@ -554,6 +557,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; } @@ -577,6 +589,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) @@ -1167,6 +1181,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 2ac598614a8f..31a2dc016a8b 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -399,6 +399,7 @@ enum fuse_opcode { FUSE_RENAME2 = 45, FUSE_LSEEK = 46, FUSE_COPY_FILE_RANGE = 47, + FUSE_GETHASH = 48, /* CUSE specific operations */ CUSE_INIT = 4096, @@ -822,4 +823,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 Fri May 17 21:24:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10948629 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 9C6A1933 for ; Fri, 17 May 2019 21:25:03 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8A67A28479 for ; Fri, 17 May 2019 21:25:03 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 79DE02847E; Fri, 17 May 2019 21:25:03 +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 094DC28479 for ; Fri, 17 May 2019 21:25:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728962AbfEQVZC (ORCPT ); Fri, 17 May 2019 17:25:02 -0400 Received: from mail-pl1-f201.google.com ([209.85.214.201]:36082 "EHLO mail-pl1-f201.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728164AbfEQVZC (ORCPT ); Fri, 17 May 2019 17:25:02 -0400 Received: by mail-pl1-f201.google.com with SMTP id g11so4934293plb.3 for ; Fri, 17 May 2019 14:25:02 -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=ZXa+6PpEq25vw32Il9yKyuZ4OvWq+Nl2SyCgp80AC/1Us0wp+cyOb6GdmVF8xKeTg4 Lumm9hPXPYfFoRK7nnxRZis/v0wLrsusWoSnyosHIE265vS8/ZwZZB2LU8A784J1kPTQ xWDs9BUC66IsAr+welIu2WpJ68pm338DTVdS48QiAubCa7CIzj2AhtaGU7epoqo/1k6e 822Q7F6DfKBtxm6XB+P80mb0kia75mWWU+gCjuCKY7rPL6dBv6IOleUnSt/CNW0XcDYD 5Yp8CiS1+tmqGiVizW5g6aqjKhqpeQy9NFSa27Z1zwfcTEjL0zgxLQ5fLqA/1gCTL4v/ Ogng== 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=O0pmzw3AI69phRdifbqJVFZ1kdbOP+RcjXB1sFMktakVXBolvrmGcy72qrVfKyIkeI 5Kplus1BxSbIvXDU7vEGQ35PjjGNFGM4BLnhoRsIVLcP79ZVbOKBLm3gm1TtMX4f8J2T c5lx31W4Iogqo3P17JZEtEdJH7fRLwtGT+QkOrtqrKHxAuUnn3AO2Vw1f+zO4FfBp85A YKLTQwKkDAe+BroCn0R5IbFPRoUyy1GimGer5nUl9uHjID2IEgmsaN716XySfDXbgvor f4CdbQFfKsF+msC4Kc5tA1SE3vXy55Cb0CV6C34qh0de8BPa1vlOpAWtG9RGemXVSoiB YycQ== X-Gm-Message-State: APjAAAVzXCZkkA6070udx8HZiU+hZDfF6rRkA3bTBD5gCHa/htVSGGZ/ +yDUZ1X0BzuW7xZL7RtzagUUT95/qUm9U+DF6K7SLW0oOsq2wvIJ3JxMGNcZfsZTtQeKucr6r2x bOVwnUjTGl0G1ZMMnqMgdhClPz2GWGFqN5Nb3iyOWjREsCb3x3X0ir/bIcg+ac1OqUOfYznajDY oZMXWoiYdjNYK/9Cenqm4= X-Google-Smtp-Source: APXvYqwo+ESMkPLpKypeMK8H6U6nIhz+3gFIps9LOJCfyaXKPzWzK3MQNUHDHm+egVvEz8GLZIhZh5TWQspui96K8/OPLw== X-Received: by 2002:a63:5cb:: with SMTP id 194mr59565142pgf.294.1558128301705; Fri, 17 May 2019 14:25:01 -0700 (PDT) Date: Fri, 17 May 2019 14:24:45 -0700 In-Reply-To: <20190517212448.14256-1-matthewgarrett@google.com> Message-Id: <20190517212448.14256-4-matthewgarrett@google.com> Mime-Version: 1.0 References: <20190517212448.14256-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.21.0.1020.gf2820cf01a-goog Subject: [PATCH V3 3/6] 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 Fri May 17 21:24:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10948633 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 2317C912 for ; Fri, 17 May 2019 21:25:08 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 12D0D28479 for ; Fri, 17 May 2019 21:25:08 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 073072847E; Fri, 17 May 2019 21:25:08 +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 1680128479 for ; Fri, 17 May 2019 21:25:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729033AbfEQVZF (ORCPT ); Fri, 17 May 2019 17:25:05 -0400 Received: from mail-vk1-f201.google.com ([209.85.221.201]:54491 "EHLO mail-vk1-f201.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729028AbfEQVZF (ORCPT ); Fri, 17 May 2019 17:25:05 -0400 Received: by mail-vk1-f201.google.com with SMTP id 1so1256581vky.21 for ; Fri, 17 May 2019 14:25:04 -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=BLoKd5JLJMfKPW5l7eN3gWFm7KhsRgY404yjUUoL80c=; b=InQsJZsY17kRCzgIuq9O1BqfkYYkn7JZ8zXK8Agx7WKP6EFPA+7YP08NhWs5MQvg+Z CmEuWbbcydHLXSGXzfwkSEsWZBnBHxmEiu4IYT0j/fvPmYyrxsZPY4hw6bCfJC1YuXQI cVouqAfox+PDZeN2qN3q+GkbIKEP4ac7gqCwAM5WETsV3zoRq3VNDA6+HnFQAOTPT/Xj sVVD8EtJEDkJzX6gq3T3VhIEbCTJugrTPahj42u2p5Q7S0PvWh8zvXx/A+KVZeqdWIJn ByPcE+tCMGTeXJDAlLNAo0pwSYZ+uhxtdtmKfMw3bt2uK+dsPJfBX1wcDG9y6Pd5UGDZ vmdg== 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=BLoKd5JLJMfKPW5l7eN3gWFm7KhsRgY404yjUUoL80c=; b=PvjTOpv8qEa0R58IFMCZN1qP2qzbjHUdCthDy88Joa9RrjGpaOKCfLPaopHGzcYtDJ dYMsNPb9S5Y3bWtuT6i3keRNy4cm7X8C0swVR3PDatV11keMs0St8AAU+/j3OSsdP9b6 Cyl+7ioWfliVTOyisF82Em73trdMCaQPNZA8PKZCYq4VbdRmXBfPxQLYCCLartk3hlZU oklSMyY3zmR9ZArlV5VqZzNAApVUs1Bm/Qu0tID2WTMwaf5rdCtjVWs2H6Tq86+3GCVX WbeOIdlWJ6pTQ+IZMN7Obn6XEjevhrZe23UV1oi0zD8lfT6GOxLDunfIrQHZNhhhCk59 iIRw== X-Gm-Message-State: APjAAAX59tSykA6eRKzPvIMVMtQJ60UoLiaYu+IIoX2jfrknIIHQVrWS ApzCSZsnFmUPxYwNnR3+2EFG3pienB4ohGhP6B9rw4qJ2iWcyKueFSSjDYSizOmpEsCWKCjA6e3 lXsaZG3Nu82HEzhLfn8sqnZGdSADtr3MlqWVSK5CGwkJU/CbqNuUYGrKPJbRPjr0tZdY1VidN8Y FTQHj9MaKs03W2EzoTj4g= X-Google-Smtp-Source: APXvYqzC7i1k3xBs8Acb5XaZfkwAAikudoJJANjPJZDxtyVJ8Y+ZEfTYfb/4AJ98KHvnjToAdMaIKI1mUuDuEWw575MSAw== X-Received: by 2002:a67:eb13:: with SMTP id a19mr18982363vso.233.1558128304247; Fri, 17 May 2019 14:25:04 -0700 (PDT) Date: Fri, 17 May 2019 14:24:46 -0700 In-Reply-To: <20190517212448.14256-1-matthewgarrett@google.com> Message-Id: <20190517212448.14256-5-matthewgarrett@google.com> Mime-Version: 1.0 References: <20190517212448.14256-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.21.0.1020.gf2820cf01a-goog Subject: [PATCH V3 4/6] 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 2b8ee90bb644..573cef13d268 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1656,6 +1656,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 16a4f45863b1..cceedce750d3 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 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 Fri May 17 21:24:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10948637 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 BBE21912 for ; Fri, 17 May 2019 21:25:09 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AB4F128479 for ; Fri, 17 May 2019 21:25:09 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9F7C328481; Fri, 17 May 2019 21:25:09 +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 DE2E228479 for ; Fri, 17 May 2019 21:25:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729036AbfEQVZI (ORCPT ); Fri, 17 May 2019 17:25:08 -0400 Received: from mail-yb1-f201.google.com ([209.85.219.201]:45299 "EHLO mail-yb1-f201.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728334AbfEQVZI (ORCPT ); Fri, 17 May 2019 17:25:08 -0400 Received: by mail-yb1-f201.google.com with SMTP id x194so7359475ybg.12 for ; Fri, 17 May 2019 14:25:07 -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=Zl3/Rnw7EQS3Z+Zsbp/vOJNYpSsHIdTqkNKdqugEpeA=; b=I6a/LS+o2HJd5uUaVhavxbPxPjV96426L0jS9BGOerOlLlqkcalMt92xpBYK1GBWUB wPCL2e+tRqWjdbHDsKN3xXP0cP1A1zYHd2OKUKa2crnEXD7jNtt6amIrOpOUgM8hkPVe CpCJGpfYiYGKdAZpI38o++llgXwCJ4BormpqF0iSGgissHeoK86lTC+ebRY8wgTBf2rH JVLIrkyRtDt8s9JY8S8WvcYTNg+jSXY6dWncSjXwlpasXs2VtVN+itFiUsOSLJjUdpX6 FIG7rFm6LGV7VNe9lz0YIUnNyjvYBW//dr2Czg4Vs9qMbUn1X5ltjNUTegKuTlHfQ8+Y yRjQ== 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=Zl3/Rnw7EQS3Z+Zsbp/vOJNYpSsHIdTqkNKdqugEpeA=; b=UB9iH/TXaoNO3lHJvhB9dQiOuXS7E9etYIaDuQTmWshG12avehvsHUlRtBePPJ9OvK Q5wMWaq34kV4PkrfnNHGnww9TJJM1UqCisDpwqr8eLLUiEt0RLemZNsmLTwLt+KICxUB 5SxP3a6s9fxE7nIJD2yW3mFe92reGcOyv5azYp9Tg+T9+g3WLZAgCBok5fFiFcuOBHkm ihO8y1DWJremYap/uPAp4/gJuuGCyndJ46ZQkcAWhLy9LWHZZQsLYTV+wLHhQmFiNiUG bcTQFZi95BgHVIH7qemoZIin6QUxkX0PFtnbD3bUn2kNzb6FocaswiCiuRQNcrEerSYJ 9Ynw== X-Gm-Message-State: APjAAAXkLxigDta7zchuLSknH6JOfTRL8UQXHrj12XeMQpSS+yr6eMaB ldg6+tpu9pPMRqnHsXm6iEl8a8vI1pEwi+oCajK86qRrqRI4hfXI+LALJ9ScKHKNO9FfmqFRcKZ wvxwxr+Wwkcy9eSJrAfTGz1jgS9owALPsLVRnQx4D8G0a+pq7M4S4lutVOWD/+usi2JfMoaR17o q/Y2oPvZIPutC/3a4WaXw= X-Google-Smtp-Source: APXvYqxhoUxPRHt0GzeXmuwcl0k+JPbW78hOCSMGd+677rVy429jpB5wqwdyV7nSUIofDAT4zByzgzHe0FppDp2jyWFW5g== X-Received: by 2002:a0d:edc5:: with SMTP id w188mr9387948ywe.17.1558128307137; Fri, 17 May 2019 14:25:07 -0700 (PDT) Date: Fri, 17 May 2019 14:24:47 -0700 In-Reply-To: <20190517212448.14256-1-matthewgarrett@google.com> Message-Id: <20190517212448.14256-6-matthewgarrett@google.com> Mime-Version: 1.0 References: <20190517212448.14256-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.21.0.1020.gf2820cf01a-goog Subject: [PATCH V3 5/6] 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 | 41 ++++++++++++++++++++--- security/integrity/ima/ima_template_lib.h | 2 ++ security/integrity/integrity.h | 1 + 8 files changed, 59 insertions(+), 10 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 cceedce750d3..721893073607 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -407,7 +407,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; @@ -432,7 +432,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); @@ -440,6 +440,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..863e95281c4b 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,10 +239,13 @@ 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", - hash_algo_name[hash_algo]); + offset += snprintf(buffer + offset, CRYPTO_MAX_ALG_NAME + 1, + "%s", hash_algo_name[hash_algo]); buffer[offset] = ':'; offset += 2; } @@ -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, From patchwork Fri May 17 21:24:48 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10948643 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 C445B14DB for ; Fri, 17 May 2019 21:25:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B5A4228479 for ; Fri, 17 May 2019 21:25:12 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AA04F2847D; Fri, 17 May 2019 21:25:12 +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 D19612847A for ; Fri, 17 May 2019 21:25:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729124AbfEQVZK (ORCPT ); Fri, 17 May 2019 17:25:10 -0400 Received: from mail-qt1-f202.google.com ([209.85.160.202]:35023 "EHLO mail-qt1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729074AbfEQVZK (ORCPT ); Fri, 17 May 2019 17:25:10 -0400 Received: by mail-qt1-f202.google.com with SMTP id z7so1346175qtj.2 for ; Fri, 17 May 2019 14:25:10 -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=tPAbrtlGE6SuoqUuOjDsdEAArkm68YXQYVAiqtSOAZs=; b=jh7U/j5BgZBhUOx9yl9O7MwACSVwrD3EoNOq7ZdaPjiBiXN51yhX3NeOGC0bbj3WAC YrOjq6y1FyVgL+wg0uRn90womExArFt+llVOF/OC2tsWlCXCYAwR7PtDTi67LKSTPlEe autijAWOcakdawpkFPCdNPVqtUb+t4gBmQyXfDv0gFzlwzg0J8c3s1AJgCckhW7D6O2K S53fc367Gj2LVLicKqIsvfKCiHCRL8y8EqTxXBCCudwUiIGbMcbRMr2CWrAwQiHPtcvB Ps2W8l7NkuzLINTyQ9TIstddfn8PBqDG8yIbiZgx9fPI/aKfCXZyokylLJRZT5E48Rsm QWWQ== 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=tPAbrtlGE6SuoqUuOjDsdEAArkm68YXQYVAiqtSOAZs=; b=dWJfqDeFOSBoTS+Ewnnw4ZxptGo8zLS+WoBaEJnkdmfr8JPtKyEn+JdhJelE0ivan2 Wod4ridfZ0NIrCODcdWjhR3LMIV68/QukGpe0m0IkitrA2QTBEnXeDqCVfCH1P9W8y3P d4tcc8GRZn4z+xZ8iB9xfbcrwXOnzgFI8rNwzJhqdga2L5ywMlnJ+v8at13Dw0dDg6pJ 4JPYEIqmcbIdtE39vw4p4ZgW/VaseYPHDh/3JEJz3eZw8RKpRE70VyWFV5Pl/5HHm1BM VyVXGZjttIVlPLDAdcyUSdpU5F2bd3cCEXR1HqLqRd19NlKH+Oqp1ibq8T5xON8cZx46 h+Lg== X-Gm-Message-State: APjAAAUR+8zVb9eLXEb9WtAk9ogv9IzjoAelGUmwD1j3Pw911VuZe1Xy PGfMboe+36WCCJCL0nVbZgIPqMaVfpEx/Kb6uy90bw218YeNrxaG3ynf5UX0uGKcx8xvM2kiv+l 39bJfFdslGWUTniXnaR3pmoUj8aQQkUO1xyAaHrasuYv1h9dg0k5Aqe9Y+lxFy3FU+5Bc/rgw7y sMqdQ3JRHQK+Ywr+vqqMM= X-Google-Smtp-Source: APXvYqxRFNt6eymUuKmN2k8dumIGj8/uQlQWvb2F+3c6UbTkSgdKUSJpGycLaog4F7DreHCpp4oaqTKvIZRwOTMcSj+liw== X-Received: by 2002:ac8:384f:: with SMTP id r15mr49326766qtb.290.1558128309570; Fri, 17 May 2019 14:25:09 -0700 (PDT) Date: Fri, 17 May 2019 14:24:48 -0700 In-Reply-To: <20190517212448.14256-1-matthewgarrett@google.com> Message-Id: <20190517212448.14256-7-matthewgarrett@google.com> Mime-Version: 1.0 References: <20190517212448.14256-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.21.0.1020.gf2820cf01a-goog Subject: [PATCH V3 6/6] IMA: Allow profiles to define the desired IMA 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 log different measurements using different IMA templates. Add support for overriding the default template on a per-rule basis. Signed-off-by: Matthew Garrett --- Documentation/ABI/testing/ima_policy | 3 ++- security/integrity/ima/ima.h | 7 +++++-- security/integrity/ima/ima_api.c | 7 +++++-- security/integrity/ima/ima_appraise.c | 2 +- security/integrity/ima/ima_main.c | 9 ++++++--- security/integrity/ima/ima_policy.c | 24 ++++++++++++++++++++++-- security/integrity/ima/ima_template.c | 10 ++++++++-- security/integrity/integrity.h | 1 + 8 files changed, 50 insertions(+), 13 deletions(-) diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy index 6a517282068d..f707ef7eda88 100644 --- a/Documentation/ABI/testing/ima_policy +++ b/Documentation/ABI/testing/ima_policy @@ -24,7 +24,7 @@ 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=] [template=] [permit_directio] [trust_vfs]] base: func:= [BPRM_CHECK][MMAP_CHECK][CREDS_CHECK][FILE_CHECK][MODULE_CHECK] @@ -41,6 +41,7 @@ Description: fowner:= decimal value lsm: are LSM specific option: appraise_type:= [imasig] + template:= name of an IMA template type (eg, d-ng) pcr:= decimal value permit_directio:= allow directio accesses trust_vfs:= trust VFS-provided hash values diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index d99b867bdc53..29a71c2e6cfa 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -148,6 +148,7 @@ int ima_init_crypto(void); void ima_putc(struct seq_file *m, void *data, int datalen); void ima_print_digest(struct seq_file *m, u8 *digest, u32 size); struct ima_template_desc *ima_template_desc_current(void); +struct ima_template_desc *lookup_template_desc(const char *name); int ima_restore_measurement_entry(struct ima_template_entry *entry); int ima_restore_measurement_list(loff_t bufsize, void *buf); int ima_measurements_show(struct seq_file *m, void *v); @@ -194,7 +195,8 @@ enum ima_hooks { /* LIM API function definitions */ int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid, - int mask, enum ima_hooks func, int *pcr); + int mask, enum ima_hooks func, int *pcr, + struct ima_template_desc **template_desc); int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func); int ima_collect_measurement(struct integrity_iint_cache *iint, struct file *file, void *buf, loff_t size, @@ -215,7 +217,8 @@ const char *ima_d_path(const struct path *path, char **pathbuf, char *filename); /* IMA policy related functions */ int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid, - enum ima_hooks func, int mask, int flags, int *pcr); + enum ima_hooks func, int mask, int flags, int *pcr, + struct ima_template_desc **template_desc); void ima_init_policy(void); void ima_update_policy(void); void ima_update_policy_flag(void); diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 55bafce3d9c0..457b071669ff 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -164,6 +164,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename, * MAY_APPEND) * @func: caller identifier * @pcr: pointer filled in if matched measure policy sets pcr= + * @template_desc: pointer filled in if matched measure policy sets template= * * The policy is defined in terms of keypairs: * subj=, obj=, type=, func=, mask=, fsmagic= @@ -176,13 +177,15 @@ void ima_add_violation(struct file *file, const unsigned char *filename, * */ int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid, - int mask, enum ima_hooks func, int *pcr) + int mask, enum ima_hooks func, int *pcr, + struct ima_template_desc **template_desc) { int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH; flags &= ima_policy_flag; - return ima_match_policy(inode, cred, secid, func, mask, flags, pcr); + return ima_match_policy(inode, cred, secid, func, mask, flags, pcr, + template_desc); } /* diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 5fb7127bbe68..2f6536ab69e8 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -57,7 +57,7 @@ int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func) security_task_getsecid(current, &secid); return ima_match_policy(inode, current_cred(), secid, func, mask, - IMA_APPRAISE | IMA_HASH, NULL); + IMA_APPRAISE | IMA_HASH, NULL, NULL); } static int ima_fix_xattr(struct dentry *dentry, diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 357edd140c09..f23069d9e43d 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -174,7 +174,7 @@ static int process_measurement(struct file *file, const struct cred *cred, { struct inode *inode = file_inode(file); struct integrity_iint_cache *iint = NULL; - struct ima_template_desc *template_desc; + struct ima_template_desc *template_desc = NULL; char *pathbuf = NULL; char filename[NAME_MAX]; const char *pathname = NULL; @@ -192,7 +192,8 @@ static int process_measurement(struct file *file, const struct cred *cred, * bitmask based on the appraise/audit/measurement policy. * Included is the appraise submask. */ - action = ima_get_action(inode, cred, secid, mask, func, &pcr); + action = ima_get_action(inode, cred, secid, mask, func, &pcr, + &template_desc); violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) && (ima_policy_flag & IMA_MEASURE)); if (!action && !violation_check) @@ -275,7 +276,9 @@ static int process_measurement(struct file *file, const struct cred *cred, goto out_locked; } - template_desc = ima_template_desc_current(); + if (!template_desc) + template_desc = ima_template_desc_current(); + if ((action & IMA_APPRAISE_SUBMASK) || strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0) /* read 'security.ima' */ diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index c293cbc6c578..33c52466bc8a 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -82,6 +82,7 @@ struct ima_rule_entry { } lsm[MAX_LSM_RULES]; char *fsname; char *subtype; + struct ima_template_desc *template; }; /* @@ -403,6 +404,7 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) * @func: IMA hook identifier * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) * @pcr: set the pcr to extend + * @template_desc: the template that should be used for this rule * * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type) * conditions. @@ -412,7 +414,8 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) * than writes so ima_match_policy() is classical RCU candidate. */ int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid, - enum ima_hooks func, int mask, int flags, int *pcr) + enum ima_hooks func, int mask, int flags, int *pcr, + struct ima_template_desc **template_desc) { struct ima_rule_entry *entry; int action = 0, actmask = flags | (flags << 1); @@ -444,6 +447,9 @@ int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid, if ((pcr) && (entry->flags & IMA_PCR)) *pcr = entry->pcr; + if (template_desc && entry->flags & IMA_TEMPLATE) + *template_desc = entry->template; + if (!actmask) break; } @@ -681,7 +687,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_trust_vfs, Opt_err + Opt_pcr, Opt_trust_vfs, Opt_template, Opt_err }; static const match_table_t policy_tokens = { @@ -717,6 +723,7 @@ static const match_table_t policy_tokens = { {Opt_permit_directio, "permit_directio"}, {Opt_pcr, "pcr=%s"}, {Opt_trust_vfs, "trust_vfs"}, + {Opt_template, "template=%s"}, {Opt_err, NULL} }; @@ -770,6 +777,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) char *from; char *p; bool uid_token; + struct ima_template_desc *template_desc; int result = 0; ab = integrity_audit_log_start(audit_context(), GFP_KERNEL, @@ -1079,6 +1087,16 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) else entry->flags |= IMA_PCR; + break; + case Opt_template: + ima_log_string(ab, "template", args[0].from); + template_desc = lookup_template_desc(args[0].from); + if (!template_desc) { + result = -EINVAL; + } else { + entry->template = template_desc; + entry->flags |= IMA_TEMPLATE; + } break; case Opt_err: ima_log_string(ab, "UNKNOWN", p); @@ -1358,6 +1376,8 @@ int ima_policy_show(struct seq_file *m, void *v) } } } + if (entry->flags & IMA_TEMPLATE) + seq_printf(m, "template=%s ", entry->template->name); if (entry->flags & IMA_DIGSIG_REQUIRED) seq_puts(m, "appraise_type=imasig "); if (entry->flags & IMA_PERMIT_DIRECTIO) diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index 78bd8fea8b35..aea95754d523 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -50,7 +50,6 @@ static const struct ima_template_field supported_fields[] = { #define MAX_TEMPLATE_NAME_LEN 15 static struct ima_template_desc *ima_template; -static struct ima_template_desc *lookup_template_desc(const char *name); static int template_desc_init_fields(const char *template_fmt, const struct ima_template_field ***fields, int *num_fields); @@ -111,7 +110,7 @@ static int __init ima_template_fmt_setup(char *str) } __setup("ima_template_fmt=", ima_template_fmt_setup); -static struct ima_template_desc *lookup_template_desc(const char *name) +struct ima_template_desc *lookup_template_desc(const char *name) { struct ima_template_desc *template_desc; int found = 0; @@ -120,6 +119,13 @@ static struct ima_template_desc *lookup_template_desc(const char *name) list_for_each_entry_rcu(template_desc, &defined_templates, list) { if ((strcmp(template_desc->name, name) == 0) || (strcmp(template_desc->fmt, name) == 0)) { + /* + * template_desc_init_fields() will return immediately + * if the template is already initialised + */ + template_desc_init_fields(template_desc->fmt, + &(template_desc->fields), + &(template_desc->num_fields)); found = 1; break; } diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 9d74119bcdfd..9f647b04fc23 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -37,6 +37,7 @@ #define EVM_IMMUTABLE_DIGSIG 0x08000000 #define IMA_FAIL_UNVERIFIABLE_SIGS 0x10000000 #define IMA_TRUST_VFS 0x20000000 +#define IMA_TEMPLATE 0x40000000 #define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \ IMA_HASH | IMA_APPRAISE_SUBMASK)