I got a kernel panic, and can't figure out why.
What conditions could possibly cause the following function to crash in a kernel extension in OS X 10.11.3, resulting in a panic?
static int parent_pid(int pid) {
int ppid = 0;
proc_t process = proc_find(pid);
if (process) {
ppid = proc_ppid(process);
proc_rele(process);
}
return ppid;
}
The panic occurred inside the proc_rele(), as it called _lck_mtx_lock in turn. To the best of my knowledge, the proc_rele() is used absolutely correctly here. There are no other calls to proc_find() or proc_self() in the entire kext, so the reason shouldn't be a missing proc_rele() somewhere else in the code.
Are there some kind of race conditions or thread issues I haven't considered? Do I need to protect calls to proc_find()/proc_rele() with a lock, for example?
Related
I do not know, if this is ok, but it compiles:
typedef struct
{
int fd;
char *str;
int c;
} ARG;
void *ww(void *arg){
ARG *a = (ARG *)arg;
write(a->fd,a->str,a->c);
return NULL;
}
int main (void) {
int fd = open("./smf", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
int ch = fork();
if (ch==0){
ARG *arg; pthread_t p1;
arg->fd = fd;
arg->str = malloc(6);
strcpy(arg->str, "child");
arg->c = 6;
pthread_create( &p1, NULL, ww, arg);
} else {
write(fd, "parent\0", 7);
wait(NULL);
}
return 0;
}
I am wait()int in parent, but I do not know if I should also pthread_join to merge threads or it is implicitly by wait(). However is it even safe to write to the same file in two threads? I run few times and sometimes output was 1) parentchild but sometimes only 2) parent, no other cases - I do not know why child did not write as well when parent wait()s for it. Can someone please explain why these outputs?
You need to call pthread_join() in the child process to avoid potential race conditions during the child process’s exit sequence (for example the child process can otherwise exit before its thread gets a chance to write to the file). Calling pthread_join() in the parent process won’t help,
As for the file, having both processes write to it is safe in the sense that it won’t cause a crash, but the order in which the data is written to the file will be indeterminate since the two processes are executing concurrently.
I do not know, if this is ok, but it compiles:
Without even any warnings? Really? I suppose the code you are compiling must include all the needed headers (else you should have loads of warnings), but if your compiler cannot be persuaded to spot
buggy.c:30:15: warning: ‘arg’ may be used uninitialized in this
function [-Wmaybe-uninitialized]
arg->fd = fd;
^
then it's not worth its salt. Indeed, variable arg is used uninitialized, and your program therefore exhibits undefined behavior.
But even if you fix that, after which the program can be made to compile without warnings, it still is not ok.
I am wait()int in parent, but I do not know if I should also
pthread_join to merge threads or it is implicitly by wait().
The parent process is calling wait(). This waits for a child process to terminate, if there are any. Period. It has no implications for the behavior of the child prior to its termination.
Moreover, in a pthreads program, the main thread is special: when it terminates, the whole program terminates, including all other threads. Your child process therefore suffers from a race condition: the main thread terminates immediately after creating a second thread, without ensuring that the other thread terminates first, so it is undefined what, if any, of the behavior of the second thread is actually performed. To avoid this issue, yes, in the child process, the main thread should join the other one before itself terminating.
However
is it even safe to write to the same file in two threads?
It depends -- both on the circumstances and on what you mean by "safe". POSIX requires the write() function to be thread-safe, but that does not mean that multiple threads or processes writing to the same file cannot still interfere with each other by overwriting each other's output.
Yours is a somewhat special case, however, in that parent and child are writing via the same open file description in the kernel, the child having inherited an association with that from its parent. According to POSIX, then, you should see both processes' output (if any; see above) in the file. POSIX provides no way to predict the order in which those outputs will appear, however.
I run few
times and sometimes output was 1) parentchild but sometimes only 2)
parent, no other cases - I do not know why child did not write as well
when parent wait()s for it. Can someone please explain why these
outputs?
The child process can terminate before its second thread performs its write. In this case you will see only the parent's output, not the child's.
I'm working with Android 8.1 Pixel2 XL phone.
I have hooked the sys_call_table and have replaced the syscalls with my own functions using the kernel module.
I want to make an application unable to quit.
I'm trying to invalidate an application's sys_exit_group and sys_kill.
What should I do in my own function.
I want to debug an application, but it turns on anti-debugging. So I want to hook the system call
I have tried direct return, but It wasn't work. System will call sys_kill again.But this time, I can't get the application's uid from its pid.
asmlinkage long my_sys_kill(pid_t pid, int sig)
{
char buff[MAX_PATH] = {0};
kuid_t uid = current->cred->uid;
int target_uid = get_uid_from_pid(pid);
if (target_uid == targetuid)
{
printk(KERN_DEBUG "#Tsingxing: kill hooked uid is %d pid is %d, tragetuid is %d, packagename: %s\n",uid.val,pid, target_uid, buff);
return 0;
}
printk(KERN_DEBUG "#Tsingxing:kill called uid is %d,pid is %d, traget_uid is %d\n",uid.val,pid,target_uid);
return origin_sys_kill(pid, sig);
}
asmlinkage long my_sys_exit_group(int error_code)
{
char buff[MAX_PATH] = {0};
kuid_t uid = current->cred->uid;
long tgid = current -> tgid;
long pid = current->pid;
int target_uid = get_uid_from_pid(pid);
if (uid.val == targetuid || target_uid == targetuid)
{
printk(KERN_DEBUG "#Tsingxing:exit group hooked, pid is %ld\n",pid);
return 0;
}
return origin_sys_exit_group(error_code);
}
I have solved this problem. I mixed sys_call_table and compat_sys_call_table. The Target application is using compat_sys_call_table but I'm using the __NR_xxx. I solved the problem using __NR_compat_xxx method. Just return direct in compat_sys_call_exit_group.
At a very high level, this can't work. When an application calls _Exit (possibly/likely at the end of exit), it has no path to any further code to be run. These functions are normally even marked _Noreturn, meaning that the compiler does not leave the registers/calling stack frame in a meaningful state where resumption of execution could occur. Even if it did, the program itself at the source level is not prepared to continue execution.
If the function somehow returned, the next step would be runaway wrong code execution, likely leading to arbitrary code execution under the control of an attacker if the application had been processing untrusted input of any kind.
In practice, the libc side implementation of the exit and _Exit functions likely hardens against kernel bugs (yes, what you're asking for is a bug) whereby SYS_exit_group fails to exit. I haven't verified other implementations lately but I know mine in musl do this, because it's cheap and the alternative is very dangerous.
I have read this and this post on stackoverflow, but no one of them give me what I want to do.
In my case, I want to create a Thread, launch it and let it running with no blocking stat as long as the main process runs. This thread has no communication, no synchronization with the main process, it do his job fully independent.
Consider this code:
#define DAY_PERIOD 86400 /* 3600*24 seconds */
int main() {
char wDir[255] = "/path/to/log/files";
compress_logfiles(wDir);
// do other things, this things let the main process runs all the time.
// just segmentation fault, stackoverflow, memory overwrite or
// somethings like that stop it.
return 0;
}
/* Create and launch thread */
void compress_logfiles(char *wDir)
{
pthread_t compressfiles_th;
if (pthread_create(&compressfiles_th, NULL, compress, wDir))
{
fprintf(stderr, "Error create compressfiles thread\n");
return;
}
if (pthread_join(compressfiles_th, NULL))
{
//fprintf(stderr, "Error joining thread\n");
return;
}
return;
}
void *compress(void *wDir)
{
while(1)
{
// Do job to compress files
// and sleep for one day
sleep(DAY_PERIOD); /* sleep one day*/
}
return NULL;
}
With ptheard_join in compress_logfiles function, the thread compresses all files successfully and never returns because it is in infinite while loop, so the main process still blocked all the time. If I remove ptheard_join from compress_logfiles function, the main process is not blocked because it don't wait thread returns, but the thread compresses one file and exit (there a lot of files, arround one haundred).
So, is there a way to let main process launch compressfiles_th thread and let it do his job without waiting it to finish or exit?
I found pthread_tryjoin_np and pthread_timedjoin_np in Linux Programmer's Manual, it seems that pthread_tryjoin_np do the job if I don't care of the returned value, it is good idea to use it?
Thank you.
Edit 1:
Please note that the main process is daemonized after call to compress_logfiles(wDir), perhaps the daemonization kill the main process and re-launch it is the problem?
Edit 2: the solution
Credit to dbush
Yes, fork causes the problem, and pthread_atfork() solves it. I made this change to run the compressfiles_th without blocking main process:
#define DAY_PERIOD 86400 /* 3600*24 seconds */
char wDir[255] = "/path/to/log/files"; // global now
// function added
void child_handler(){
compress_logfiles(wDir); // wDir is global variable now
}
int main()
{
pthread_atfork(NULL, NULL, child_handler);
// Daemonize the process.
becomeDaemon(BD_NO_CHDIR & BD_NO_CLOSE_FILES & BD_NO_REOPEN_STD_FDS & BD_NO_UMASK0 & BD_MAX_CLOSE);
// do other things, this things let the main process runs all the time.
// just segmentation fault, stackoverflow, memory overwrite or
// somethings like that stop it.
return 0;
}
child_handler() function is called after fork. pthread_atfork
When you fork a new process, only the calling thread is duplicated, not all threads.
If you wish to daemonize, you need to fork first, then create your threads.
From the man page for fork:
The child process is created with a single thread--the one that
called fork(). The entire virtual address space of the parent is
replicated in the child, including the states of mutexes, condition
variables, and other pthreads objects; the use of pthread_atfork(3)
may be helpful for dealing with problems that this can cause.
I have to migrate a C-program from OpenVMS to Linux, and have now difficulties with a program generating subprocesses. A subprocess is generated (fork works fine), but execve fails (which is correct, as the wrong program name is given).
But to reset the number of active subprocesses, I afterwards call a wait() which does not return. When I look at the process via ps, I see that there are no more subprocesses, but wait() does not return ECHILD as I had thought.
while (jobs_to_be_done)
{
if (running_process_cnt < max_process_cnt)
{
if ((pid = vfork()) == 0)
{
params[0] = param1 ;
params[1] = NULL ;
if ((cstatus = execv(command, params)) == -1)
{
perror("Child - Exec failed") ; // this happens
exit(EXIT_FAILURE) ;
}
}
else if (pid < 0)
{
printf("\nMain - Child process failed") ;
}
else
{
running_process_cnt++ ;
}
}
else // no more free process slot, wait
{
if ((pid = wait(&cstatus)) == -1) // does not return from this statement
{
if (errno != ECHILD)
{
perror("Main: Wait failed") ;
}
anz_sub = 0 ;
}
else
{
...
}
}
}
Is the anything that has to be done to tell the wait-command that there are no more subprocesses?
With OpenVMS the program works fine.
Thanks a lot in advance for your help
I don't recommend using vfork these days on Linux, since fork(2) is efficient enough, thanks to lazy copy-on-write techniques in the Linux kernel.
You should check the result of fork. Unless it is failing, a process has been created, and wait (or waitpid(2), perhaps with WNOHANG if you don't want to really wait, but just find out about already ended child processes ...) should not fail (even if the exec function in the child has failed, the fork did succeed).
You might also carefully use the SIGCHLD signal, see signal(7). A defensive way of using signals is to set some volatile sigatomic_t flag in signal handlers, and test and clear these flags inside your loop. Recall that only async signal safe functions (and there are quite few of them) can be called -even indirectly- inside a signal handler. Read also about POSIX signals.
Take time to read Advanced Linux Programming to get a wider picture in your mind. Don't try to mimic OpenVMS on POSIX, but think in a POSIX or Linux way!
You probably may want to always waitpid in your loop, perhaps (sometimes or always) with WNOHANG. So waitpid should not be only called in the else part of your if (running_process_cnt < max_process_cnt) but probably in every iteration of your loop.
You might want to compile with all warnings & debug info (gcc -Wall -Wextra -g) then use the gdb debugger. You could also strace(1) your program (probably with -f)
You might want to learn about memory overcommitment. I dislike this feature and usually disable it (e.g. by running echo 0 > /proc/sys/vm/overcommit_memory as root). See also proc(5) -which is very useful to know about...
From man vfork:
The child must not return from the current function or call exit(3), but may call _exit(2)
You must not call exit() when the call to execv (after vfork) fails - you must use _exit() instead. It is quite possible that this alone is causing the problem you see with wait not returning.
I suggest you use fork instead of vfork. It's much easier and safer to use.
If that alone doesn't solve the problem, you need to do some debugging or reduce the code down until you find the cause. For example the following should run without hanging:
#include <sys/wait.h>
int main(int argc, char ** argv)
{
pid_t pid;
int cstatus;
pid = wait(&cstatus);
return 0;
}
If you can verify that this program doesn't hang, then it must be some aspect of your program that is causing a hang. I suggest putting in print statements just before and after the call to wait.
Calling tzset() after forking appears to be very slow. I only see the slowness if I first call tzset() in the parent process before forking. My TZ environment variable is not set. I dtruss'd my test program and it revealed the child process reads /etc/localtime for every tzset() invocation, while the parent process only reads it once. This file access seems to be the source of the slowness, but I wasn't able to determine why it's accessing it every time in the child process.
Here is my test program foo.c:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
void check(char *msg);
int main(int argc, char **argv) {
check("before");
pid_t c = fork();
if (c == 0) {
check("fork");
exit(0);
}
wait(NULL);
check("after");
}
void check(char *msg) {
struct timeval tv;
gettimeofday(&tv, NULL);
time_t start = tv.tv_sec;
suseconds_t mstart = tv.tv_usec;
for (int i = 0; i < 10000; i++) {
tzset();
}
gettimeofday(&tv, NULL);
double delta = (double)(tv.tv_sec - start);
delta += (double)(tv.tv_usec - mstart)/1000000.0;
printf("%s took: %fs\n", msg, delta);
}
I compiled and executed foo.c like this:
[muir#muir-work-mb scratch]$ clang -o foo foo.c
[muir#muir-work-mb scratch]$ env -i ./foo
before took: 0.002135s
fork took: 1.122254s
after took: 0.001120s
I'm running Mac OS X 10.10.1 (also reproduced on 10.9.5).
I originally noticed the slowness via ruby (Time#localtime slow in child process).
Ken Thomases's response may be correct, but I was curious about a more specific answer because I still find the slowness unexpected behavior for a single-threaded program performing such a simple/common operation after forking. After examining http://opensource.apple.com/source/Libc/Libc-997.1.1/stdtime/FreeBSD/localtime.c (not 100% sure this is the correct source), I think I have an answer.
The code uses passive notifications to determine if the time zone has changed (as opposed to stating /etc/localtime every time). It appears that the registered notification token becomes invalid in the child process after forking. Furthermore, the code treats the error from using an invalid token as a positive notification that the timezone has changed, and proceeds to read /etc/localtime every time. I guess this is the kind of undefined behavior you can get after forking? It would be nice if the library noticed the error and re-registered for the notification, though.
Here is the snippet of code from localtime.c that mixes the error value with the status value:
nstat = notify_check(p->token, &ncheck);
if (nstat || ncheck) {
I demonstrated that the registration token becomes invalid after fork using this program:
#include <notify.h>
#include <stdio.h>
#include <stdlib.h>
void bail(char *msg) {
printf("Error: %s\n", msg);
exit(1);
}
int main(int argc, char **argv) {
int token, something_changed, ret;
notify_register_check("com.apple.system.timezone", &token);
ret = notify_check(token, &something_changed);
if (ret)
bail("notify_check #1 failed");
if (!something_changed)
bail("expected change on first call");
ret = notify_check(token, &something_changed);
if (ret)
bail("notify_check #2 failed");
if (something_changed)
bail("expected no change");
pid_t c = fork();
if (c == 0) {
ret = notify_check(token, &something_changed);
if (ret) {
if (ret == NOTIFY_STATUS_INVALID_TOKEN)
printf("ret is invalid token\n");
if (!notify_is_valid_token(token))
printf("token is not valid\n");
bail("notify_check in fork failed");
}
if (something_changed)
bail("expected not changed");
exit(0);
}
wait(NULL);
}
And ran it like this:
muir-mb:projects muir$ clang -o notify_test notify_test.c
muir-mb:projects muir$ ./notify_test
ret is invalid token
token is not valid
Error: notify_check in fork failed
You're lucky you didn't experience nasal demons!
POSIX states that only async-signal-safe functions are legal to call in the child process after the fork() and before a call to an exec*() function. From the standard (emphasis added):
… the child process may only execute async-signal-safe operations until such time as one of the exec functions is called.
…
There are two reasons why POSIX programmers call fork(). One reason is
to create a new thread of control within the same program (which was
originally only possible in POSIX by creating a new process); the
other is to create a new process running a different program. In the
latter case, the call to fork() is soon followed by a call to one of
the exec functions.
The general problem with making fork() work in a multi-threaded world
is what to do with all of the threads. There are two alternatives. One
is to copy all of the threads into the new process. This causes the
programmer or implementation to deal with threads that are suspended
on system calls or that might be about to execute system calls that
should not be executed in the new process. The other alternative is to
copy only the thread that calls fork(). This creates the difficulty
that the state of process-local resources is usually held in process
memory. If a thread that is not calling fork() holds a resource, that
resource is never released in the child process because the thread
whose job it is to release the resource does not exist in the child
process.
When a programmer is writing a multi-threaded program, the first
described use of fork(), creating new threads in the same program, is
provided by the pthread_create() function. The fork() function is thus
used only to run new programs, and the effects of calling functions
that require certain resources between the call to fork() and the call
to an exec function are undefined.
There are lists of async-signal-safe functions here and here. For any other function, if it's not specifically documented that the implementations on the platforms to which you're deploying add a non-standard safety guarantee, then you must consider it unsafe and its behavior on the child side of a fork() to be undefined.