From patchwork Mon Feb 1 19:40:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrei Vagin X-Patchwork-Id: 12059853 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.7 required=3.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B2FE6C433E0 for ; Mon, 1 Feb 2021 19:43:19 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 592EC64EA8 for ; Mon, 1 Feb 2021 19:43:19 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 592EC64EA8 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: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:List-Owner; bh=Lk0PwRaEN2ZFoLhUV57/z4EVYt1M7/VOW9Wy4aSVExA=; b=UkLBHgUNSyc9do7v/b7pOsXcs oCrRRZL0BjFrUsHbxTOWnzf4qXHgy1+d0BfWx7MdjyNKyG8DbRWxeARCukk09t37/k4pWtw3KsrT5 MLeWz/wNhIlPXG+WmBMN+6toCOynVgTt4weKILp5IrY4VvJPGSWB+foww3q86cVGVu02NAEJj5V3w /MQ79/G8i1tQnv62VtplK4cA3gtBXrcOIzPHnN1/c6X/16qM4MvuQL6SGNAE6cCoYIiPkHVtVHMNl twe/HjKw308KdazU0YBM9xNShMuZPVhqA4fzRUt1dzxkPJjs6hyufjr7dGu+z6bAwKX9Rkh3cQC2W CEJymAt4A==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1l6f5U-00018F-Uc; Mon, 01 Feb 2021 19:42:16 +0000 Received: from mail-pj1-x1034.google.com ([2607:f8b0:4864:20::1034]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1l6f5I-0000zr-10 for linux-arm-kernel@lists.infradead.org; Mon, 01 Feb 2021 19:42:08 +0000 Received: by mail-pj1-x1034.google.com with SMTP id kx7so234806pjb.2 for ; Mon, 01 Feb 2021 11:42:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=EQLuUgJy+o1hW9AunpfEc1qlY4Nc1HNzMaooRQ/maGI=; b=c+2FqPenYDUXmY2kNElCjc1zpbv1nfM3B2pKaKRri5HOpiZXABTyHA/PQlo65RJr+Z 14Pt8sXeP01DXpN2ebzEEbqt4n938aJ3hopdR7MCIZlmle6G3XvdFqZapeDec2yFUeUJ 0avNYAVfgR+txKKakSpI+lBCzfKr//gTUa7x9uJ2gwwFu8V7eldlnJMjKhTgEnsQzER7 d0L/5h4KFw/n8EMVErFTT/nrrzJtdlioCpEas5H7QzuuqaU1bqnMPpsf4yAQNMLU6zax /VMRyu313OLhK+I5lm57OtJpwofCPks0qjOWNX6mDMCAkxinGN7D9Mg5wEdg4IHQRdeX 6g8w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=EQLuUgJy+o1hW9AunpfEc1qlY4Nc1HNzMaooRQ/maGI=; b=avByOpxRj+DVjrSP8wzGS2yc86t0RyyBP+d0sGf8r/snuRwblJxoi0DN+a/sC+bdxe Xq5HcY1SxHeI3nJEg61gaWWkjzcgCRKGwZmd2meVOF4Gu5VYL9mC8PmMjchiM/6hV8+o +OU1dMmTTPrlcyaTq5GV2BcsSnRL9iM5QKJnwWkHo4G4ATLkJ3nd6di+PkgsWFBpbVKB ZRjsQqyQax9ZboVv8zxRZcAq3TMN4i18X3nT4C8LJDM4of0CiGz+FC2eG846omkJAf8J xG6LupZOTb319BGL4mHgx9vIL49ngDIDMIaU1NYNZjjjL63B2ryPRRPWFj5ySFTT+yOZ eb0g== X-Gm-Message-State: AOAM533AbZf1P3kggMSET5i1ou3FjCFV2nwpK0G9czDoi9oe2IPcs2hi rWeo4xH+ErFHS5G29R2Fw5I= X-Google-Smtp-Source: ABdhPJyUpFpB8WB7DGdGa42I0331TOpmj95xQ5DyrrcB4Il8FwZOLlGyylyvihXjujMle9NwJNLgTA== X-Received: by 2002:a17:902:7d96:b029:e0:151c:598b with SMTP id a22-20020a1709027d96b02900e0151c598bmr18881431plm.2.1612208519740; Mon, 01 Feb 2021 11:41:59 -0800 (PST) Received: from laptop.hsd1.wa.comcast.net ([2601:600:9b7f:872e:a655:30fb:7373:c762]) by smtp.gmail.com with ESMTPSA id i4sm18213155pfo.40.2021.02.01.11.41.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 11:41:59 -0800 (PST) From: Andrei Vagin To: Will Deacon , Catalin Marinas Subject: [PATCH 1/3] arm64/ptrace: don't clobber task registers on syscall entry/exit traps Date: Mon, 1 Feb 2021 11:40:10 -0800 Message-Id: <20210201194012.524831-2-avagin@gmail.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210201194012.524831-1-avagin@gmail.com> References: <20210201194012.524831-1-avagin@gmail.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210201_144204_182233_E080B928 X-CRM114-Status: GOOD ( 24.11 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Anthony Steinhauser , linux-api@vger.kernel.org, Oleg Nesterov , linux-kernel@vger.kernel.org, Keno Fischer , Andrei Vagin , Dave Martin , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org ip/r12 for AArch32 and x7 for AArch64 is used to indicate whether or not the stop has been signalled from syscall entry or syscall exit. This means that: - Any writes by the tracer to this register during the stop are ignored/discarded. - The actual value of the register is not available during the stop, so the tracer cannot save it and restore it later. Right now, these registers are clobbered in tracehook_report_syscall. This change moves the logic to gpr_get and compat_gpr_get where registers are copied into a user-space buffer. This will allow to change these registers and to introduce a new ptrace option to get the full set of registers. Signed-off-by: Andrei Vagin --- arch/arm64/include/asm/ptrace.h | 5 ++ arch/arm64/kernel/ptrace.c | 104 ++++++++++++++++++++------------ 2 files changed, 69 insertions(+), 40 deletions(-) diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h index e58bca832dff..0a9552b4f61e 100644 --- a/arch/arm64/include/asm/ptrace.h +++ b/arch/arm64/include/asm/ptrace.h @@ -170,6 +170,11 @@ static inline unsigned long pstate_to_compat_psr(const unsigned long pstate) return psr; } +enum ptrace_syscall_dir { + PTRACE_SYSCALL_ENTER = 0, + PTRACE_SYSCALL_EXIT, +}; + /* * This struct defines the way the registers are stored on the stack during an * exception. Note that sizeof(struct pt_regs) has to be a multiple of 16 (for diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 8ac487c84e37..39da03104528 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -40,6 +40,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -561,7 +562,31 @@ static int gpr_get(struct task_struct *target, struct membuf to) { struct user_pt_regs *uregs = &task_pt_regs(target)->user_regs; - return membuf_write(&to, uregs, sizeof(*uregs)); + unsigned long saved_reg; + int ret; + + /* + * We have some ABI weirdness here in the way that we handle syscall + * exit stops because we indicate whether or not the stop has been + * signalled from syscall entry or syscall exit by clobbering the general + * purpose register x7. + */ + saved_reg = uregs->regs[7]; + + switch (target->ptrace_message) { + case PTRACE_EVENTMSG_SYSCALL_ENTRY: + uregs->regs[7] = PTRACE_SYSCALL_ENTER; + break; + case PTRACE_EVENTMSG_SYSCALL_EXIT: + uregs->regs[7] = PTRACE_SYSCALL_EXIT; + break; + } + + ret = membuf_write(&to, uregs, sizeof(*uregs)); + + uregs->regs[7] = saved_reg; + + return ret; } static int gpr_set(struct task_struct *target, const struct user_regset *regset, @@ -575,6 +600,17 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset, if (ret) return ret; + /* + * Historically, x7 can't be changed if the stop has been signalled + * from syscall-enter of syscall-exit. + */ + switch (target->ptrace_message) { + case PTRACE_EVENTMSG_SYSCALL_ENTRY: + case PTRACE_EVENTMSG_SYSCALL_EXIT: + newregs.regs[7] = task_pt_regs(target)->regs[7]; + break; + } + if (!valid_user_regs(&newregs, target)) return -EINVAL; @@ -1206,6 +1242,20 @@ static inline compat_ulong_t compat_get_user_reg(struct task_struct *task, int i struct pt_regs *regs = task_pt_regs(task); switch (idx) { + case 12: + /* + * We have some ABI weirdness here in the way that we handle + * syscall exit stops because we indicate whether or not the + * stop has been signalled from syscall entry or syscall exit + * by clobbering the general purpose register r12. + */ + switch (task->ptrace_message) { + case PTRACE_EVENTMSG_SYSCALL_ENTRY: + return PTRACE_SYSCALL_ENTER; + case PTRACE_EVENTMSG_SYSCALL_EXIT: + return PTRACE_SYSCALL_EXIT; + } + return regs->regs[idx]; case 15: return regs->pc; case 16: @@ -1282,6 +1332,17 @@ static int compat_gpr_set(struct task_struct *target, } + /* + * Historically, x12 can't be changed if the stop has been signalled + * from syscall-enter of syscall-exit. + */ + switch (target->ptrace_message) { + case PTRACE_EVENTMSG_SYSCALL_ENTRY: + case PTRACE_EVENTMSG_SYSCALL_EXIT: + newregs.regs[12] = task_pt_regs(target)->regs[12]; + break; + } + if (valid_user_regs(&newregs.user_regs, target)) *task_pt_regs(target) = newregs; else @@ -1740,53 +1801,16 @@ long arch_ptrace(struct task_struct *child, long request, return ptrace_request(child, request, addr, data); } -enum ptrace_syscall_dir { - PTRACE_SYSCALL_ENTER = 0, - PTRACE_SYSCALL_EXIT, -}; - static void tracehook_report_syscall(struct pt_regs *regs, enum ptrace_syscall_dir dir) { - int regno; - unsigned long saved_reg; - - /* - * We have some ABI weirdness here in the way that we handle syscall - * exit stops because we indicate whether or not the stop has been - * signalled from syscall entry or syscall exit by clobbering a general - * purpose register (ip/r12 for AArch32, x7 for AArch64) in the tracee - * and restoring its old value after the stop. This means that: - * - * - Any writes by the tracer to this register during the stop are - * ignored/discarded. - * - * - The actual value of the register is not available during the stop, - * so the tracer cannot save it and restore it later. - * - * - Syscall stops behave differently to seccomp and pseudo-step traps - * (the latter do not nobble any registers). - */ - regno = (is_compat_task() ? 12 : 7); - saved_reg = regs->regs[regno]; - regs->regs[regno] = dir; - if (dir == PTRACE_SYSCALL_ENTER) { if (tracehook_report_syscall_entry(regs)) forget_syscall(regs); - regs->regs[regno] = saved_reg; - } else if (!test_thread_flag(TIF_SINGLESTEP)) { - tracehook_report_syscall_exit(regs, 0); - regs->regs[regno] = saved_reg; } else { - regs->regs[regno] = saved_reg; + int singlestep = test_thread_flag(TIF_SINGLESTEP); - /* - * Signal a pseudo-step exception since we are stepping but - * tracer modifications to the registers may have rewound the - * state machine. - */ - tracehook_report_syscall_exit(regs, 1); + tracehook_report_syscall_exit(regs, singlestep); } } From patchwork Mon Feb 1 19:40:11 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrei Vagin X-Patchwork-Id: 12059855 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.7 required=3.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D1B66C433DB for ; Mon, 1 Feb 2021 19:43:22 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 874ED64EA8 for ; Mon, 1 Feb 2021 19:43:22 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 874ED64EA8 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: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:List-Owner; bh=f2xgYvvliYum+E9mgQIuzRqUov00OokNDvfN/woj0Xk=; b=PzvDxBDoSvMoq79SA34GkJnYm OthWTPzGTCEzNaEnqKAixUn5RwzZqWL0kHfU0lu9s7G3GyXilnI2fqFWnT/+BmNZyl+QLC96IsJ60 cT5fOZm6Odgzrv+Mefu5Gw1seQtaNRE5uItV69D+NDv6XnRXVxsiBal5Ycnb0D92x8x8hvEYWZhUv C8IcuPWDqLgBZeC+zPRHc7kjD9LEfvsYIBqizCVWMxLLQJzVarAF2lytRh/KdH2vlp5uiGHGceYyI 7w7ETPtcrydvwQztYtJIq/qZ83NOQdP0YjAKPt99SekynpMUBEUfQ01KEJvh52th56r8DYqlSVPbI kC3Vewb1A==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1l6f5R-00016l-Ig; Mon, 01 Feb 2021 19:42:13 +0000 Received: from mail-pl1-x62b.google.com ([2607:f8b0:4864:20::62b]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1l6f5I-00010R-16 for linux-arm-kernel@lists.infradead.org; Mon, 01 Feb 2021 19:42:08 +0000 Received: by mail-pl1-x62b.google.com with SMTP id u11so10584082plg.13 for ; Mon, 01 Feb 2021 11:42:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=54HaqmXpfsd5zEV3HoPbFBl5GxWxzwJ8Zfrym0Khwo8=; b=DyokyQNh+PByr5WdoEJ15eDHP6uAClVcSsLQ8bJfzh7+fb6F0petWfGhE1b3rAuRxR rn1mQWomuvuuT6ar9JJJuTmEOVpAuIPYfh+gL2YOFHqV7rF6KK0JhQE4dC7ZzNMu9iFs PAd8op3ZxMXLDcBS7VvG4BSq5Kvl5/+7zFFQpMaQeJITXQXKdBxIuOFAn3YOOGzHZc0Y WUc/8air7gZV6G4ruIthZlHHhhKmTEbNrzqQ9v9TLa47mfTNKeBJXMJ8ODkKUMsfdQNq 9chTAtxh1A+ZzQkZOekFDQFt9WedIlOVbNAwAGsgOoqk1qmLBwho0B62/G4h9DMdHOKP 2+8g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=54HaqmXpfsd5zEV3HoPbFBl5GxWxzwJ8Zfrym0Khwo8=; b=aiyrf4JAoRDhmlRZyygEz4ZbDD2lSULFwNNohCIefXbxgScKPzCBxK+EdWJ1ls2qnD SaqY9Kstu9ANey2v8rSQA5K2kUNgIIN9Sx3gM2k8k9vGiMMtq9eJ2G7j+Jrzb6VsI2CE o5HVosdf0ZZH48hx/x/ZTUR17sxUOLWZKCOmk+We1diCu3awe2TWyvGjCA/z+pqzKxNu yxj87WCjo2TfKFxj1Qq7Grtl5KTw6gWgjuAmxk1yHOI+yd7pkOzEcIMKuBQE2hmmdr84 aC4EXS9Hrt9BxWg6dNq+LmpdXiaZfep/c/Mfu1OxsbC/ANty8LungfECRRd8TaUHFpOw 4OsQ== X-Gm-Message-State: AOAM531Xph6yD7hy+t0DAzYqEEWAGr0ql/MMgpJMnzfCVDjEB1eJHSW+ EhEOcAc/AKNdLp76c3ezMzo= X-Google-Smtp-Source: ABdhPJwfWrhxZkDE5l0bwgoiSOHOseDRKOL8wG7innfO3wgvBgOKr7r36RB2BQhqZUrDBbueiCpj5Q== X-Received: by 2002:a17:90b:4b86:: with SMTP id lr6mr444008pjb.107.1612208521215; Mon, 01 Feb 2021 11:42:01 -0800 (PST) Received: from laptop.hsd1.wa.comcast.net ([2601:600:9b7f:872e:a655:30fb:7373:c762]) by smtp.gmail.com with ESMTPSA id i4sm18213155pfo.40.2021.02.01.11.41.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 11:42:00 -0800 (PST) From: Andrei Vagin To: Will Deacon , Catalin Marinas Subject: [PATCH 2/3] arm64/ptrace: introduce PTRACE_O_ARM64_RAW_REGS Date: Mon, 1 Feb 2021 11:40:11 -0800 Message-Id: <20210201194012.524831-3-avagin@gmail.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210201194012.524831-1-avagin@gmail.com> References: <20210201194012.524831-1-avagin@gmail.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210201_144204_182418_ABAF97D1 X-CRM114-Status: GOOD ( 19.10 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Anthony Steinhauser , linux-api@vger.kernel.org, Oleg Nesterov , linux-kernel@vger.kernel.org, Keno Fischer , Andrei Vagin , Dave Martin , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org We have some ABI weirdness in the way that we handle syscall exit stops because we indicate whether or not the stop has been signalled from syscall entry or syscall exit by clobbering a general purpose register (ip/r12 for AArch32, x7 for AArch64) in the tracee and restoring its old value after the stop. This behavior was inherited from ARM and it isn't common for other architectures. Now, we have PTRACE_GET_SYSCALL_INFO that gives all required information about system calls, so the hack with clobbering registers isn't needed anymore. This change adds the new ptrace option PTRACE_O_ARM64_RAW_REGS. If it is set, PTRACE_GETREGSET returns values of all registers without clobbering r12 or x7 and PTRACE_SETREGSE sets all registers even if a process has been stopped in syscall-enter or syscall-exit. Signed-off-by: Andrei Vagin --- arch/arm64/include/uapi/asm/ptrace.h | 4 ++ arch/arm64/kernel/ptrace.c | 70 ++++++++++++++++------------ include/linux/ptrace.h | 1 + include/uapi/linux/ptrace.h | 9 +++- 4 files changed, 52 insertions(+), 32 deletions(-) diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h index 758ae984ff97..465cc9713895 100644 --- a/arch/arm64/include/uapi/asm/ptrace.h +++ b/arch/arm64/include/uapi/asm/ptrace.h @@ -109,6 +109,10 @@ struct user_hwdebug_state { } dbg_regs[16]; }; +#define PTRACE_O_ARM64_RAW_REGS (1 << 28) + +#define _PTRACE_O_ARCH_OPTIONS PTRACE_O_ARM64_RAW_REGS + /* SVE/FP/SIMD state (NT_ARM_SVE) */ struct user_sve_header { diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 39da03104528..591a4478ad76 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -565,21 +565,23 @@ static int gpr_get(struct task_struct *target, unsigned long saved_reg; int ret; - /* - * We have some ABI weirdness here in the way that we handle syscall - * exit stops because we indicate whether or not the stop has been - * signalled from syscall entry or syscall exit by clobbering the general - * purpose register x7. - */ saved_reg = uregs->regs[7]; - switch (target->ptrace_message) { - case PTRACE_EVENTMSG_SYSCALL_ENTRY: - uregs->regs[7] = PTRACE_SYSCALL_ENTER; - break; - case PTRACE_EVENTMSG_SYSCALL_EXIT: - uregs->regs[7] = PTRACE_SYSCALL_EXIT; - break; + if (!(target->ptrace & PT_ARM64_RAW_REGS)) { + /* + * We have some ABI weirdness here in the way that we handle + * syscall exit stops because we indicate whether or not the + * stop has been signalled from syscall entry or syscall exit + * by clobbering the general purpose register x7. + */ + switch (target->ptrace_message) { + case PTRACE_EVENTMSG_SYSCALL_ENTRY: + uregs->regs[7] = PTRACE_SYSCALL_ENTER; + break; + case PTRACE_EVENTMSG_SYSCALL_EXIT: + uregs->regs[7] = PTRACE_SYSCALL_EXIT; + break; + } } ret = membuf_write(&to, uregs, sizeof(*uregs)); @@ -600,15 +602,17 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset, if (ret) return ret; - /* - * Historically, x7 can't be changed if the stop has been signalled - * from syscall-enter of syscall-exit. - */ - switch (target->ptrace_message) { - case PTRACE_EVENTMSG_SYSCALL_ENTRY: - case PTRACE_EVENTMSG_SYSCALL_EXIT: - newregs.regs[7] = task_pt_regs(target)->regs[7]; - break; + if (!(target->ptrace & PT_ARM64_RAW_REGS)) { + /* + * Historically, x7 can't be changed if the stop has been + * signalled from syscall-enter of syscall-exit. + */ + switch (target->ptrace_message) { + case PTRACE_EVENTMSG_SYSCALL_ENTRY: + case PTRACE_EVENTMSG_SYSCALL_EXIT: + newregs.regs[7] = task_pt_regs(target)->regs[7]; + break; + } } if (!valid_user_regs(&newregs, target)) @@ -1243,6 +1247,8 @@ static inline compat_ulong_t compat_get_user_reg(struct task_struct *task, int i switch (idx) { case 12: + if (task->ptrace & PT_ARM64_RAW_REGS) + return regs->regs[idx]; /* * We have some ABI weirdness here in the way that we handle * syscall exit stops because we indicate whether or not the @@ -1332,15 +1338,17 @@ static int compat_gpr_set(struct task_struct *target, } - /* - * Historically, x12 can't be changed if the stop has been signalled - * from syscall-enter of syscall-exit. - */ - switch (target->ptrace_message) { - case PTRACE_EVENTMSG_SYSCALL_ENTRY: - case PTRACE_EVENTMSG_SYSCALL_EXIT: - newregs.regs[12] = task_pt_regs(target)->regs[12]; - break; + if (!(target->ptrace & PT_ARM64_RAW_REGS)) { + /* + * Historically, r12 can't be changed if the stop has been + * signalled from syscall-enter of syscall-exit. + */ + switch (target->ptrace_message) { + case PTRACE_EVENTMSG_SYSCALL_ENTRY: + case PTRACE_EVENTMSG_SYSCALL_EXIT: + newregs.regs[12] = task_pt_regs(target)->regs[12]; + break; + } } if (valid_user_regs(&newregs.user_regs, target)) diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 2a9df80ea887..987d6ec5f0ce 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -46,6 +46,7 @@ extern int ptrace_access_vm(struct task_struct *tsk, unsigned long addr, #define PT_EXITKILL (PTRACE_O_EXITKILL << PT_OPT_FLAG_SHIFT) #define PT_SUSPEND_SECCOMP (PTRACE_O_SUSPEND_SECCOMP << PT_OPT_FLAG_SHIFT) +#define PT_ARM64_RAW_REGS (PTRACE_O_ARM64_RAW_REGS << PT_OPT_FLAG_SHIFT) /* single stepping state bits (used on ARM and PA-RISC) */ #define PT_SINGLESTEP_BIT 31 diff --git a/include/uapi/linux/ptrace.h b/include/uapi/linux/ptrace.h index 83ee45fa634b..bcc8c362ddd9 100644 --- a/include/uapi/linux/ptrace.h +++ b/include/uapi/linux/ptrace.h @@ -7,6 +7,7 @@ /* has the defines to get at the registers. */ #include +#include #define PTRACE_TRACEME 0 #define PTRACE_PEEKTEXT 1 @@ -137,8 +138,14 @@ struct ptrace_syscall_info { #define PTRACE_O_EXITKILL (1 << 20) #define PTRACE_O_SUSPEND_SECCOMP (1 << 21) +/* (1<<28) is reserved for arch specific options. */ +#ifndef _PTRACE_O_ARCH_OPTIONS +#define _PTRACE_O_ARCH_OPTIONS 0 +#endif + #define PTRACE_O_MASK (\ - 0x000000ff | PTRACE_O_EXITKILL | PTRACE_O_SUSPEND_SECCOMP) + 0x000000ff | PTRACE_O_EXITKILL | \ + PTRACE_O_SUSPEND_SECCOMP | _PTRACE_O_ARCH_OPTIONS) #include From patchwork Mon Feb 1 19:40:12 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrei Vagin X-Patchwork-Id: 12059859 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.7 required=3.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A776DC433E0 for ; Mon, 1 Feb 2021 19:43:28 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 4695A64DBA for ; Mon, 1 Feb 2021 19:43:28 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4695A64DBA Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: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:List-Owner; bh=nJ3/SuNwEUbwbhM6EWJhGp7RywKVlcoTywH8VMDnm3A=; b=F8H1IFHlHWchpY4u85YuTVBao jv4ZKojdxTtzsk9G0LVD/5MaQ0IjVaN76BMH/ZG+LotKPyCsJOsmahPzQrtaJVqholqVirdce50Zq uQvLsL3FQsJR2Ki41AFQrdzTau2DHAnz18ZkFaa3rQgWolX3AAsJK15gvUIC3rM/ubrA8K1v8qyBR jpIEAzoxoyeITOdZl8SjinwZk8r5FoUWtcrQ8PkuxlgnKaUujb7d0yjWaXhDuIv4z4Q97xv9x7RA4 a5oPqaO+4LCHyJu2p51XD3df0nXSU2mf5GSIsjBcO+YlsNSanZonCNi3AHMJnXPyVtF6N4TKWc8uC WF/L6gZvw==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1l6f5Y-0001A4-NM; Mon, 01 Feb 2021 19:42:20 +0000 Received: from mail-pj1-x1029.google.com ([2607:f8b0:4864:20::1029]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1l6f5J-00011u-8O for linux-arm-kernel@lists.infradead.org; Mon, 01 Feb 2021 19:42:09 +0000 Received: by mail-pj1-x1029.google.com with SMTP id kx7so234879pjb.2 for ; Mon, 01 Feb 2021 11:42:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=6sPxRlDZVCgLrmX5i4bW0vNdjIwlKi4D6sFiaqH5u5g=; b=G+qStO7CkVvgsNXqB/Wb0xndz5YAZ0RZrs54KBqSeBWnQwmZZrW4vLkgw3gfK3GZt6 RpXWZRrP+uCyvoqxHBKNCS/uC8MXa7J7miKMoZeZelacqSbSARKbDmMaMBP79iE63Mv4 CzVYO6kKxCRIdhWNYow5YNV3mfte0MkkmbXcsRdk+Fo3t73XIlUekwU3nv/YhOCC5AKb jqh9UWlv1tRU0f7qxTS1rydAYnNyhZdJZNoYgZUyFfmNOt0R7KLbbTnz4F9unRrd+t5P heRn8ZL7Tj39fs+lxdA7Os0HhAnyzYpgv7n0U3mYoBOVOntHK1FvTDWzuNw3vMw5XtQL re/A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=6sPxRlDZVCgLrmX5i4bW0vNdjIwlKi4D6sFiaqH5u5g=; b=DuVh6bv5fRCbIkzC8DxZlb4+ZsCbJr2C3b+Iqxbei3YB1r/BhaqbNE0BZfEuLf0zQD kSGYrx2LlqAe9ZRYJ23Hh0CZjcqRMuk43bCf6XgwEXMuW5sBLme0UfD7ixHaendc1ItD L+51HcMzS4to8w+q11kdCW4m9q68Xd2RPARV3q2dym5N38rs2nqrbkXKpa+zPA6vhkPZ smK/XhvTT0DAz4fOtlQl2uSR84lsKrGXK6+ZRnUzlSDQ411M6ECgcD2cqfHZt2eH0Wtw ToYyEIDzj/2NnoGNw6HBtwnVyVUmL8p2WvYcQU6RUTYYt3K/MDaghXD0osNGgg6LXvhV y4IA== X-Gm-Message-State: AOAM533zHos2G26XVHM4XLPzzwDJtnFnxKhUsB/kHbbbNGHvUvbfeqQ/ DWYzx+RIxLJ1inreXWNLWeA= X-Google-Smtp-Source: ABdhPJw9YWcNuHFuTmMPxsVUG3s1VGIHPRHmuVePCWcxJqJN2Qj4tJcarkH23fR/KYYV3RZnTL99Kg== X-Received: by 2002:a17:902:a58c:b029:df:f345:80ec with SMTP id az12-20020a170902a58cb02900dff34580ecmr18525611plb.66.1612208522619; Mon, 01 Feb 2021 11:42:02 -0800 (PST) Received: from laptop.hsd1.wa.comcast.net ([2601:600:9b7f:872e:a655:30fb:7373:c762]) by smtp.gmail.com with ESMTPSA id i4sm18213155pfo.40.2021.02.01.11.42.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Feb 2021 11:42:01 -0800 (PST) From: Andrei Vagin To: Will Deacon , Catalin Marinas Subject: [PATCH 3/3] selftest/arm64/ptrace: add tests for PTRACE_O_ARM64_RAW_REGS Date: Mon, 1 Feb 2021 11:40:12 -0800 Message-Id: <20210201194012.524831-4-avagin@gmail.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210201194012.524831-1-avagin@gmail.com> References: <20210201194012.524831-1-avagin@gmail.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210201_144205_354733_1266E5DD X-CRM114-Status: GOOD ( 20.75 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Anthony Steinhauser , linux-api@vger.kernel.org, Oleg Nesterov , linux-kernel@vger.kernel.org, Keno Fischer , Andrei Vagin , Dave Martin , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Test output: TAP version 13 1..2 # selftests: arm64/ptrace: ptrace_syscall_raw_regs_test # 1..2 # ok 1 x7: 686920776f726c64 # ok 2 The child exited with code 0. # # Totals: pass:2 fail:0 xfail:0 xpass:0 skip:0 error:0 ok 1 selftests: arm64/ptrace: ptrace_syscall_raw_regs_test # selftests: arm64/ptrace: ptrace_syscall_regs_test # 1..3 # ok 1 x7: 0 # ok 2 x7: 1 # ok 3 The child exited with code 0. # # Totals: pass:3 fail:0 xfail:0 xpass:0 skip:0 error:0 ok 2 selftests: arm64/ptrace: ptrace_syscall_regs_test Signed-off-by: Andrei Vagin --- tools/testing/selftests/arm64/Makefile | 2 +- tools/testing/selftests/arm64/ptrace/Makefile | 6 + .../ptrace/ptrace_syscall_raw_regs_test.c | 142 +++++++++++++++++ .../arm64/ptrace/ptrace_syscall_regs_test.c | 150 ++++++++++++++++++ 4 files changed, 299 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/arm64/ptrace/Makefile create mode 100644 tools/testing/selftests/arm64/ptrace/ptrace_syscall_raw_regs_test.c create mode 100644 tools/testing/selftests/arm64/ptrace/ptrace_syscall_regs_test.c diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile index 2c9d012797a7..704770a60ece 100644 --- a/tools/testing/selftests/arm64/Makefile +++ b/tools/testing/selftests/arm64/Makefile @@ -4,7 +4,7 @@ ARCH ?= $(shell uname -m 2>/dev/null || echo not) ifneq (,$(filter $(ARCH),aarch64 arm64)) -ARM64_SUBTARGETS ?= tags signal pauth fp mte +ARM64_SUBTARGETS ?= tags signal pauth fp mte ptrace else ARM64_SUBTARGETS := endif diff --git a/tools/testing/selftests/arm64/ptrace/Makefile b/tools/testing/selftests/arm64/ptrace/Makefile new file mode 100644 index 000000000000..84b27449f3d1 --- /dev/null +++ b/tools/testing/selftests/arm64/ptrace/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 + +CFLAGS += -g -I../../../../../usr/include/ +TEST_GEN_PROGS := ptrace_syscall_raw_regs_test ptrace_syscall_regs_test + +include ../../lib.mk diff --git a/tools/testing/selftests/arm64/ptrace/ptrace_syscall_raw_regs_test.c b/tools/testing/selftests/arm64/ptrace/ptrace_syscall_raw_regs_test.c new file mode 100644 index 000000000000..78f913303a99 --- /dev/null +++ b/tools/testing/selftests/arm64/ptrace/ptrace_syscall_raw_regs_test.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../../kselftest.h" + +#define TEST_VAL 0x686920776f726c64UL + +#define pr_p(func, fmt, ...) func(fmt ": %m", ##__VA_ARGS__) + +#define pr_err(fmt, ...) \ + ({ \ + ksft_test_result_error(fmt "\n", ##__VA_ARGS__); \ + -1; \ + }) + +#define pr_fail(fmt, ...) \ + ({ \ + ksft_test_result_fail(fmt "\n", ##__VA_ARGS__); \ + -1; \ + }) + +#define pr_perror(fmt, ...) pr_p(pr_err, fmt, ##__VA_ARGS__) + +static long loop(void *val) +{ + register long x0 __asm__("x0"); + register void *x1 __asm__("x1") = val; + register long x8 __asm__("x8") = 555; + + __asm__ ( + "again:\n" + "ldr x7, [x1, 0]\n" + "svc 0\n" + "str x7, [x1, 0]\n" + : "=r"(x0) + : "r"(x1), "r"(x8) + : + ); + return 0; +} + +static int child(void) +{ + long val = TEST_VAL; + + loop(&val); + if (val != ~TEST_VAL) { + ksft_print_msg("Unexpected x7: %lx\n", val); + return 1; + } + + return 0; +} + +#ifndef PTRACE_SYSEMU +#define PTRACE_SYSEMU 31 +#endif + +#ifndef PTRACE_O_ARM64_RAW_REGS +#define PTRACE_O_ARM64_RAW_REGS (1 << 28) +#endif + +int main(int argc, void **argv) +{ + struct user_regs_struct regs = {}; + struct iovec iov = { + .iov_base = ®s, + .iov_len = sizeof(struct user_regs_struct), + }; + int status; + pid_t pid; + + ksft_set_plan(2); + + pid = fork(); + if (pid == 0) { + kill(getpid(), SIGSTOP); + child(); + _exit(0); + } + if (pid < 0) + return 1; + + if (ptrace(PTRACE_ATTACH, pid, 0, 0)) + return pr_perror("Can't attach to the child %d", pid); + if (waitpid(pid, &status, 0) != pid) + return pr_perror("Can't wait for the child %d", pid); + if (ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_ARM64_RAW_REGS)) + return pr_perror("Can't set PTRACE_O_ARM64_RAW_REGS"); + /* skip SIGSTOP */ + if (ptrace(PTRACE_CONT, pid, 0, 0)) + return pr_perror("Can't resume the child %d", pid); + if (waitpid(pid, &status, 0) != pid) + return pr_perror("Can't wait for the child %d", pid); + + /* Resume the child to the next system call. */ + if (ptrace(PTRACE_SYSEMU, pid, 0, 0)) + return pr_perror("Can't resume the child %d", pid); + if (waitpid(pid, &status, 0) != pid) + return pr_perror("Can't wait for the child %d", pid); + if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP) + return pr_err("Unexpected status: %d", status); + + /* Check that x7 isnt't clobbered if PTRACE_O_ARM64_RAW_REGS is set. */ + if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov)) + return pr_perror("Can't get child registers"); + if (regs.regs[7] != TEST_VAL) + return pr_fail("unexpected x7: %lx", regs.regs[7]); + ksft_test_result_pass("x7: %llx\n", regs.regs[7]); + + /* Check that the child will see a new value of x7. */ + regs.regs[0] = 0; + regs.regs[7] = ~TEST_VAL; + if (ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov)) + return pr_perror("Can't set child registers"); + + if (ptrace(PTRACE_CONT, pid, 0, 0)) + return pr_perror("Can't resume the child %d", pid); + if (waitpid(pid, &status, 0) != pid) + return pr_perror("Can't wait for the child %d", pid); + + if (status != 0) + return pr_fail("Child exited with code %d.", status); + + ksft_test_result_pass("The child exited with code 0.\n"); + ksft_exit_pass(); + return 0; +} + diff --git a/tools/testing/selftests/arm64/ptrace/ptrace_syscall_regs_test.c b/tools/testing/selftests/arm64/ptrace/ptrace_syscall_regs_test.c new file mode 100644 index 000000000000..d1534525ef26 --- /dev/null +++ b/tools/testing/selftests/arm64/ptrace/ptrace_syscall_regs_test.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../../kselftest.h" + +#define TEST_VAL 0x686920776f726c64UL + +#define pr_p(func, fmt, ...) func(fmt ": %m", ##__VA_ARGS__) + +#define pr_err(fmt, ...) \ + ({ \ + ksft_test_result_error(fmt "\n", ##__VA_ARGS__); \ + -1; \ + }) + +#define pr_fail(fmt, ...) \ + ({ \ + ksft_test_result_fail(fmt "\n", ##__VA_ARGS__); \ + -1; \ + }) + +#define pr_perror(fmt, ...) pr_p(pr_err, fmt, ##__VA_ARGS__) + +static long loop(void *val) +{ + register long x0 __asm__("x0"); + register void *x1 __asm__("x1") = val; + register long x8 __asm__("x8") = 555; + + __asm__ ( + "again:\n" + "ldr x7, [x1, 0]\n" + "svc 0\n" + "str x7, [x1, 0]\n" + : "=r"(x0) + : "r"(x1), "r"(x8) + : + ); + return 0; +} + +static int child(void) +{ + long val = TEST_VAL; + + loop(&val); + if (val != TEST_VAL) { + ksft_print_msg("Unexpected x7: %lx\n", val); + return 1; + } + + return 0; +} + +#ifndef PTRACE_O_ARM64_RAW_REGS +#define PTRACE_O_ARM64_RAW_REGS (1 << 28) +#endif + +int main(int argc, void **argv) +{ + struct user_regs_struct regs = {}; + struct iovec iov = { + .iov_base = ®s, + .iov_len = sizeof(struct user_regs_struct), + }; + int status; + pid_t pid; + + ksft_set_plan(3); + + pid = fork(); + if (pid == 0) { + kill(getpid(), SIGSTOP); + child(); + _exit(0); + } + if (pid < 0) + return 1; + + if (ptrace(PTRACE_ATTACH, pid, 0, 0)) + return pr_perror("Can't attach to the child %d", pid); + if (waitpid(pid, &status, 0) != pid) + return pr_perror("Can't wait for the child %d", pid); + /* skip SIGSTOP */ + if (ptrace(PTRACE_CONT, pid, 0, 0)) + return pr_perror("Can't resume the child %d", pid); + if (waitpid(pid, &status, 0) != pid) + return pr_perror("Can't wait for the child %d", pid); + + /* Resume the child to the next system call. */ + if (ptrace(PTRACE_SYSCALL, pid, 0, 0)) + return pr_perror("Can't resume the child %d", pid); + if (waitpid(pid, &status, 0) != pid) + return pr_perror("Can't wait for the child %d", pid); + if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP) + return pr_err("Unexpected status: %d", status); + + /* Check that x7 is 0 on syscall-enter. */ + if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov)) + return pr_perror("Can't get child registers"); + if (regs.regs[7] != 0) + return pr_fail("Unexpected x7: %lx", regs.regs[7]); + ksft_test_result_pass("x7: %llx\n", regs.regs[7]); + + if (ptrace(PTRACE_SYSCALL, pid, 0, 0)) + return pr_perror("Can't resume the child %d", pid); + if (waitpid(pid, &status, 0) != pid) + return pr_perror("Can't wait for the child %d", pid); + if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP) + return pr_err("Unexpected status: %d", status); + + /* Check that x7 is 1 on syscall-exit. */ + if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov)) + return pr_perror("Can't get child registers"); + if (regs.regs[7] != 1) + return pr_fail("Unexpected x7: %lx", regs.regs[7]); + ksft_test_result_pass("x7: %llx\n", regs.regs[7]); + + /* Check that the child will not a new value of x7. */ + regs.regs[0] = 0; + regs.regs[7] = ~TEST_VAL; + if (ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov)) + return pr_perror("Can't set child registers"); + + if (ptrace(PTRACE_CONT, pid, 0, 0)) + return pr_perror("Can't resume the child %d", pid); + if (waitpid(pid, &status, 0) != pid) + return pr_perror("Can't wait for the child %d", pid); + + if (status != 0) + return pr_fail("Child exited with code %d.", status); + + ksft_test_result_pass("The child exited with code 0.\n"); + ksft_exit_pass(); + return 0; +} +