You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: lkmpg.tex
+94Lines changed: 94 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -1204,6 +1204,100 @@ \section{System Calls}
1204
1204
So, if we want to change the way a certain system call works, what we need to do is to write our own function to implement it (usually by adding a bit of our own code, and then calling the original function) and then change the pointer at \cpp|sys_call_table| to point to our function.
1205
1205
Because we might be removed later and we don't want to leave the system in an unstable state, it's important for \cpp|cleanup_module| to restore the table to its original state.
1206
1206
1207
+
To modify the content of \cpp|sys_call_table|, we need to consider the control register.
1208
+
A control register is a processor register that changes or controls the general behavior of the CPU.
1209
+
For x86 architecture, the \verb|cr0| register has various control flags that modify the basic operation of the processor.
1210
+
The \verb|WP| flag in \verb|cr0| stands for write protection.
1211
+
Once the \verb|WP| flag is set, the processor disallows further write attempts to the read-only sections
1212
+
Therefore, we must disable the \verb|WP| flag before modifying \cpp|sys_call_table|.
1213
+
Since Linux v5.3, the \cpp|write_cr0| function cannot be used because of the sensitive \verb|cr0| bits pinned by the security issue, the attacker may write into CPU control registers to disable CPU protections like write protection.
1214
+
As a result, we have to provide the custom assembly routine to bypass it.
1215
+
1216
+
However, \cpp|sys_call_table| symbol is unexported to prevent misuse.
1217
+
But there have few ways to get the symbol, manual symbol lookup and \cpp|kallsyms_lookup_name|.
1218
+
Here we use both depend on the kernel version.
1219
+
1220
+
Because of the \textit{control-flow integrity}, which is a technique to prevent the redirect execution code from the attacker, for making sure that the indirect calls go to the expected addresses and the return addresses are not changed.
1221
+
Since Linux v5.7, the kernel patched the series of \textit{control-flow enforcement} (CET) for x86, and some configurations of GCC, like GCC versions 9 and 10 in Ubuntu, will add with CET (the \verb|-fcf-protection| option) in the kernel by default.
1222
+
Using that GCC to compile the kernel with retpoline off may result in CET being enabled in the kernel.
1223
+
You can use the following command to check out the \verb|-fcf-protection| option is enabled or not:
GNU C17 (Ubuntu 9.3.0-17ubuntu1~20.04) version 9.3.0 (x86_64-linux-gnu)
1234
+
...
1235
+
\end{verbatim}
1236
+
But CET should not be enabled in the kernel, it may break the Kprobes and bpf.
1237
+
Consequently, CET is disabled since v.11.
1238
+
To guarantee the manual symbol lookup worked, we only use up to v5.4.
1239
+
1240
+
Unfortunately, since Linux v5.7 \cpp|kallsyms_lookup_name| is also unexported, it needs certain trick to get the address of \cpp|kallsyms_lookup_name|.
1241
+
If \cpp|CONFIG_KPROBES| is enabled, we can facilitate the retrieval of function addresses by means of Kprobes to dynamically break into the specific kernel routine.
1242
+
Kprobes inserts a breakpoint at the entry of function by replacing the first bytes of the probed instruction.
1243
+
When a CPU hits the breakpoint, registers are stored, and the control will pass to Kprobes.
1244
+
It passes the addresses of the saved registers and the Kprobe struct to the handler you defined, then executes it.
1245
+
Kprobes can be registered by symbol name or address.
1246
+
Within the symbol name, the address will be handled by the kernel.
1247
+
1248
+
Otherwise, specify the address of \cpp|sys_call_table| from \verb|/proc/kallsyms| and \verb|/boot/System.map| into \cpp|sym| parameter.
1249
+
Following is the sample usage for \verb|/proc/kallsyms|:
1250
+
\begin{verbatim}
1251
+
$ sudo grep sys_call_table /proc/kallsyms
1252
+
ffffffff82000280 R x32_sys_call_table
1253
+
ffffffff820013a0 R sys_call_table
1254
+
ffffffff820023e0 R ia32_sys_call_table
1255
+
$ sudo insmod syscall.ko sym=0xffffffff820013a0
1256
+
\end{verbatim}
1257
+
1258
+
Using the address from \verb|/boot/System.map|, be careful about \verb|KASLR| (Kernel Address Space Layout Randomization).
1259
+
\verb|KASLR| may randomize the address of kernel code and data at every boot time, such as the static address listed in \verb|/boot/System.map| will offset by some entropy.
1260
+
The purpose of \verb|KASLR| is to protect the kernel space from the attacker.
1261
+
Without \verb|KASLR|, the attacker may find the target address in the fixed address easily.
1262
+
Then the attacker can use return-oriented programming to insert some malicious codes to execute or receive the target data by a tampered pointer.
1263
+
\verb|KASLR| mitigates these kinds of attacks because the attacker cannot immediately know the target address, but a brute-force attack can still work.
1264
+
If the address of a symbol in \verb|/proc/kallsyms| is different from the address in \verb|/boot/System.map|, \verb|KASLR| is enabled with the kernel, which your system running on.
0 commit comments