Message ID | 20230807-arm64-gcs-v4-7-68cfa37f9069@kernel.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | arm64/gcs: Provide support for GCS in userspace | expand |
On Mon, Aug 07, 2023 at 11:00:12PM +0100, Mark Brown wrote: > +static inline int copy_to_user_gcs(unsigned long __user *addr, > + unsigned long *val, > + int count) > +{ > + int ret = -EFAULT; > + int i; > + > + if (access_ok((char __user *)addr, count * sizeof(u64))) { > + uaccess_ttbr0_enable(); > + for (i = 0; i < count; i++) { > + ret = gcssttr(addr++, *val++); > + if (ret != 0) > + break; > + } > + uaccess_ttbr0_disable(); > + } > + > + return ret; > +} I think it makes more sense to have a put_user_gcs() of a single element. I've only seen it used with 2 elements in the signal code but we could as well do two put_user_gcs() calls (as we do for other stuff that we push to the signal frame).
On Fri, Aug 11, 2023 at 05:36:05PM +0100, Catalin Marinas wrote: > On Mon, Aug 07, 2023 at 11:00:12PM +0100, Mark Brown wrote: > > +static inline int copy_to_user_gcs(unsigned long __user *addr, > > + unsigned long *val, > > + int count) > I think it makes more sense to have a put_user_gcs() of a single > element. I've only seen it used with 2 elements in the signal code but > we could as well do two put_user_gcs() calls (as we do for other stuff > that we push to the signal frame). Right, it's just the two element array in the signals code and the one element for the context token in map_shadow_stack(). I can refactor to a single read/write operation, I'd originally written it that way but I wasn't thrilled with either writing a load of fun macros to mirror the way vanilla put_user() is written or having code that looked very different to the other similarly named functions were done.
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index 22e10e79f56a..24aa804e95a7 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -445,6 +445,26 @@ static inline int gcssttr(unsigned long __user *addr, unsigned long val) return err; } +static inline int copy_to_user_gcs(unsigned long __user *addr, + unsigned long *val, + int count) +{ + int ret = -EFAULT; + int i; + + if (access_ok((char __user *)addr, count * sizeof(u64))) { + uaccess_ttbr0_enable(); + for (i = 0; i < count; i++) { + ret = gcssttr(addr++, *val++); + if (ret != 0) + break; + } + uaccess_ttbr0_disable(); + } + + return ret; +} + #endif /* CONFIG_ARM64_GCS */ #endif /* __ASM_UACCESS_H */
In order for EL1 to write to an EL0 GCS it must use the GCSSTTR instruction rather than a normal STTR. Provide a copy_to_user_gcs() which does this. Since it is not possible to store anything other than a 64 bit value the interface is presented in terms of 64 bit values, using unsigned long rather than u64 due to sparse. Signed-off-by: Mark Brown <broonie@kernel.org> --- arch/arm64/include/asm/uaccess.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)