2021-09-27 09:43:29

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH] vboxsf: fix old signature detection

From: Arnd Bergmann <[email protected]>

The constant-out-of-range check in clang found an actual bug in
vboxsf, which leads to the detection of old mount signatures always
failing:

fs/vboxsf/super.c:394:21: error: result of comparison of constant -3 with expression of type 'unsigned char' is always false [-Werror,-Wtautological-constant-out-of-range-compare]
options[3] == VBSF_MOUNT_SIGNATURE_BYTE_3) {
~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
fs/vboxsf/super.c:393:21: error: result of comparison of constant -2 with expression of type 'unsigned char' is always false [-Werror,-Wtautological-constant-out-of-range-compare]
options[2] == VBSF_MOUNT_SIGNATURE_BYTE_2 &&
~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
fs/vboxsf/super.c:392:21: error: result of comparison of constant -1 with expression of type 'unsigned char' is always false [-Werror,-Wtautological-constant-out-of-range-compare]
options[1] == VBSF_MOUNT_SIGNATURE_BYTE_1 &&
~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~

The problem is that the pointer is of type 'unsigned char' but the
constant is a 'char'. My first idea was to change the type of the
pointer to 'char *', but I noticed that this was the original code
and it got changed after 'smatch' complained about this.

I don't know if there is a bug in smatch here, but it sounds to me
that clang's warning is correct. Forcing the constants to an unsigned
type should make the code behave consistently and avoid the warning
on both.

Fixes: 9d682ea6bcc7 ("vboxsf: Fix the check for the old binary mount-arguments struct")
Cc: Dan Carpenter <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
fs/vboxsf/super.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/fs/vboxsf/super.c b/fs/vboxsf/super.c
index 4f5e59f06284..84e2236021de 100644
--- a/fs/vboxsf/super.c
+++ b/fs/vboxsf/super.c
@@ -21,10 +21,10 @@

#define VBOXSF_SUPER_MAGIC 0x786f4256 /* 'VBox' little endian */

-#define VBSF_MOUNT_SIGNATURE_BYTE_0 ('\000')
-#define VBSF_MOUNT_SIGNATURE_BYTE_1 ('\377')
-#define VBSF_MOUNT_SIGNATURE_BYTE_2 ('\376')
-#define VBSF_MOUNT_SIGNATURE_BYTE_3 ('\375')
+#define VBSF_MOUNT_SIGNATURE_BYTE_0 (u8)('\000')
+#define VBSF_MOUNT_SIGNATURE_BYTE_1 (u8)('\377')
+#define VBSF_MOUNT_SIGNATURE_BYTE_2 (u8)('\376')
+#define VBSF_MOUNT_SIGNATURE_BYTE_3 (u8)('\375')

static int follow_symlinks;
module_param(follow_symlinks, int, 0444);
--
2.29.2


2021-09-27 10:11:00

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH] vboxsf: fix old signature detection

Hi,

On 9/27/21 11:40 AM, Arnd Bergmann wrote:
> From: Arnd Bergmann <[email protected]>
>
> The constant-out-of-range check in clang found an actual bug in
> vboxsf, which leads to the detection of old mount signatures always
> failing:
>
> fs/vboxsf/super.c:394:21: error: result of comparison of constant -3 with expression of type 'unsigned char' is always false [-Werror,-Wtautological-constant-out-of-range-compare]
> options[3] == VBSF_MOUNT_SIGNATURE_BYTE_3) {
> ~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~

This actually seems to be a clang bug though, or at least a weird
interpretation (and different from gcc) of the C spec.

VBSF_MOUNT_SIGNATURE_BYTE_3 is defined as:

#define VBSF_MOUNT_SIGNATURE_BYTE_3 ('\375')

The C-spec:

http://port70.net/~nsz/c/c11/n1570.html#6.4.4.4p5

Says the following:

"The octal digits that follow the backslash in an octal escape sequence are taken to be part of the construction of a single character for an integer character constant or of a single wide character for a wide character constant. The numerical value of the octal integer so formed specifies the value of the desired character or wide character."

Character constants have a type of int, so 0375
clearly fits in the range of that.

I guess the problem is that gcc sees this as

const int VBSF_MOUNT_SIGNATURE_BYTE_3 = 0375;

Where as clang sees this as:

const int VBSF_MOUNT_SIGNATURE_BYTE_3 = (char)0375;

Which is a nice subtle incompatibility between the 2 :|


With that said, the patch is fine and I have no objections
against it:

Reviewed-by: Hans de Goede <[email protected]>

Although maybe it is better to actually remove any
ambiguity and just replace the defines with:

static const u8 VBSF_MOUNT_SIGNATURE_BYTE_0 = 0000;
static const u8 VBSF_MOUNT_SIGNATURE_BYTE_1 = 0377;
static const u8 VBSF_MOUNT_SIGNATURE_BYTE_2 = 0376;
static const u8 VBSF_MOUNT_SIGNATURE_BYTE_3 = 0375;

?

Regards,

Hans










> fs/vboxsf/super.c:393:21: error: result of comparison of constant -2 with expression of type 'unsigned char' is always false [-Werror,-Wtautological-constant-out-of-range-compare]
> options[2] == VBSF_MOUNT_SIGNATURE_BYTE_2 &&
> ~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
> fs/vboxsf/super.c:392:21: error: result of comparison of constant -1 with expression of type 'unsigned char' is always false [-Werror,-Wtautological-constant-out-of-range-compare]
> options[1] == VBSF_MOUNT_SIGNATURE_BYTE_1 &&
> ~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> The problem is that the pointer is of type 'unsigned char' but the
> constant is a 'char'. My first idea was to change the type of the
> pointer to 'char *', but I noticed that this was the original code
> and it got changed after 'smatch' complained about this.
>
> I don't know if there is a bug in smatch here, but it sounds to me
> that clang's warning is correct. Forcing the constants to an unsigned
> type should make the code behave consistently and avoid the warning
> on both.
>
> Fixes: 9d682ea6bcc7 ("vboxsf: Fix the check for the old binary mount-arguments struct")
> Cc: Dan Carpenter <[email protected]>
> Signed-off-by: Arnd Bergmann <[email protected]>
> ---
> fs/vboxsf/super.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/fs/vboxsf/super.c b/fs/vboxsf/super.c
> index 4f5e59f06284..84e2236021de 100644
> --- a/fs/vboxsf/super.c
> +++ b/fs/vboxsf/super.c
> @@ -21,10 +21,10 @@
>
> #define VBOXSF_SUPER_MAGIC 0x786f4256 /* 'VBox' little endian */
>
> -#define VBSF_MOUNT_SIGNATURE_BYTE_0 ('\000')
> -#define VBSF_MOUNT_SIGNATURE_BYTE_1 ('\377')
> -#define VBSF_MOUNT_SIGNATURE_BYTE_2 ('\376')
> -#define VBSF_MOUNT_SIGNATURE_BYTE_3 ('\375')
> +#define VBSF_MOUNT_SIGNATURE_BYTE_0 (u8)('\000')
> +#define VBSF_MOUNT_SIGNATURE_BYTE_1 (u8)('\377')
> +#define VBSF_MOUNT_SIGNATURE_BYTE_2 (u8)('\376')
> +#define VBSF_MOUNT_SIGNATURE_BYTE_3 (u8)('\375')
>
> static int follow_symlinks;
> module_param(follow_symlinks, int, 0444);
>

2021-09-27 13:05:47

by Dan Carpenter

[permalink] [raw]
Subject: Re: [PATCH] vboxsf: fix old signature detection

GCC handles it the same way as Clang. '\377' is -1 but in Sparse it's
255. I've added the Sparse mailing list to the CC.

regards,
dan carpenter

On Mon, Sep 27, 2021 at 12:09:01PM +0200, Hans de Goede wrote:
> Hi,
>
> On 9/27/21 11:40 AM, Arnd Bergmann wrote:
> > From: Arnd Bergmann <[email protected]>
> >
> > The constant-out-of-range check in clang found an actual bug in
> > vboxsf, which leads to the detection of old mount signatures always
> > failing:
> >
> > fs/vboxsf/super.c:394:21: error: result of comparison of constant -3 with expression of type 'unsigned char' is always false [-Werror,-Wtautological-constant-out-of-range-compare]
> > options[3] == VBSF_MOUNT_SIGNATURE_BYTE_3) {
> > ~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> This actually seems to be a clang bug though, or at least a weird
> interpretation (and different from gcc) of the C spec.
>
> VBSF_MOUNT_SIGNATURE_BYTE_3 is defined as:
>
> #define VBSF_MOUNT_SIGNATURE_BYTE_3 ('\375')
>
> The C-spec:
>
> http://port70.net/~nsz/c/c11/n1570.html#6.4.4.4p5
>
> Says the following:
>
> "The octal digits that follow the backslash in an octal escape sequence are taken to be part of the construction of a single character for an integer character constant or of a single wide character for a wide character constant. The numerical value of the octal integer so formed specifies the value of the desired character or wide character."
>
> Character constants have a type of int, so 0375
> clearly fits in the range of that.
>
> I guess the problem is that gcc sees this as
>
> const int VBSF_MOUNT_SIGNATURE_BYTE_3 = 0375;
>
> Where as clang sees this as:
>
> const int VBSF_MOUNT_SIGNATURE_BYTE_3 = (char)0375;
>
> Which is a nice subtle incompatibility between the 2 :|
>
>
> With that said, the patch is fine and I have no objections
> against it:
>
> Reviewed-by: Hans de Goede <[email protected]>
>
> Although maybe it is better to actually remove any
> ambiguity and just replace the defines with:
>
> static const u8 VBSF_MOUNT_SIGNATURE_BYTE_0 = 0000;
> static const u8 VBSF_MOUNT_SIGNATURE_BYTE_1 = 0377;
> static const u8 VBSF_MOUNT_SIGNATURE_BYTE_2 = 0376;
> static const u8 VBSF_MOUNT_SIGNATURE_BYTE_3 = 0375;
>
> ?
>
> Regards,
>
> Hans
>
>
>
>
>
>
>
>
>
>
> > fs/vboxsf/super.c:393:21: error: result of comparison of constant -2 with expression of type 'unsigned char' is always false [-Werror,-Wtautological-constant-out-of-range-compare]
> > options[2] == VBSF_MOUNT_SIGNATURE_BYTE_2 &&
> > ~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > fs/vboxsf/super.c:392:21: error: result of comparison of constant -1 with expression of type 'unsigned char' is always false [-Werror,-Wtautological-constant-out-of-range-compare]
> > options[1] == VBSF_MOUNT_SIGNATURE_BYTE_1 &&
> > ~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
> >
> > The problem is that the pointer is of type 'unsigned char' but the
> > constant is a 'char'. My first idea was to change the type of the
> > pointer to 'char *', but I noticed that this was the original code
> > and it got changed after 'smatch' complained about this.
> >
> > I don't know if there is a bug in smatch here, but it sounds to me
> > that clang's warning is correct. Forcing the constants to an unsigned
> > type should make the code behave consistently and avoid the warning
> > on both.
> >
> > Fixes: 9d682ea6bcc7 ("vboxsf: Fix the check for the old binary mount-arguments struct")
> > Cc: Dan Carpenter <[email protected]>
> > Signed-off-by: Arnd Bergmann <[email protected]>
> > ---
> > fs/vboxsf/super.c | 8 ++++----
> > 1 file changed, 4 insertions(+), 4 deletions(-)
> >
> > diff --git a/fs/vboxsf/super.c b/fs/vboxsf/super.c
> > index 4f5e59f06284..84e2236021de 100644
> > --- a/fs/vboxsf/super.c
> > +++ b/fs/vboxsf/super.c
> > @@ -21,10 +21,10 @@
> >
> > #define VBOXSF_SUPER_MAGIC 0x786f4256 /* 'VBox' little endian */
> >
> > -#define VBSF_MOUNT_SIGNATURE_BYTE_0 ('\000')
> > -#define VBSF_MOUNT_SIGNATURE_BYTE_1 ('\377')
> > -#define VBSF_MOUNT_SIGNATURE_BYTE_2 ('\376')
> > -#define VBSF_MOUNT_SIGNATURE_BYTE_3 ('\375')
> > +#define VBSF_MOUNT_SIGNATURE_BYTE_0 (u8)('\000')
> > +#define VBSF_MOUNT_SIGNATURE_BYTE_1 (u8)('\377')
> > +#define VBSF_MOUNT_SIGNATURE_BYTE_2 (u8)('\376')
> > +#define VBSF_MOUNT_SIGNATURE_BYTE_3 (u8)('\375')
> >
> > static int follow_symlinks;
> > module_param(follow_symlinks, int, 0444);
> >

2021-09-27 13:23:14

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH] vboxsf: fix old signature detection

On Mon, Sep 27, 2021 at 3:02 PM Dan Carpenter <[email protected]> wrote:
>
> GCC handles it the same way as Clang. '\377' is -1 but in Sparse it's
> 255. I've added the Sparse mailing list to the CC.

More specifically, ' think '\377' may be either -1 or 255 depending on
the architecture.
On most architectures, 'char' is implicitly signed, but on some others
it is not.

The original code before 9d682ea6bcc7 should have worked either way because
both sides of the comparison were the same 'char' type, marking one of them
as explicitly 'unsigned char' seems to have broken all architectures on which
the type is implicitly 'signed'.

Arnd

2021-09-27 18:35:22

by Linus Torvalds

[permalink] [raw]
Subject: Re: [PATCH] vboxsf: fix old signature detection

On Mon, Sep 27, 2021 at 6:22 AM Arnd Bergmann <[email protected]> wrote:
>
> More specifically, ' think '\377' may be either -1 or 255 depending on
> the architecture.
> On most architectures, 'char' is implicitly signed, but on some others
> it is not.

Yeah. That code is just broken.

And Arnd, your patch may be "conceptually minimal", in that it keeps
thed broken code and makes it work. But it just dials up the oddity to
11.

The proper patch is just this appended thing that stops playing silly
games, and just uses "memcmp()".

I've verified that with sane build configurations, it just generates

testq %rsi, %rsi
je .L25
cmpl $-33620224, (%rsi)
je .L31

for that

if (data && !memcmp(data, VBSF_MOUNT_SIGNATURE, 4)) {

test. With a lot of crazy debug options you'll actually see the
"memcmp()", but the bad code generation is the least of your options
in that case.

Linus


Attachments:
patch.diff (1.21 kB)

2021-09-28 09:41:24

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH] vboxsf: fix old signature detection

Hi Linus,

On 9/27/21 8:33 PM, Linus Torvalds wrote:
> On Mon, Sep 27, 2021 at 6:22 AM Arnd Bergmann <[email protected]> wrote:
>>
>> More specifically, ' think '\377' may be either -1 or 255 depending on
>> the architecture.
>> On most architectures, 'char' is implicitly signed, but on some others
>> it is not.
>
> Yeah. That code is just broken.
>
> And Arnd, your patch may be "conceptually minimal", in that it keeps
> thed broken code and makes it work. But it just dials up the oddity to
> 11.
>
> The proper patch is just this appended thing that stops playing silly
> games, and just uses "memcmp()".
>
> I've verified that with sane build configurations, it just generates
>
> testq %rsi, %rsi
> je .L25
> cmpl $-33620224, (%rsi)
> je .L31
>
> for that
>
> if (data && !memcmp(data, VBSF_MOUNT_SIGNATURE, 4)) {
>
> test. With a lot of crazy debug options you'll actually see the
> "memcmp()", but the bad code generation is the least of your options
> in that case.

I agree that your suggestion is to be the best solution,
so how do we move forward with this, do I turn this into a
proper patch with you as the author and Arnd as Reported-by and
if yes may I add your Signed-off-by to the patch ?

Or do I make myself author and set you as Suggested-by ?

Regards,

Hans

2021-09-28 09:58:51

by Rasmus Villemoes

[permalink] [raw]
Subject: Re: [PATCH] vboxsf: fix old signature detection

On 27/09/2021 15.02, Dan Carpenter wrote:
> GCC handles it the same way as Clang. '\377' is -1 but in Sparse it's
> 255. I've added the Sparse mailing list to the CC.

FTR, while examples are not normative, this:

EXAMPLE 2 Consider implementations that use two's complement
representation for integers and eight bits for objects that have type
char. In an implementation in which type char has the same range of
values as signed char, the integer character constant '\xFF' has the
value -1; if type char has the same range of values as unsigned char,
the character constant '\xFF' has the value +255.

doesn't leave any ambiguity or (implementation|un)-definednes, and
sparse interpreting '\377' as 255 independent of its
target->unsigned_char is a plain bug in sparse.

Rasmus

2021-09-28 10:13:12

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH] vboxsf: fix old signature detection

On Tue, Sep 28, 2021 at 11:40 AM Hans de Goede <[email protected]> wrote:
> On 9/27/21 8:33 PM, Linus Torvalds wrote:
> > On Mon, Sep 27, 2021 at 6:22 AM Arnd Bergmann <[email protected]> wrote:
> >>
> >> More specifically, ' think '\377' may be either -1 or 255 depending on
> >> the architecture.
> >> On most architectures, 'char' is implicitly signed, but on some others
> >> it is not.
> >
> > Yeah. That code is just broken.
> >
> > And Arnd, your patch may be "conceptually minimal", in that it keeps
> > thed broken code and makes it work. But it just dials up the oddity to
> > 11.

Thank you for addressing it. I usually try to avoid overthinking changes
to "unusual" code like this, but your solution is clearly an improvement.

What really threw me off this time is that my first attempt to address
the warning was an exact revert of 9d682ea6bcc7 ("vboxsf: Fix the
check for the old binary mount-arguments struct"), which in turn
came from a tool that is usually correct and and that both Dan
and Al thought the original patch was correct when it looked like
it turned a working (though unusual) implementation into a broken
one.

> I agree that your suggestion is to be the best solution,
> so how do we move forward with this, do I turn this into a
> proper patch with you as the author and Arnd as Reported-by and
> if yes may I add your Signed-off-by to the patch ?

It's already upstream, see d5f6545934c4 ("qnx4: work around gcc
false positive warning bug").

Arnd

2021-09-28 10:33:42

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH] vboxsf: fix old signature detection

Hi,

On 9/28/21 12:11 PM, Arnd Bergmann wrote:
> On Tue, Sep 28, 2021 at 11:40 AM Hans de Goede <[email protected]> wrote:
>> On 9/27/21 8:33 PM, Linus Torvalds wrote:
>>> On Mon, Sep 27, 2021 at 6:22 AM Arnd Bergmann <[email protected]> wrote:
>>>>
>>>> More specifically, ' think '\377' may be either -1 or 255 depending on
>>>> the architecture.
>>>> On most architectures, 'char' is implicitly signed, but on some others
>>>> it is not.
>>>
>>> Yeah. That code is just broken.
>>>
>>> And Arnd, your patch may be "conceptually minimal", in that it keeps
>>> thed broken code and makes it work. But it just dials up the oddity to
>>> 11.
>
> Thank you for addressing it. I usually try to avoid overthinking changes
> to "unusual" code like this, but your solution is clearly an improvement.
>
> What really threw me off this time is that my first attempt to address
> the warning was an exact revert of 9d682ea6bcc7 ("vboxsf: Fix the
> check for the old binary mount-arguments struct"), which in turn
> came from a tool that is usually correct and and that both Dan
> and Al thought the original patch was correct when it looked like
> it turned a working (though unusual) implementation into a broken
> one.
>
>> I agree that your suggestion is to be the best solution,
>> so how do we move forward with this, do I turn this into a
>> proper patch with you as the author and Arnd as Reported-by and
>> if yes may I add your Signed-off-by to the patch ?
>
> It's already upstream, see d5f6545934c4 ("qnx4: work around gcc
> false positive warning bug").

Ah, actually you mean: 9b3b353ef330 ("vboxfs: fix broken legacy mount
signature checking"), but other then that yes you're right it
is already upstream.

Thank you Arnd and thank you Linus.

Regards,

Hans

2021-09-28 10:42:50

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH] vboxsf: fix old signature detection

On Tue, Sep 28, 2021 at 12:31 PM Hans de Goede <[email protected]> wrote:
> On 9/28/21 12:11 PM, Arnd Bergmann wrote:
> > It's already upstream, see d5f6545934c4 ("qnx4: work around gcc
> > false positive warning bug").
>
> Ah, actually you mean: 9b3b353ef330 ("vboxfs: fix broken legacy mount
> signature checking"),

Yes, that's the right one of course.

Arnd