kernel: sucompat: increase reliability, commonize and micro-optimize tiann #2656

On plain ARMv8.0 devices (A53,A57,A73), strncpy_from_user_nofault() sometimes
fails to copy `filename_user` string correctly. This breaks su ofc, breaking
some apps like Termux (Play Store ver), ZArchiver and Root Explorer.

Apply the susfs patch

This does NOT seem to affect newer ARMv8.2+ CPUs (A75/A76 and newer)

My speculation? ARMv8.0 has weak speculation :)

here we replace `ksu_strncpy_from_user_nofault` with ksu_strncpy_from_user_retry:
- ksu_strncpy_from_user_nofault as fast-path copy
- fallback to access_ok to validate the pointer + strncpy_from_user
- manual null-termination just in case, as strncpy_from_user_nofault also does it
- remove that memset, seems useless as it is an strncpy, not strncat

basically, we retry on pagefualt

for usercopies, its not like were doing
    memset(dest, 0, sizeof(dest));
    strncat(dest, var, bytes);

that memset seems unneeded. instead we use strncpy itself to do proper
error and oob check and null term it after.

as for optimizations
- just return early if unauthorized
- commonized logic
- reduced duplication

Tested on:
- ARMv8.0 A73.a53, A57.a53, A53.a53
- ARMv8.2 A76.a55

Stale: tiann #2656

Co-authored-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
Co-authored-by: rsuntk <rsuntk@yukiprjkt.my.id>
Signed-off-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
This commit is contained in:
ShirkNeko
2025-09-25 19:41:26 +08:00
parent a85ce2bc35
commit dd1eb98963
5 changed files with 84 additions and 223 deletions

View File

@@ -57,13 +57,6 @@ static inline __maybe_unused size_t list_count_nodes(const struct list_head *hea
#endif
#endif
extern long ksu_strncpy_from_user_nofault(char *dst,
const void __user *unsafe_addr,
long count);
extern long ksu_strncpy_from_user_retry(char *dst,
const void __user *unsafe_addr,
long count);
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \
defined(CONFIG_IS_HW_HISI) || \
defined(CONFIG_KSU_ALLOWLIST_WORKAROUND)
@@ -78,22 +71,7 @@ extern ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count,
extern ssize_t ksu_kernel_write_compat(struct file *p, const void *buf,
size_t count, loff_t *pos);
extern long ksu_copy_from_user_nofault(void *dst, const void __user *src, size_t size);
/*
* ksu_copy_from_user_retry
* try nofault copy first, if it fails, try with plain
* paramters are the same as copy_from_user
* 0 = success
*/
static long ksu_copy_from_user_retry(void *to,
const void __user *from, unsigned long count)
{
long ret = ksu_copy_from_user_nofault(to, from, count);
if (likely(!ret))
return ret;
// we faulted! fallback to slow path
return copy_from_user(to, from, count);
}
extern long ksu_copy_from_user_retry(void *to, const void __user *from, unsigned long count);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
#define ksu_access_ok(addr, size) access_ok(addr, size)