1

After trying the suggested solution for deriving the KASLR offset shift on a previous question on this topic, i realized that the run time address of system_wq is different from that in /boot/System.map-$(uname -r) whether or not KASLR is enabled (although it does remain the same across different KASLR-disabled boots, which obviously doesn't happen on the opposite case).

The following snippet should calculate the sys_call_table address using the run time address of system_wq and the System.map addresses of both system_wq and sys_call_table (assume sysmap_* to contain the corresponding System.map addresses). dmesg outputs are below the snippet.

runtime_sys_call_table = (unsigned long *)
((unsigned long)system_wq - (sysmap_system_wq - sysmap_sys_call_table));

printk("System.map system_wq:             0x%lx\n", sysmap_system_wq);
printk("System.map sys_call_table:        0x%lx\n", sysmap_sys_call_table);
printk("Run time system_wq:               0x%lx\n", (unsigned long)system_wq);
printk("Expected run time sys_call_table: 0x%lx\n", (unsigned long)runtime_sys_call_table);


KASLR enabled

Boot 1:

[  126.922753] [lkm] lkm_init: System.map system_wq:             0xffffffff821204b8
[  127.230661] [lkm] lkm_init: System.map sys_call_table:        0xffffffff81c002a0
[  127.230662] [lkm] lkm_init: Run time system_wq:               0xffff91fcbe40ae00
[  127.230662] [lkm] lkm_init: Expected run time sys_call_table: 0xffff91fcbdeeabe8

Boot 2:

[  140.689652] [lkm] lkm_init: System.map system_wq:             0xffffffff821204b8
[  140.993379] [lkm] lkm_init: System.map sys_call_table:        0xffffffff81c002a0
[  140.993381] [lkm] lkm_init: Run time system_wq:               0xffff9a69be40ae00
[  140.993382] [lkm] lkm_init: Expected run time sys_call_table: 0xffff9a69bdeeabe8


KASLR disabled

Boot 1:

[  143.699539] [lkm] lkm_init: System.map system_wq:             0xffffffff821204b8
[  144.002094] [lkm] lkm_init: System.map sys_call_table:        0xffffffff81c002a0
[  144.002095] [lkm] lkm_init: Run time system_wq:               0xffff88803e40ae00
[  144.002096] [lkm] lkm_init: Expected run time sys_call_table: 0xffff88803deeabe8

Boot 2:

[  133.828917] [lkm] lkm_init: System.map system_wq:             0xffffffff821204b8
[  134.132394] [lkm] lkm_init: System.map sys_call_table:        0xffffffff81c002a0
[  134.132395] [lkm] lkm_init: Run time system_wq:               0xffff88803e40ae00
[  134.132395] [lkm] lkm_init: Expected run time sys_call_table: 0xffff88803deeabe8


Questions

1. Why does the run time address of sys_call_table match that of System.map (which i know because system calls were successfully hooked) when KASLR is disabled while that of system_wq does not?

2. Why does the snippet fail to calculate the run time address of sys_call_table whether or not KASLR is enabled?

3. If it is the case that the run time address of system_wq will differ from that of System.map anyway, then what other exported symbols can be used to derive sys_call_table?

Caio Joca
  • 80
  • 6
  • 1
    Are you sure you're using the _address_ of `system_wq`? – Ian Abbott Nov 27 '19 at 15:00
  • Am i not? In `workqueue.h`, `system_wq` is declared as a `struct workqueue_struct *`, so i believe `(unsigned long)system_wq` casts it's address to `unsigned long` correctly; am i wrong? – Caio Joca Nov 28 '19 at 02:01
  • 1
    The address of `system_wq` is `&system_wq`. You want `(unsigned long)&system_wq`. – Ian Abbott Nov 28 '19 at 10:30
  • Thank you, that solved it; i was unknowingly assuming `system_wq` as having the same reference level as `sys_call_table`. – Caio Joca Nov 28 '19 at 13:35
  • 1
    The difference is that `sys_call_table` has array type, so in most expressions it will decay to a pointer to the first element (`&sys_call_table[0]`), but `system_wq` is a simple (non-array) variable (which happens to have pointer type) so you need to use the `&` operator explicitly. – Ian Abbott Nov 28 '19 at 14:05

1 Answers1

0

Ian Abbott's comment solved my problem and made all questions obsolete. For clarification, my confusion was the fact that system_wq is a simple pointer to struct workqueue_struct, which made me think it already contained the address i wanted; I then thought I only had to cast it as I did with sys_call_table, which is actually an array of pointers, making (unsigned long)sys_call_table a correct address for sys_call_table whereas (unsigned long)&system_wq would be for system_wq.

Caio Joca
  • 80
  • 6