Replace system call in linux kernel 3
I would recommend using kprobes for this kind of job, you can easily break on any kernel address (or symbol...) and alter the execution path, all of this at runtime, with a kernel module if you need to :)
Kprobes work by dynamically replacing an instruction (e.g. first instruction of your syscall entry) by a break (e.g. int3 on x86). Inside the do_int3 handler, a notifier notifies kprobes, which in turn passes the execution to your registered function, from which point you can do almost anything.
A very good documentation is given in Documentation/kprobes.txt so as a tiny example in samples/kprobes/kprobes_example.c (in this example they break on do_fork to log each fork on the system). It has a very simple API and is very portable nowdays.
Warning: If you need to alter the execution path, make sure your kprobes are not optimized (i.e. a jmp instruction to your handler replaces the instruction you break onto instead of an int3) otherwize you won't be able to really alter the execution easily (after the ret of your function, the syscall function will still be executed as usual). If you are only interested in tracing, then this is fine and you can safely ignore this issue.
How to define a system call in Linux with non-default return type?
Returning long
is the only proper way for a system call in Linux.
There is no way for a system call to return a value, which size differs from the size of long
.
Do you expect ssize_t
to have the same size as long
on all platforms? If yes (this is a correct expectation), then there is no reason to prefer ssize_t
over long
. If you are not sure that your return type will fit to long
on every platform, then you simply cannot use this return type.
For example, from the C standard you knows, that read function returns ssize_t
. But read
system call has long
as return type (it is defined using DEFINE_SYSCALL
macro):
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
{
struct fd f = fdget(fd);
ssize_t ret = -EBADF;
if (f.file) {
loff_t pos = file_pos_read(f.file);
ret = vfs_read(f.file, buf, count, &pos);
file_pos_write(f.file, pos);
fdput(f);
}
return ret;
}
Note, that despite on long
being return type of the system call, the above implementation returns a value of type ssize_t
.
How to implement my own system call without recompiling the Linux kernel?
You can't.
Without recompiling the kernel, all you can do is build and load kernel modules, and kernel modules cannot add new system calls.
Overriding functionality with modules in Linux kernel
I realise that the question is three years old, but for the benefit of other people trying to do this sort of thing, the kernel has an interface called kprobes to do just what you needed.
Related Topics
Using "And" in Bash While Loop
Short Command to Find Total Size of Files Matching a Wild Card
Opening Default Text Editor in Bash
What Is The Equivalent of /Proc/Cpuinfo on Freebsd V8.1
Jenkins Failed to Start in Linux
How to Set Default Arguments for "Ls" in Linux
Amazon Ec2 Lost Private Key, How to Get Access to The Server
Why Is "Autoreconf" Not Used Often
Runner Is Not Healthy and Will Be Disabled
How to List Dependencies of C/C++ Static Library
Git Clone Fails: Server Certificate Verification Failed
Customize Tab Completion in Shell
How to Execute The Command 'Appcfg Rollback'