Received: by 2002:a05:6358:700f:b0:131:369:b2a3 with SMTP id 15csp2962638rwo; Thu, 3 Aug 2023 19:03:45 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHX5FVgtTFgfFp1q3kOI/NQZU0gDwW5s7wgdMnAUCsZs768D8xD+WNV6g0byAz/M7f6nQqk X-Received: by 2002:a17:906:8462:b0:993:ffcb:ad4e with SMTP id hx2-20020a170906846200b00993ffcbad4emr248204ejc.13.1691114625209; Thu, 03 Aug 2023 19:03:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1691114625; cv=none; d=google.com; s=arc-20160816; b=Y3FoNNgl3/k0/Zi0X2XdWims9l+kX/6FwZFuQ2OBKhwk6bM2sqKvLdqWCBl1BJ9rkD a4dz67YSS+ImebTJpXVYhR4XeFZvHy5Ndg7Lb1P/56DNZDjf4+g+9+RO97TGtFOCQE69 j7BlOpN7i/BuMc9GSRSY3ZmNXk/M0obVsTj7eyiRK/KndTuQm1KTlvfVPq+9rEqR+y55 SZ65/hzqHkKYd+DgBaBbK/oRIQfmqogUbJDV9LOg0wx2UqUhBVkDY4XSj1tKZUv2otUz ZUVCADliKChDmmXi6LfBgwk4LDMlSkUURy1ftoHAIrHGfH7qzChv4O2qEVaPvAxoYW8D TyNQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:cc:to:subject :message-id:date:from:in-reply-to:references:mime-version :dkim-signature; bh=GFkbHti0MGtdbXCdhMo4YsqfcazHRy+oVImEdcVlxZ8=; fh=XTMOu7GWbVXtawl7ZM2qxkaSVGnZ5coz0jwG+6U2v0Y=; b=C1TRdDndvw18ankILe5HzxT4Hbu9bFAllcwuq9IP1oNrh8sIudF0srT6zWE0PyAfQ0 /61SCroxaF9t2SLg3m2o5vffPSZ3U68In18WzEKBEI9hE0qnf7U3H352moG2IYqAqHcK Z5tHdtvvbF1f2nW85VXgRKotkah/Fo/P1tOrZEZdiBfB/43Fp40OqO4/2nLxXKsQakHT fTJxp974Kg0zddr7xeyQ2nhBzIh4rcL9PoRhuC1atrkF8Fk1eIL1y5VEvZiY+OVKbXdv IPoDbFuHlqTocX3lcdS0ddhCTHumM2X7u2aSm51uR0Xk9Hx3br1i/lkW6dL9AiOPx5hA yQ/A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=RU68zc5W; 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=kernel.org Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id h23-20020a1709060f5700b0099bcf69f506si826772ejj.202.2023.08.03.19.03.09; Thu, 03 Aug 2023 19:03:45 -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=@kernel.org header.s=k20201202 header.b=RU68zc5W; 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=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229867AbjHDBJL (ORCPT + 99 others); Thu, 3 Aug 2023 21:09:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45264 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229560AbjHDBJK (ORCPT ); Thu, 3 Aug 2023 21:09:10 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3F51F4215 for ; Thu, 3 Aug 2023 18:09:09 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id AE72D61EFE for ; Fri, 4 Aug 2023 01:09:08 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0730AC433C9 for ; Fri, 4 Aug 2023 01:09:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1691111348; bh=jB/AVgWdSOZxlMIXgH0/3k+Ww5e4ngKqwvGg7rkTYSY=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=RU68zc5WSt0gnYG47NTqrPIJ0U91nlLuXUqM7CRVhMbnMs6WWesLNwCbiDTFES1PP kHG0ppCMVpxRBVyWa9ieBbSVJnGOHM5wSVX01JoW56Ft/4O93MgQDO6hQ8BiK6Txza ixK7FEJ/++FiJZRLSY25X9RCeXMi2XehoFf2cw+XcamWWEzFpLjrofwa63jzwr8pDa 9bOmDriItiNkVU5DpsDi1VpdglDI2oqSBbYo2YQpAEm+H1Qeou758qK6b8uSRUwOWO W0FZMM3JUekYkid96Wp/br9ST1eDSJEYET0jLUPvIG1kaXv1+TUC/juT99APfA9ol5 S8xMjlZy0VAqQ== Received: by mail-lf1-f52.google.com with SMTP id 2adb3069b0e04-4fe2d152f62so2691878e87.0 for ; Thu, 03 Aug 2023 18:09:07 -0700 (PDT) X-Gm-Message-State: AOJu0YyVZx0ZAVNayqBuOB6Moif6a5UTJVa66lprQrYlIKwTZ4/qQ/YE dwwiqijBLgXNLJLqvjSqa5WspyulUIaPoXIBif8= X-Received: by 2002:a19:914d:0:b0:4fb:9da2:6cec with SMTP id y13-20020a19914d000000b004fb9da26cecmr155510lfj.7.1691111345965; Thu, 03 Aug 2023 18:09:05 -0700 (PDT) MIME-Version: 1.0 References: <20230803224458.4156006-1-ancientmodern4@gmail.com> In-Reply-To: <20230803224458.4156006-1-ancientmodern4@gmail.com> From: Guo Ren Date: Fri, 4 Aug 2023 09:08:53 +0800 X-Gmail-Original-Message-ID: Message-ID: Subject: Re: [PATCH] riscv: signal: handle syscall restart before get_signal To: Haorong Lu Cc: Paul Walmsley , Palmer Dabbelt , Albert Ou , Conor Dooley , Andy Chiu , Heiko Stuebner , Al Viro , Mathis Salmen , Andrew Bresticker , Greentime Hu , Vincent Chen , "open list:RISC-V ARCHITECTURE" , open list Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF, RCVD_IN_DNSWL_BLOCKED,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 On Fri, Aug 4, 2023 at 6:45=E2=80=AFAM Haorong Lu wrote: > > In the current riscv implementation, blocking syscalls like read() may > not correctly restart after being interrupted by ptrace. This problem > arises when the syscall restart process in arch_do_signal_or_restart() > is bypassed due to changes to the regs->cause register, such as an > ebreak instruction. > > Steps to reproduce: > 1. Interrupt the tracee process with PTRACE_SEIZE & PTRACE_INTERRUPT. > 2. Backup original registers and instruction at new_pc. > 3. Change pc to new_pc, and inject an instruction (like ebreak) to this > address. > 4. Resume with PTRACE_CONT and wait for the process to stop again after > executing ebreak. > 5. Restore original registers and instructions, and detach from the > tracee process. > 6. Now the read() syscall in tracee will return -1 with errno set to > ERESTARTSYS. > > Specifically, during an interrupt, the regs->cause changes from > EXC_SYSCALL to EXC_BREAKPOINT due to the injected ebreak, which is > inaccessible via ptrace so we cannot restore it. This alteration breaks > the syscall restart condition and ends the read() syscall with an > ERESTARTSYS error. According to include/linux/errno.h, it should never > be seen by user programs. X86 can avoid this issue as it checks the > syscall condition using a register (orig_ax) exposed to user space. > Arm64 handles syscall restart before calling get_signal, where it could > be paused and inspected by ptrace/debugger. > > This patch adjusts the riscv implementation to arm64 style, which also > checks syscall using a kernel register (syscallno). It ensures the > syscall restart process is not bypassed when changes to the cause > register occur, providing more consistent behavior across various > architectures. > > For a simplified reproduction program, feel free to visit: > https://github.com/ancientmodern/riscv-ptrace-bug-demo. > > Signed-off-by: Haorong Lu > --- > arch/riscv/kernel/signal.c | 85 +++++++++++++++++++++----------------- > 1 file changed, 46 insertions(+), 39 deletions(-) > > diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c > index 180d951d3624..d2d7169048ea 100644 > --- a/arch/riscv/kernel/signal.c > +++ b/arch/riscv/kernel/signal.c > @@ -391,30 +391,6 @@ static void handle_signal(struct ksignal *ksig, stru= ct pt_regs *regs) > sigset_t *oldset =3D sigmask_to_save(); > int ret; > > - /* Are we from a system call? */ > - if (regs->cause =3D=3D EXC_SYSCALL) { > - /* Avoid additional syscall restarting via ret_from_excep= tion */ > - regs->cause =3D -1UL; > - /* If so, check system call restarting.. */ > - switch (regs->a0) { > - case -ERESTART_RESTARTBLOCK: > - case -ERESTARTNOHAND: > - regs->a0 =3D -EINTR; > - break; > - > - case -ERESTARTSYS: > - if (!(ksig->ka.sa.sa_flags & SA_RESTART)) { > - regs->a0 =3D -EINTR; > - break; > - } > - fallthrough; > - case -ERESTARTNOINTR: > - regs->a0 =3D regs->orig_a0; > - regs->epc -=3D 0x4; > - break; > - } > - } > - > rseq_signal_deliver(ksig, regs); > > /* Set up the stack frame */ > @@ -428,35 +404,66 @@ static void handle_signal(struct ksignal *ksig, str= uct pt_regs *regs) > > void arch_do_signal_or_restart(struct pt_regs *regs) > { > + unsigned long continue_addr =3D 0, restart_addr =3D 0; > + int retval =3D 0; > struct ksignal ksig; > + bool syscall =3D (regs->cause =3D=3D EXC_SYSCALL); > > - if (get_signal(&ksig)) { > - /* Actually deliver the signal */ > - handle_signal(&ksig, regs); > - return; > - } > + /* If we were from a system call, check for system call restartin= g */ > + if (syscall) { > + continue_addr =3D regs->epc; > + restart_addr =3D continue_addr - 4; > + retval =3D regs->a0; > > - /* Did we come from a system call? */ > - if (regs->cause =3D=3D EXC_SYSCALL) { > /* Avoid additional syscall restarting via ret_from_excep= tion */ > regs->cause =3D -1UL; > > - /* Restart the system call - no handlers present */ > - switch (regs->a0) { > + /* > + * Prepare for system call restart. We do this here so th= at a > + * debugger will see the already changed PC. > + */ > + switch (retval) { > case -ERESTARTNOHAND: > case -ERESTARTSYS: > case -ERESTARTNOINTR: > - regs->a0 =3D regs->orig_a0; > - regs->epc -=3D 0x4; > - break; > case -ERESTART_RESTARTBLOCK: > - regs->a0 =3D regs->orig_a0; > - regs->a7 =3D __NR_restart_syscall; > - regs->epc -=3D 0x4; > + regs->a0 =3D regs->orig_a0; > + regs->epc =3D restart_addr; > break; > } > } > > + /* > + * Get the signal to deliver. When running under ptrace, at this = point > + * the debugger may change all of our registers. > + */ > + if (get_signal(&ksig)) { > + /* > + * Depending on the signal settings, we may need to rever= t the > + * decision to restart the system call, but skip this if = a > + * debugger has chosen to restart at a different PC. > + */ > + if (regs->epc =3D=3D restart_addr && > + (retval =3D=3D -ERESTARTNOHAND || > + retval =3D=3D -ERESTART_RESTARTBLOCK || > + (retval =3D=3D -ERESTARTSYS && > + !(ksig.ka.sa.sa_flags & SA_RESTART)))) { > + regs->a0 =3D -EINTR; > + regs->epc =3D continue_addr; > + } > + > + /* Actually deliver the signal */ > + handle_signal(&ksig, regs); > + return; > + } > + > + /* > + * Handle restarting a different system call. As above, if a debu= gger > + * has chosen to restart at a different PC, ignore the restart. > + */ > + if (syscall && regs->epc =3D=3D restart_addr && retval =3D=3D -ER= ESTART_RESTARTBLOCK) > + regs->a7 =3D __NR_restart_syscall; > + I thought your patch contains two parts: 1. bugfix 2. Some coding conventions or adjusting some logic of the original signal. Could we separate them into two pieces and make the bugfix one minimalistic? Then, people could easier to review your patches. > /* > * If there is no signal to deliver, we just put the saved > * sigmask back. > -- > 2.41.0 > --=20 Best Regards Guo Ren