0

These are the steps I followed.

1) I was running on 4.15.0 kernel so I updated to more recent kernel.

wget https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.17.4.tar.xz

2)Extracted the kernel source code using

  sudo tar -xvf linux-4.17.4.tar.xz -C/usr/src/

3) In cd /usr/src/linux-4.17.4/ created a new directory called it

sub

Then created

sub.c

inside

sub

directory.

In

sub.c

I wrote the code to subtract y from x if (y>x) or else return 0; Here x is Integer and y is double.

#include <linux/kernel.h>

asmlinkage int sys_sub(int x,double y)
{
    printk("working...");
    if(y>x){
        return ((int)y-x);}
    else
        return 0;
}

4) created a Makefile in the same sub directory and added obj-y := sub.o

5) In

/usr/src/linux-4.17.4

opened Makefile and modified the core-y line to

core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ sub/

6) Then in

cd arch/x86/entry/syscalls/

I opened

gedit syscall_64.tbl

and as 548th system call I entered

548       64        hello          sys_sub

7) In

cd include/linux/

I opened

gedit syscalls.h

and added

asmlinkage int sys_sub(int x,double y);

as the last line just before endif

8) I made sure ext4 is chosen in

sudo make menuconfig

9) I compiled the kernel using

sudo make modules_install install

10) performed

shutdown -r now

11) Checked

uname -r

to make sure that I'm running

4.17.4

indeed which I was.

12) I created a C program to check the system call

#include <stdio.h>
#include <linux/kernel.h>
#include <sys/syscall.h>
#include <unistd.h>
int main()
{
      int res = syscall(548,10,44);
         printf("System call sys_sub returned %d ", res);
return 0;

}

But it is only returning

System call sys_sub returned 0

and

dmesg

shows Hello World for some reason. Please help me. What am I doing wrong?

Edit:

I made necessary changes in my code as per the comments I read. Now my system call code looks like this:

#include <linux/kernel.h>

asmlinkage long sys_sub(int a,int b)
{
        printk("System call is working...\n");
        printk("Inputs are %d and %d",a,b);
        if(b>a)
    {
        int c= b-a;
        printk("Answer is %d",c);
        return c;   
    }
    printk("Answer is 0");
    return 0;
}

I added some print statements to make sure that the system calls are correctly invoked. I recompiled the kernel and ran again and now I'm getting

dmesg

output as

System call is working... Inputs are 1114685272 and 1114685272 Answer is 0

Seems like the kernel is getting random junk values instead of the parameters that I'm passing which makes it to always fail the if loop. The random values for both parameters seems to always be the same! I dont know where I'm going wrong now.

honest w
  • 11
  • 2
  • It smells like the kernel wrongly operates `double` argument, because it isn't intended to work with floating-point operations. Try to replace `double` with `int` or `long`. – Tsyvarev Feb 03 '19 at 13:56
  • Does this answer your question? [System call hooking example arguments are incorrect](https://stackoverflow.com/questions/59851520/system-call-hooking-example-arguments-are-incorrect) – Tsyvarev Jul 03 '21 at 08:40
  • Correct way for declare a system call function is using one of `SYSCALL_DEFINE*` macros. E.g. the function for your `sub` syscall could be defined as `SYSCALL_DEFINE2(sub, int, a, int, b)`. Being declared with that macro, a syscall would work both for older and new Linux kernels. – Tsyvarev Jul 03 '21 at 08:45

1 Answers1

0

In one internet article it is mentioned to compile whole kernel and then modules_install. Also return of system call has to be long instead of int. unistd.h file needs some changes for new system call. The article is for 2.6 kernel but can be referred at http://www.tldp.org/HOWTO/html_single/Implement-Sys-Call-Linux-2.6-i386/

anand
  • 163
  • 7