0

I am beginning to develop a kernel module with inline assembly, I am trying to perform the write syscall in order to write in a file. It is compiling well (in addition, in a C program works correctly), but when I load the module It drop a segmentation fault and when I look in the diagnostic message (dmesg) i see the following:

[  672.687568] BUG: stack guard page was hit at ffffb8a601d13fa8 (stack is ffffb8a601d14000..ffffb8a601d17fff)
[  672.687577] kernel stack overflow (double-fault): 0000 [#1] SMP
...
[  672.777032]  [<ffffffffa50fda16>] ? SYSC_finit_module+0xc6/0xf0
[  672.777396]  [<ffffffffa55ebebb>] ? system_call_fast_compare_end+0xc/0x9b
[  672.777765] Code: 48 89 e7 48 8b 74 24 78 48 c7 44 24 78 ff ff ff ff e8 28 09 a7 ff e9 53 02 00 00 0f 1f 00 0f 1f 00 66 0f 1f 44 00 00 48 83 c4 88 <e8> 7e 01 00 00 48 89 e7 48 8b 74 24 78 48 c7 44 24 78 ff ff ff 
[  672.779059] RIP  [<ffffffffa55ed27d>] page_fault+0xd/0x30
[  672.779481]  RSP <ffffb8a601d13fb8>
[  672.779901] fbcon_switch: detected unhandled fb_set_par error, error code -16

The code of the kernel module is the following:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>

MODULE_LICENSE("GPL");
int example_init(void);
void example_exit(void);
module_init(example_init);
module_exit(example_exit);


int example_init(void) {
    char *file = "/root/test2";
    char *msg = "AAAAAA\n";

    asm( "mov eax, 0x2;"
        "mov rdi, %0;" 
        "mov rsi, 0x441;"
        "xor rdx, rdx;"
        "syscall;"
        "mov rdi, rax;"
        "mov eax, 0x1;"
        "mov rsi, %1;"
        "mov rdx, 7;"
        "syscall;"
        "mov eax, 0x3;"
        "syscall;"
        : "=m" (file), "=m" (msg)
    );
        printk("Example: module loaded.\n");
        return 0;
}

void example_exit(void) {
       printk("Example: module removed\n");
}

I know that the failure is in the syscall instruction because I tried without syscall instruction and the assembly code works correctly and just does a segmentation fault when syscall is launched.

sinkmanu
  • 1,034
  • 1
  • 12
  • 24
  • 4
    Not sure whether calling syscall from the kernel space should **ever work**. Instead, call the kernel's function, which implements specific syscall (they are defined with `SYSCALL_DEFINE0` - `SYSCALL_DEFINE6` macros). But this way do not work for every syscall. – Tsyvarev Mar 07 '18 at 21:48
  • Even if you were doing this in user-space where this could work, your code is clunky and inefficient. Use constraints to ask for the string pointers in registers. Use `mov eax, 2` like a normal person; that's the same length as your inefficient 3-byte `xor rax,rax` + 2 byte `mov al, 2`. (Or 1 byte longer than [if you'd used `xor eax,eax`](https://stackoverflow.com/questions/33666617/what-is-the-best-way-to-set-a-register-to-zero-in-x86-assembly-xor-mov-or-and)). Related: https://stackoverflow.com/questions/45105164/set-all-bits-in-cpu-register-to-1-efficiently. – Peter Cordes Mar 07 '18 at 22:14
  • @PeterCordes, you are right, anyway, it is not the question. I found this that it is a quite similar https://stackoverflow.com/questions/15841327/can-we-call-system-call-in-kernel-space – sinkmanu Mar 07 '18 at 22:27
  • 2
    The SYSCALL instruction fundamentally doesn't work from kernel as it destroys the value in CS without saving the previous value anywhere. The kernel has no way of knowing whether the SYSCALL instruction was invoked from user or kernel code so always assumes that it was invoked from user code. – Ross Ridge Mar 08 '18 at 01:10
  • @RossRidge Can you add this as "answer"? – Martin Rosenau Mar 08 '18 at 05:55
  • 1
    @MartinRosenau That by itself is not really an answer. That only says why you can't use the `syscall` instruction, but you in theory could call syscall instructions directly. Unfortunately that may not be possible either because many of them are not available because they may not exported. sys_read and sys_write in particular may not be available if referenced. As well if they are available then you have to use `get_fs` to get old FS selector, set FS to KERNEL_DS with `set_fs()` if passing pointers to the system call functions. When finished you restore FS to its original value. – Michael Petch Mar 08 '18 at 06:34
  • Of course reading and writing files from kernel space is opening yourself up to another vector of attack. Not sure it is worth it. – Michael Petch Mar 08 '18 at 06:37
  • @MichaelPetch I was guessing that. Could you provide the source of this information and make an answer? – sinkmanu Mar 08 '18 at 07:39

1 Answers1

1

As noted by @RossRidge in the comments, Linux kernel is not designed for syscalls being used from the kernel code. So syscall instruction shouldn't be used in the kernel code.

Some functionality obtained by syscalls has in-kernel alternative. E.g, for open a file in the kernel one may use filp_open, and for writing a file - vfs_write. See that question for more information about using files in the kernel code.

Tsyvarev
  • 60,011
  • 17
  • 110
  • 153