From a102a531615ac2eed153c37eb6ae44386573a04a Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Wed, 11 Mar 2020 19:02:52 -0400 Subject: [PATCH 4/4] work around negated error code bug on some mips kernels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit on all mips variants, Linux did (and maybe still does) have some syscall return paths that wrongly return both the error flag in r7 and a negated error code in r2. in particular this happened for at least some causes of ENOSYS. add an extra check to only negate the error code if it's positive to begin with. bug report and concept for patch by Andreas Dröscher. --- arch/mips/syscall_arch.h | 16 ++++++++-------- arch/mips64/syscall_arch.h | 14 +++++++------- arch/mipsn32/syscall_arch.h | 14 +++++++------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/arch/mips/syscall_arch.h b/arch/mips/syscall_arch.h index 0a5d6d8f..fc301db8 100644 --- a/arch/mips/syscall_arch.h +++ b/arch/mips/syscall_arch.h @@ -24,7 +24,7 @@ static inline long __syscall0(long n) : "=&r"(r2), "=r"(r7) : "ir"(n) : SYSCALL_CLOBBERLIST, "$8", "$9", "$10"); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } static inline long __syscall1(long n, long a) @@ -37,7 +37,7 @@ static inline long __syscall1(long n, long a) : "=&r"(r2), "=r"(r7) : "ir"(n), "r"(r4) : SYSCALL_CLOBBERLIST, "$8", "$9", "$10"); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } static inline long __syscall2(long n, long a, long b) @@ -51,7 +51,7 @@ static inline long __syscall2(long n, long a, long b) : "=&r"(r2), "=r"(r7) : "ir"(n), "r"(r4), "r"(r5) : SYSCALL_CLOBBERLIST, "$8", "$9", "$10"); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } static inline long __syscall3(long n, long a, long b, long c) @@ -66,7 +66,7 @@ static inline long __syscall3(long n, long a, long b, long c) : "=&r"(r2), "=r"(r7) : "ir"(n), "r"(r4), "r"(r5), "r"(r6) : SYSCALL_CLOBBERLIST, "$8", "$9", "$10"); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } static inline long __syscall4(long n, long a, long b, long c, long d) @@ -81,7 +81,7 @@ static inline long __syscall4(long n, long a, long b, long c, long d) : "=&r"(r2), "+r"(r7) : "ir"(n), "r"(r4), "r"(r5), "r"(r6) : SYSCALL_CLOBBERLIST, "$8", "$9", "$10"); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } static inline long __syscall5(long n, long a, long b, long c, long d, long e) @@ -99,7 +99,7 @@ static inline long __syscall5(long n, long a, long b, long c, long d, long e) : "=&r"(r2), "+r"(r7), "+r"(r8) : "ir"(n), "r"(r4), "r"(r5), "r"(r6) : SYSCALL_CLOBBERLIST, "$9", "$10"); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } static inline long __syscall6(long n, long a, long b, long c, long d, long e, long f) @@ -118,7 +118,7 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo : "=&r"(r2), "+r"(r7), "+r"(r8), "+r"(r9) : "ir"(n), "r"(r4), "r"(r5), "r"(r6) : SYSCALL_CLOBBERLIST, "$10"); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } static inline long __syscall7(long n, long a, long b, long c, long d, long e, long f, long g) @@ -138,7 +138,7 @@ static inline long __syscall7(long n, long a, long b, long c, long d, long e, lo : "=&r"(r2), "+r"(r7), "+r"(r8), "+r"(r9), "+r"(r10) : "ir"(n), "r"(r4), "r"(r5), "r"(r6) : SYSCALL_CLOBBERLIST); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } #define VDSO_USEFUL diff --git a/arch/mips64/syscall_arch.h b/arch/mips64/syscall_arch.h index 8f6758d3..62492640 100644 --- a/arch/mips64/syscall_arch.h +++ b/arch/mips64/syscall_arch.h @@ -22,7 +22,7 @@ static inline long __syscall0(long n) : "=&r"(r2), "=r"(r7) : "ir"(n) : SYSCALL_CLOBBERLIST); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } static inline long __syscall1(long n, long a) @@ -35,7 +35,7 @@ static inline long __syscall1(long n, long a) : "=&r"(r2), "=r"(r7) : "ir"(n), "r"(r4) : SYSCALL_CLOBBERLIST); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } static inline long __syscall2(long n, long a, long b) @@ -50,7 +50,7 @@ static inline long __syscall2(long n, long a, long b) : "=&r"(r2), "=r"(r7) : "ir"(n), "r"(r4), "r"(r5) : SYSCALL_CLOBBERLIST); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } static inline long __syscall3(long n, long a, long b, long c) @@ -66,7 +66,7 @@ static inline long __syscall3(long n, long a, long b, long c) : "=&r"(r2), "=r"(r7) : "ir"(n), "r"(r4), "r"(r5), "r"(r6) : SYSCALL_CLOBBERLIST); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } static inline long __syscall4(long n, long a, long b, long c, long d) @@ -82,7 +82,7 @@ static inline long __syscall4(long n, long a, long b, long c, long d) : "=&r"(r2), "+r"(r7) : "ir"(n), "r"(r4), "r"(r5), "r"(r6) : SYSCALL_CLOBBERLIST); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } static inline long __syscall5(long n, long a, long b, long c, long d, long e) @@ -99,7 +99,7 @@ static inline long __syscall5(long n, long a, long b, long c, long d, long e) : "=&r"(r2), "+r"(r7) : "ir"(n), "r"(r4), "r"(r5), "r"(r6), "r"(r8) : SYSCALL_CLOBBERLIST); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } static inline long __syscall6(long n, long a, long b, long c, long d, long e, long f) @@ -117,7 +117,7 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo : "=&r"(r2), "+r"(r7) : "ir"(n), "r"(r4), "r"(r5), "r"(r6), "r"(r8), "r"(r9) : SYSCALL_CLOBBERLIST); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } #define VDSO_USEFUL diff --git a/arch/mipsn32/syscall_arch.h b/arch/mipsn32/syscall_arch.h index bc29e318..8b9e9ddd 100644 --- a/arch/mipsn32/syscall_arch.h +++ b/arch/mipsn32/syscall_arch.h @@ -22,7 +22,7 @@ static inline long __syscall0(long n) : "=&r"(r2), "=r"(r7) : "ir"(n) : SYSCALL_CLOBBERLIST); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } static inline long __syscall1(long n, long a) @@ -35,7 +35,7 @@ static inline long __syscall1(long n, long a) : "=&r"(r2), "=r"(r7) : "ir"(n), "r"(r4) : SYSCALL_CLOBBERLIST); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } static inline long __syscall2(long n, long a, long b) @@ -50,7 +50,7 @@ static inline long __syscall2(long n, long a, long b) : "=&r"(r2), "=r"(r7) : "ir"(n), "r"(r4), "r"(r5) : SYSCALL_CLOBBERLIST); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } static inline long __syscall3(long n, long a, long b, long c) @@ -66,7 +66,7 @@ static inline long __syscall3(long n, long a, long b, long c) : "=&r"(r2), "=r"(r7) : "ir"(n), "r"(r4), "r"(r5), "r"(r6) : SYSCALL_CLOBBERLIST); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } static inline long __syscall4(long n, long a, long b, long c, long d) @@ -82,7 +82,7 @@ static inline long __syscall4(long n, long a, long b, long c, long d) : "=&r"(r2), "+r"(r7) : "ir"(n), "r"(r4), "r"(r5), "r"(r6) : SYSCALL_CLOBBERLIST); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } static inline long __syscall5(long n, long a, long b, long c, long d, long e) @@ -99,7 +99,7 @@ static inline long __syscall5(long n, long a, long b, long c, long d, long e) : "=&r"(r2), "+r"(r7) : "ir"(n), "r"(r4), "r"(r5), "r"(r6), "r"(r8) : SYSCALL_CLOBBERLIST); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } static inline long __syscall6(long n, long a, long b, long c, long d, long e, long f) @@ -117,7 +117,7 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo : "=&r"(r2), "+r"(r7) : "ir"(n), "r"(r4), "r"(r5), "r"(r6), "r"(r8), "r"(r9) : SYSCALL_CLOBBERLIST); - return r7 ? -r2 : r2; + return r7 && r2>0 ? -r2 : r2; } #define VDSO_USEFUL -- 2.21.0