2017-06-21 16:40:42

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH] futex: avoid undefined behaviour when shift exponent is negative


* zhong jiang <[email protected]> wrote:

> when shift expoment is negative, left shift alway zero. therefore, we
> modify the logic to avoid the warining.
>
> Signed-off-by: zhong jiang <[email protected]>
> ---
> arch/x86/include/asm/futex.h | 8 ++++++--
> 1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h
> index b4c1f54..2425fca 100644
> --- a/arch/x86/include/asm/futex.h
> +++ b/arch/x86/include/asm/futex.h
> @@ -49,8 +49,12 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
> int cmparg = (encoded_op << 20) >> 20;
> int oldval = 0, ret, tem;
>
> - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> - oparg = 1 << oparg;
> + if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) {
> + if (oparg >= 0)
> + oparg = 1 << oparg;
> + else
> + oparg = 0;
> + }

Could we avoid all these complications by using an unsigned type?

Thanks,

Ingo


2017-06-28 04:36:58

by zhong jiang

[permalink] [raw]
Subject: Re: [PATCH] futex: avoid undefined behaviour when shift exponent is negative

Hi, Ingo

Thank you for the comment.
On 2017/6/22 0:40, Ingo Molnar wrote:
> * zhong jiang <[email protected]> wrote:
>
>> when shift expoment is negative, left shift alway zero. therefore, we
>> modify the logic to avoid the warining.
>>
>> Signed-off-by: zhong jiang <[email protected]>
>> ---
>> arch/x86/include/asm/futex.h | 8 ++++++--
>> 1 file changed, 6 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h
>> index b4c1f54..2425fca 100644
>> --- a/arch/x86/include/asm/futex.h
>> +++ b/arch/x86/include/asm/futex.h
>> @@ -49,8 +49,12 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
>> int cmparg = (encoded_op << 20) >> 20;
>> int oldval = 0, ret, tem;
>>
>> - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
>> - oparg = 1 << oparg;
>> + if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) {
>> + if (oparg >= 0)
>> + oparg = 1 << oparg;
>> + else
>> + oparg = 0;
>> + }
> Could we avoid all these complications by using an unsigned type?
I think it is not feasible. a negative shift exponent is likely existence and reasonable.
as the above case, oparg is a negative is common.

I think it can be avoided by following change.

diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h
index b4c1f54..3205e86 100644
--- a/arch/x86/include/asm/futex.h
+++ b/arch/x86/include/asm/futex.h
@@ -50,7 +50,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
int oldval = 0, ret, tem;

if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
- oparg = 1 << oparg;
+ oparg = safe_shift(1, oparg);

if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 069fe79..b4edda3 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -190,11 +190,6 @@ char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size

#ifdef CONFIG_LOGO

-static inline unsigned safe_shift(unsigned d, int n)
-{
- return n < 0 ? d >> -n : d << n;
-}
-
static void fb_set_logocmap(struct fb_info *info,
const struct linux_logo *logo)
{
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index d043ada..f3b8856 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -841,6 +841,10 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
*/
#define clamp_val(val, lo, hi) clamp_t(typeof(val), val, lo, hi)

+static inline unsigned safe_shift(unsigned d, int n)
+{
+ return n < 0 ? d >> -n : d << n;
+}

Thansk
zhongjiang

> Thanks,
>
> Ingo
>
> .
>


2017-06-28 21:49:45

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH] futex: avoid undefined behaviour when shift exponent is negative

On June 27, 2017 9:35:10 PM PDT, zhong jiang <[email protected]> wrote:
>Hi, Ingo
>
>Thank you for the comment.
>On 2017/6/22 0:40, Ingo Molnar wrote:
>> * zhong jiang <[email protected]> wrote:
>>
>>> when shift expoment is negative, left shift alway zero. therefore,
>we
>>> modify the logic to avoid the warining.
>>>
>>> Signed-off-by: zhong jiang <[email protected]>
>>> ---
>>> arch/x86/include/asm/futex.h | 8 ++++++--
>>> 1 file changed, 6 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/arch/x86/include/asm/futex.h
>b/arch/x86/include/asm/futex.h
>>> index b4c1f54..2425fca 100644
>>> --- a/arch/x86/include/asm/futex.h
>>> +++ b/arch/x86/include/asm/futex.h
>>> @@ -49,8 +49,12 @@ static inline int futex_atomic_op_inuser(int
>encoded_op, u32 __user *uaddr)
>>> int cmparg = (encoded_op << 20) >> 20;
>>> int oldval = 0, ret, tem;
>>>
>>> - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
>>> - oparg = 1 << oparg;
>>> + if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) {
>>> + if (oparg >= 0)
>>> + oparg = 1 << oparg;
>>> + else
>>> + oparg = 0;
>>> + }
>> Could we avoid all these complications by using an unsigned type?
>I think it is not feasible. a negative shift exponent is likely
>existence and reasonable.
> as the above case, oparg is a negative is common.
>
> I think it can be avoided by following change.
>
>diff --git a/arch/x86/include/asm/futex.h
>b/arch/x86/include/asm/futex.h
>index b4c1f54..3205e86 100644
>--- a/arch/x86/include/asm/futex.h
>+++ b/arch/x86/include/asm/futex.h
>@@ -50,7 +50,7 @@ static inline int futex_atomic_op_inuser(int
>encoded_op, u32 __user *uaddr)
> int oldval = 0, ret, tem;
>
> if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
>- oparg = 1 << oparg;
>+ oparg = safe_shift(1, oparg);
>
> if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
> return -EFAULT;
>diff --git a/drivers/video/fbdev/core/fbmem.c
>b/drivers/video/fbdev/core/fbmem.c
>index 069fe79..b4edda3 100644
>--- a/drivers/video/fbdev/core/fbmem.c
>+++ b/drivers/video/fbdev/core/fbmem.c
>@@ -190,11 +190,6 @@ char* fb_get_buffer_offset(struct fb_info *info,
>struct fb_pixmap *buf, u32 size
>
> #ifdef CONFIG_LOGO
>
>-static inline unsigned safe_shift(unsigned d, int n)
>-{
>- return n < 0 ? d >> -n : d << n;
>-}
>-
> static void fb_set_logocmap(struct fb_info *info,
> const struct linux_logo *logo)
> {
>diff --git a/include/linux/kernel.h b/include/linux/kernel.h
>index d043ada..f3b8856 100644
>--- a/include/linux/kernel.h
>+++ b/include/linux/kernel.h
>@@ -841,6 +841,10 @@ static inline void ftrace_dump(enum
>ftrace_dump_mode oops_dump_mode) { }
> */
> #define clamp_val(val, lo, hi) clamp_t(typeof(val), val, lo, hi)
>
>+static inline unsigned safe_shift(unsigned d, int n)
>+{
>+ return n < 0 ? d >> -n : d << n;
>+}
>
>Thansk
>zhongjiang
>
>> Thanks,
>>
>> Ingo
>>
>> .
>>

What makes it reasonable? It is totally ill-defined and doesn't do anything useful now?
--
Sent from my Android device with K-9 Mail. Please excuse my brevity.

2017-06-28 22:14:43

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH] futex: avoid undefined behaviour when shift exponent is negative

On Wed, 28 Jun 2017, zhong jiang wrote:
> On 2017/6/22 0:40, Ingo Molnar wrote:
> > * zhong jiang <[email protected]> wrote:
> >
> >> when shift expoment is negative, left shift alway zero. therefore, we
> >> modify the logic to avoid the warining.
> >>
> >> Signed-off-by: zhong jiang <[email protected]>
> >> ---
> >> arch/x86/include/asm/futex.h | 8 ++++++--
> >> 1 file changed, 6 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h
> >> index b4c1f54..2425fca 100644
> >> --- a/arch/x86/include/asm/futex.h
> >> +++ b/arch/x86/include/asm/futex.h
> >> @@ -49,8 +49,12 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
> >> int cmparg = (encoded_op << 20) >> 20;
> >> int oldval = 0, ret, tem;
> >>
> >> - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> >> - oparg = 1 << oparg;
> >> + if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) {
> >> + if (oparg >= 0)
> >> + oparg = 1 << oparg;
> >> + else
> >> + oparg = 0;
> >> + }
> > Could we avoid all these complications by using an unsigned type?
>
> I think it is not feasible. a negative shift exponent is likely
> existence and reasonable.

What is reasonable about a negative shift value?

> as the above case, oparg is a negative is common.

That's simply wrong. If oparg is negative and the SHIFT bit is set then the
result is undefined today and there is no way that this can be used at
all.

On x86:

1 << -1 = 0x80000000
1 << -2048 = 0x00000001
1 << -2047 = 0x00000002

Anything using a shift value < 0 or > 31 will get crap as a
result. Rightfully so because it's just undefined.

Yes I know that the insanity of user space is unlimited, but anything
attempting this is so broken that we cannot break it further by making that
shift arg unsigned and actually limit it to 0-31

Thanks,

tglx


2017-06-29 01:56:08

by zhong jiang

[permalink] [raw]
Subject: Re: [PATCH] futex: avoid undefined behaviour when shift exponent is negative

Hi, Thomas

Thank you for clarification.
On 2017/6/29 6:13, Thomas Gleixner wrote:
> On Wed, 28 Jun 2017, zhong jiang wrote:
>> On 2017/6/22 0:40, Ingo Molnar wrote:
>>> * zhong jiang <[email protected]> wrote:
>>>
>>>> when shift expoment is negative, left shift alway zero. therefore, we
>>>> modify the logic to avoid the warining.
>>>>
>>>> Signed-off-by: zhong jiang <[email protected]>
>>>> ---
>>>> arch/x86/include/asm/futex.h | 8 ++++++--
>>>> 1 file changed, 6 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h
>>>> index b4c1f54..2425fca 100644
>>>> --- a/arch/x86/include/asm/futex.h
>>>> +++ b/arch/x86/include/asm/futex.h
>>>> @@ -49,8 +49,12 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
>>>> int cmparg = (encoded_op << 20) >> 20;
>>>> int oldval = 0, ret, tem;
>>>>
>>>> - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
>>>> - oparg = 1 << oparg;
>>>> + if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) {
>>>> + if (oparg >= 0)
>>>> + oparg = 1 << oparg;
>>>> + else
>>>> + oparg = 0;
>>>> + }
>>> Could we avoid all these complications by using an unsigned type?
>> I think it is not feasible. a negative shift exponent is likely
>> existence and reasonable.
> What is reasonable about a negative shift value?
>
>> as the above case, oparg is a negative is common.
> That's simply wrong. If oparg is negative and the SHIFT bit is set then the
> result is undefined today and there is no way that this can be used at
> all.
>
> On x86:
>
> 1 << -1 = 0x80000000
> 1 << -2048 = 0x00000001
> 1 << -2047 = 0x00000002
but I test the cases in x86_64 all is zero. I wonder whether it is related to gcc or not

zj.c:15:8: warning: left shift count is negative [-Wshift-count-negative]
j = 1 << -2048;
^
[root@localhost zhongjiang]# ./zj
j = 0

Thanks
zhongjiang
> Anything using a shift value < 0 or > 31 will get crap as a
> result. Rightfully so because it's just undefined.
>
> Yes I know that the insanity of user space is unlimited, but anything
> attempting this is so broken that we cannot break it further by making that
> shift arg unsigned and actually limit it to 0-31
> Thanks,
>
> tglx
>
>
>
> .
>


2017-06-29 02:13:02

by zhong jiang

[permalink] [raw]
Subject: Re: [PATCH] futex: avoid undefined behaviour when shift exponent is negative

On 2017/6/29 5:43, [email protected] wrote:
> On June 27, 2017 9:35:10 PM PDT, zhong jiang <[email protected]> wrote:
>> Hi, Ingo
>>
>> Thank you for the comment.
>> On 2017/6/22 0:40, Ingo Molnar wrote:
>>> * zhong jiang <[email protected]> wrote:
>>>
>>>> when shift expoment is negative, left shift alway zero. therefore,
>> we
>>>> modify the logic to avoid the warining.
>>>>
>>>> Signed-off-by: zhong jiang <[email protected]>
>>>> ---
>>>> arch/x86/include/asm/futex.h | 8 ++++++--
>>>> 1 file changed, 6 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/arch/x86/include/asm/futex.h
>> b/arch/x86/include/asm/futex.h
>>>> index b4c1f54..2425fca 100644
>>>> --- a/arch/x86/include/asm/futex.h
>>>> +++ b/arch/x86/include/asm/futex.h
>>>> @@ -49,8 +49,12 @@ static inline int futex_atomic_op_inuser(int
>> encoded_op, u32 __user *uaddr)
>>>> int cmparg = (encoded_op << 20) >> 20;
>>>> int oldval = 0, ret, tem;
>>>>
>>>> - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
>>>> - oparg = 1 << oparg;
>>>> + if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) {
>>>> + if (oparg >= 0)
>>>> + oparg = 1 << oparg;
>>>> + else
>>>> + oparg = 0;
>>>> + }
>>> Could we avoid all these complications by using an unsigned type?
>> I think it is not feasible. a negative shift exponent is likely
>> existence and reasonable.
>> as the above case, oparg is a negative is common.
>>
>> I think it can be avoided by following change.
>>
>> diff --git a/arch/x86/include/asm/futex.h
>> b/arch/x86/include/asm/futex.h
>> index b4c1f54..3205e86 100644
>> --- a/arch/x86/include/asm/futex.h
>> +++ b/arch/x86/include/asm/futex.h
>> @@ -50,7 +50,7 @@ static inline int futex_atomic_op_inuser(int
>> encoded_op, u32 __user *uaddr)
>> int oldval = 0, ret, tem;
>>
>> if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
>> - oparg = 1 << oparg;
>> + oparg = safe_shift(1, oparg);
>>
>> if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
>> return -EFAULT;
>> diff --git a/drivers/video/fbdev/core/fbmem.c
>> b/drivers/video/fbdev/core/fbmem.c
>> index 069fe79..b4edda3 100644
>> --- a/drivers/video/fbdev/core/fbmem.c
>> +++ b/drivers/video/fbdev/core/fbmem.c
>> @@ -190,11 +190,6 @@ char* fb_get_buffer_offset(struct fb_info *info,
>> struct fb_pixmap *buf, u32 size
>>
>> #ifdef CONFIG_LOGO
>>
>> -static inline unsigned safe_shift(unsigned d, int n)
>> -{
>> - return n < 0 ? d >> -n : d << n;
>> -}
>> -
>> static void fb_set_logocmap(struct fb_info *info,
>> const struct linux_logo *logo)
>> {
>> diff --git a/include/linux/kernel.h b/include/linux/kernel.h
>> index d043ada..f3b8856 100644
>> --- a/include/linux/kernel.h
>> +++ b/include/linux/kernel.h
>> @@ -841,6 +841,10 @@ static inline void ftrace_dump(enum
>> ftrace_dump_mode oops_dump_mode) { }
>> */
>> #define clamp_val(val, lo, hi) clamp_t(typeof(val), val, lo, hi)
>>
>> +static inline unsigned safe_shift(unsigned d, int n)
>> +{
>> + return n < 0 ? d >> -n : d << n;
>> +}
>>
>> Thansk
>> zhongjiang
>>
>>> Thanks,
>>>
>>> Ingo
>>>
>>> .
>>>
> What makes it reasonable? It is totally ill-defined and doesn't do anything useful now?
Thanks you for comments.

Maybe I mismake the meaning. I test the negative cases in x86 , all case is zero. so I come to a conclusion.

zj.c:15:8: warning: left shift count is negative [-Wshift-count-negative]
j = 1 << -2048;
^
[root@localhost zhongjiang]# ./zj
j = 0
j.c:15:8: warning: left shift count is negative [-Wshift-count-negative]
j = 1 << -2047;
^
[root@localhost zhongjiang]# ./zj
j = 0

I insmod a module into kernel to test the testcasts, all of the result is zero.

I wonder whether I miss some point or not. Do you point out to me? please

Thanks
zhongjiang



2017-06-29 04:34:10

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH] futex: avoid undefined behaviour when shift exponent is negative

On June 28, 2017 7:12:04 PM PDT, zhong jiang <[email protected]> wrote:
>On 2017/6/29 5:43, [email protected] wrote:
>> On June 27, 2017 9:35:10 PM PDT, zhong jiang <[email protected]>
>wrote:
>>> Hi, Ingo
>>>
>>> Thank you for the comment.
>>> On 2017/6/22 0:40, Ingo Molnar wrote:
>>>> * zhong jiang <[email protected]> wrote:
>>>>
>>>>> when shift expoment is negative, left shift alway zero. therefore,
>>> we
>>>>> modify the logic to avoid the warining.
>>>>>
>>>>> Signed-off-by: zhong jiang <[email protected]>
>>>>> ---
>>>>> arch/x86/include/asm/futex.h | 8 ++++++--
>>>>> 1 file changed, 6 insertions(+), 2 deletions(-)
>>>>>
>>>>> diff --git a/arch/x86/include/asm/futex.h
>>> b/arch/x86/include/asm/futex.h
>>>>> index b4c1f54..2425fca 100644
>>>>> --- a/arch/x86/include/asm/futex.h
>>>>> +++ b/arch/x86/include/asm/futex.h
>>>>> @@ -49,8 +49,12 @@ static inline int futex_atomic_op_inuser(int
>>> encoded_op, u32 __user *uaddr)
>>>>> int cmparg = (encoded_op << 20) >> 20;
>>>>> int oldval = 0, ret, tem;
>>>>>
>>>>> - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
>>>>> - oparg = 1 << oparg;
>>>>> + if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) {
>>>>> + if (oparg >= 0)
>>>>> + oparg = 1 << oparg;
>>>>> + else
>>>>> + oparg = 0;
>>>>> + }
>>>> Could we avoid all these complications by using an unsigned type?
>>> I think it is not feasible. a negative shift exponent is likely
>>> existence and reasonable.
>>> as the above case, oparg is a negative is common.
>>>
>>> I think it can be avoided by following change.
>>>
>>> diff --git a/arch/x86/include/asm/futex.h
>>> b/arch/x86/include/asm/futex.h
>>> index b4c1f54..3205e86 100644
>>> --- a/arch/x86/include/asm/futex.h
>>> +++ b/arch/x86/include/asm/futex.h
>>> @@ -50,7 +50,7 @@ static inline int futex_atomic_op_inuser(int
>>> encoded_op, u32 __user *uaddr)
>>> int oldval = 0, ret, tem;
>>>
>>> if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
>>> - oparg = 1 << oparg;
>>> + oparg = safe_shift(1, oparg);
>>>
>>> if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
>>> return -EFAULT;
>>> diff --git a/drivers/video/fbdev/core/fbmem.c
>>> b/drivers/video/fbdev/core/fbmem.c
>>> index 069fe79..b4edda3 100644
>>> --- a/drivers/video/fbdev/core/fbmem.c
>>> +++ b/drivers/video/fbdev/core/fbmem.c
>>> @@ -190,11 +190,6 @@ char* fb_get_buffer_offset(struct fb_info
>*info,
>>> struct fb_pixmap *buf, u32 size
>>>
>>> #ifdef CONFIG_LOGO
>>>
>>> -static inline unsigned safe_shift(unsigned d, int n)
>>> -{
>>> - return n < 0 ? d >> -n : d << n;
>>> -}
>>> -
>>> static void fb_set_logocmap(struct fb_info *info,
>>> const struct linux_logo *logo)
>>> {
>>> diff --git a/include/linux/kernel.h b/include/linux/kernel.h
>>> index d043ada..f3b8856 100644
>>> --- a/include/linux/kernel.h
>>> +++ b/include/linux/kernel.h
>>> @@ -841,6 +841,10 @@ static inline void ftrace_dump(enum
>>> ftrace_dump_mode oops_dump_mode) { }
>>> */
>>> #define clamp_val(val, lo, hi) clamp_t(typeof(val), val, lo, hi)
>>>
>>> +static inline unsigned safe_shift(unsigned d, int n)
>>> +{
>>> + return n < 0 ? d >> -n : d << n;
>>> +}
>>>
>>> Thansk
>>> zhongjiang
>>>
>>>> Thanks,
>>>>
>>>> Ingo
>>>>
>>>> .
>>>>
>> What makes it reasonable? It is totally ill-defined and doesn't do
>anything useful now?
> Thanks you for comments.
>
>Maybe I mismake the meaning. I test the negative cases in x86 , all
>case is zero. so I come to a conclusion.
>
>zj.c:15:8: warning: left shift count is negative
>[-Wshift-count-negative]
> j = 1 << -2048;
> ^
>[root@localhost zhongjiang]# ./zj
>j = 0
>j.c:15:8: warning: left shift count is negative
>[-Wshift-count-negative]
> j = 1 << -2047;
> ^
>[root@localhost zhongjiang]# ./zj
>j = 0
>
>I insmod a module into kernel to test the testcasts, all of the result
>is zero.
>
>I wonder whether I miss some point or not. Do you point out to me?
>please
>
>Thanks
>zhongjiang
>
>

When you use compile-time constants, the compiler generates the value at compile time, which can be totally different.
--
Sent from my Android device with K-9 Mail. Please excuse my brevity.

2017-06-29 05:59:07

by zhong jiang

[permalink] [raw]
Subject: Re: [PATCH] futex: avoid undefined behaviour when shift exponent is negative

On 2017/6/29 12:29, [email protected] wrote:
> On June 28, 2017 7:12:04 PM PDT, zhong jiang <[email protected]> wrote:
>> On 2017/6/29 5:43, [email protected] wrote:
>>> On June 27, 2017 9:35:10 PM PDT, zhong jiang <[email protected]>
>> wrote:
>>>> Hi, Ingo
>>>>
>>>> Thank you for the comment.
>>>> On 2017/6/22 0:40, Ingo Molnar wrote:
>>>>> * zhong jiang <[email protected]> wrote:
>>>>>
>>>>>> when shift expoment is negative, left shift alway zero. therefore,
>>>> we
>>>>>> modify the logic to avoid the warining.
>>>>>>
>>>>>> Signed-off-by: zhong jiang <[email protected]>
>>>>>> ---
>>>>>> arch/x86/include/asm/futex.h | 8 ++++++--
>>>>>> 1 file changed, 6 insertions(+), 2 deletions(-)
>>>>>>
>>>>>> diff --git a/arch/x86/include/asm/futex.h
>>>> b/arch/x86/include/asm/futex.h
>>>>>> index b4c1f54..2425fca 100644
>>>>>> --- a/arch/x86/include/asm/futex.h
>>>>>> +++ b/arch/x86/include/asm/futex.h
>>>>>> @@ -49,8 +49,12 @@ static inline int futex_atomic_op_inuser(int
>>>> encoded_op, u32 __user *uaddr)
>>>>>> int cmparg = (encoded_op << 20) >> 20;
>>>>>> int oldval = 0, ret, tem;
>>>>>>
>>>>>> - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
>>>>>> - oparg = 1 << oparg;
>>>>>> + if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) {
>>>>>> + if (oparg >= 0)
>>>>>> + oparg = 1 << oparg;
>>>>>> + else
>>>>>> + oparg = 0;
>>>>>> + }
>>>>> Could we avoid all these complications by using an unsigned type?
>>>> I think it is not feasible. a negative shift exponent is likely
>>>> existence and reasonable.
>>>> as the above case, oparg is a negative is common.
>>>>
>>>> I think it can be avoided by following change.
>>>>
>>>> diff --git a/arch/x86/include/asm/futex.h
>>>> b/arch/x86/include/asm/futex.h
>>>> index b4c1f54..3205e86 100644
>>>> --- a/arch/x86/include/asm/futex.h
>>>> +++ b/arch/x86/include/asm/futex.h
>>>> @@ -50,7 +50,7 @@ static inline int futex_atomic_op_inuser(int
>>>> encoded_op, u32 __user *uaddr)
>>>> int oldval = 0, ret, tem;
>>>>
>>>> if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
>>>> - oparg = 1 << oparg;
>>>> + oparg = safe_shift(1, oparg);
>>>>
>>>> if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
>>>> return -EFAULT;
>>>> diff --git a/drivers/video/fbdev/core/fbmem.c
>>>> b/drivers/video/fbdev/core/fbmem.c
>>>> index 069fe79..b4edda3 100644
>>>> --- a/drivers/video/fbdev/core/fbmem.c
>>>> +++ b/drivers/video/fbdev/core/fbmem.c
>>>> @@ -190,11 +190,6 @@ char* fb_get_buffer_offset(struct fb_info
>> *info,
>>>> struct fb_pixmap *buf, u32 size
>>>>
>>>> #ifdef CONFIG_LOGO
>>>>
>>>> -static inline unsigned safe_shift(unsigned d, int n)
>>>> -{
>>>> - return n < 0 ? d >> -n : d << n;
>>>> -}
>>>> -
>>>> static void fb_set_logocmap(struct fb_info *info,
>>>> const struct linux_logo *logo)
>>>> {
>>>> diff --git a/include/linux/kernel.h b/include/linux/kernel.h
>>>> index d043ada..f3b8856 100644
>>>> --- a/include/linux/kernel.h
>>>> +++ b/include/linux/kernel.h
>>>> @@ -841,6 +841,10 @@ static inline void ftrace_dump(enum
>>>> ftrace_dump_mode oops_dump_mode) { }
>>>> */
>>>> #define clamp_val(val, lo, hi) clamp_t(typeof(val), val, lo, hi)
>>>>
>>>> +static inline unsigned safe_shift(unsigned d, int n)
>>>> +{
>>>> + return n < 0 ? d >> -n : d << n;
>>>> +}
>>>>
>>>> Thansk
>>>> zhongjiang
>>>>
>>>>> Thanks,
>>>>>
>>>>> Ingo
>>>>>
>>>>> .
>>>>>
>>> What makes it reasonable? It is totally ill-defined and doesn't do
>> anything useful now?
>> Thanks you for comments.
>>
>> Maybe I mismake the meaning. I test the negative cases in x86 , all
>> case is zero. so I come to a conclusion.
>>
>> zj.c:15:8: warning: left shift count is negative
>> [-Wshift-count-negative]
>> j = 1 << -2048;
>> ^
>> [root@localhost zhongjiang]# ./zj
>> j = 0
>> j.c:15:8: warning: left shift count is negative
>> [-Wshift-count-negative]
>> j = 1 << -2047;
>> ^
>> [root@localhost zhongjiang]# ./zj
>> j = 0
>>
>> I insmod a module into kernel to test the testcasts, all of the result
>> is zero.
>>
>> I wonder whether I miss some point or not. Do you point out to me?
>> please
>>
>> Thanks
>> zhongjiang
>>
>>
> When you use compile-time constants, the compiler generates the value at compile time, which can be totally different.
yes, I test that. Thanks.

Thanks
zhongjiang

2017-06-29 06:34:34

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH] futex: avoid undefined behaviour when shift exponent is negative

On Thu, 29 Jun 2017, zhong jiang wrote:
> On 2017/6/29 6:13, Thomas Gleixner wrote:
> > That's simply wrong. If oparg is negative and the SHIFT bit is set then the
> > result is undefined today and there is no way that this can be used at
> > all.
> >
> > On x86:
> >
> > 1 << -1 = 0x80000000
> > 1 << -2048 = 0x00000001
> > 1 << -2047 = 0x00000002
> but I test the cases in x86_64 all is zero. I wonder whether it is related to gcc or not
>
> zj.c:15:8: warning: left shift count is negative [-Wshift-count-negative]
> j = 1 << -2048;
> ^
> [root@localhost zhongjiang]# ./zj
> j = 0

Which is not a surprise because the compiler can detect it as the shift is
a constant. oparg is not so constant ...

Thanks,

tglx

2017-06-29 07:05:46

by zhong jiang

[permalink] [raw]
Subject: Re: [PATCH] futex: avoid undefined behaviour when shift exponent is negative

On 2017/6/29 14:33, Thomas Gleixner wrote:
> On Thu, 29 Jun 2017, zhong jiang wrote:
>> On 2017/6/29 6:13, Thomas Gleixner wrote:
>>> That's simply wrong. If oparg is negative and the SHIFT bit is set then the
>>> result is undefined today and there is no way that this can be used at
>>> all.
>>>
>>> On x86:
>>>
>>> 1 << -1 = 0x80000000
>>> 1 << -2048 = 0x00000001
>>> 1 << -2047 = 0x00000002
>> but I test the cases in x86_64 all is zero. I wonder whether it is related to gcc or not
>>
>> zj.c:15:8: warning: left shift count is negative [-Wshift-count-negative]
>> j = 1 << -2048;
>> ^
>> [root@localhost zhongjiang]# ./zj
>> j = 0
> Which is not a surprise because the compiler can detect it as the shift is
> a constant. oparg is not so constant ...
I get it. Thanks

Thanks
zhongjiang
> Thanks,
>
> tglx
>
> .
>


2017-08-25 05:22:33

by zhong jiang

[permalink] [raw]
Subject: Re: [PATCH] futex: avoid undefined behaviour when shift exponent is negative

On 2017/6/29 6:13, Thomas Gleixner wrote:
> On Wed, 28 Jun 2017, zhong jiang wrote:
>> On 2017/6/22 0:40, Ingo Molnar wrote:
>>> * zhong jiang <[email protected]> wrote:
>>>
>>>> when shift expoment is negative, left shift alway zero. therefore, we
>>>> modify the logic to avoid the warining.
>>>>
>>>> Signed-off-by: zhong jiang <[email protected]>
>>>> ---
>>>> arch/x86/include/asm/futex.h | 8 ++++++--
>>>> 1 file changed, 6 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h
>>>> index b4c1f54..2425fca 100644
>>>> --- a/arch/x86/include/asm/futex.h
>>>> +++ b/arch/x86/include/asm/futex.h
>>>> @@ -49,8 +49,12 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
>>>> int cmparg = (encoded_op << 20) >> 20;
>>>> int oldval = 0, ret, tem;
>>>>
>>>> - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
>>>> - oparg = 1 << oparg;
>>>> + if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) {
>>>> + if (oparg >= 0)
>>>> + oparg = 1 << oparg;
>>>> + else
>>>> + oparg = 0;
>>>> + }
>>> Could we avoid all these complications by using an unsigned type?
>> I think it is not feasible. a negative shift exponent is likely
>> existence and reasonable.
> What is reasonable about a negative shift value?
>
>> as the above case, oparg is a negative is common.
> That's simply wrong. If oparg is negative and the SHIFT bit is set then the
> result is undefined today and there is no way that this can be used at
> all.
>
> On x86:
>
> 1 << -1 = 0x80000000
> 1 << -2048 = 0x00000001
> 1 << -2047 = 0x00000002
>
> Anything using a shift value < 0 or > 31 will get crap as a
> result. Rightfully so because it's just undefined.
>
> Yes I know that the insanity of user space is unlimited, but anything
> attempting this is so broken that we cannot break it further by making that
> shift arg unsigned and actually limit it to 0-31
>
> Thanks,
>
> tglx
>
>
>
> .
>
>From df9e2a5a3f1f401943aeb2718d5876b854dea3a3 Mon Sep 17 00:00:00 2001
From: zhong jiang <[email protected]>
Date: Fri, 25 Aug 2017 12:05:56 +0800
Subject: [PATCH v2] futex: avoid undefined behaviour when shift exponent is
negative

when futex syscall is called from userspace, we find the following
warning by ubsan detection.

[ 63.237803] UBSAN: Undefined behaviour in /root/rpmbuild/BUILDROOT/kernel-3.10.0-327.49.58.52.x86_64/usr/src/linux-3.10.0-327.49.58.52.x86_64/arch/x86/include/asm/futex.h:53:13
[ 63.237803] shift exponent -16 is negative
[ 63.237803] CPU: 0 PID: 67 Comm: driver Not tainted 3.10.0 #1
[ 63.237803] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.8.1-0-g4adadbd-20150316_085822-nilsson.home.kraxel.org 04/01/2014
[ 63.237803] fffffffffffffff0 000000009ad70fde ffff88000002fa08 ffffffff81ef0d6f
[ 63.237803] ffff88000002fa20 ffffffff81ef0e2c ffffffff828f2540 ffff88000002fb90
[ 63.237803] ffffffff81ef1ad0 ffffffff8141cc88 1ffff10000005f48 0000000041b58ab3
[ 63.237803] Call Trace:
[ 63.237803] [<ffffffff81ef0d6f>] dump_stack+0x1e/0x20
[ 63.237803] [<ffffffff81ef0e2c>] ubsan_epilogue+0x12/0x55
[ 63.237803] [<ffffffff81ef1ad0>] __ubsan_handle_shift_out_of_bounds+0x237/0x29c
[ 63.237803] [<ffffffff8141cc88>] ? kasan_alloc_pages+0x38/0x40
[ 63.237803] [<ffffffff81ef1899>] ? __ubsan_handle_load_invalid_value+0x162/0x162
[ 63.237803] [<ffffffff812092c1>] ? get_futex_key+0x361/0x6c0
[ 63.237803] [<ffffffff81208f60>] ? get_futex_key_refs+0xb0/0xb0
[ 63.237803] [<ffffffff8120b938>] futex_wake_op+0xb48/0xc70
[ 63.237803] [<ffffffff8120b938>] ? futex_wake_op+0xb48/0xc70
[ 63.237803] [<ffffffff8120adf0>] ? futex_wake+0x380/0x380
[ 63.237803] [<ffffffff8121006c>] do_futex+0x2cc/0xb60
[ 63.237803] [<ffffffff8120fda0>] ? exit_robust_list+0x350/0x350
[ 63.237803] [<ffffffff814fa140>] ? __fsnotify_inode_delete+0x20/0x20
[ 63.237803] [<ffffffff818cabc0>] ? n_tty_flush_buffer+0x80/0x80
[ 63.237803] [<ffffffff814faed3>] ? __fsnotify_parent+0x53/0x210
[ 63.237803] [<ffffffff81210a47>] SyS_futex+0x147/0x300
[ 63.237803] [<ffffffff81210900>] ? do_futex+0xb60/0xb60
[ 63.237803] [<ffffffff81f0a134>] ? do_page_fault+0x44/0xa0
[ 63.237803] [<ffffffff81f16809>] system_call_fastpath+0x16/0x1b

using a shift value < 0 or > 31 will get crap as a result. because
it's just undefined. The issue still disturb me, so I try to fix
it again by excluding the especially condition.

Signed-off-by: zhong jiang <[email protected]>
---
arch/x86/include/asm/futex.h | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h
index b4c1f54..c414d76 100644
--- a/arch/x86/include/asm/futex.h
+++ b/arch/x86/include/asm/futex.h
@@ -49,9 +49,11 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
int cmparg = (encoded_op << 20) >> 20;
int oldval = 0, ret, tem;

- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) {
+ if (oparg < 0 || oparg > 31)
+ return -EINVAL;
oparg = 1 << oparg;
-
+ }
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;


2017-08-25 21:14:01

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH] futex: avoid undefined behaviour when shift exponent is negative

On Fri, 25 Aug 2017, zhong jiang wrote:
> From: zhong jiang <[email protected]>
> Date: Fri, 25 Aug 2017 12:05:56 +0800
> Subject: [PATCH v2] futex: avoid undefined behaviour when shift exponent is
> negative

Please do not send patches without changing the subject line so it's clear
that there is a new patch.

> using a shift value < 0 or > 31 will get crap as a result. because
> it's just undefined. The issue still disturb me, so I try to fix
> it again by excluding the especially condition.

Which is obsolete now as this code is unified accross all architectures and
the shift issue is addressed in the generic version of it. So all
architectures get the same fix. See:

http://git.kernel.org/tip/30d6e0a4190d37740e9447e4e4815f06992dd8c3

And no, we won't add that x86 fix before that unification hits mainline
because that undefined behaviour is harmless as it only affects the user
space value of the futex. IOW, the caller gets what it asked for: crap.

Thanks,

tglx

2017-08-26 02:52:55

by zhong jiang

[permalink] [raw]
Subject: Re: [PATCH] futex: avoid undefined behaviour when shift exponent is negative

On 2017/8/26 5:13, Thomas Gleixner wrote:
> On Fri, 25 Aug 2017, zhong jiang wrote:
>> From: zhong jiang <[email protected]>
>> Date: Fri, 25 Aug 2017 12:05:56 +0800
>> Subject: [PATCH v2] futex: avoid undefined behaviour when shift exponent is
>> negative
> Please do not send patches without changing the subject line so it's clear
> that there is a new patch.
ok
>> using a shift value < 0 or > 31 will get crap as a result. because
>> it's just undefined. The issue still disturb me, so I try to fix
>> it again by excluding the especially condition.
> Which is obsolete now as this code is unified accross all architectures and
> the shift issue is addressed in the generic version of it. So all
> architectures get the same fix. See:
>
> http://git.kernel.org/tip/30d6e0a4190d37740e9447e4e4815f06992dd8c3
ok , I miss the above patch.
> And no, we won't add that x86 fix before that unification hits mainline
> because that undefined behaviour is harmless as it only affects the user
> space value of the futex. IOW, the caller gets what it asked for: crap.
Thank you for clarification.

Regards
zhongjiang
> Thanks,
>
> tglx
>
>
> .
>