[arc] get_user() not clearing destination on failure
Vineet Gupta
Vineet.Gupta1 at synopsys.com
Thu Aug 18 23:11:09 PDT 2016
On 08/17/2016 08:00 PM, Al Viro wrote:
> First of all, my apologies if I'd managed to misread the ARC assembler
> in uaccess.h. AFAICS, neither __arc_get_user_one() nor __arc_get_user_one_64()
> end up zeroing the destination upon exception. Your __get_user_fn() is
> ({ \
> long __ret = 0; /* success by default */ \
> switch (sz) { \
> case 1: __arc_get_user_one(*(k), u, "ldb", __ret); break; \
> case 2: __arc_get_user_one(*(k), u, "ldw", __ret); break; \
> case 4: __arc_get_user_one(*(k), u, "ld", __ret); break; \
> case 8: __arc_get_user_one_64(*(k), u, __ret); break; \
> } \
> __ret; \
> })
> so it doesn't do that on its own either. Neither does __get_user() (from
> asm-generic/uaccess.h) nor get_user() (ditto), so unless I've missed something
> subtle about your exception handling, after
> char c = 0;
> int y = get_user(c, unmapped_address);
> you will get -EFAULT in y and random junk in c. We get to __get_user(c, ...),
> which turns into
> int __gu_err = -EFAULT;
> unsigned char __x; // uninitialized
> __gu_err = __get_user_fn(1, unmapped_address, &__x);
> c = (char) __x;
> y = __gu_err;
> i.e.
> int __gu_err = -EFAULT;
> unsigned char __x;
> long __ret = 0;
> __arc_get_user_one(*(&__x), unmapped_address, "ldb", __ret);
> __gu_err = __ret;
> c = (char) __x;
> y = __gu_err;
> and AFAICS your assembler in __arc_get_user_one() will boil down to something
> along the lines of
> r2 = unmapped_address;
> 1: r1 = *(unsigned char *)r2;
> 2:
> __x = r1;
>
> fixup(1):
> __ret = -EFAULT;
> goto 2;
> with nothing to clear r1 on the fixup path.
>
> *IF* the above is correct
It is - you got it all right
> (and I'm really unfamiliar with the architecture
> in question), you have a problem. get_user() and __get_user() ought to
> clear the destination even in case of EFAULT.
Just curious - why is that. The typical usage paradigm is check for return value
and if 0 only then proceed to use the actual value.
Also for discussion sake, will eliminating the intermediate __x be helpful - so it
would use the actual variable defined in caller of get_user() so if it is init
properly, the value would be "retained" for -EFAULT. Anyways all of this is just
for understanding better.
> There definitely is a bug
> in asm-generic get_user() (it doesn't clear destination in case of access_ok()
> failure), but that's not ARC-specific. I won't try to slap together a fix
> (no idea which forms of "zero that register" are better, for starters), but
> something like mov %1,0 in the fixup part might be needed.
I'll send that over tomorrow - after a bit of testing.
> And I've really
> no idea whatsoever about the syntax in __arc_get_user_one_64() - it needs to
> clear the entire 64bit value there.
Yeah the %R asm modifier seems to be undocumented in gcc manual - and it has been
there forever. But I checked that it correctly generates a register pair for the
64-bit word.
-Vineet
More information about the linux-snps-arc
mailing list