libbpf: Fix sign expansion bug in btf_dump_get_enum_value()
authorDan Carpenter <dan.carpenter@oracle.com>
Tue, 19 Jul 2022 09:49:34 +0000 (12:49 +0300)
committerDaniel Borkmann <daniel@iogearbox.net>
Thu, 21 Jul 2022 12:24:18 +0000 (14:24 +0200)
The code here is supposed to take a signed int and store it in a signed
long long. Unfortunately, the way that the type promotion works with
this conditional statement is that it takes a signed int, type promotes
it to a __u32, and then stores that as a signed long long. The result is
never negative.

This is from static analysis, but I made a little test program just to
test it before I sent the patch:

  #include <stdio.h>

  int main(void)
  {
        unsigned long long src = -1ULL;
        signed long long dst1, dst2;
        int is_signed = 1;

        dst1 = is_signed ? *(int *)&src : *(unsigned int *)0;
        dst2 = is_signed ? (signed long long)*(int *)&src : *(unsigned int *)0;

        printf("%lld\n", dst1);
        printf("%lld\n", dst2);

        return 0;
  }

Fixes: d90ec262b35b ("libbpf: Add enum64 support for btf_dump")
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Link: https://lore.kernel.org/bpf/YtZ+LpgPADm7BeEd@kili
tools/lib/bpf/btf_dump.c

index 400e84f..627edb5 100644 (file)
@@ -2045,7 +2045,7 @@ static int btf_dump_get_enum_value(struct btf_dump *d,
                *value = *(__s64 *)data;
                return 0;
        case 4:
-               *value = is_signed ? *(__s32 *)data : *(__u32 *)data;
+               *value = is_signed ? (__s64)*(__s32 *)data : *(__u32 *)data;
                return 0;
        case 2:
                *value = is_signed ? *(__s16 *)data : *(__u16 *)data;