I don't know if it's related to SO. I know that when I use the Linux kernel panic function, its job is to freeze my system, but it takes 1 argument, a message. Where can I actually see the message if my system is completely frozen and I force shutdown my PC by holding the power-off button?
main.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h> // panic
MODULE_LICENSE("GPL");
static int __init initialization_function(void)
{
panic("Module: my message!\n");
return 0;
}
static void __exit cleanup_funcion(void)
{
printk(KERN_INFO "Module: Cleanup done, exiting.\n");
}
module_init(initialization_function);
module_exit(cleanup_funcion);
By the way, I don't know how can I see the actual oops message, where and how can I see it?
It goes to the kernel console, the same place where printk() message goes. There is a screenshot in Wikipedia article on kernel panic:
Usually, you will be able to see it if the kernel panic happens at boot time.
As for what happens if you have a running desktop system, unfortunately I don't remember. Either you won't see it, or X/Wayland server will crash and you will see the message it in the console.
As you have noticed yourself, this is pretty tricky since the system gets frozen. What you can do is to have a look in the system log after reboot. Exactly how that is done depends on the distribution. On a system with systemd you can use journalctl -xe.
Related
I am making an online code judge using Replit, and I want to use seccomp to securely run submitted code.
Through reading a few tutorials, I have made a simple test program to test seccomp:
#include <stdio.h>
#include <unistd.h>
#include <sys/prctl.h>
#include <linux/seccomp.h>
int main(){
prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT);
printf("Message #1\n");
fork();
printf("Message #2\n");
}
When I run the program, Message #2 prints twice, which must mean seccomp didn't do it's job of stopping the fork. When I investigate using strace, I notice the following message within the output, though I am not sure what to do with it:
...
prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT) = -1 EINVAL (Invalid argument)
...
How can I fix this problem, and get seccomp running in strict mode? I do not own a Linux machine, so I am not sure if this problem is specific to Replit, or I am doing something wrong.
Seccomp is already in use on replit. Make your program do prctl(PR_GET_SECCOMP);, or check /proc/self/status, and you'll see it's already active and in filter mode. While I don't see anything about that in prctl's man page, I do in seccomp's (which fails the same way if you try syscall(SYS_seccomp, SECCOMP_SET_MODE_STRICT, 0, NULL);):
EINVAL A secure computing mode has already been set, and
operation differs from the existing setting.
So if you want to use seccomp strict mode, you'll need to do so somewhere else. Setting up a Linux VM on your computer is easy and free, so that's what I'd recommend.
Short Background
I'm currently writing a linux kernel module as a project to better understand linux kernel internals. I've written 'hello world'-type modules before, but I want to get beyond that, so I'm trying to replace some common system calls like open, read, write, and close with my own so that I can print a bit more information into the system log.
Some content I found while searching was either pre-2.6 kernel, which is not useful because the sys_call_table symbol stopped being exported starting on kernel 2.6.x. On the other hand, those that I found for 2.6.x or later appear seem to have problems of their own, even though they apparently worked at the time.
One particular O'Reilly article, which I found on the sys_call_table in linux kernel 2.6.18 post, suggests that what I'm trying to do ought to work, but it isn't. (Specifically, see the Intercepting sys_unlink() Using System.map section.)
I also read through the Linux Kernel: System call hooking example and Kernel sys_call_table address does not match address specified in system.map which, while somewhat informative, were not useful for me.
Problems and Questions
Part 1 - Unexpected Address Mismatch
I'm using Linux kernel 4.2.0-16-generic on a Kubuntu 15.10 x86_64 architecture installation. Since the sys_call_table symbol is no longer exported, I grepped the address from the system map file:
# grep 'sys_call_table' < System.map-4.2.0-16-generic
ffffffff818001c0 R sys_call_table
ffffffff81801580 R ia32_sys_call_table
With this in hand, I added the following line to my kernel module:
static unsigned long *syscall_table = (unsigned long *) 0xffffffff818001c0;
Based on this, I was expecting that a simple check would actually confirm that I was actually pointing to the location I thought I was pointing to, i.e. the base address of the kernel's unexported sys_call_table. So, I wrote a simple check like the one below into the module's init function to verify:
if(syscall_table[__NR_close] != (unsigned long *)sys_close)
{
pr_info("sys_close = 0x%p, syscall_table[__NR_close] = 0x%p\n", sys_close, syscall_table[__NR_close]);
return -ENXIO;
}
This check failed and different addresses were printed in the log.
I was not expecting the body of this if statement to get executed because I thought the address returned by syscall_table[__NR_close] would be the same as that of sys_close, but it does enter.
Q1: Have I missed something so far regarding the expected address-based comparison? If so, what?
Part 2 - Partially Successful?
If I remove this check, it seems I'm partially successful, because, apparently, I can at least replace the read call successfully using the code below:
static asmlinkage ssize_t (*original_read)(unsigned int fd, char __user *buf, size_t count);
// ...
static void systrap_replace_syscalls(void)
{
pr_debug("systrap: replacing system calls\n");
original_read = syscall_table[__NR_read];
original_write = syscall_table[__NR_write];
original_close = syscall_table[__NR_close];
write_cr0(read_cr0() & ~0x10000);
syscall_table[__NR_read] = systrap_read;
syscall_table[__NR_write] = systrap_write;
syscall_table[__NR_close] = systrap_close;
write_cr0(read_cr0() | 0x10000);
pr_debug("systrap: system calls replaced\n");
}
My replacement functions simply print a message and forward the call to the actual system call. For example, the read replacement function's code is below:
static asmlinkage ssize_t systrap_read(unsigned int fd, char __user *buf, size_t count)
{
pr_debug("systrap: reading from fd = %u\n", fd);
return original_read(fd, buf, count);
}
And the system log shows the following output when I insmod and rmmod the module:
kernel: [23226.797460] systrap: setting up module
kernel: [23226.797462] systrap: replacing system calls
kernel: [23226.797464] systrap: system calls replaced
kernel: [23226.797465] systrap: module setup complete
kernel: [23226.864198] systrap: reading from fd = 4279272912
<similar output ommitted for brevity>
kernel: [23235.560663] systrap: reading from fd = 2835745072
kernel: [23235.564774] systrap: reading from fd = 861079840
kernel: [23235.564986] systrap: cleaning up module
kernel: [23235.564990] systrap: trying to restore system calls
kernel: [23235.564993] systrap: restored sys_read
kernel: [23235.564995] systrap: restored sys_write
kernel: [23235.564997] systrap: restored sys_close
kernel: [23235.565000] systrap: system call restoration attempt complete
kernel: [23235.565002] systrap: module cleanup complete
I can let it run for a long time and, oddly enough, I never observe entries for the write and close function calls --only for the reads, which is why I thought I was only partially successful.
Q2: Have I missed something regarding the replaced system calls? If so, what?
Part 3 - Unexpected Error Message on rmmod Command
Even though the module seems to operate normally, I always get the following error when I rmmod the module from the kernel:
rmmod: ERROR: ../libkmod/libkmod.c:506 lookup_builtin_file() could not open builtin file '(null)/modules.builtin.bin'
My module cleanup function simply calls another one (below) that tries to restore the function calls by doing the opposite of the replacement function above:
// called by the exit function
static void systrap_restore_syscalls(void)
{
pr_debug("systrap: trying to restore system calls\n");
write_cr0(read_cr0() & ~0x10000);
/* make sure no other modules have made changes before restoring */
if(syscall_table[__NR_read] == systrap_read)
{
syscall_table[__NR_read] = original_read;
pr_debug("systrap: restored sys_read\n");
}
else
{
pr_warn("systrap: sys_read not restored; address mismatch\n");
}
// ... ommitted: same stuff for other sys calls
write_cr0(read_cr0() | 0x10000);
pr_debug("systrap: system call restoration attempt complete\n");
}
Q3: I don't know what causes the error message; any ideas here?
Part 4 - sys_open Marked for Deprecation?
In another unexpected turn of events, I find that the __NR_open macro is no longer be defined by default. In order for me to see the definition, I have to #define __ARCH_WANT_SYSCALL_NO_AT before #includeing the header files:
/*
* Force __NR_open definition. It seems sys_open has been replaced by sys_openat(?)
* See include/uapi/asm-generic/unistd.h:724-725
*/
#define __ARCH_WANT_SYSCALL_NO_AT
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
// ...
Going through the kernel source code (mentioned in comment above), you find the following comments:
/*
* All syscalls below here should go away really,
* these are provided for both review and as a porting
* help for the C library version.
*
* Last chance: are any of these important enough to
* enable by default?
*/
#ifdef __ARCH_WANT_SYSCALL_NO_AT
#define __NR_open 1024
__SYSCALL(__NR_open, sys_open)
// ...
Can anyone clarify:
Q4: ...the comments above on why __NR_open is not available by default?,
Q5: ...whether it's a good idea to do what I'm doing with the #define?, and
Q6: ...what I should be using instead if I really shouldn't be trying to use __NR_open?
Epiloge - Crashing My System 😑
I tried using __NR_openat, replacing that call as I had done with the previous ones:
static asmlinkage long systrap_openat(int dfd, const char __user *filename, int flags, umode_t mode)
{
pr_debug("systrap: opening file dfd = %d, name = % s\n", filename);
return original_openat(dfd, filename, flags, mode);
}
But this simply helped me unceremoniously crash my own system 😑 by causing other processes to segfault when they tried to open a file, with gems such as:
kernel: [135489.202693] systrap: opening file dfd = 0, name = P^Q
kernel: [135489.202913] zsh[11806]: segfault at 410 ip 00007f3a380abe60 sp 00007ffd04c5b550 error 4 in libc-2.21.so[7f3a37fe1000+1c0000]
Trying to print argument data also showed odd/garbage info.
Q7: Any additional suggestions on why it would suddenly crash and why the arguments seem to be garbage-like?
I've spent several days trying to work through this and I just hope I've not missed something utterly stupid...
Please, let me know if something's not entirely clear to you in the comments and I'll attempt to clarify.
I'd be most helpful if you could provide some code snippets that actually work and/or point me in a precise-enough direction that would allow me to understand what I'm doing wrong and how to quickly get this fixed.
I've managed to complete this and I'm now taking the time to document my findings.
Q1: Have I missed something so far regarding the expected address-based comparison?
The problem with this comparison is that, after checking /proc/kallsyms, I saw that sys_close and other related symbols are also no longer exported. I already knew this for some symbols, but I was still under the (mistaken) impression that some others were still available. So the check I was using (below) evaluates to true and causes the module to fail the 'safety' check.
if(syscall_table[__NR_close] != (unsigned long *)sys_close)
{
/* ... */
}
In short, you simply need to trust the assumption about the system call table address retrieved from the System.map-$(uname -r) file. The 'safety' check is unnecessary and will also not work as expected.
Q2: Have I missed something regarding the replaced system calls?
This problem was eventually traced to either one or both of the following header files I had included (I didn't bother to figure out which one.):
#include <uapi/asm-generic/unistd.h>
#include <uapi/asm-generic/errno-base.h>
These were causing the __NR_* macros to get redefined, and therefore expanded, to incorrect values --at least for the x86_64 architecture. For example, the indices for sys_read and sys_write in the system call table are supposed to be 0 and 1 respectively, but they were getting other values and ended up indexing to completely unexpected locations in the table.
Just removing the header files above fixed the issue without additional code changes.
Q3: I don't know what causes the error message; any ideas here?
The error message was a side-effect of the previous issue. Obviously, the fact that the system call table was being indexed incorrectly (see Q2) caused other locations in memory to get modified.
Q4: ...the comments above on why __NR_open is not available by default?
This was a mis-report of the IDE, which I stopped using. The __NR_open macro was already defined; the fix on Q2 made it even more obvious.
Q5: ...whether it's a good idea to do what I'm doing with the #define?
Short answer: No, not a good idea and definitely not needed. See Q2 above.
Q6: ...what I should be using instead if I really shouldn't be trying to use __NR_open
Based on answers to previous questions, this is not a problem. Using __NR_open is just fine and expected. This part had gotten messed up due to the header files in Q2
Q7: Any additional suggestions on why it would suddenly crash and why the arguments seem to be garbage-like?
The use of __NR_openat and the crashes was likely being caused by the macro being expanded to an incorrect value (see Q2 again). However, I can say that I had no real need to use it. I was supposed to be using __NR_open as specified above, but was trying out __NR_openat as a workaround for the issue fixed in Q2.
In short, the answer to Q2 helped fix several issues in a cascading effect.
Is there any function in C to check if the computer is going to sleep,hibernate or locked and waking up from these state?
In msdn they provided for C#, C++ but not for C.
My OS is windows7
Like below is the code I'm using to check the time duration between starting the program and terminating it(shutting down the system will terminate the program so this way time duration can be measured).
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include<time.h>
clock_t start_time=0;
void bye (void)
{
FILE *read,*write;
write=fopen("F:\\count.txt","w");
clock_t end_time=clock();
fprintf(write,"Time: %d",(end_time-start_time)/CLOCKS_PER_SEC);
fclose(write);
}
int main (void)
{
start_time=clock();
atexit (bye);
//exit (EXIT_SUCCESS);
getch();
}
In the same way I want to check for locked/sleep/hibernate.
One possible way to wrap the c++ code(provided in the link) in c as mentioned by #ddriver
But is it not possible in C at all?
The WinAPI has generally at least the same possibilities as .NET framework. What your are asking for is the PowerManagement API.
You will have to register to receive PowerSettingNotificationEvents with the RegisterPowerSettingNotification function. Unfortunately, it is used differently for a GUI application where you give a handle to a window that will then receive a WM_POWERBROADCAST message each time the system is about to change state (one of the suspend modes or the hibernate mode), and for a non GUI (typically a service) that registers a HandlerEx callback with a dwControl parameter of SERVICE_CONTROL_POWEREVENT and a dwEventType of PBT_POWERSETTINGCHANGE.
The link you provide is about signals, emitted when power mode is changing. So, obviously, you can check when the system is about to go to sleep, or it just woke up.
As of checking if the system currently sleeps, that is simply not possible, as user code will simply not be running during deep sleep states. Maybe some platform specific, very low level BIOS API, but those are usually not public, and far from portable.
I should write a linux device driver code that periodically print an information. This information should be printed until the module will be unloaded. I should write something like this
int boolean = 1;
static int hello_init(void)
{
while(boolean){
printk(KERN_ALERT "An information\n");
msleep(1000);
}
return 0;
}
static void hello_exit(void)
{
boolean=0;
printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
Obviously, this code doesn't work (I suppose because __init and __exit can't work concurrently, so the boolean value cannot change). Can anyone help me to solve this problem?
If the task you are performing periodically needs to go to sleep, you may not be able to use timer functions. Delayed workqueues can be used in that situation -- they are not as precise as the hrtimer but if the timing requirements aren't too strict, they work just fine.
I recently posted a question about doing things periodically here:
Calling spi_write periodically in a linux driver
I posted a workqueue example in it that you may find useful.
I also found this documentation to be helpful:
http://www.makelinux.net/ldd3/chp-7-sect-6
However, some changes have been made to the API since it was published. This article outlines these changes:
http://lwn.net/Articles/211279/
You should set up a timer with hrtimer_start() at the hello_init().
The struct hrtimer *timer contains a function pointer what will be called at the time you set. That callback function should contains the printk(). You have to renew the timer each time the callback called.
Don't forget to call the hrtimer_cancel() at the hello_exit().
You can use the ktime_set() function to calculate the expire time you want. Have a look here, there are some related and useful functions: High-resolution timers
I have been trying to intercept the system call at the kernel level. I got the basic idea from this question . The system call I was trying to intercept was the fork(). So I found out the address of the sys_fork() from System.map and it turned out to be 0xc1010e0c.Now I wrote the module as below.
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/unistd.h>
#include<linux/semaphore.h>
#include<asm/cacheflush.h>
MODULE_LICENSE("GPL");
void **sys_call_table;
asmlinkage int (*original_call)(struct pt_regs);
asmlinkage int our_call(struct pt_regs regs)
{
printk("Intercepted sys_fork");
return original_call(regs);
}
static int __init p_entry(void)
{
printk(KERN_ALERT "Module Intercept inserted");
sys_call_table=(void *)0xc1010e0c;
original_call=sys_call_table[__NR_open];
set_memory_rw((long unsigned int)sys_call_table,1);
sys_call_table[__NR_open]=our_call;
return 0;
}
static void __exit p_exit(void)
{
sys_call_table[__NR_open]=original_call;
set_memory_ro((long unsigned int)sys_call_table,1);
printk(KERN_ALERT "Module Intercept removed");
}
module_init(p_entry);
module_exit(p_exit);
However , after compiling the module and when I tried to insert it to the kernel, I got the following from the dmesg output.
Of course its not intercepting the system call.Can you help me figure out the problem? I am using 3.2.0-4-686 version of Linux kernel.
http://lxr.linux.no/linux+*/arch/x86/mm/pageattr.c#L874 says
if (*addr & ~PAGE_MASK) {
*addr &= PAGE_MASK;
/*
* People should not be passing in unaligned addresses:
*/
WARN_ON_ONCE(1);
}
So the warning is because your sys_call_table variable is not page-aligned.
It should be said that patching the system call table is officially discouraged by the kernel maintainers, and they've put some deliberate roadblocks in your way -- you've probably already noticed that you can't access the real sys_call_table symbol, and the write protection is also deliberate. If you can possibly find another way to do what you want, then you should. Depending on your larger goal, you might be able to accomplish it using ptrace and no kernel module at all. The trace_sched_process_fork hook may also be useful.
original_call=sys_call_table[__NR_open];
....
sys_call_table[__NR_open]=our_call;
If you're intercepting fork, the entry for open is not what you want to change.
And instead of the address of the sys_fork() from System.map, you should have used the address of sys_call_table.
It is not clear if you solved your problem, but depending on how you test your module glib don't use sys_fork anymore, but use sys_clone instead.