From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 082F8C0218A for ; Tue, 14 Jan 2025 11:32:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=exXQ4twzHhx+69VgkOasIACN9ZNsWPg08dNNqO76+Uk=; b=KTaxDC4k/g1uv+qL9xBKtvJKjr tt0eBDx7DolRTFqh1fNFGK/G1QARBUfMhKdZeC/mEtSvbeewDjdzyhNgBJl5AqpC312Cc+N8lBzlY xuuGPVGJuoCD5fG8TIZ6lhazenS6VRWwKyHwyjdTytve2abHE1falHbGl3yGOV9eQf5Da2XiKp0G0 Wsk0XiYxpE7PMNqnWiLCFFxyii+IXLdCRIxLaDKviqTT3YDKJnUt0EgLqtBeHKDH+l+d7o0yIzRHZ Wpfb1wRv/eMAKvujvwVXihnOXtRXkWIsnOtsd9bn5u+brM2SV+cYCJHPZK+0NXTxHI7wT3u4hUxpV NJiq4EnA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tXf9c-00000008GMG-2tHo; Tue, 14 Jan 2025 11:32:16 +0000 Received: from mail-pl1-x629.google.com ([2607:f8b0:4864:20::629]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tXf8f-00000008G6b-2M2j for linux-um@lists.infradead.org; Tue, 14 Jan 2025 11:31:18 +0000 Received: by mail-pl1-x629.google.com with SMTP id d9443c01a7336-2166651f752so119030545ad.3 for ; Tue, 14 Jan 2025 03:31:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1736854276; x=1737459076; darn=lists.infradead.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=exXQ4twzHhx+69VgkOasIACN9ZNsWPg08dNNqO76+Uk=; b=T6qoZxZ2uE/vPyb5x6si8KPNmuxGE4Ly8poNG7Y+cv2Wt26SvgHRPR0n24kT7WqPep B4aKgivM+4pU1B9MKdMRVXiNUylNl7UH8t4dUEr+lllXlFO/0z1BK1k9NBEA4pn5ArpW hUHAaqSywP1vaio3TXUJM1/u8D6052WlMiFA5aSQUC+UggC/A14giwr989RZW9NHzVbr Qp8BUWEAgkL4vUoXsx+SNwyZWg8K0wLU+oDToP3S2k6LE8DHM7cZ/3zz+CHDiMMejSGU 2ZPkZEkhKTB/q+qclUsUUoxmXhe+d8r3ojJnR34yxWUtdmIJV/Sjyqw5GLdzt0xdPLm3 bxkQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736854276; x=1737459076; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=exXQ4twzHhx+69VgkOasIACN9ZNsWPg08dNNqO76+Uk=; b=W1B+ECFZQpojTGincJ8EZAZ7y+UKRZz6G0UTXd4pjLj6xUz9vIrJSInll+v+//F5tW a8BMNeWgd5VQAy6G2FsXnubLxIB+tO5y2BQ+lCFQfA1tUF3ozsuFDWQ+OTotafZ9rqKl AfJBMlwQxhW34JKv5h25QSywd7g7CeQ90UjBU+XRXkf3t4tFXqM1vv2k9hiP5e49zJJz R66y1cS2jZcxGSxRuFYxSpGFVLxPBz3xcgwv1R/6o9YfxHeBLFEa1Gub55lfz5pR/zrO M4RGFgY7fMAbv8nq/trZ3CoTrZbGOajIR7GhIDfsGkysTBbX4m/Svf1fIgpNj5JpWVGq bIhQ== X-Gm-Message-State: AOJu0YxGaDLep2dJe+5djR1/PIb0ZTm2IefUGrKAuKKtsF5cbi0hWWxX Hwm5mid+3M2l4sE47axeSnaN7yIYK/03XjJxIYMQIzPrikQ09xEY X-Gm-Gg: ASbGncvVypfqO99fwCb0tunC8spwCr+BjdfRxOLV/QdQt9WK62M7HkuBmFisi/GcPtC xfzRlj3cpr5hqgDRDQdbbY4K9XC9cxEmwQ1P8EkevLDdtTLqMnyoJA/FGFwV83fFTtRYoCX08Rk NWYrFCj9QjblVJt896HuIT1k2I6AY7Mtydmw64lBWAZZifCZ/xRm5vh+UvJ7WAxZteaP8YpZZSa aAZiosj8pPqfcAJbnmnxgzp9itOjSi0F4DvDx2myPJqt2XUDt84IKDSmvIDavWFI08K2sDrf2jV ARs8p76j3c4Zpmh+hjJU5Fj6TNkP X-Google-Smtp-Source: AGHT+IHFpKsfCd5pBeConVbR9qdXCMqsLDOEXdSeGPw9TiJ1NlCOWKVzVCirEM2IYttr3tbg2L35lA== X-Received: by 2002:a05:6a00:35ce:b0:729:1c0f:b94a with SMTP id d2e1a72fcca58-72d220077aamr36712799b3a.23.1736854276500; Tue, 14 Jan 2025 03:31:16 -0800 (PST) Received: from ikb-h07-29-noble.in.iijlab.net ([202.214.97.5]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-72d4067ef71sm7464637b3a.135.2025.01.14.03.31.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 14 Jan 2025 03:31:15 -0800 (PST) Received: by ikb-h07-29-noble.in.iijlab.net (Postfix, from userid 1010) id 73318E1AB5C; Tue, 14 Jan 2025 20:31:13 +0900 (JST) From: Hajime Tazaki To: linux-um@lists.infradead.org Cc: thehajime@gmail.com, ricarkol@google.com, Liam.Howlett@oracle.com Subject: [PATCH v6 08/13] um: nommu: configure fs register on host syscall invocation Date: Tue, 14 Jan 2025 20:30:46 +0900 Message-ID: X-Mailer: git-send-email 2.43.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250114_033117_604739_17D87B37 X-CRM114-Status: GOOD ( 20.47 ) X-BeenThere: linux-um@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-um" Errors-To: linux-um-bounces+linux-um=archiver.kernel.org@lists.infradead.org As userspace on UML/!MMU also need to configure %fs register when it is running to correctly access thread structure, host syscalls implemented in os-Linux drivers may be puzzled when they are called. Thus it has to configure %fs register via arch_prctl(SET_FS) on every host syscalls. Signed-off-by: Hajime Tazaki Signed-off-by: Ricardo Koller --- arch/um/include/shared/os.h | 6 +++ arch/um/os-Linux/process.c | 6 +++ arch/um/os-Linux/start_up.c | 20 +++++++++ arch/x86/um/nommu/do_syscall_64.c | 37 ++++++++++++++++ arch/x86/um/nommu/syscalls_64.c | 71 +++++++++++++++++++++++++++++++ 5 files changed, 140 insertions(+) diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h index d29b967a009e..abb6f03414c5 100644 --- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h @@ -190,6 +190,7 @@ extern void check_host_supports_tls(int *supports_tls, int *tls_min); extern void get_host_cpu_features( void (*flags_helper_func)(char *line), void (*cache_helper_func)(char *line)); +extern int host_has_fsgsbase; /* mem.c */ extern int create_mem_file(unsigned long long len); @@ -214,6 +215,11 @@ extern int os_unmap_memory(void *addr, int len); extern int os_drop_memory(void *addr, int length); extern int can_drop_memory(void); extern int os_mincore(void *addr, unsigned long len); +extern int os_arch_prctl(int pid, int option, unsigned long *arg); +#ifndef CONFIG_MMU +extern long long host_fs; +#endif + void os_set_pdeathsig(void); diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index 49aa8e92205e..9acb865e2399 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -16,6 +16,7 @@ #include #include #include +#include /* For SYS_xxx definitions */ #include #include #include @@ -206,6 +207,11 @@ int os_mincore(void *addr, unsigned long len) return ret; } +int os_arch_prctl(int pid, int option, unsigned long *arg2) +{ + return syscall(SYS_arch_prctl, option, arg2); +} + void init_new_thread_signals(void) { set_handler(SIGSEGV); diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 93fc82c01aba..dbab091892b3 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include #include @@ -28,6 +30,8 @@ #include #include "internal.h" +int host_has_fsgsbase; + static void ptrace_child(void) { int ret; @@ -278,6 +282,19 @@ void __init get_host_cpu_features( } } +static void __init check_fsgsbase(void) +{ + unsigned long auxv = getauxval(AT_HWCAP2); + + os_info("Checking FSGSBASE instructions..."); + if (auxv & HWCAP2_FSGSBASE) { + host_has_fsgsbase = 1; + os_info("OK\n"); + } else { + host_has_fsgsbase = 0; + os_info("disabled\n"); + } +} void __init os_early_checks(void) { @@ -293,6 +310,9 @@ void __init os_early_checks(void) */ check_tmpexec(); + /* probe fsgsbase instruction */ + check_fsgsbase(); + pid = start_ptraced_child(); if (init_pid_registers(pid)) fatal("Failed to initialize default registers"); diff --git a/arch/x86/um/nommu/do_syscall_64.c b/arch/x86/um/nommu/do_syscall_64.c index 5d0fa83e7fdc..796beb0089fc 100644 --- a/arch/x86/um/nommu/do_syscall_64.c +++ b/arch/x86/um/nommu/do_syscall_64.c @@ -2,10 +2,38 @@ #include #include +#include +#include #include #include #include +static int os_x86_arch_prctl(int pid, int option, unsigned long *arg2) +{ + if (!host_has_fsgsbase) + return os_arch_prctl(pid, option, arg2); + + switch (option) { + case ARCH_SET_FS: + wrfsbase(*arg2); + break; + case ARCH_SET_GS: + wrgsbase(*arg2); + break; + case ARCH_GET_FS: + *arg2 = rdfsbase(); + break; + case ARCH_GET_GS: + *arg2 = rdgsbase(); + break; + default: + pr_warn("%s: unsupported option: 0x%x", __func__, option); + break; + } + + return 0; +} + __visible void do_syscall_64(struct pt_regs *regs) { int syscall; @@ -17,6 +45,9 @@ __visible void do_syscall_64(struct pt_regs *regs) syscall, (unsigned long)current, (unsigned long)sys_call_table[syscall]); + /* set fs register to the original host one */ + os_x86_arch_prctl(0, ARCH_SET_FS, (void *)host_fs); + if (likely(syscall < NR_syscalls)) { PT_REGS_SET_SYSCALL_RETURN(regs, EXECUTE_SYSCALL(syscall, regs)); @@ -34,4 +65,10 @@ __visible void do_syscall_64(struct pt_regs *regs) /* force do_signal() --> is_syscall() */ set_thread_flag(TIF_SIGPENDING); interrupt_end(); + + /* restore back fs register to userspace configured one */ + os_x86_arch_prctl(0, ARCH_SET_FS, + (void *)(current->thread.regs.regs.gp[FS_BASE + / sizeof(unsigned long)])); + } diff --git a/arch/x86/um/nommu/syscalls_64.c b/arch/x86/um/nommu/syscalls_64.c index c78c442aed1d..5bb6d55b4bb5 100644 --- a/arch/x86/um/nommu/syscalls_64.c +++ b/arch/x86/um/nommu/syscalls_64.c @@ -13,8 +13,70 @@ #include /* XXX This should get the constants from libc */ #include #include +#include +#include #include "syscalls.h" +/* + * The guest libc can change FS, which confuses the host libc. + * In fact, changing FS directly is not supported (check + * man arch_prctl). So, whenever we make a host syscall, + * we should be changing FS to the original FS (not the + * one set by the guest libc). This original FS is stored + * in host_fs. + */ +long long host_fs = -1; + +long arch_prctl(struct task_struct *task, int option, + unsigned long __user *arg2) +{ + long ret = -EINVAL; + unsigned long *ptr = arg2, tmp; + + switch (option) { + case ARCH_SET_FS: + if (host_fs == -1) + os_arch_prctl(0, ARCH_GET_FS, (void *)&host_fs); + ret = 0; + break; + case ARCH_SET_GS: + ret = 0; + break; + case ARCH_GET_FS: + case ARCH_GET_GS: + ptr = &tmp; + break; + } + + ret = os_arch_prctl(0, option, ptr); + if (ret) + return ret; + + switch (option) { + case ARCH_SET_FS: + current->thread.regs.regs.gp[FS_BASE / sizeof(unsigned long)] = + (unsigned long) arg2; + break; + case ARCH_SET_GS: + current->thread.regs.regs.gp[GS_BASE / sizeof(unsigned long)] = + (unsigned long) arg2; + break; + case ARCH_GET_FS: + ret = put_user(current->thread.regs.regs.gp[FS_BASE / sizeof(unsigned long)], arg2); + break; + case ARCH_GET_GS: + ret = put_user(current->thread.regs.regs.gp[GS_BASE / sizeof(unsigned long)], arg2); + break; + } + + return ret; +} + +SYSCALL_DEFINE2(arch_prctl, int, option, unsigned long, arg2) +{ + return arch_prctl(current, option, (unsigned long __user *) arg2); +} + void arch_switch_to(struct task_struct *to) { /* @@ -42,3 +104,12 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len, return ksys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT); } + +static int __init um_nommu_setup_hostfs(void) +{ + /* initialize the host_fs value at boottime */ + os_arch_prctl(0, ARCH_GET_FS, (void *)&host_fs); + + return 0; +} +arch_initcall(um_nommu_setup_hostfs); -- 2.43.0