From patchwork Mon Jun 26 11:19:46 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Weinberger X-Patchwork-Id: 780667 X-Patchwork-Delegate: richard@nod.at Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3wx67S3BBzz9s7f for ; Mon, 26 Jun 2017 21:21:08 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="eEuKMJ+o"; dkim-atps=neutral DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:Message-Id:Date: Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Owner; bh=zxc5F7FXaYo+QzslFsojHyEI4SOjJVhBWqxClh4tZ5U=; b=eEu KMJ+ovv6WJk8uvTHbFSlRUYqsazWiC6k8/4sqfUwGcJfuIOzVW3dNHtzakFvTFDIPOLDEH2Vt2UWo ki2JkWNeWbJkVlDH84ghMbNhvCGGq9kyW9o0KMaeDsDtQu/kMqrmuWmz7tdHMdkG/G+IxTMH8N1MZ aJGGZknvcgYNmt2nht3vJ+/s9Iwhqvpt6V5L1YFg534XpbKQooSY/y3A3egE2x+JwVeCTuULzrDcQ PNbyMuhMdllL0L6mzOO9xOnU0ZErKfL1UcJlh5aig8flp8STnnZodkPyPOqtUh0G+icc1PJNqK2Y+ RE6EhfLQ6Hr++Mk3KNX3plJflr7jcFw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1dPS4m-0004Mf-H7; Mon, 26 Jun 2017 11:21:04 +0000 Received: from mail.sigma-star.at ([95.130.255.111]) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1dPS4K-0004LS-4G for linux-mtd@lists.infradead.org; Mon, 26 Jun 2017 11:20:39 +0000 Received: from localhost (localhost.localdomain [127.0.0.1]) by mail.sigma-star.at (Postfix) with ESMTP id 3925624E0011; Mon, 26 Jun 2017 13:20:05 +0200 (CEST) Received: from linux-7gg8.suse (richard.vpn.sigmapriv.at [10.3.0.5]) by mail.sigma-star.at (Postfix) with ESMTPSA id 2D39D24E0010; Mon, 26 Jun 2017 13:20:04 +0200 (CEST) From: Richard Weinberger To: linux-mtd@lists.infradead.org Subject: [PATCH] ubifs: replay: Detect and kill orphaned xattrs Date: Mon, 26 Jun 2017 13:19:46 +0200 Message-Id: <20170626111947.17092-1-richard@nod.at> X-Mailer: git-send-email 2.12.3 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170626_042036_543646_2640F1F1 X-CRM114-Status: GOOD ( 19.83 ) X-Spam-Score: -1.9 (-) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-1.9 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: david@sigma-star.at, Subodh Nijsure , Artem Bityutskiy , Ben Shelton , Richard Weinberger , Adrian Hunter , stable@vger.kernel.org, linux-kernel@vger.kernel.org, Terry Wilcox , Marc Kleine-Budde , Gratian Crisan , Brad Mouring MIME-Version: 1.0 Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Creating an xattr is an independent journal transaction and the xattr code assumes that there is always a valid host inode present when a new xattr is created. This assumption is not correct for LSM and now fscrypt, for these users UBIFS creates the xattr before the host inode is created and visible to the user. Since these are two journal transactions it can happen that due to a power-cut only the xattr is present but not the host inode nor the directory entry for it. As result of this UBIFS will lose free space and can run out of space at some time. It is also not possible to create the xattr after the host inode because this would violate LSM and fscrypt model. After a power-cut we could end up with a inode without security context. This is an intermediate fix that can go into -stable, as long term solution we have to make sure that creating the xattr and the host inode is a single journal transaction. But to achieve this the journal code need some rework first. Cc: Subodh Nijsure Cc: Marc Kleine-Budde Cc: Ben Shelton Cc: Brad Mouring Cc: Terry Wilcox Cc: Gratian Crisan Cc: stable@vger.kernel.org Fixes: d7f0b70d30ff ("UBIFS: Add security.* XATTR support for the UBIFS") Signed-off-by: Richard Weinberger --- fs/ubifs/replay.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c index ae5c02f22f3e..58a3d10f3191 100644 --- a/fs/ubifs/replay.c +++ b/fs/ubifs/replay.c @@ -290,6 +290,85 @@ static int replay_entries_cmp(void *priv, struct list_head *a, return -1; } +static void inspect_xattr_nodes(struct ubifs_info *c, struct replay_entry *pos) +{ + int n, found; + struct ubifs_znode *znode; + struct replay_entry *r, *r1, *r2, *r3; + + r1 = pos; + + /* Don't wrap around. */ + if (list_is_last(&r1->list, &c->replay_list)) + return; + + r2 = list_next_entry(r1, list); + + if (list_is_last(&r2->list, &c->replay_list)) + return; + + r3 = list_next_entry(r2, list); + + if (key_type(c, &r2->key) != UBIFS_INO_KEY) { + /* We always write a xent node, followed by two ino nodes. */ + ubifs_err(c, "Expected ino node, got: %i", key_type(c, &r2->key)); + return; + } + + if (key_type(c, &r3->key) != UBIFS_INO_KEY) { + /* We always write a xent node, followed by two ino nodes. */ + ubifs_err(c, "Expected ino node, got: %i", key_type(c, &r3->key)); + return; + } + + /* + * If the replay list container another reference to the host inode, @r3, + * we can assume that the xattr is not orphaned. + */ + list_for_each_entry(r, &c->replay_list, list) { + if (key_type(c, &r->key) == UBIFS_INO_KEY && + key_inum(c, &r->key) == key_inum(c, &r3->key) && + r->sqnum != r3->sqnum) + return; + } + + /* + * Also make sure that the TNC does not know the host inode. + */ + found = ubifs_lookup_level0(c, &r3->key, &znode, &n); + if (found) + return; + + /* The xattr is really an orphan, mark all three nodes for deletion. */ + r1->deletion = 1; + r2->deletion = 1; + r3->deletion = 1; +} + +/** + * kill_orphan_xattrs - search and kill orphaned xattr nodes. + * @c: UBIFS file-system description object + * + * Creating a xattr is an independent journal transaction and the xattr + * code assumes that there is always a valid host inode present when a + * new xattr is created. + * This assumption is not correct for LSM and fscrypt, for these users + * UBIFS creates the xattr before the host inode is created and visible to + * the user. Since these are two journal transactions it can happen that + * due to a power-cut only the xattr is present but not the host inode + * nor a directory entry for it. To deal with that problem we have to + * scan the replay list for such orphans and kill them. + */ +static void kill_orphan_xattrs(struct ubifs_info *c) +{ + struct replay_entry *r; + + list_for_each_entry(r, &c->replay_list, list) { + if (!r->deletion && key_type(c, &r->key) == UBIFS_XENT_KEY) + inspect_xattr_nodes(c, r); + } +} + /** * apply_replay_list - apply the replay list to the TNC. * @c: UBIFS file-system description object @@ -304,6 +383,8 @@ static int apply_replay_list(struct ubifs_info *c) list_sort(c, &c->replay_list, &replay_entries_cmp); + kill_orphan_xattrs(c); + list_for_each_entry(r, &c->replay_list, list) { cond_resched();