From patchwork Wed Jun 6 08:52:39 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Po-Hsu Lin X-Patchwork-Id: 925773 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4112Wg3Vr1zB3sh; Wed, 6 Jun 2018 18:53:19 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1fQUBn-0004wx-Oj; Wed, 06 Jun 2018 08:53:07 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:128) (Exim 4.86_2) (envelope-from ) id 1fQUBm-0004wk-AB for kernel-team@lists.ubuntu.com; Wed, 06 Jun 2018 08:53:06 +0000 Received: from mail-pg0-f72.google.com ([74.125.83.72]) by youngberry.canonical.com with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1fQUBl-0006JC-QT for kernel-team@lists.ubuntu.com; Wed, 06 Jun 2018 08:53:06 +0000 Received: by mail-pg0-f72.google.com with SMTP id x6-v6so2026567pgp.9 for ; Wed, 06 Jun 2018 01:53:05 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=aMXSQmyeJe5SxHkv4iGzUZzFRNQ+3t/RkwQaz4MwcMo=; b=NkyfVPjRU9ftT0u0bjOcMPSq/bUfNEAKMjMSysopAY0nFUpmgIpOQM4WNFAt6YVMho 7iJw0VbsXan5Sn83Op1247U7OiWTrw7dqbnsvSm9pd9pYMBzmuSCXY8DlpaVDAFwgnHK wA7R9GcyfZpE6Muh9GP8lXsLpzyyxVPU1q42ZDq2MFdNS9PyHkhXC5ypnHrogDoDKppD 6UuIvO5HRGVDSnGA6GabKkqPzr+Z8RRJjPK2wa/s0bl0ACBaJhTQPgv3ZRbnZuBU0Rc0 sgyga/gecZBN80SZRCaCVT0C/ko1qa6ilEZ49hEMXtdl+eKK1QaTNbbc1c/aYUGe4iTx m+eg== X-Gm-Message-State: APt69E3/EwC7GU2sIwViQRH4mAJdnSE8k9Os/WbrKTBIMz6UU1/2voWB 0GDe7CKAEnQY/6jrhMO1IcitxenHCk4KDb+aTj8WrGGAASofB2oKNcA60d+CeM7A2oeFpUnScN3 ZRlPpUEIK4m0st0YP6tEVe1tsrmTAUFFjyFJUE9DH X-Received: by 2002:a63:7459:: with SMTP id e25-v6mr1813472pgn.186.1528275184349; Wed, 06 Jun 2018 01:53:04 -0700 (PDT) X-Google-Smtp-Source: ADUXVKKy4kaEBtJnkGFGhkdEQCDLI9mQa89I6TnEeEhWcTXOY2uWBSq3hcsDSlY2ys+TT+uEMIaLeg== X-Received: by 2002:a63:7459:: with SMTP id e25-v6mr1813460pgn.186.1528275184155; Wed, 06 Jun 2018 01:53:04 -0700 (PDT) Received: from Leggiero.taipei.internal ([175.41.48.77]) by smtp.gmail.com with ESMTPSA id s16-v6sm78806246pfm.114.2018.06.06.01.53.02 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Jun 2018 01:53:03 -0700 (PDT) From: Po-Hsu Lin To: kernel-team@lists.ubuntu.com Subject: [CVE-2017-12193][T][SRU][PATCH 1/1] assoc_array: Fix a buggy node-splitting case Date: Wed, 6 Jun 2018 16:52:39 +0800 Message-Id: <20180606085239.22499-2-po-hsu.lin@canonical.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20180606085239.22499-1-po-hsu.lin@canonical.com> References: <20180606085239.22499-1-po-hsu.lin@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: David Howells CVE-2017-12193 BugLink: https://bugs.launchpad.net/bugs/1775316 This fixes CVE-2017-12193. Fix a case in the assoc_array implementation in which a new leaf is added that needs to go into a node that happens to be full, where the existing leaves in that node cluster together at that level to the exclusion of new leaf. What needs to happen is that the existing leaves get moved out to a new node, N1, at level + 1 and the existing node needs replacing with one, N0, that has pointers to the new leaf and to N1. The code that tries to do this gets this wrong in two ways: (1) The pointer that should've pointed from N0 to N1 is set to point recursively to N0 instead. (2) The backpointer from N0 needs to be set correctly in the case N0 is either the root node or reached through a shortcut. Fix this by removing this path and using the split_node path instead, which achieves the same end, but in a more general way (thanks to Eric Biggers for spotting the redundancy). The problem manifests itself as: BUG: unable to handle kernel NULL pointer dereference at 0000000000000010 IP: assoc_array_apply_edit+0x59/0xe5 Fixes: 3cb989501c26 ("Add a generic associative array implementation.") Reported-and-tested-by: WU Fan Signed-off-by: David Howells Cc: stable@vger.kernel.org [v3.13-rc1+] Signed-off-by: Linus Torvalds (cherry picked from commit ea6789980fdaa610d7eb63602c746bf6ec70cd2b) Signed-off-by: Po-Hsu Lin Acked-by: Stefan Bader Acked-by: Kleber Sacilotto de Souza --- lib/assoc_array.c | 51 +++++++++++++++++---------------------------------- 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/lib/assoc_array.c b/lib/assoc_array.c index afef906..035c236 100644 --- a/lib/assoc_array.c +++ b/lib/assoc_array.c @@ -597,21 +597,31 @@ static bool assoc_array_insert_into_terminal_node(struct assoc_array_edit *edit, if ((edit->segment_cache[ASSOC_ARRAY_FAN_OUT] ^ base_seg) == 0) goto all_leaves_cluster_together; - /* Otherwise we can just insert a new node ahead of the old - * one. + /* Otherwise all the old leaves cluster in the same slot, but + * the new leaf wants to go into a different slot - so we + * create a new node (n0) to hold the new leaf and a pointer to + * a new node (n1) holding all the old leaves. + * + * This can be done by falling through to the node splitting + * path. */ - goto present_leaves_cluster_but_not_new_leaf; + pr_devel("present leaves cluster but not new leaf\n"); } split_node: pr_devel("split node\n"); - /* We need to split the current node; we know that the node doesn't - * simply contain a full set of leaves that cluster together (it - * contains meta pointers and/or non-clustering leaves). + /* We need to split the current node. The node must contain anything + * from a single leaf (in the one leaf case, this leaf will cluster + * with the new leaf) and the rest meta-pointers, to all leaves, some + * of which may cluster. + * + * It won't contain the case in which all the current leaves plus the + * new leaves want to cluster in the same slot. * * We need to expel at least two leaves out of a set consisting of the - * leaves in the node and the new leaf. + * leaves in the node and the new leaf. The current meta pointers can + * just be copied as they shouldn't cluster with any of the leaves. * * We need a new node (n0) to replace the current one and a new node to * take the expelled nodes (n1). @@ -716,33 +726,6 @@ found_slot_for_multiple_occupancy: pr_devel("<--%s() = ok [split node]\n", __func__); return true; -present_leaves_cluster_but_not_new_leaf: - /* All the old leaves cluster in the same slot, but the new leaf wants - * to go into a different slot, so we create a new node to hold the new - * leaf and a pointer to a new node holding all the old leaves. - */ - pr_devel("present leaves cluster but not new leaf\n"); - - new_n0->back_pointer = node->back_pointer; - new_n0->parent_slot = node->parent_slot; - new_n0->nr_leaves_on_branch = node->nr_leaves_on_branch; - new_n1->back_pointer = assoc_array_node_to_ptr(new_n0); - new_n1->parent_slot = edit->segment_cache[0]; - new_n1->nr_leaves_on_branch = node->nr_leaves_on_branch; - edit->adjust_count_on = new_n0; - - for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) - new_n1->slots[i] = node->slots[i]; - - new_n0->slots[edit->segment_cache[0]] = assoc_array_node_to_ptr(new_n0); - edit->leaf_p = &new_n0->slots[edit->segment_cache[ASSOC_ARRAY_FAN_OUT]]; - - edit->set[0].ptr = &assoc_array_ptr_to_node(node->back_pointer)->slots[node->parent_slot]; - edit->set[0].to = assoc_array_node_to_ptr(new_n0); - edit->excised_meta[0] = assoc_array_node_to_ptr(node); - pr_devel("<--%s() = ok [insert node before]\n", __func__); - return true; - all_leaves_cluster_together: /* All the leaves, new and old, want to cluster together in this node * in the same slot, so we have to replace this node with a shortcut to