From: Charlie Jenkins <charlie@rivosinc.com>
To: Samuel Holland <samuel.holland@sifive.com>
Cc: Palmer Dabbelt <palmer@dabbelt.com>,
linux-riscv@lists.infradead.org, devicetree@vger.kernel.org,
Catalin Marinas <catalin.marinas@arm.com>,
linux-kernel@vger.kernel.org, Anup Patel <anup@brainfault.org>,
Conor Dooley <conor@kernel.org>,
kasan-dev@googlegroups.com, Atish Patra <atishp@atishpatra.org>,
Evgenii Stepanov <eugenis@google.com>,
Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
Rob Herring <robh+dt@kernel.org>,
"Kirill A . Shutemov" <kirill.shutemov@linux.intel.com>
Subject: Re: [PATCH v4 05/10] riscv: Add support for the tagged address ABI
Date: Fri, 13 Sep 2024 20:16:48 -0700 [thread overview]
Message-ID: <ZuUAIPZBl6EWomb6@ghost> (raw)
In-Reply-To: <b5b1b654-b603-4e22-ae9c-b712e4d6babe@sifive.com>
On Fri, Sep 13, 2024 at 09:57:05PM -0500, Samuel Holland wrote:
> Hi Charlie,
>
> On 2024-09-12 9:45 PM, Charlie Jenkins wrote:
> > On Wed, Aug 28, 2024 at 06:01:27PM -0700, Samuel Holland wrote:
> >> When pointer masking is enabled for userspace, the kernel can accept
> >> tagged pointers as arguments to some system calls. Allow this by
> >> untagging the pointers in access_ok() and the uaccess routines. The
> >> uaccess routines must peform untagging in software because U-mode and
> >> S-mode have entirely separate pointer masking configurations. In fact,
> >> hardware may not even implement pointer masking for S-mode.
> >>
> >> Since the number of tag bits is variable, untagged_addr_remote() needs
> >> to know what PMLEN to use for the remote mm. Therefore, the pointer
> >> masking mode must be the same for all threads sharing an mm. Enforce
> >> this with a lock flag in the mm context, as x86 does for LAM. The flag
> >> gets reset in init_new_context() during fork(), as the new mm is no
> >> longer multithreaded.
> >>
> >> Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
> >> ---
> >
> > Not necessary, but what do you think about adding riscv to include/uapi/linux/prctl.h:
> >
> > /* Tagged user address controls for arm64 */
> > #define PR_SET_TAGGED_ADDR_CTRL 55
> > #define PR_GET_TAGGED_ADDR_CTRL 56
> > # define PR_TAGGED_ADDR_ENABLE (1UL << 0)
>
> Yes, I'll add this in v5.
>
> > Also looks like this last line should probably be under SET rather than
> > GET.
>
> The same bit fields are used for both prctl() functions, so I think the current
> grouping is okay (compare PR_RISCV_V_GET_CONTROL).
Oh perfect, I had missed that when I briefly looked.
>
> Regards,
> Samuel
>
> > Reviewed-by: Charlie Jenkins <charlie@rivosinc.com>
> > Tested-by: Charlie Jenkins <charlie@rivosinc.com>
> >
> >>
> >> Changes in v4:
> >> - Combine __untagged_addr() and __untagged_addr_remote()
> >>
> >> Changes in v3:
> >> - Use IS_ENABLED instead of #ifdef when possible
> >> - Implement mm_untag_mask()
> >> - Remove pmlen from struct thread_info (now only in mm_context_t)
> >>
> >> Changes in v2:
> >> - Implement untagged_addr_remote()
> >> - Restrict PMLEN changes once a process is multithreaded
> >>
> >> arch/riscv/include/asm/mmu.h | 7 +++
> >> arch/riscv/include/asm/mmu_context.h | 13 +++++
> >> arch/riscv/include/asm/uaccess.h | 43 ++++++++++++++--
> >> arch/riscv/kernel/process.c | 73 ++++++++++++++++++++++++++--
> >> 4 files changed, 126 insertions(+), 10 deletions(-)
> >>
> >> diff --git a/arch/riscv/include/asm/mmu.h b/arch/riscv/include/asm/mmu.h
> >> index c9e03e9da3dc..1cc90465d75b 100644
> >> --- a/arch/riscv/include/asm/mmu.h
> >> +++ b/arch/riscv/include/asm/mmu.h
> >> @@ -25,9 +25,16 @@ typedef struct {
> >> #ifdef CONFIG_BINFMT_ELF_FDPIC
> >> unsigned long exec_fdpic_loadmap;
> >> unsigned long interp_fdpic_loadmap;
> >> +#endif
> >> + unsigned long flags;
> >> +#ifdef CONFIG_RISCV_ISA_SUPM
> >> + u8 pmlen;
> >> #endif
> >> } mm_context_t;
> >>
> >> +/* Lock the pointer masking mode because this mm is multithreaded */
> >> +#define MM_CONTEXT_LOCK_PMLEN 0
> >> +
> >> #define cntx2asid(cntx) ((cntx) & SATP_ASID_MASK)
> >> #define cntx2version(cntx) ((cntx) & ~SATP_ASID_MASK)
> >>
> >> diff --git a/arch/riscv/include/asm/mmu_context.h b/arch/riscv/include/asm/mmu_context.h
> >> index 7030837adc1a..8c4bc49a3a0f 100644
> >> --- a/arch/riscv/include/asm/mmu_context.h
> >> +++ b/arch/riscv/include/asm/mmu_context.h
> >> @@ -20,6 +20,9 @@ void switch_mm(struct mm_struct *prev, struct mm_struct *next,
> >> static inline void activate_mm(struct mm_struct *prev,
> >> struct mm_struct *next)
> >> {
> >> +#ifdef CONFIG_RISCV_ISA_SUPM
> >> + next->context.pmlen = 0;
> >> +#endif
> >> switch_mm(prev, next, NULL);
> >> }
> >>
> >> @@ -30,11 +33,21 @@ static inline int init_new_context(struct task_struct *tsk,
> >> #ifdef CONFIG_MMU
> >> atomic_long_set(&mm->context.id, 0);
> >> #endif
> >> + if (IS_ENABLED(CONFIG_RISCV_ISA_SUPM))
> >> + clear_bit(MM_CONTEXT_LOCK_PMLEN, &mm->context.flags);
> >> return 0;
> >> }
> >>
> >> DECLARE_STATIC_KEY_FALSE(use_asid_allocator);
> >>
> >> +#ifdef CONFIG_RISCV_ISA_SUPM
> >> +#define mm_untag_mask mm_untag_mask
> >> +static inline unsigned long mm_untag_mask(struct mm_struct *mm)
> >> +{
> >> + return -1UL >> mm->context.pmlen;
> >> +}
> >> +#endif
> >> +
> >> #include <asm-generic/mmu_context.h>
> >>
> >> #endif /* _ASM_RISCV_MMU_CONTEXT_H */
> >> diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h
> >> index 72ec1d9bd3f3..fee56b0c8058 100644
> >> --- a/arch/riscv/include/asm/uaccess.h
> >> +++ b/arch/riscv/include/asm/uaccess.h
> >> @@ -9,8 +9,41 @@
> >> #define _ASM_RISCV_UACCESS_H
> >>
> >> #include <asm/asm-extable.h>
> >> +#include <asm/cpufeature.h>
> >> #include <asm/pgtable.h> /* for TASK_SIZE */
> >>
> >> +#ifdef CONFIG_RISCV_ISA_SUPM
> >> +static inline unsigned long __untagged_addr_remote(struct mm_struct *mm, unsigned long addr)
> >> +{
> >> + if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SUPM)) {
> >> + u8 pmlen = mm->context.pmlen;
> >> +
> >> + /* Virtual addresses are sign-extended; physical addresses are zero-extended. */
> >> + if (IS_ENABLED(CONFIG_MMU))
> >> + return (long)(addr << pmlen) >> pmlen;
> >> + else
> >> + return (addr << pmlen) >> pmlen;
> >> + }
> >> +
> >> + return addr;
> >> +}
> >> +
> >> +#define untagged_addr(addr) ({ \
> >> + unsigned long __addr = (__force unsigned long)(addr); \
> >> + (__force __typeof__(addr))__untagged_addr_remote(current->mm, __addr); \
> >> +})
> >> +
> >> +#define untagged_addr_remote(mm, addr) ({ \
> >> + unsigned long __addr = (__force unsigned long)(addr); \
> >> + mmap_assert_locked(mm); \
> >> + (__force __typeof__(addr))__untagged_addr_remote(mm, __addr); \
> >> +})
> >> +
> >> +#define access_ok(addr, size) likely(__access_ok(untagged_addr(addr), size))
> >> +#else
> >> +#define untagged_addr(addr) (addr)
> >> +#endif
> >> +
> >> /*
> >> * User space memory access functions
> >> */
> >> @@ -130,7 +163,7 @@ do { \
> >> */
> >> #define __get_user(x, ptr) \
> >> ({ \
> >> - const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \
> >> + const __typeof__(*(ptr)) __user *__gu_ptr = untagged_addr(ptr); \
> >> long __gu_err = 0; \
> >> \
> >> __chk_user_ptr(__gu_ptr); \
> >> @@ -246,7 +279,7 @@ do { \
> >> */
> >> #define __put_user(x, ptr) \
> >> ({ \
> >> - __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \
> >> + __typeof__(*(ptr)) __user *__gu_ptr = untagged_addr(ptr); \
> >> __typeof__(*__gu_ptr) __val = (x); \
> >> long __pu_err = 0; \
> >> \
> >> @@ -293,13 +326,13 @@ unsigned long __must_check __asm_copy_from_user(void *to,
> >> static inline unsigned long
> >> raw_copy_from_user(void *to, const void __user *from, unsigned long n)
> >> {
> >> - return __asm_copy_from_user(to, from, n);
> >> + return __asm_copy_from_user(to, untagged_addr(from), n);
> >> }
> >>
> >> static inline unsigned long
> >> raw_copy_to_user(void __user *to, const void *from, unsigned long n)
> >> {
> >> - return __asm_copy_to_user(to, from, n);
> >> + return __asm_copy_to_user(untagged_addr(to), from, n);
> >> }
> >>
> >> extern long strncpy_from_user(char *dest, const char __user *src, long count);
> >> @@ -314,7 +347,7 @@ unsigned long __must_check clear_user(void __user *to, unsigned long n)
> >> {
> >> might_fault();
> >> return access_ok(to, n) ?
> >> - __clear_user(to, n) : n;
> >> + __clear_user(untagged_addr(to), n) : n;
> >> }
> >>
> >> #define __get_kernel_nofault(dst, src, type, err_label) \
> >> diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
> >> index f39221ab5ddd..6e9c84a41c29 100644
> >> --- a/arch/riscv/kernel/process.c
> >> +++ b/arch/riscv/kernel/process.c
> >> @@ -204,6 +204,10 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> >> unsigned long tls = args->tls;
> >> struct pt_regs *childregs = task_pt_regs(p);
> >>
> >> + /* Ensure all threads in this mm have the same pointer masking mode. */
> >> + if (IS_ENABLED(CONFIG_RISCV_ISA_SUPM) && p->mm && (clone_flags & CLONE_VM))
> >> + set_bit(MM_CONTEXT_LOCK_PMLEN, &p->mm->context.flags);
> >> +
> >> memset(&p->thread.s, 0, sizeof(p->thread.s));
> >>
> >> /* p->thread holds context to be restored by __switch_to() */
> >> @@ -249,10 +253,16 @@ enum {
> >> static bool have_user_pmlen_7;
> >> static bool have_user_pmlen_16;
> >>
> >> +/*
> >> + * Control the relaxed ABI allowing tagged user addresses into the kernel.
> >> + */
> >> +static unsigned int tagged_addr_disabled;
> >> +
> >> long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg)
> >> {
> >> - unsigned long valid_mask = PR_PMLEN_MASK;
> >> + unsigned long valid_mask = PR_PMLEN_MASK | PR_TAGGED_ADDR_ENABLE;
> >> struct thread_info *ti = task_thread_info(task);
> >> + struct mm_struct *mm = task->mm;
> >> unsigned long pmm;
> >> u8 pmlen;
> >>
> >> @@ -267,16 +277,41 @@ long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg)
> >> * in case choosing a larger PMLEN has a performance impact.
> >> */
> >> pmlen = FIELD_GET(PR_PMLEN_MASK, arg);
> >> - if (pmlen == PMLEN_0)
> >> + if (pmlen == PMLEN_0) {
> >> pmm = ENVCFG_PMM_PMLEN_0;
> >> - else if (pmlen <= PMLEN_7 && have_user_pmlen_7)
> >> + } else if (pmlen <= PMLEN_7 && have_user_pmlen_7) {
> >> + pmlen = PMLEN_7;
> >> pmm = ENVCFG_PMM_PMLEN_7;
> >> - else if (pmlen <= PMLEN_16 && have_user_pmlen_16)
> >> + } else if (pmlen <= PMLEN_16 && have_user_pmlen_16) {
> >> + pmlen = PMLEN_16;
> >> pmm = ENVCFG_PMM_PMLEN_16;
> >> - else
> >> + } else {
> >> return -EINVAL;
> >> + }
> >> +
> >> + /*
> >> + * Do not allow the enabling of the tagged address ABI if globally
> >> + * disabled via sysctl abi.tagged_addr_disabled, if pointer masking
> >> + * is disabled for userspace.
> >> + */
> >> + if (arg & PR_TAGGED_ADDR_ENABLE && (tagged_addr_disabled || !pmlen))
> >> + return -EINVAL;
> >> +
> >> + if (!(arg & PR_TAGGED_ADDR_ENABLE))
> >> + pmlen = PMLEN_0;
> >> +
> >> + if (mmap_write_lock_killable(mm))
> >> + return -EINTR;
> >> +
> >> + if (test_bit(MM_CONTEXT_LOCK_PMLEN, &mm->context.flags) && mm->context.pmlen != pmlen) {
> >> + mmap_write_unlock(mm);
> >> + return -EBUSY;
> >> + }
> >>
> >> envcfg_update_bits(task, ENVCFG_PMM, pmm);
> >> + mm->context.pmlen = pmlen;
> >> +
> >> + mmap_write_unlock(mm);
> >>
> >> return 0;
> >> }
> >> @@ -289,6 +324,10 @@ long get_tagged_addr_ctrl(struct task_struct *task)
> >> if (is_compat_thread(ti))
> >> return -EINVAL;
> >>
> >> + /*
> >> + * The mm context's pmlen is set only when the tagged address ABI is
> >> + * enabled, so the effective PMLEN must be extracted from envcfg.PMM.
> >> + */
> >> switch (task->thread.envcfg & ENVCFG_PMM) {
> >> case ENVCFG_PMM_PMLEN_7:
> >> ret = FIELD_PREP(PR_PMLEN_MASK, PMLEN_7);
> >> @@ -298,6 +337,9 @@ long get_tagged_addr_ctrl(struct task_struct *task)
> >> break;
> >> }
> >>
> >> + if (task->mm->context.pmlen)
> >> + ret |= PR_TAGGED_ADDR_ENABLE;
> >> +
> >> return ret;
> >> }
> >>
> >> @@ -307,6 +349,24 @@ static bool try_to_set_pmm(unsigned long value)
> >> return (csr_read_clear(CSR_ENVCFG, ENVCFG_PMM) & ENVCFG_PMM) == value;
> >> }
> >>
> >> +/*
> >> + * Global sysctl to disable the tagged user addresses support. This control
> >> + * only prevents the tagged address ABI enabling via prctl() and does not
> >> + * disable it for tasks that already opted in to the relaxed ABI.
> >> + */
> >> +
> >> +static struct ctl_table tagged_addr_sysctl_table[] = {
> >> + {
> >> + .procname = "tagged_addr_disabled",
> >> + .mode = 0644,
> >> + .data = &tagged_addr_disabled,
> >> + .maxlen = sizeof(int),
> >> + .proc_handler = proc_dointvec_minmax,
> >> + .extra1 = SYSCTL_ZERO,
> >> + .extra2 = SYSCTL_ONE,
> >> + },
> >> +};
> >> +
> >> static int __init tagged_addr_init(void)
> >> {
> >> if (!riscv_has_extension_unlikely(RISCV_ISA_EXT_SUPM))
> >> @@ -320,6 +380,9 @@ static int __init tagged_addr_init(void)
> >> have_user_pmlen_7 = try_to_set_pmm(ENVCFG_PMM_PMLEN_7);
> >> have_user_pmlen_16 = try_to_set_pmm(ENVCFG_PMM_PMLEN_16);
> >>
> >> + if (!register_sysctl("abi", tagged_addr_sysctl_table))
> >> + return -EINVAL;
> >> +
> >> return 0;
> >> }
> >> core_initcall(tagged_addr_init);
> >> --
> >> 2.45.1
> >>
> >>
> >> _______________________________________________
> >> linux-riscv mailing list
> >> linux-riscv@lists.infradead.org
> >> http://lists.infradead.org/mailman/listinfo/linux-riscv
>
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
WARNING: multiple messages have this Message-ID (diff)
From: Charlie Jenkins <charlie@rivosinc.com>
To: Samuel Holland <samuel.holland@sifive.com>
Cc: Palmer Dabbelt <palmer@dabbelt.com>,
linux-riscv@lists.infradead.org, devicetree@vger.kernel.org,
Catalin Marinas <catalin.marinas@arm.com>,
linux-kernel@vger.kernel.org, Anup Patel <anup@brainfault.org>,
Conor Dooley <conor@kernel.org>,
kasan-dev@googlegroups.com, Atish Patra <atishp@atishpatra.org>,
Evgenii Stepanov <eugenis@google.com>,
Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
Rob Herring <robh+dt@kernel.org>,
"Kirill A . Shutemov" <kirill.shutemov@linux.intel.com>
Subject: Re: [PATCH v4 05/10] riscv: Add support for the tagged address ABI
Date: Fri, 13 Sep 2024 20:16:48 -0700 [thread overview]
Message-ID: <ZuUAIPZBl6EWomb6@ghost> (raw)
In-Reply-To: <b5b1b654-b603-4e22-ae9c-b712e4d6babe@sifive.com>
On Fri, Sep 13, 2024 at 09:57:05PM -0500, Samuel Holland wrote:
> Hi Charlie,
>
> On 2024-09-12 9:45 PM, Charlie Jenkins wrote:
> > On Wed, Aug 28, 2024 at 06:01:27PM -0700, Samuel Holland wrote:
> >> When pointer masking is enabled for userspace, the kernel can accept
> >> tagged pointers as arguments to some system calls. Allow this by
> >> untagging the pointers in access_ok() and the uaccess routines. The
> >> uaccess routines must peform untagging in software because U-mode and
> >> S-mode have entirely separate pointer masking configurations. In fact,
> >> hardware may not even implement pointer masking for S-mode.
> >>
> >> Since the number of tag bits is variable, untagged_addr_remote() needs
> >> to know what PMLEN to use for the remote mm. Therefore, the pointer
> >> masking mode must be the same for all threads sharing an mm. Enforce
> >> this with a lock flag in the mm context, as x86 does for LAM. The flag
> >> gets reset in init_new_context() during fork(), as the new mm is no
> >> longer multithreaded.
> >>
> >> Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
> >> ---
> >
> > Not necessary, but what do you think about adding riscv to include/uapi/linux/prctl.h:
> >
> > /* Tagged user address controls for arm64 */
> > #define PR_SET_TAGGED_ADDR_CTRL 55
> > #define PR_GET_TAGGED_ADDR_CTRL 56
> > # define PR_TAGGED_ADDR_ENABLE (1UL << 0)
>
> Yes, I'll add this in v5.
>
> > Also looks like this last line should probably be under SET rather than
> > GET.
>
> The same bit fields are used for both prctl() functions, so I think the current
> grouping is okay (compare PR_RISCV_V_GET_CONTROL).
Oh perfect, I had missed that when I briefly looked.
>
> Regards,
> Samuel
>
> > Reviewed-by: Charlie Jenkins <charlie@rivosinc.com>
> > Tested-by: Charlie Jenkins <charlie@rivosinc.com>
> >
> >>
> >> Changes in v4:
> >> - Combine __untagged_addr() and __untagged_addr_remote()
> >>
> >> Changes in v3:
> >> - Use IS_ENABLED instead of #ifdef when possible
> >> - Implement mm_untag_mask()
> >> - Remove pmlen from struct thread_info (now only in mm_context_t)
> >>
> >> Changes in v2:
> >> - Implement untagged_addr_remote()
> >> - Restrict PMLEN changes once a process is multithreaded
> >>
> >> arch/riscv/include/asm/mmu.h | 7 +++
> >> arch/riscv/include/asm/mmu_context.h | 13 +++++
> >> arch/riscv/include/asm/uaccess.h | 43 ++++++++++++++--
> >> arch/riscv/kernel/process.c | 73 ++++++++++++++++++++++++++--
> >> 4 files changed, 126 insertions(+), 10 deletions(-)
> >>
> >> diff --git a/arch/riscv/include/asm/mmu.h b/arch/riscv/include/asm/mmu.h
> >> index c9e03e9da3dc..1cc90465d75b 100644
> >> --- a/arch/riscv/include/asm/mmu.h
> >> +++ b/arch/riscv/include/asm/mmu.h
> >> @@ -25,9 +25,16 @@ typedef struct {
> >> #ifdef CONFIG_BINFMT_ELF_FDPIC
> >> unsigned long exec_fdpic_loadmap;
> >> unsigned long interp_fdpic_loadmap;
> >> +#endif
> >> + unsigned long flags;
> >> +#ifdef CONFIG_RISCV_ISA_SUPM
> >> + u8 pmlen;
> >> #endif
> >> } mm_context_t;
> >>
> >> +/* Lock the pointer masking mode because this mm is multithreaded */
> >> +#define MM_CONTEXT_LOCK_PMLEN 0
> >> +
> >> #define cntx2asid(cntx) ((cntx) & SATP_ASID_MASK)
> >> #define cntx2version(cntx) ((cntx) & ~SATP_ASID_MASK)
> >>
> >> diff --git a/arch/riscv/include/asm/mmu_context.h b/arch/riscv/include/asm/mmu_context.h
> >> index 7030837adc1a..8c4bc49a3a0f 100644
> >> --- a/arch/riscv/include/asm/mmu_context.h
> >> +++ b/arch/riscv/include/asm/mmu_context.h
> >> @@ -20,6 +20,9 @@ void switch_mm(struct mm_struct *prev, struct mm_struct *next,
> >> static inline void activate_mm(struct mm_struct *prev,
> >> struct mm_struct *next)
> >> {
> >> +#ifdef CONFIG_RISCV_ISA_SUPM
> >> + next->context.pmlen = 0;
> >> +#endif
> >> switch_mm(prev, next, NULL);
> >> }
> >>
> >> @@ -30,11 +33,21 @@ static inline int init_new_context(struct task_struct *tsk,
> >> #ifdef CONFIG_MMU
> >> atomic_long_set(&mm->context.id, 0);
> >> #endif
> >> + if (IS_ENABLED(CONFIG_RISCV_ISA_SUPM))
> >> + clear_bit(MM_CONTEXT_LOCK_PMLEN, &mm->context.flags);
> >> return 0;
> >> }
> >>
> >> DECLARE_STATIC_KEY_FALSE(use_asid_allocator);
> >>
> >> +#ifdef CONFIG_RISCV_ISA_SUPM
> >> +#define mm_untag_mask mm_untag_mask
> >> +static inline unsigned long mm_untag_mask(struct mm_struct *mm)
> >> +{
> >> + return -1UL >> mm->context.pmlen;
> >> +}
> >> +#endif
> >> +
> >> #include <asm-generic/mmu_context.h>
> >>
> >> #endif /* _ASM_RISCV_MMU_CONTEXT_H */
> >> diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h
> >> index 72ec1d9bd3f3..fee56b0c8058 100644
> >> --- a/arch/riscv/include/asm/uaccess.h
> >> +++ b/arch/riscv/include/asm/uaccess.h
> >> @@ -9,8 +9,41 @@
> >> #define _ASM_RISCV_UACCESS_H
> >>
> >> #include <asm/asm-extable.h>
> >> +#include <asm/cpufeature.h>
> >> #include <asm/pgtable.h> /* for TASK_SIZE */
> >>
> >> +#ifdef CONFIG_RISCV_ISA_SUPM
> >> +static inline unsigned long __untagged_addr_remote(struct mm_struct *mm, unsigned long addr)
> >> +{
> >> + if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SUPM)) {
> >> + u8 pmlen = mm->context.pmlen;
> >> +
> >> + /* Virtual addresses are sign-extended; physical addresses are zero-extended. */
> >> + if (IS_ENABLED(CONFIG_MMU))
> >> + return (long)(addr << pmlen) >> pmlen;
> >> + else
> >> + return (addr << pmlen) >> pmlen;
> >> + }
> >> +
> >> + return addr;
> >> +}
> >> +
> >> +#define untagged_addr(addr) ({ \
> >> + unsigned long __addr = (__force unsigned long)(addr); \
> >> + (__force __typeof__(addr))__untagged_addr_remote(current->mm, __addr); \
> >> +})
> >> +
> >> +#define untagged_addr_remote(mm, addr) ({ \
> >> + unsigned long __addr = (__force unsigned long)(addr); \
> >> + mmap_assert_locked(mm); \
> >> + (__force __typeof__(addr))__untagged_addr_remote(mm, __addr); \
> >> +})
> >> +
> >> +#define access_ok(addr, size) likely(__access_ok(untagged_addr(addr), size))
> >> +#else
> >> +#define untagged_addr(addr) (addr)
> >> +#endif
> >> +
> >> /*
> >> * User space memory access functions
> >> */
> >> @@ -130,7 +163,7 @@ do { \
> >> */
> >> #define __get_user(x, ptr) \
> >> ({ \
> >> - const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \
> >> + const __typeof__(*(ptr)) __user *__gu_ptr = untagged_addr(ptr); \
> >> long __gu_err = 0; \
> >> \
> >> __chk_user_ptr(__gu_ptr); \
> >> @@ -246,7 +279,7 @@ do { \
> >> */
> >> #define __put_user(x, ptr) \
> >> ({ \
> >> - __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \
> >> + __typeof__(*(ptr)) __user *__gu_ptr = untagged_addr(ptr); \
> >> __typeof__(*__gu_ptr) __val = (x); \
> >> long __pu_err = 0; \
> >> \
> >> @@ -293,13 +326,13 @@ unsigned long __must_check __asm_copy_from_user(void *to,
> >> static inline unsigned long
> >> raw_copy_from_user(void *to, const void __user *from, unsigned long n)
> >> {
> >> - return __asm_copy_from_user(to, from, n);
> >> + return __asm_copy_from_user(to, untagged_addr(from), n);
> >> }
> >>
> >> static inline unsigned long
> >> raw_copy_to_user(void __user *to, const void *from, unsigned long n)
> >> {
> >> - return __asm_copy_to_user(to, from, n);
> >> + return __asm_copy_to_user(untagged_addr(to), from, n);
> >> }
> >>
> >> extern long strncpy_from_user(char *dest, const char __user *src, long count);
> >> @@ -314,7 +347,7 @@ unsigned long __must_check clear_user(void __user *to, unsigned long n)
> >> {
> >> might_fault();
> >> return access_ok(to, n) ?
> >> - __clear_user(to, n) : n;
> >> + __clear_user(untagged_addr(to), n) : n;
> >> }
> >>
> >> #define __get_kernel_nofault(dst, src, type, err_label) \
> >> diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
> >> index f39221ab5ddd..6e9c84a41c29 100644
> >> --- a/arch/riscv/kernel/process.c
> >> +++ b/arch/riscv/kernel/process.c
> >> @@ -204,6 +204,10 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> >> unsigned long tls = args->tls;
> >> struct pt_regs *childregs = task_pt_regs(p);
> >>
> >> + /* Ensure all threads in this mm have the same pointer masking mode. */
> >> + if (IS_ENABLED(CONFIG_RISCV_ISA_SUPM) && p->mm && (clone_flags & CLONE_VM))
> >> + set_bit(MM_CONTEXT_LOCK_PMLEN, &p->mm->context.flags);
> >> +
> >> memset(&p->thread.s, 0, sizeof(p->thread.s));
> >>
> >> /* p->thread holds context to be restored by __switch_to() */
> >> @@ -249,10 +253,16 @@ enum {
> >> static bool have_user_pmlen_7;
> >> static bool have_user_pmlen_16;
> >>
> >> +/*
> >> + * Control the relaxed ABI allowing tagged user addresses into the kernel.
> >> + */
> >> +static unsigned int tagged_addr_disabled;
> >> +
> >> long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg)
> >> {
> >> - unsigned long valid_mask = PR_PMLEN_MASK;
> >> + unsigned long valid_mask = PR_PMLEN_MASK | PR_TAGGED_ADDR_ENABLE;
> >> struct thread_info *ti = task_thread_info(task);
> >> + struct mm_struct *mm = task->mm;
> >> unsigned long pmm;
> >> u8 pmlen;
> >>
> >> @@ -267,16 +277,41 @@ long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg)
> >> * in case choosing a larger PMLEN has a performance impact.
> >> */
> >> pmlen = FIELD_GET(PR_PMLEN_MASK, arg);
> >> - if (pmlen == PMLEN_0)
> >> + if (pmlen == PMLEN_0) {
> >> pmm = ENVCFG_PMM_PMLEN_0;
> >> - else if (pmlen <= PMLEN_7 && have_user_pmlen_7)
> >> + } else if (pmlen <= PMLEN_7 && have_user_pmlen_7) {
> >> + pmlen = PMLEN_7;
> >> pmm = ENVCFG_PMM_PMLEN_7;
> >> - else if (pmlen <= PMLEN_16 && have_user_pmlen_16)
> >> + } else if (pmlen <= PMLEN_16 && have_user_pmlen_16) {
> >> + pmlen = PMLEN_16;
> >> pmm = ENVCFG_PMM_PMLEN_16;
> >> - else
> >> + } else {
> >> return -EINVAL;
> >> + }
> >> +
> >> + /*
> >> + * Do not allow the enabling of the tagged address ABI if globally
> >> + * disabled via sysctl abi.tagged_addr_disabled, if pointer masking
> >> + * is disabled for userspace.
> >> + */
> >> + if (arg & PR_TAGGED_ADDR_ENABLE && (tagged_addr_disabled || !pmlen))
> >> + return -EINVAL;
> >> +
> >> + if (!(arg & PR_TAGGED_ADDR_ENABLE))
> >> + pmlen = PMLEN_0;
> >> +
> >> + if (mmap_write_lock_killable(mm))
> >> + return -EINTR;
> >> +
> >> + if (test_bit(MM_CONTEXT_LOCK_PMLEN, &mm->context.flags) && mm->context.pmlen != pmlen) {
> >> + mmap_write_unlock(mm);
> >> + return -EBUSY;
> >> + }
> >>
> >> envcfg_update_bits(task, ENVCFG_PMM, pmm);
> >> + mm->context.pmlen = pmlen;
> >> +
> >> + mmap_write_unlock(mm);
> >>
> >> return 0;
> >> }
> >> @@ -289,6 +324,10 @@ long get_tagged_addr_ctrl(struct task_struct *task)
> >> if (is_compat_thread(ti))
> >> return -EINVAL;
> >>
> >> + /*
> >> + * The mm context's pmlen is set only when the tagged address ABI is
> >> + * enabled, so the effective PMLEN must be extracted from envcfg.PMM.
> >> + */
> >> switch (task->thread.envcfg & ENVCFG_PMM) {
> >> case ENVCFG_PMM_PMLEN_7:
> >> ret = FIELD_PREP(PR_PMLEN_MASK, PMLEN_7);
> >> @@ -298,6 +337,9 @@ long get_tagged_addr_ctrl(struct task_struct *task)
> >> break;
> >> }
> >>
> >> + if (task->mm->context.pmlen)
> >> + ret |= PR_TAGGED_ADDR_ENABLE;
> >> +
> >> return ret;
> >> }
> >>
> >> @@ -307,6 +349,24 @@ static bool try_to_set_pmm(unsigned long value)
> >> return (csr_read_clear(CSR_ENVCFG, ENVCFG_PMM) & ENVCFG_PMM) == value;
> >> }
> >>
> >> +/*
> >> + * Global sysctl to disable the tagged user addresses support. This control
> >> + * only prevents the tagged address ABI enabling via prctl() and does not
> >> + * disable it for tasks that already opted in to the relaxed ABI.
> >> + */
> >> +
> >> +static struct ctl_table tagged_addr_sysctl_table[] = {
> >> + {
> >> + .procname = "tagged_addr_disabled",
> >> + .mode = 0644,
> >> + .data = &tagged_addr_disabled,
> >> + .maxlen = sizeof(int),
> >> + .proc_handler = proc_dointvec_minmax,
> >> + .extra1 = SYSCTL_ZERO,
> >> + .extra2 = SYSCTL_ONE,
> >> + },
> >> +};
> >> +
> >> static int __init tagged_addr_init(void)
> >> {
> >> if (!riscv_has_extension_unlikely(RISCV_ISA_EXT_SUPM))
> >> @@ -320,6 +380,9 @@ static int __init tagged_addr_init(void)
> >> have_user_pmlen_7 = try_to_set_pmm(ENVCFG_PMM_PMLEN_7);
> >> have_user_pmlen_16 = try_to_set_pmm(ENVCFG_PMM_PMLEN_16);
> >>
> >> + if (!register_sysctl("abi", tagged_addr_sysctl_table))
> >> + return -EINVAL;
> >> +
> >> return 0;
> >> }
> >> core_initcall(tagged_addr_init);
> >> --
> >> 2.45.1
> >>
> >>
> >> _______________________________________________
> >> linux-riscv mailing list
> >> linux-riscv@lists.infradead.org
> >> http://lists.infradead.org/mailman/listinfo/linux-riscv
>
next prev parent reply other threads:[~2024-09-14 3:17 UTC|newest]
Thread overview: 73+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-08-29 1:01 [PATCH v4 00/10] riscv: Userspace pointer masking and tagged address ABI Samuel Holland
2024-08-29 1:01 ` Samuel Holland
2024-08-29 1:01 ` [PATCH v4 01/10] dt-bindings: riscv: Add pointer masking ISA extensions Samuel Holland
2024-08-29 1:01 ` Samuel Holland
2024-09-13 1:08 ` Charlie Jenkins
2024-09-13 1:08 ` Charlie Jenkins
2024-08-29 1:01 ` [PATCH v4 02/10] riscv: Add ISA extension parsing for pointer masking Samuel Holland
2024-08-29 1:01 ` Samuel Holland
2024-09-13 1:09 ` Charlie Jenkins
2024-09-13 1:09 ` Charlie Jenkins
2024-08-29 1:01 ` [PATCH v4 03/10] riscv: Add CSR definitions " Samuel Holland
2024-08-29 1:01 ` Samuel Holland
2024-09-13 1:16 ` Charlie Jenkins
2024-09-13 1:16 ` Charlie Jenkins
2024-08-29 1:01 ` [PATCH v4 04/10] riscv: Add support for userspace " Samuel Holland
2024-08-29 1:01 ` Samuel Holland
2024-09-13 1:52 ` Charlie Jenkins
2024-09-13 1:52 ` Charlie Jenkins
2024-08-29 1:01 ` [PATCH v4 05/10] riscv: Add support for the tagged address ABI Samuel Holland
2024-08-29 1:01 ` Samuel Holland
2024-09-13 2:45 ` Charlie Jenkins
2024-09-13 2:45 ` Charlie Jenkins
2024-09-14 2:57 ` Samuel Holland
2024-09-14 2:57 ` Samuel Holland
2024-09-14 3:16 ` Charlie Jenkins [this message]
2024-09-14 3:16 ` Charlie Jenkins
2024-08-29 1:01 ` [PATCH v4 06/10] riscv: Allow ptrace control of " Samuel Holland
2024-08-29 1:01 ` Samuel Holland
2024-09-13 2:51 ` Charlie Jenkins
2024-09-13 2:51 ` Charlie Jenkins
2024-10-16 17:50 ` Samuel Holland
2024-10-16 17:50 ` Samuel Holland
2024-10-17 0:58 ` Charlie Jenkins
2024-10-17 0:58 ` Charlie Jenkins
2024-08-29 1:01 ` [PATCH v4 07/10] selftests: riscv: Add a pointer masking test Samuel Holland
2024-08-29 1:01 ` Samuel Holland
2024-09-13 2:54 ` Charlie Jenkins
2024-09-13 2:54 ` Charlie Jenkins
2024-08-29 1:01 ` [PATCH v4 08/10] riscv: hwprobe: Export the Supm ISA extension Samuel Holland
2024-08-29 1:01 ` Samuel Holland
2024-08-29 1:01 ` [PATCH v4 09/10] RISC-V: KVM: Allow Smnpm and Ssnpm extensions for guests Samuel Holland
2024-08-29 1:01 ` Samuel Holland
2024-09-04 12:17 ` Anup Patel
2024-09-04 12:17 ` Anup Patel
2024-09-04 14:31 ` Samuel Holland
2024-09-04 14:31 ` Samuel Holland
2024-09-04 14:31 ` Samuel Holland
2024-09-04 14:45 ` Anup Patel
2024-09-04 14:45 ` Anup Patel
2024-09-04 14:45 ` Anup Patel
2024-09-04 14:57 ` Samuel Holland
2024-09-04 14:57 ` Samuel Holland
2024-09-04 14:57 ` Samuel Holland
2024-09-04 15:20 ` Anup Patel
2024-09-04 15:20 ` Anup Patel
2024-09-04 15:20 ` Anup Patel
2024-09-04 15:55 ` Samuel Holland
2024-09-04 15:55 ` Samuel Holland
2024-09-04 15:55 ` Samuel Holland
2024-09-05 5:18 ` Anup Patel
2024-09-05 5:18 ` Anup Patel
2024-09-05 5:18 ` Anup Patel
2024-09-14 2:52 ` Samuel Holland
2024-09-14 2:52 ` Samuel Holland
2024-09-14 2:52 ` Samuel Holland
2024-08-29 1:01 ` [PATCH v4 10/10] KVM: riscv: selftests: Add Smnpm and Ssnpm to get-reg-list test Samuel Holland
2024-08-29 1:01 ` Samuel Holland
2024-09-04 12:22 ` Anup Patel
2024-09-04 12:22 ` Anup Patel
2024-09-04 12:32 ` [PATCH v4 00/10] riscv: Userspace pointer masking and tagged address ABI Anup Patel
2024-09-04 12:32 ` Anup Patel
2024-09-13 18:08 ` Charlie Jenkins
2024-09-13 18:08 ` Charlie Jenkins
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ZuUAIPZBl6EWomb6@ghost \
--to=charlie@rivosinc.com \
--cc=anup@brainfault.org \
--cc=atishp@atishpatra.org \
--cc=catalin.marinas@arm.com \
--cc=conor@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=eugenis@google.com \
--cc=kasan-dev@googlegroups.com \
--cc=kirill.shutemov@linux.intel.com \
--cc=krzysztof.kozlowski+dt@linaro.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-riscv@lists.infradead.org \
--cc=palmer@dabbelt.com \
--cc=robh+dt@kernel.org \
--cc=samuel.holland@sifive.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.