I am developing a kernel module. In the event specific errors occur I want to break into the debugger or otherwise stop execution.
How can I conditionally trigger an error condition
which is removed when optimization are enabled
and
which is not removed when optimization are enabled?
Use KASSERT. It's slightly different from userspace assert(); use it like this:
KASSERT(x == y, ("%s: %d != %d", func, x, y));
KASSERTs are enabled if INVARIANTS option is defined in the kernel config. In 11-CURRENT it's enabled by default; in stable releases it's disabled.
Related
Kprobe has a pre-handler function vaguely documented as followed:
User's pre-handler (kp->pre_handler)::
#include <linux/kprobes.h>
#include <linux/ptrace.h>
int pre_handler(struct kprobe *p, struct pt_regs *regs);
Called with p pointing to the kprobe associated with the breakpoint,
and regs pointing to the struct containing the registers saved when
the breakpoint was hit. Return 0 here unless you're a Kprobes geek.
I was wondering if one can use this function (or any other Kprobe feature) to prevent a process from being executed \ forked.
As documented in the kernel documentation, you can change the execution path by changing the appropriate register (e.g., IP register in x86):
Changing Execution Path
-----------------------
Since kprobes can probe into a running kernel code, it can change the
register set, including instruction pointer. This operation requires
maximum care, such as keeping the stack frame, recovering the execution
path etc. Since it operates on a running kernel and needs deep knowledge
of computer architecture and concurrent computing, you can easily shoot
your foot.
If you change the instruction pointer (and set up other related
registers) in pre_handler, you must return !0 so that kprobes stops
single stepping and just returns to the given address.
This also means post_handler should not be called anymore.
Note that this operation may be harder on some architectures which use
TOC (Table of Contents) for function call, since you have to setup a new
TOC for your function in your module, and recover the old one after
returning from it.
So you might be able to block a process' execution by jumping over some code. I wouldn't recommend it; you're more likely to cause a kernel crash than to succeed in stopping the execution of a new process.
seccomp-bpf is probably better suited for your use case. This StackOverflow answer gives you all the information you need to leverage seccomp-bpf.
How can I generate a kernel oops or crash in kernel code? Is there a function for that?
The usual way to crash the kernel is by using BUG() macro. There's also WARN() macro, which dumps the stack down to console but the kernel keeps running.
http://kernelnewbies.org/FAQ/BUG
What happens after kernels hits a BUG() macro (which eventually results in an internal trap) or some similar error condition (like null pointer dereference) depends on a setting of panic_on_oops global variable. If it's set to 0, the kernel will try to keep running (with whatever awful consequences). If it's set to 1, the kernel will enter the panic state and halt.
If you want to crash the kernel from user space, you've got a handy <SysRq> + <c> key combo (or, alternatively, echo c > /proc/sysrq-trigger). It's worth looking at the handler implementation for this action (http://code.metager.de/source/xref/linux/stable/drivers/tty/sysrq.c#134):
static void sysrq_handle_crash(int key)
{
char *killer = NULL;
panic_on_oops = 1; /* force panic */
wmb();
*killer = 1;
}
The handler sets the global flag to make kernel panic on traps, then tries to dereference a random null pointer.
panic() function
The kernel also has a panic() function if you want to do it from inside a kernel module code:
#include <kernel.h>
panic("my message");
It is defined at kernel/panic.c.
Here is a minimal runnable example.
Related threads:
Using assertion in the Linux kernel
https://unix.stackexchange.com/questions/66197/how-to-cause-kernel-panic-with-a-single-command
This question already has an answer here:
volatile variable using in making application
(1 answer)
Closed 8 years ago.
I am new in this field. Previously i was doing microcontroller programming. where I used in volatile variable to avoid compiler optimization. But I never saw such volatile declaration before variable declaration.Does it mean compilation is done without any optimization in arago build. Here I have two doubts.
How can I enable different types of optimization during compilation
like speed and space optimization in angstrom build?
If it already optimization compilation, why do not we need volatile declaration?
Optimization is typically controlled via compiler settings - such as the compiler command line. It is not controlled in code.
However for doing optimization the compiler assumes that variables behave like "normal variables" while the code is not interrupted.
This may lead to the following error: Some example code:
int a;
void myFunc(void)
{
a=1;
/* Wait until the interrupt sets a back to 0 */
while(a==1);
}
void interruptHandler(void)
{
/* Some hardware interrupt */
if(a==1) doSomeAction();
a=0;
}
The compiler assumes that there are no interrupts. Therefore it would see that
"a" is set to 1 and never changed before the "while" loop
The while loop is an endless loop because "a" does not change whithin this loop
"a" is never read before this endless loop
Therefore the optimizing compiler may change the code internally like this:
void myFunc(void)
{
while(1);
}
Leaving the "volatile" away may work but may not work.
If you do not have hardware interrupts (and no parallel threads, multi-core CPUs etc.) "volatile" makes the code only slower and has no benefit because it is not required.
I am facing crash while trying to create one tcl interpreter per thread. I am using TCL version 8.5.9 on linux rh6. It crashes in different functions each time seems some kind of memory corruption. Going through net it seems a valid approach. Has anybody faced similar issue? Does multi-threaded use of Tcl need any kind of special support?
Here is the following small program causing crash with tcl version 8.5.9.
#include <tcl.h>
#include <pthread.h>
void* run (void*)
{
Tcl_Interp *interp = Tcl_CreateInterp();
sleep(1);
Tcl_DeleteInterp(interp);
}
main ()
{
pthread_t t1, t2;
pthread_create(&t1, NULL, run, NULL);
pthread_create(&t2, NULL, run, NULL);
pthread_join (t1, NULL);
pthread_join (t2, NULL);
}
The default Tcl library isn't built thread enabled. (well, not with 8.5.9 afaik, 8.6 is).
So did you check that your tcl lib was built thread enabled?
If you have a tclsh built against the lib, you can simply run:
% parray ::tcl_platform
::tcl_platform(byteOrder) = littleEndian
::tcl_platform(machine) = intel
::tcl_platform(os) = Windows NT
::tcl_platform(osVersion) = 6.2
::tcl_platform(pathSeparator) = ;
::tcl_platform(platform) = windows
::tcl_platform(pointerSize) = 4
::tcl_platform(threaded) = 1
::tcl_platform(wordSize) = 4
If ::tcl_platform(threaded) is 0, your build isn't thread enabled. You would need to build a version with thread support by passing --enable-threads to the configure script.
Did you use the correct defines to declare you want the thread enabled Macros from tcl.h?
You should add -DTCL_THREADS to your compiler invocation, otherwise the locking macros are compiled as no-ops.
You need to use a thread-enabled build of the library.
When built without thread-enabling, Tcl internally uses quite a bit of global static data in places like memory management. It's pretty pervasive. While it might be possible to eventually make things work (provided you do all the initialisation and setup within a single thread) it's going to be rather unadvisable. That things crash in strange ways in your case isn't very surprising at all.
When you use a thread-enabled build of Tcl, all that global static data is converted to either thread-specific data or to appropriate mutex-guarded global data. That then allows Tcl to be used from many threads at once. However, a particular Tcl_Interp is bound to the thread that created it (as it uses lots of thread-specific data). In your case, that will be no problem; your interpreters are happily per-thread entities.
(Well, provided you also add a call to initialise the Tcl library itself, which only needs to be done once. Put Tcl_FindExecutable(NULL); inside main() before you create any of those threads.)
Tcl 8.5 defaulted to not being thread-enabled on Unix for backward-compatibility reasons — on Windows and Mac OS X it was thread-enabled due to the different ways they handle low-level events — but this was changed in 8.6. I don't know how to get a thread-enabled build on RH6 (other than building it yourself from source, which should be straight-forward).
The following macro is defined in ./kernel/sched/sched.h
#define sched_feat(x) (static_branch_##x(&sched_feat_keys[__SCHED_FEAT_##x]))
#else /* !(SCHED_DEBUG && HAVE_JUMP_LABEL) */
#define sched_feat(x) (sysctl_sched_features & (1UL << __SCHED_FEAT_##x))
#endif /* SCHED_DEBUG && HAVE_JUMP_LABEL */
I am unable to understand what role does it play.
The sched_feat() macro is used in scheduler code to test if a certain scheduler feature is enabled. For example, in kernel/sched/core.c, there is a snippet of code
int mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner)
{
if (!sched_feat(OWNER_SPIN))
return 0;
which is testing whether the "spin-wait on mutex acquisition if the mutex owner is running" feature is set. You can see the full list of scheduler features in kernel/sched/features.h but a short summary is that they are tunables settable at runtime without rebuilding the kernel through /sys/kernel/debug/sched_features.
For example if you have not changed the default settings on your system, you will see "OWNER_SPIN" in your /sys/kernel/debug/sched_features, which means the !sched_feat(OWNER_SPIN) in the snippet above will evaluate to false and the scheduler code will continue on into the rest of the code in mutex_spin_on_owner().
The reason that the macro definition you partially copied is more complicated than you might expect is that it uses the jump labels feature when available and needed to eliminate the overhead of these conditional tests in frequently run scheduler code paths. (The jump label version is only used when HAVE_JUMP_LABEL is set in the config, for obvious reasons, and when SCHED_DEBUG is set because otherwise the scheduler feature bits can't change at runtime) You can follow the link above to lwn.net for more details, but in a nutshell jump labels are a way to use runtime binary patching to make conditional tests of flags much cheaper at the cost of making changing the flags much more expensive.
You can also look at the scheduler commit that introduced jump label use to see how the code used to be a bit simpler but not quite as efficient.