Received: by 2002:a6b:fb09:0:0:0:0:0 with SMTP id h9csp442360iog; Mon, 13 Jun 2022 06:05:51 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwoPvdJAC438yJhCb6knmDQu3wv5Nbt9jIdjAYyzLoltvOeGIJtyNZ6N29IVYHPKlGUL0kc X-Received: by 2002:a17:906:5053:b0:70d:a0cc:b3fd with SMTP id e19-20020a170906505300b0070da0ccb3fdmr46720364ejk.162.1655125550919; Mon, 13 Jun 2022 06:05:50 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1655125550; cv=none; d=google.com; s=arc-20160816; b=MHGUVJMwqt7HUjfBWqNTP9DSCxubRhxyrpYEhkdKVhGYBnMKb/0Vv3ERcMcxVU3JdS u2MsWXRoopgV81NBOdheuZWNuUdLfeqZAFDSNbBNd9hh0c6/rcsrmDqLxUAsBBTVg/kw wo2ZM4cgqKYGV4rU3+NFu01DrGpKy8eAMujh8P/RLqSMvOLxEHCas+qBMZ2LdgvyW14f BcJ+D6+IGIQfkT/d3qj/2mjycOwNDU67dna4OoFohs9vks7VCOx55f75GlzqoiB+ufqC N2lCtwfUEi0G+YRgEwp+HtNk6Ay5h6q5t2eNE9kRvY06kqXzXp6n4EUj/9FL3cFtQqI8 CI3A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=4regfyAtmmPFtR7fAD7UyC6g8KuPpJw/opH9qRplgtg=; b=0qVJcANYV0U18/KLUlfYiBp+3QDT5doBFgxZbrF+Gf6W11p+JSIR3VTGenM915z/UO Zwr7HpmcaY7by/ahCltoAfl0GxbvHJxXu/AzyQI76CKC8ZH7TaMGPn8B5KKKzaK4EqXa 7p4jErDDeLEfo0ttmvSlLECjfnz/SxDvxDu4hjC1WRKgNh41Sa8z/rM40uUyqc2ogliF mm+U+vvQRIXflgm6cPqrOMeZEzppcREspdFbR7+DjpwKNlOC0m0p9Kp7WPtTB3DYbFMX 9At9TcBsxZYeMYYM1ism5+4KwToZ+3fVEOTfu0Yoew2azpQGEelMO6LvAzoHdszVzWI9 9yzw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=mkvrPmv3; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id l4-20020a170906414400b006e88579e94fsi7000359ejk.798.2022.06.13.06.05.18; Mon, 13 Jun 2022 06:05:50 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=mkvrPmv3; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1357656AbiFML5O (ORCPT + 99 others); Mon, 13 Jun 2022 07:57:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57060 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1356538AbiFMLup (ORCPT ); Mon, 13 Jun 2022 07:50:45 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C365C248E8; Mon, 13 Jun 2022 03:54:17 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 2120961257; Mon, 13 Jun 2022 10:54:17 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2DD82C34114; Mon, 13 Jun 2022 10:54:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1655117656; bh=oiQf7bhjH3/0dZtin5jhzsgE0FZbvH9eoOvmsWE92Rw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mkvrPmv3x3T1djergDob2XKxDhy4WLtbQtM5yrnLUJM3BCkOHkm8ACZAWhuCKOsNF R35oHN0CcMQ/XR4Z4oFOeXgY6Jue3O1wRTC4uJVkG7jhq+JZiEUAUus3Jz0g/kjF5a ZWOnxoTYbkSXMutrB9E+3iLVoBlOnCx4hfX2o4Oo= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Ariel Miculas , Christophe Leroy , Michael Ellerman Subject: [PATCH 5.4 409/411] powerpc/32: Fix overread/overwrite of thread_struct via ptrace Date: Mon, 13 Jun 2022 12:11:22 +0200 Message-Id: <20220613094941.083654103@linuxfoundation.org> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20220613094928.482772422@linuxfoundation.org> References: <20220613094928.482772422@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-8.3 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_HI, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Michael Ellerman commit 8e1278444446fc97778a5e5c99bca1ce0bbc5ec9 upstream. The ptrace PEEKUSR/POKEUSR (aka PEEKUSER/POKEUSER) API allows a process to read/write registers of another process. To get/set a register, the API takes an index into an imaginary address space called the "USER area", where the registers of the process are laid out in some fashion. The kernel then maps that index to a particular register in its own data structures and gets/sets the value. The API only allows a single machine-word to be read/written at a time. So 4 bytes on 32-bit kernels and 8 bytes on 64-bit kernels. The way floating point registers (FPRs) are addressed is somewhat complicated, because double precision float values are 64-bit even on 32-bit CPUs. That means on 32-bit kernels each FPR occupies two word-sized locations in the USER area. On 64-bit kernels each FPR occupies one word-sized location in the USER area. Internally the kernel stores the FPRs in an array of u64s, or if VSX is enabled, an array of pairs of u64s where one half of each pair stores the FPR. Which half of the pair stores the FPR depends on the kernel's endianness. To handle the different layouts of the FPRs depending on VSX/no-VSX and big/little endian, the TS_FPR() macro was introduced. Unfortunately the TS_FPR() macro does not take into account the fact that the addressing of each FPR differs between 32-bit and 64-bit kernels. It just takes the index into the "USER area" passed from userspace and indexes into the fp_state.fpr array. On 32-bit there are 64 indexes that address FPRs, but only 32 entries in the fp_state.fpr array, meaning the user can read/write 256 bytes past the end of the array. Because the fp_state sits in the middle of the thread_struct there are various fields than can be overwritten, including some pointers. As such it may be exploitable. It has also been observed to cause systems to hang or otherwise misbehave when using gdbserver, and is probably the root cause of this report which could not be easily reproduced: https://lore.kernel.org/linuxppc-dev/dc38afe9-6b78-f3f5-666b-986939e40fc6@keymile.com/ Rather than trying to make the TS_FPR() macro even more complicated to fix the bug, or add more macros, instead add a special-case for 32-bit kernels. This is more obvious and hopefully avoids a similar bug happening again in future. Note that because 32-bit kernels never have VSX enabled the code doesn't need to consider TS_FPRWIDTH/OFFSET at all. Add a BUILD_BUG_ON() to ensure that 32-bit && VSX is never enabled. Fixes: 87fec0514f61 ("powerpc: PTRACE_PEEKUSR/PTRACE_POKEUSER of FPR registers in little endian builds") Cc: stable@vger.kernel.org # v3.13+ Reported-by: Ariel Miculas Tested-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20220609133245.573565-1-mpe@ellerman.id.au Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/ptrace.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -3014,8 +3014,13 @@ long arch_ptrace(struct task_struct *chi flush_fp_to_thread(child); if (fpidx < (PT_FPSCR - PT_FPR0)) - memcpy(&tmp, &child->thread.TS_FPR(fpidx), - sizeof(long)); + if (IS_ENABLED(CONFIG_PPC32)) { + // On 32-bit the index we are passed refers to 32-bit words + tmp = ((u32 *)child->thread.fp_state.fpr)[fpidx]; + } else { + memcpy(&tmp, &child->thread.TS_FPR(fpidx), + sizeof(long)); + } else tmp = child->thread.fp_state.fpscr; } @@ -3047,8 +3052,13 @@ long arch_ptrace(struct task_struct *chi flush_fp_to_thread(child); if (fpidx < (PT_FPSCR - PT_FPR0)) - memcpy(&child->thread.TS_FPR(fpidx), &data, - sizeof(long)); + if (IS_ENABLED(CONFIG_PPC32)) { + // On 32-bit the index we are passed refers to 32-bit words + ((u32 *)child->thread.fp_state.fpr)[fpidx] = data; + } else { + memcpy(&child->thread.TS_FPR(fpidx), &data, + sizeof(long)); + } else child->thread.fp_state.fpscr = data; ret = 0; @@ -3398,4 +3408,7 @@ void __init pt_regs_check(void) offsetof(struct user_pt_regs, result)); BUILD_BUG_ON(sizeof(struct user_pt_regs) > sizeof(struct pt_regs)); + + // ptrace_get/put_fpr() rely on PPC32 and VSX being incompatible + BUILD_BUG_ON(IS_ENABLED(CONFIG_PPC32) && IS_ENABLED(CONFIG_VSX)); }