Automatically connect to a CGI process and break in GDB before it exits? - c

For a C application accessed via CGI-BIN, documentation online for accessing the process and breaking in GDB relies on manipulating the source code (i.e. adding an infinite loop), in order for the process to be available long enough for a developer to attach, exit the loop, and debug.
Is it feasible that a tool could monitor the process list, and attach via GDB, immediately breaking in order for a developer to achieve this without requiring source code changes?
The rough structure of what I have in mind to develop is something along the lines of:
1. My process monitors the process list on the system.
2. A process matching the name of my application, and owner Apache appears in the list.
3. My process immediately performs a 'pgrep' and 'gdb -p' command, then sending a break-point command to pause the process.
4. The developer can then access the process and look at the flow of execution.
Is this feasible as an idea or not possible due to some constraints (i.e. a race condition which may not always be fufilled?)

Is this feasible
Sure: a trivial shell script will do:
while true; do
PID=$(pgrep my_app)
if [[ -n "$PID" ]]; then
gdb -p "$PID"
fi
done
a race condition
The problem is that between pgrep and gdb -p the application may make significant progress, or even run to completion.
The only way to avoid that is to intercept all execve system calls on the system, as Tom Tromey's preattach.stp does.

Related

How to execute commands in chroot?

In my source code I make chroot and then have some code doing some staff then I want to execute linux command. But the command does not work since I changed the root with chroot.
here after the source code:
int main(void)
{
if (chroot("/tmp") < 0)
printf("error in chroot\n");
/* some source code doing staffs */
system("ls > /logloglog.txt"); // command failed
return 0;
}
How to execute command in chroot?
Or is it possible to exit from chrood then execute the command and then back to the chroot again?
If you use chroot(), you have to consider the consequences of what you do. One of the major consequences is that many (most, all) of the commands normally available are not available unless you make them available in the chroot()'d environment.
Doing that job properly is non-trivial. You may need parts of /dev, /bin, /etc, /usr, /lib (and probably others too) installed appropriately under the new root directory. Symlinks back to 'outside the chroot() environment' won't work, in general. You have to make copies of what's important. One side effect of all this: /tmp is very rarely an appropriate place to create a fully operational chroot() environment. You might get away with a limited access sub-directory under /tmp, but putting a user in /tmp doesn't isolate them from other users, or other users from them, very well.
One other major possibility: you do not give the user access to other commands after you've done chroot(). That is, you do not try to use system() in your code; and you don't give the victim user access to a shell or shell utilities.
Using chroot() is not something you do casually, in other words. To do a good job takes quite a lot of careful thought and preparation.
Would you be better off with a container or virtual machine of some sort instead?
Do use Google or any other search engine to search for terms such as:
'chroot jail escape'
'chroot jail setup'
'chroot jail vs docker'
Is it possible to exit from chroot then execute the command and then back to the chroot again?
Not really. You might be able have a controlling program that forks a child that does chroot() and processes material and then terminates, so that the controlling program can do its job (execute the command) and then you could fork another child that goes back into the chroot() jail. But that's not the same as the current process getting out of jail — it would make chroot() totally ineffective if any program could cancel its jail time on a whim and resume unjailed activity.
What about:
system("chroot /tmp /bin/bash -c \"<COMMAND>\"");
You can just run chroot using system directly and with -c execute command inside /tmp environment

Does /usr/bin/perl run as separate processes when invoked with one script multiple times?

It's a web server scenario. Linux is the OS. Different IP Addresses call the same script.
Does Linux start a new process of Perl for every script call or does Perl run the multiple calls interleaved or do the scripts run serially (one after another)?
Sorry, I didn't find an answer within the first few results of Google.
I need to know in order to know how much I have to worry about concurrent database access.
The script itself is NOT using multiple threads, it's a straightforward Perl script.
Update: more sophisticated scheduler or serialiser of comment to answer below, still untested:
#! usr/bin/perl
use Fcntl;
use Time::HiRes;
sysopen(INDICATOR, "indicator", O_RDWR | O_APPEND); # filename hardcoded, must exist
flock(INDICATOR, LOCK_EX);
print INDICATOR $$."\n"; # print a value unique to this script
# in single-process context it's serial anyway
# in multi-process context the pid is unique
seek(INDICATOR,0,0);
my $firstline = <INDICATOR>;
close(INDICATOR);
while("$firstline" ne $$."\n")
{
nanosleep(1000000); # time your script to find a better value
open(INDICATOR, "<", "indicator");
$firstline = <INDICATOR>;
close(INDICATOR);
}
do "transferHandler.pl"; # name of your script to run
sysopen(INDICATOR, "indicator", O_RDWR);
flock(INDICATOR, LOCK_EX);
my #content = <INDICATOR>;
shift #content;
truncate(INDICATOR,0);
seek(INDICATOR,0,0);
foreach $line(#content)
{
print INDICATOR $line;
}
close(INDICATOR);
Edit again: above script would not work if perl runs in a single process and threads (interleaves) scripts itself. Such a scenario is the only one of the 3 asked by me which appears not to be the case based on the answer and feedback I got verbally separately. Above script can be made to work then by changing the unique value to a random number rather than the pid on quick thought however.
It is completely depended on set up of your web server. Does it uses plain CGI, FastCGI, mod_perl? You can set up both of scenarios you've described. In case of FastCGI you can also set up for a script to never exit, but do all its work inside a loop that keeps accepting connections from frontend web server.
Regarding an update to your question, I suggest you to start worrying about concurrent access from very start. Unless you're doing some absolutely personal application and deliberately set up your server to strictly run one copy of your script, pretty much any other site will sometime grow into something that will require 2 or more parallel processing scripts. You will save yourself a lot of headache if you plan this very common task ahead. Even if you only have one serving script, you will need indexing/clean up/whatever done by offline tasks and this will mean concurrent access once again.
If the perl scripts as invoked separately they will result in separate processes. Here is an demo using two scripts:
#master.pl
system('perl ./sleep.pl &');
system('perl ./sleep.pl &');
system('perl ./sleep.pl &');
#sleep.pl
sleep(10);
Then run:
perl tmp.pl & (sleep 1 && ps -A | grep perl)

create process independent of bash

I have written a program which calculates the amount of battery level available in my laptop. I have also defined a threshold value in the program. Whenever the battery level falls below threshold i would like to call another process. I have used system("./invoke.o") where invoke.o is the program that i have to run. I am running a script which runs the battery level checker program for every 5 seconds. Everything is working fine but when i close the bash shell the automatic invocation of invoke.o is not happening. How should i make the invoke.o to be invoked irrespective of whether bash is closed or not??. I am using UBUNTU LINUX
Try running it as: nohup ./myscript.sh, where the nohup command allows you to close the shell without terminating the process.
You could run your script as a cron job. This lets cron set up standard input and output for you, reschedule the job, and it will send you email if it fails.
The alternative is to run a script in the background with all input and output, including standard error output, redirected.
While you could make a proper daemon out of your program that kind of effort is probably not necessary.
man nohup
man upstart
man 2 setsid (more complex, leads to longer trail of breadcrumbs on daemon launching).

How to detect pending system shutdown on Linux?

I am working on an application where I need to detect a system shutdown.
However, I have not found any reliable way get a notification on this event.
I know that on shutdown, my app will receive a SIGTERM signal followed by a SIGKILL. I want to know if there is any way to query if a SIGTERM is part of a shutdown sequence?
Does any one know if there is a way to query that programmatically (C API)?
As far as I know, the system does not provide any other method to query for an impending shutdown. If it does, that would solve my problem as well. I have been trying out runlevels as well, but change in runlevels seem to be instantaneous and without any prior warnings.
Maybe a little bit late. Yes, you can determine if a SIGTERM is in a shutting down process by invoking the runlevel command. Example:
#!/bin/bash
trap "runlevel >$HOME/run-level; exit 1" term
read line
echo "Input: $line"
save it as, say, term.sh and run it. By executing killall term.sh, you should able to see and investigate the run-level file in your home directory. By executing any of the following:
sudo reboot
sudo halt -p
sudo shutdown -P
and compare the difference in the file. Then you should have the idea on how to do it.
There is no way to determine if a SIGTERM is a part of a shutdown sequence. To detect a shutdown sequence you can either use use rc.d scripts like ereOn and Eric Sepanson suggested or use mechanisms like DBus.
However, from a design point of view it makes no sense to ignore SIGTERM even if it is not part of a shutdown. SIGTERM's primary purpose is to politely ask apps to exit cleanly and it is not likely that someone with enough privileges will issue a SIGTERM if he/she does not want the app to exit.
From man shutdown:
If the time argument is used, 5 minutes before the system goes down
the /etc/nologin file is created to ensure that further logins shall
not be allowed.
So you can test existence of /etc/nologin. It is not optimal, but probably best you can get.
Its a little bit of a hack but if the server is running systemd if you can run
/bin/systemctl list-jobs shutdown.target
... it will report ...
JOB UNIT TYPE STATE
755 shutdown.target start waiting <---- existence means shutting down
1 jobs listed.
... if the server is shutting down or rebooting ( hint: there's a reboot.target if you want to look specifically for that )
You will get No jobs running. if its not being shutdown.
You have to parse the output which is a bit messy as the systemctl doesnt return a different exit code for the two results. But it does seem reasonably reliable. You will need to watch out for a format change in the messages if you update the system however.
Making your application responding differently to some SIGTERM signals than others seems opaque and potentially confusing. It's arguable that you should always respond the same way to a given signal. Adding unusual conditions makes it harder to understand and test application behavior.
Adding an rc script that handles shutdown (by sending a special signal) is a completely standard way to handle such a problem; if this script is installed as part of a standard package (make install or rpm/deb packaging) there should be no worries about control of user machines.
I think I got it.
Source =
https://github.com/mozilla-b2g/busybox/blob/master/miscutils/runlevel.c
I copy part of the code here, just in case the reference disappears.
#include "libbb.h"
...
struct utmp *ut;
char prev;
if (argv[1]) utmpname(argv[1]);
setutent();
while ((ut = getutent()) != NULL) {
if (ut->ut_type == RUN_LVL) {
prev = ut->ut_pid / 256;
if (prev == 0) prev = 'N';
printf("Runlevel: prev=%c current=%c\n", prev, ut->ut_pid % 256);
endutent();
return 0;
}
}
puts("unknown");
see man systemctl, you can determine if the system is shutting down like this:
if [ "`systemctl is-system-running`" = "stopping" ]; then
# Do what you need
fi
this is in bash, but you can do it with 'system' in C
The practical answer to do what you originally wanted is that you check for the shutdown process (e.g ps aux | grep "shutdown -h" ) and then, if you want to be sure you check it's command line arguments and time it was started (e.g. "shutdown -h +240" started at 14:51 will shutdown at 18:51).
In the general case there is from the point of view of the entire system there is no way to do this. There are many different ways a "shutdown" can happen. For example someone can decide to pull the plug in order to hard stop a program that they now has bad/dangerous behaviour at shutdown time or a UPS could first send a SIGHUP and then simply fail. Since such a shutdown can happen suddenly and with no warning anywhere in a system there is no way to be sure that it's okay to keep running after a SIGHUP.
If a process receives SIGHUP you should basically assume that something nastier will follow soon. If you want to do something special and partially ignore SIGHUP then a) you need to coordinate that with whatever program will do the shutdown and b) you need to be ready that if some other system does the shutdown and kills you dead soon after a SIGHUP your software and data will survive. Write out any data you have and only continue writing to append-only files with safe atomic updates.
For your case I'm almost sure your current solution (treat all SIGHUPs as a shutdown) is the correct way to go. If you want to improve things, you should probably add a feature to the shutdown program which does a notify via DBUS or something similar.
When the system shuts down, the rc.d scripts are called.
Maybe you can add a script there that sends some special signal to your program.
However, I doubt you can stop the system shutdown that way.

System call time out?

I'm using unix system() calls to gunzip and gzip files. With very large files sometimes (i.e. on the cluster compute node) these get aborted, while other times (i.e. on the login nodes) they go through. Is there some soft limit on the time a system call may take? What else could it be?
The calling thread should block indefinitely until the task you initiated with system() completes. If what you are observing is that the call returns and the file operation as not completed it is an indication that the spawned operation failed for some reason.
What does the return value indicate?
Almost certainly not a problem with use of system(), but with the operation you're performing. Always check the return value, but even more so, you'll want to see the output of the command you're calling. For non-interactive use, it's often best to write stdout and stderr to log files. One way to do this is to write a wrapper script that checks for the underlying command, logs the commandline, redirects stdout and stderr (and closes stdin if you want to be careful), then execs the commandline. Run this via system() rather than the OS command directly.
My bet is that the failing machines have limited disk space, or are missing either the target file or the actual gzip/gunzip commands.
I'm using unix system() calls to
gunzip and gzip files.
Probably silly question: why not use zlib directly from your application?
And system() isn't a system call. It is a wrapper for fork()/exec()/wait(). Check the system() man page. If it doesn't unblock, it might be that your application interferes somehow with wait() - e.g. do you have a SIGCHLD handler?
If it's a Linux system I would recommend using strace to see what's going on and which syscall blocks.
You can even attach strace to already running processes:
# strace -p $PID
Sounds like I'm running into the same intermittent issue indicating a timeout of some kind. My script runs every day. I'm starting to believe GZIP has a timeout.
gzip -vd filename.txt.gz 2>> tmp/errorcatch.txt 1>> logfile.log
stderr: Error for filename.txt.gz
Moves to next command 'cp filename* new/directory/', resulting in zipped version of filename in new directory
stdout from earlier gzip showing successful unzip of SAME file:
filename.txt.gz: 95.7% -- replaced with filename.txt
Successful out file from gzip is not there in source or new directory.
Following alerts, manual run of 'gzip -vd filename.txt.gz' never fails.
Details:
Only one call in script to unzip that file
Call for unzip is inside a function (for more rebust logging and alerting)
Unable to strace in production
Unable to replicate locally
In occurences over last month, found no consistency among file size, only
I'll simply be working around it with a retry logic and general scripting improvements, but I want the next google-er to know they're not crazy. This is happening to other people!

Resources