volatilityfoundation / dwarf2json

convert ELF/DWARF symbol and type information into vol3's intermediate JSON
Other
104 stars 28 forks source link

bitfields have wrong bit position #25

Closed gcmoreira closed 3 years ago

gcmoreira commented 4 years ago
struct printk_log {
  u64 ts_nsec;    /* timestamp in nanoseconds */
  u16 len;    /* length of entire record */
  u16 text_len;   /* length of text buffer */
  u16 dict_len;   /* length of dictionary buffer */
  u8 facility;    /* syslog facility */
  u8 flags:5;   /* internal record flags */
  u8 level:3;   /* syslog level */
#ifdef CONFIG_PRINTK_CALLER
  u32 caller_id;            /* thread id or processor id */
#endif
}

Debugging the Linux kernel I got:

>>> p msg->flags
$14 = 6 '\006'

>>> p msg->level
$15 = 5 '\005'

>>> p *(unsigned char*)&msg->flags
$16 = 166 '\246'

Debugging Volatility we can see we got wrong values:

> msg.flags
20
> msg.level
6

From the ISF we can see that the bit_position of flags and level are 3 and 0 respectively.

    "printk_log": {
        ...
        "flags": {
          "type": {
            "bit_length": 5,
            "bit_position": 3,
            "kind": "bitfield",
            "type": {
              "kind": "base",
              "name": "unsigned char"
            }
          },
          "offset": 15
        },
        "level": {
          "type": {
            "bit_length": 3,
            "bit_position": 0,
            "kind": "bitfield",
            "type": {
              "kind": "base",
              "name": "unsigned char"
            }
          },
          "offset": 15
        },
    ...
    }

So, due to the wrong ISF bit_position values, Volatility seems to be doing the following:

>>> 166 & 0b111
6
>>> 166>>3 & 0b11111
20

OS Debug Symbols: Linux / Ubuntu 18.10 Kernel: 4.18.0-10-generic Kernel debug symbols package: linux-image-unsigned-4.18.0-10-generic-dbgsym

linux-image-4.18.0-10-generic.zip

ikelos commented 4 years ago

So, based on https://github.com/volatilityfoundation/volatility3/blob/master/volatility/framework/objects/__init__.py#L394 and https://github.com/volatilityfoundation/volatility3/blob/master/volatility/framework/symbols/intermed.py#L399, volatility counts from the least significant bit (LSB) since. So we have:

start_bit = bit_position
end_bit = bit_position + bit_length

which would mean that based on the ISF, I would expect Flags (F) and Levels (L) to be packed in the following way:

76543210
FFFFFLLL

According to http://dwarfstd.org/doc/dwarf_1_1_0.pdf, bit field offsets are from the left most/most-significant bit (MSB), not the LSB. I'd suggest the least disruption would be to translate the DWARF values based on AT_byte_size. I think the calculation is essentially:

max_position = (AT_byte_size * 8) - 1
bit_position = max_position - AT_bit_offset
bit_length = AT_bit_size

Hope this helps?

ilch1 commented 3 years ago

@mkonshie has created a fix for this issue. @gcmoreira could verify that his PR https://github.com/volatilityfoundation/dwarf2json/pull/26 solves your original issue?

gcmoreira commented 3 years ago

Hi @ilch1, yes it does.

Continuing with the example I provided above, the new ISF for printk_log struct is:

    "printk_log": {
...
        "flags": {
          "type": {
            "bit_length": 5,
            "bit_position": 0,
            "kind": "bitfield",
            "type": {
              "kind": "base",
              "name": "unsigned char"
            }
          },
          "offset": 15
        },
...
        "level": {
          "type": {
            "bit_length": 3,
            "bit_position": 5,
            "kind": "bitfield",
            "type": {
              "kind": "base",
              "name": "unsigned char"
            }
          },
          "offset": 15
        },

Based on the above parameters I got the correct values:

flags
>>> 166 & 0b11111
6

level
>>> 166>>5 & 0b111
5

Thanks @mkonshie for the PR

ilch1 commented 3 years ago

@gcmoreira, thanks for confirming! This has now been merged.