Nitinkumar Ambekar
Nitinkumar Ambekar

Reputation: 1009

Why kernel get panic here after accessing system call table in a kernel module for 32 bit systems?

I have a kernel module, which removes write protected bit to modify system call table, in order to hook any system call - say sys_rmdir. This module works as expected for 64 bit systems, but for 32 bit systems why kernel get panic and gives oops after accessing address of system call table?

The module has problem at this point:

#ifdef __x86_64__
#define CR0_WP 0x00010000   // Write Protect Bit (CR0:16)
#else
#define CR0_WP 0x10000      // Write Protect Bit (CR0:16)
#endif

...

unsigned long cr0 = read_cr0();
write_cr0(cr0 & ~CR0_WP);

...

unsigned long addr = (unsigned long)syscall_table; //Where syscall_table is c059a170, same exists in /proc/kallsyms
if(set_memory_rw(PAGE_ALIGN(addr) - PAGE_SIZE, 3))
{
        ...
        return -1;
}

orig_sys_rmdir = syscall_table[__NR_rmdir]; //where orig_sys_rmdir is declared as : long (*orig_sys_rmdir)(const char *filename);
syscall_table[__NR_rmdir] = my_sys_rmdir; //Kerenl goes panic here, I guess.  my_sys_rmdir is a simple wrapper for sys_rmdir
...

The kernel version is 2.6.X-X-generic, Ubuntu 10.04. What could be the reason of this failure only on 32 bit systems?

Thanks for your time.

EDIT:

Error log:

BUG: unable to handle kernel NULL pointer dereference at 00000005
IP: [<c035834a>] strncmp+0x1a/0x40
*pde = 32090067 *pte = 00000000
Oops: 0000 [#2] SMP
imklog 4.2.0, log source = /proc/kmsg started.
[    0.000000] Initializing cgroup subsys cpuset
[    0.000000] Initializing cgroup subsys cpu
[    0.000000] Linux version 2.6.32-74-generic (buildd@allspice) (gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5.1) ) #142-Ubuntu SMP Tue Apr 28 10:02:35 UTC 2015 (Ubuntu 2.6.32-74.142-generic 2.6.32.63+drm33.26)

Upvotes: 1

Views: 713

Answers (2)

incompetent
incompetent

Reputation: 1822

@NTN this is for the answer asked in in your answer

I don't know why and how the same code worked on 64 bit systems, but not on 32 bit systems.

Asmlinkage tag tell the compiler to see the parametrs on cpu stack. if you do not use this tag then compiler will see in the registers according to calling conventions. for 32 bit systems you can pass 3 parameters in registers %eax,%ecx,%edx while others on stack (if any). but in 64 bit systems you can use 6 registers %rdi, %rsi, %rdx, %rcx, %r8, %r9.

that implies that your syscall is using more than 3 parameters. when you pass them with out asmlinkage, compiler is not able to locate all parameters on 32 bit systems but in 64 bits systems it locate them comfortably. when you use asmlinkage then all parametrs are passed through cpu stack so your code is successful.

Upvotes: 2

Nitinkumar Ambekar
Nitinkumar Ambekar

Reputation: 1009

I found cause of this problem, thus answering my own question. This would help to someone else, if he/she may face the same problem.

I had declared orig_sys_rmdir as:

long (*orig_sys_rmdir)(const char *filename); //Wrong!!!

which was wrong of course, it was missing the asmlinkage keyword, it must be

asmlinkage long (*orig_sys_rmdir)(const char *filename); 

The same happened with

long my_sys_rmdir(const char *filename) {...} //wrong!!!

which must be

asmlinkage long my_sys_rmdir(const char *filename){...}

I don't know why and how the same code worked on 64 bit systems, but not on 32 bit systems. I hope someone will elaborate on this in more detail; answers will be appreciated.

Upvotes: 1

Related Questions