Nested Functions lead to Segmentation fault in C on kernel versions > 5.7 - c

First SO question, so here it goes.
I'm not asking for someone to review the code, i want to get to the bottom of this.
It would be helpful if someone knew what change in the kernel could be responsible for the following.
In the University we were tasked to implement extended functionality in a modeled Operating System written in C (written by my professor), that models each core with a pthread.
Project github forked by me.
We had to implement the necessary functionality by implementing the required syscalls. (multithreading, sockets, pipes, mlfq, etc).
After implementing each functionality we had to confirm that it was working using the validate_api program.
Problem time:
The validate_api.c contains a lot of tests to check the functionality of the OS.
BOOT_TEST: bare-boots the machine and tests something.
A simple test for creating a new thread inside a process:
BOOT_TEST(test_create_join_thread,
"Test that a process thread can be created and joined. Also, that "
"the argument of the thread is passed correctly."
)
{
int flag = 0;
int task(int argl, void* args) {
ASSERT(args == &flag);
*(int*)args = 1;
return 2;
}
Tid_t t = CreateThread(task, sizeof(flag), &flag);
/* Success in creating thread */
ASSERT(t!=NOTHREAD);
int exitval;
/* Join should succeed */
ASSERT(ThreadJoin(t, &exitval)==0);
/* Exit status should be correct */
ASSERT(exitval==2);
/* Shared variable should be updates */
ASSERT(flag==1);
/* A second Join should fail! */
ASSERT(ThreadJoin(t, NULL)==-1);
return 0;
}
As you can see there is a nested function called task() which is the starting point of the thread that is going to be created using the createThread() syscall we implemented.
The problem is that, although the thread is created correctly, when scheduled to run, the program exits with segmentation fault and cannot access the memory of the task function, gdb doesn't even recognize it as a variable (in the thread struct field pointing to it). The weird thing is that this happens ONLY when using a kernel version newer than 5.7. I opened an issue in the original project's repo.
Running the actual OS and its programs it's fine with no issues whatsoever, only validate_api fails due to that nested function. If i move the task function into global scope then the test finishes successfully. Same goes for every other test that has a nested function inside.
Note: The project is finished (1 month now), i downgraded to 5.4 just to test my implementation.
Note2: I dont need help with the implementation of any functionality (the project is finished any way), i just want to figure out why it doesn't work on kernels > 5.7
Note3: I'm here because my prof. doesn't respond to my repeated emails regarding the issue
I tried compiling using -fno-stack-protector and with -z execstack with no luck. Also simple nested functions like:
int main(){
int foo(){
puts("Hello there");
}
foo();
}
work with any kernel
Machine Details:
Arch Linux - 5.10 / 5.4 LTS
GCC 10.2
Thank you
UPDATE:
The test joins the thread, so it never goes out of scope.

Related

Why doesn't Linux prevent spawning infinite number of processes and crashing?

With the very simple code below, my system (Ubuntu Linux 14.04) simply crashes not even letting my mouse respond. I had to force quit with the power button. I thought Linux is a stable OS tolerable of handling such basic program errors. Did I miss something?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
void check(int isOkay){
if(!isOkay){
printf("error\n");
abort();
}
}
int main(void){
#define n 1000000
int array[n];
sem_t blocker;
int i;
while(1){
if(!fork()){
for(i = 0; i < n; ++i){
array[i] = rand();
}
check(sem_init(&blocker, 0, 0) == 0);
check(sem_wait(&blocker) == 0);
}
}
return 0;
}
Congratulations, you've discovered the fork bomb. There are shell one-liners that can wreak the same sort of havic with a lot less typing on your part.
It is in fact possible to limit the number of processes that a user can spawn using ulimit -- see the bottom of the linked wikipedia articles for details.
A desktop install of Ubuntu is not exactly a hardened server, though. It's designed for usability first and foremost. If you need a locked down system that can't crash, there are better options.
The command ulmit -u shows the maximum number of processes that you can start. However, do not start that many processes in the background: your machine would spend time switching between processes and wouldn't get around to getting actual work done.
The linux does its job of processing your request to create a process, it is for the user to implement his code based on this limit.
The main problem here is determining the best limit. A lot of software doesn't use fork() at all, so do you set the limit to something small like 5? Some software might create a new process whenever it receives a request from network, so do you set the limit to "max. number of network packets"? If you assume most software isn't buggy, then you'd be tempted to set the limit relatively high so that correct software works properly.
The other problem is one of scheduling priorities. In a well designed system things like the GUI would be "high priority" and if it wants CPU time it'd preempt normal/lower priority work immediately. If this was the case, a massive fork bomb running at normal/lower priority would have no effect on the system's ability to respond to the user, and the user would be able to kill the fork bomb without much problem.
Sadly, for a variety of reasons, the scheduler in Linux doesn't work like that. It does support priorities, but to use them you have to be a "real time" process and have to be running as root (which is a massive security disaster). Without sane priorities, Linux assumes that every forked process is as important as everything else, and the CPU/s end up busy doing the forking and there's no CPU time left to respond to the user.

Hijacking the realtime clock in linux

I want to write a LKM (Linux Kernel Module) that hijacks the realtime clock (interrupt 8). So I want the interrupt to be set to my function and at some point send it back to the old function.
I have tried to use the request_irq function without any success, probably because the kernel function that is there is not willing to share the interrupt (which is a good decision I guess).
I also tried to edit the IDT (Interrupt Descriptor Table), according to some pages I found. Non of them worked, most didn't even compile since they where written for kernel 2.6, and I'm working with 3.10.
This is a simplified code that I have just to give you the idea of what I'm doing.
kpage =__get_free_page( GFP_KERNEL);
asm("sidt %0": : "m"(*idtr) : );
memcpy(kpage, idtr, 256*sizeof(kpage));
newidt = (unsigned long long *)(*(unsigned long*)(idtr+1));
newidt[8] = &my_function;
asm("lidt %0": "=m"(newidt):);
All my attempts ended in good times with a segmentation fault, and in bad times with the kernel crashing forcing me to reboot (luckily I work with a virtual machine and snapshots).
So how can I hijack the realtime interrupt so it does my stuff? (And then send it back to the original function to get executed.)
Here is some nice code to change the pagefault function on the IDT. I couldn't make it work, since it's also written for kernel 2.6. This question is also worth looking into.
To get the bounty please publish working code, or at least sufficient info to make it run.
This can help you : http://cormander.com/2011/12/how-to-hook-into-hijack-linux-kernel-functions-via-lkm/
Why not you simply hook a function that is call every x steps like you want and execute what ever you need ?

How to prevent linux soft lockup/unresponsiveness in C without sleep

How would be the correct way to prevent a soft lockup/unresponsiveness in a long running while loop in a C program?
(dmesg is reporting a soft lockup)
Pseudo code is like this:
while( worktodo ) {
worktodo = doWork();
}
My code is of course way more complex, and also includes a printf statement which gets executed once a second to report progress, but the problem is, the program ceases to respond to ctrl+c at this point.
Things I've tried which do work (but I want an alternative):
doing printf every loop iteration (don't know why, but the program becomes responsive again that way (???)) - wastes a lot of performance due to unneeded printf calls (each doWork() call does not take very long)
using sleep/usleep/... - also seems like a waste of (processing-)time to me, as the whole program will already be running several hours at full speed
What I'm thinking about is some kind of process_waiting_events() function or the like, and normal signals seem to be working fine as I can use kill on a different shell to stop the program.
Additional background info: I'm using GWAN and my code is running inside the main.c "maintenance script", which seems to be running in the main thread as far as I can tell.
Thank you very much.
P.S.: Yes I did check all other threads I found regarding soft lockups, but they all seem to ask about why soft lockups occur, while I know the why and want to have a way of preventing them.
P.P.S.: Optimizing the program (making it run shorter) is not really a solution, as I'm processing a 29GB bz2 file which extracts to about 400GB xml, at the speed of about 10-40MB per second on a single thread, so even at max speed I would be bound by I/O and still have it running for several hours.
While the posed answer using threads might possibly be an option, it would in reality just shift the problem to a different thread. My solution after all was using
sleep(0)
Also tested sched_yield / pthread_yield, both of which didn't really help. Unfortunately I've been unable to find a good resource which documents sleep(0) in linux, but for windows the documentation states that using a value of 0 lets the thread yield it's remaining part of the current cpu slice.
It turns out that sleep(0) is most probably relying on what is called timer slack in linux - an article about this can be found here: http://lwn.net/Articles/463357/
Another possibility is using nanosleep(&(struct timespec){0}, NULL) which seems to not necessarily rely on timer slack - linux man pages for nanosleep state that if the requested interval is below clock granularity, it will be rounded up to clock granularity, which on linux depends on CLOCK_MONOTONIC according to the man pages. Thus, a value of 0 nanoseconds is perfectly valid and should always work, as clock granularity can never be 0.
Hope this helps someone else as well ;)
Your scenario is not really a soft lock up, it is a process is busy doing something.
How about this pseudo code:
void workerThread()
{
while(workToDo)
{
if(threadSignalled)
break;
workToDo = DoWork()
}
}
void sighandler()
{
signal worker thread to finish
waitForWorkerThreadFinished;
}
void main()
{
InstallSignalHandler;
CreateSemaphore
StartThread;
waitForWorkerThreadFinished;
}
Clearly a timing issue. Using a signalling mechanism should remove the problem.
The use of printf solves the problem because printf accesses the console which is an expensive and time consuming process which in your case gives enough time for the worker to complete its work.

Message passing between threads in C

I am trying to get Thread A to communicate with Thread B. I should be using message passing between threads to do this but I am trying to find some sample source code which explains message passing.
Does anyone have any good link to some sample source code (in C) which explains message passing ?
While not having a link, there are many ways to implement this.
First is to use sockets. This is not actually a method I would recommend, as it can be quite a lot of work to get it to work right.
The second is related to the first method, and is to use something called anonymous pipes.
A third way, and the one I usually use, is "inspired" by how message passing worked on the old Amiga operating system: Simply use a queue. Since memory is shared between threads it's easy to just pass pointers around. Use one queue per thread. Just remember to protect the queues, with something like a mutex.
The platform you are using will probably have other ways of communication. Do a Google search for (for example) linux ipc.
ONe very easy way that's fairly fast on Linux at least is to use either TCP or UDP sockets for message passing between threads. The Linux kernel is pretty smart and if I remember correctly it will bypass the network stack which makes it pretty fast. Then you don't have to worry about locking and various other issues which are basically handled by the kernel. Should be good enough for a homework assignment.
Uri's TCP/IP Resources List
FAQs, tutorials, guides, web pages & sites, and books about TCP/IP
Each thread in a process can see all of the memory of other threads. If two threads hold a pointer to the same location in memory, then they can both access it.
Following is the code but not tested.
struct MessageQueue
{
std::queue<std::string> msg_queue;
pthread_mutex_t mu_queue;
pthread_cond_t cond;
};
{
// In a reader thread, far, far away...
MessageQueue *mq = <a pointer to the same instance that the main thread has>;
std::string msg = read_a_line_from_irc_or_whatever();
pthread_mutex_lock(&mq->mu_queue);
mq->msg_queue.push(msg);
pthread_mutex_unlock(&mq->mu_queue);
pthread_cond_signal(&mq->cond);
}
{
// Main thread
MessageQueue *mq = <a pointer to the same instance that the main thread has>;
while(1)
{
pthread_mutex_lock(&mq->mu_queue);
if(!mq->msg_queue.empty())
{
std::string s = mq->msg_queue.top();
mq->msg_queue.pop();
pthread_mutex_unlock(&mq->mu_queue);
handle_that_string(s);
}
else
{
pthread_cond_wait(&mq->cond, &mq->mu_queue)
}
}

Exception wrapper for Carbon C app in OSX

How can I efficiently catch and handle segmentation faults from C in an OSX Carbon application?
Background: I am making an OSX Carbon application. I must call a library function from a third party. Because of threading issues, the function can occasionally crash, usually because it's updating itself from one thread, and it's got some internally stale pointer or handle as I query it from another. The function is a black box to me. I want to be able to call the function but be able to "catch" if it has crashed and supply an alternative return.
In Windows, I can use the simple Visual C and Intel C compiler's __try{} and __except.
/* Working Windows Example */
__try { x=DangerousFunction(y);}
__except(EXCEPTION_EXECUTE_HANDLER) {x=0.0;} /* whups, func crashed! */
I am trying to make the same kind of crash-catcher for OSX. I am using pure C on a very large application. I call the function millions of times per second, so efficiency is very important too. (Impressively, the Windows __try() overhead is immeasurably small!)
Here's what I have experimented with:
1) C++ exceptions. I am not sure if C++ exceptions catch the segfault crashes. And my app is currently C. I could try wrappers and #ifdefs to make it C++ but this is a lot of work for the app, and I don't think C++ exceptions will catch the crash.
2) signal + setjump + longjmp. I thought this would work... it's what it's designed for. But I set up my SEGV error handler [in fact I set it up for every signal!] and it's never called during the crash. I can manually test (and succeed) when calling raise(SEGV). But the crashes don't seem to actually call it. My thoughts are that CFM applications do NOT have access to the full BSD signals, only a subset, and that Mach applications are necessary for the Real Thing.
3) MPSetExceptionHandler. Not well documented. I attempted to set a handler. It compiled and ran, but did not catch the segfault.
Are you sure you're not getting a SIGBUS rather then a SIGSEGV?
The below catches SIGBUS as caused by trying to write at memory location 0:
cristi:tmp diciu$ cat test.c
#include <signal.h>
static void sigac(int sig)
{
printf("sig action here, signal is %d\n", sig);
exit(1);
}
int main()
{
(void)signal(SIGSEGV, sigac);
(void)signal(SIGBUS, sigac);
printf("Raising\n");
strcpy(0, "aaksdjkajskd|");
}
cristi:tmp diciu$ ./a.out
Raising
sig action here, signal is 10

Resources