1

I'm writing a simple syscall based on this tutorial, and boot into the new kernel with my syscall in it, but when I compile a test, and execute it, it cause segmentation fault (core dumped). My my_syscall.h (hello.c equivalent in the tutorial) looks like this.

#include <linux/module.h> 
#include <linux/kernel.h> 
#include <linux/sched.h>  
#include <asm/current.h>

struct smallStruct {
    int integer;
    char str[20];
};

struct bigStruct {
    long id;
    struct smallStruct a;
    struct smallStruct b;
    struct smallStruct c;
};

asmlinkage long test_syscall(int pid, struct bigStruct *info)
{
    info->id = pid;

    info->a.integer = 0;
    info->a.str[0] = 'A';
    info->a.str[1] = '\0';

    info->b.integer = 1;
    info->b.str[0] = 'B';
    info->b.str[1] = '\0';

    info->c.integer = 2;
    info->c.str[0] = 'C';
    info->c.str[1] = '\0';

    return 0;
}

I actually try to write a syscall that get some information and store back into *info, and I need the str in the smallStruct, but everytime I try to modify the str, it cause segmentation fault (core dumped), and when I remove those modification to the str to temporarily avoid core dump, it still doesn't work as I expected. This is what my test file looks like:

#include <sys/syscall.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

struct smallStruct
{
    int integer;
    char str[20];
};

struct bigStruct
{
    long id;
    struct smallStruct a;
    struct smallStruct b;
    struct smallStruct c;
};

int main()
{
    long sys_return_value;
    struct bigStruct info;
    sys_return_value = syscall(548, 1, &info);
    printf("id = %ld, return %ld\n", info.id, sys_return_value);
    return 0;
}

It seems that the info in my test isn't modified by the syscall at all. I even use printk in the my_syscall.h and the pid I pass to my syscall isn't correct at all. this is what the printk print in dmesg

this is what the <code>printk</code> print in <code>dmesg</code>

The id in my_syscall is supposed to be the pid, and it is passed in my test with the value of 1. (syscall(548, 1, &info);)

I know it is quite long, but I would be grateful if anyone can explain what is wrong with my implement, Thank you.

Barmar
  • 741,623
  • 53
  • 500
  • 612
Felis
  • 11
  • 2
  • 2
    Do not post text as pictures. –  May 19 '20 at 19:59
  • 2
    Take a look at how existing syscalls handle user pointers. – Thomas Jager May 19 '20 at 20:01
  • to represent processes id (which is pid I guess?) you can use `p_id` data type. It translates to integer, not `long` – Roim May 19 '20 at 20:03
  • 1
    Look into `copy_to_user`. – Joseph Sible-Reinstate Monica May 19 '20 at 20:41
  • What exactly are you printk'ing in your test? Please post the same code you are using for the test. – Nate Eldredge May 19 '20 at 20:48
  • @roim Yes, but I cannot pass the value from the ```syscall(548,1,&info)``` to the syscall function, you can see that I print the value of ```pid``` through the ```info->id```. @nate-eldredge I print fields of the ```bigStruct```. – Felis May 20 '20 at 12:49
  • See https://stackoverflow.com/a/53765421/634919 for another possible issue that could explain why the `pid` parameter is wrong. Note the importance of the `SYSCALL_DEFINEx` macros. It appears your tutorial is inaccurate or incomplete (the issue doesn't affect their example because their system call takes no arguments). – Nate Eldredge May 21 '20 at 01:50

1 Answers1

1

You are passing a user pointer that is part of the part of the process stack to the kernel. This is bad practice and will never work because kernel memory and user memory are separate entities. You need to use System Apis to pass pointer to and from user to kernel memory. Look at copy_to_user and copy_from_user functions. You can also put ioctl method into use which creates a backdoor between user/application and kernel

ichaudry
  • 17
  • 1
  • Thank you a lot, I'll try that, and I'm really grateful for your help, I hope you have a nice day ^^ – Felis May 20 '20 at 08:44
  • Can you explain why the "syscall(548, 1, &info);" the ```pid``` I get is supposed to be 1, but when I ```printk``` on ```dmesg```, it has random value like in the picture, please? I see many people do that and they successfully pass the value. – Felis May 20 '20 at 12:21