From: Igor Shevlyakov <[email protected]> mincore(2) rejects a misaligned start address before it looks the range up, so a start that is both misaligned and unmapped is EINVAL. Here lock_user() runs first and fails, and the call reports ENOMEM instead.
When the range is mapped this changes nothing -- the host syscall receives the misaligned pointer and answers EINVAL by itself -- which is why only the unmapped case is visibly wrong. Caught by glibc's misc/test-errno-linux. Signed-off-by: Igor Shevlyakov <[email protected]> Reviewed-by: Helge Deller <[email protected]> Signed-off-by: Helge Deller <[email protected]> --- linux-user/syscall.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e7c9fb33a3..0380691a8b 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -13064,7 +13064,17 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_mincore case TARGET_NR_mincore: { - void *a = lock_user(VERIFY_NONE, arg1, arg2, 0); + void *a; + + /* + * The kernel rejects a misaligned start before it looks the range + * up, so a start that is both misaligned and unmapped is EINVAL, + * not the ENOMEM that a failing lock_user() would report. + */ + if (arg1 & ~TARGET_PAGE_MASK) { + return -TARGET_EINVAL; + } + a = lock_user(VERIFY_NONE, arg1, arg2, 0); if (!a) { return -TARGET_ENOMEM; } -- 2.54.0
