kernel: sucompat: increase reliability of execve_sucompat

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.

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

My speculation? ARMv8.0 has weak speculation :)

here we replace `strncpy_from_user_nofault()` with another routine:
 - access_ok() to validate the pointer
 - strncpy_from_user() to copy and validate string
 - 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

Kind of mimicking _nofault, but yes with this one we allow pagefaults.

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

Tested-by: iDead XD <rafifirdaus12bb@gmail.com>
Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
This commit is contained in:
backslashxx
2025-05-19 01:22:04 +08:00
committed by ShirkNeko
parent 80e3c736d1
commit bf06b92850

View File

@@ -161,8 +161,25 @@ int ksu_handle_execve_sucompat(int *fd, const char __user **filename_user,
if (unlikely(!filename_user)) if (unlikely(!filename_user))
return 0; return 0;
memset(path, 0, sizeof(path)); /*
ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path)); * nofault variant fails silently due to pagefault_disable
* some cpus dont really have that good speculative execution
* access_ok to substitute set_fs, we check if pointer is accessible
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0)
if (!access_ok(VERIFY_READ, *filename_user, sizeof(path)))
return 0;
#else
if (!access_ok(*filename_user, sizeof(path)))
return 0;
#endif
// success = returns number of bytes and should be less than path
long len = strncpy_from_user(path, *filename_user, sizeof(path));
if (len <= 0)
return 0;
// strncpy_from_user_nofault does this too
path[sizeof(path) - 1] = '\0';
if (likely(memcmp(path, su, sizeof(su)))) if (likely(memcmp(path, su, sizeof(su))))
return 0; return 0;