How to get maximum number of child processes inside a Docker container? - linux

I'm trying to run the following program inside a Docker container, which is started with --privileged:
root#1df00aaf673d:~# cat > sysconf_test.c
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
int main() {
long n = sysconf(_SC_CHILD_MAX);
printf("%ld %d\n", n, errno);
return 0;
}
root#1df00aaf673d:~# gcc sysconf_test.c ; ./a.out
-1 0
Going by the sysconf man page, "If name corresponds to a maximum or minimum limit, and that limit is indeterminate, -1 is returned and errno is not changed." Is there a way to make it determinate, perhaps by passing an option to the docker run command?

I'll answer my own question: it appears that sysconf returns -1L for "unlimited", although the man page doesn't spell it out:
[root#llg00amn ~]# ulimit -u
120996
[root#llg00amn ~]# docker run -ti debian /bin/bash
root#5668a7acb957:/# ulimit -u
unlimited
After setting the ulimit to an actual number, the program runs fine and returns the right result.

Related

why does GDB lower its privilege during debugging?

GDB lowers its privileges during debugging - for instance, SETUID root programs won't run
with root privilege.
I do not see why GDB should lower its privilege, since GDB is utilized on administrator-access regarding the binary. Is there any explicit reason why it lowers its privilege?
I don't understand your second paragraph at all, but lets work through an example. I'm debugging a test program borrowed from here:
#define _POSIX_C_SOURCE 200112L // Needed with glibc (e.g., linux).
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
void report (uid_t real) {
printf (
"Real UID: %d Effective UID: %d\n",
real,
geteuid()
);
}
int main (void) {
uid_t real = getuid();
report(real);
seteuid(real);
report(real);
return 0;
}
Then compile and setuid with:
gcc -g3 -O0 -o testuid testuid.c
sudo chown root testuid
sudo chmod u+s testuid
Now, when I run this without GDB:
$ ./testuid
Real UID: 1000 Effective UID: 0
Real UID: 1000 Effective UID: 1000
And now with GDB:
$ gdb -quiet -batch -ex run ./testuid
Real UID: 1000 Effective UID: 1000
Real UID: 1000 Effective UID: 1000
[Inferior 1 (process 3134807) exited normally]
I think you're asking why the setuid doesn't work when run under GDB.
It's not that GDB is choosing to drop privilege, but rather the kernel that prevents the test program acquiring privilege when being run under the debugger, when the debugger has a lower privilege level.
Imagine for a moment if this wasn't the case, I, a non privileged user can just debug a setuid binary and get root privilege. At this point I could use the debugger to inject any code I like and execute that code with root permissions.
The only way to debug a setuid binary with the setuid privilege level is to "show" the kernel that you already have access to that privilege level, so, for example:
$ sudo gdb -quiet -batch -ex run ./testuid
Real UID: 0 Effective UID: 0
Real UID: 0 Effective UID: 0
[Inferior 1 (process 3138369) exited normally]
Of course, it's no longer the setuid bit that is giving the test program root, we're starting the test program as root, but as far as I know that's going to be your only option.

Does GNU time memory output account for child processes too?

When running GNU time (/usr/bin/time) and checking for memory consumption, does its output account for the memory usage of the child processes of my target program?
Could not find anything in GNU's time manpage.
Yes.
You can easily check with:
$ /usr/bin/time -f '%M' sh -c 'perl -e "\$y=q{x}x(2*1024*1024)" & wait'
8132
$ /usr/bin/time -f '%M' sh -c 'perl -e "\$y=q{x}x(8*1024*1024)" & wait'
20648
GNU time is using the wait4 system call on Linux (via the wait3 glibc wrapper), and while undocumented, the resource usage it returns in the struct rusage also includes the descendands of the process waited for. You can look at the kernel implementation of wait4 in kernel/exit.c for all the details:
$ grep -C2 RUSAGE_BOTH include/uapi/linux/resource.h
#define RUSAGE_SELF 0
#define RUSAGE_CHILDREN (-1)
#define RUSAGE_BOTH (-2) /* sys_wait4() uses this */
#define RUSAGE_THREAD 1 /* only the calling thread */
FreeBSD and NetBSD also have a wait6 system call which returns separate info for the process waited for and for its descendants. They also clearly document that the rusage returned by wait3 and wait4 also includes grandchildren.

Passing Commands into a Binary that runs a shell using a bash script

New to bash scripting so having a little teething problem and was wondering if someone could clear up some trouble I'm having, I have a simple C file called test that creates a shell as seen below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main()
{
execl("/bin/sh", "/bin/sh", (void *) NULL);
perror("exec");
return 1;
}
I want to create a bash script to execute this file which I have done below, but then on execution I then wish to send commands to the shell that the binary creates - is this possible I am trying the following to no avail:
#!bin/bash
/var/testfolder/test; # execute the test c file to spawn the shell
??? #don't know how to pass commands to the new shell created :(
Your compiled C binary has the SETUID permission i suppose? With the binary and arguments you can execute any shell like this with this binary permission:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main( int argc, char ** argv )
{
execv("/bin/sh", argv );
perror("exec");
return 1;
}
Output of a test script to print arguments and current process:
$ ./test_execv ./test.sh foo bar
Executing $0: ./test.sh
Args $*: foo bar
process:
PID TTY TIME CMD
3300 pts/1 00:00:08 bash
3498 pts/1 00:00:00 sh
3499 pts/1 00:00:00 ps
Security issue
If you can execute a script to a root shell, anyone can do this. I think you just have to add some of your scripts (only those needed) with a sudo permission to be run as root from your the needed account.
Try this:
#!/bin/bash
/var/testfolder/test <<EOF
cmdtopass1
cmdtopass2
cmdtopass3
EOF

How to see the daemon process's output in Linux?

I wrote a test.c:
#include <unistd.h>
#include <stdio.h>
int main()
{
while(1)
{
sleep(1);
printf("====test====\r\n");
}
return 0;
}
then i compile it : gcc ./test.c -o ./test
and the i wrote a shell script:
#!/bin/sh
./test &
and then i made this script to be executed automatically on system boot.
then I login to the Linux system using secureCRT in SSH protocol.
using "ps aux | grep test" i can see the test process running,
but i just cannot see the test's output, some people told me because the test
output to tty, and i am using pts.
could anybody tell me the specific reason and how can i get the output?
thanks in advance!
It doesn't output anything because it got no terminal attached.
If you want your output to be visible to every terminal connected to the system, use wall
./test | wall
(it will be very annoying)
I suggest you to redirect the output to a log file.

How to generate a core dump in Linux on a segmentation fault?

I have a process in Linux that's getting a segmentation fault. How can I tell it to generate a core dump when it fails?
This depends on what shell you are using. If you are using bash, then the ulimit command controls several settings relating to program execution, such as whether you should dump core. If you type
ulimit -c unlimited
then that will tell bash that its programs can dump cores of any size. You can specify a size such as 52M instead of unlimited if you want, but in practice this shouldn't be necessary since the size of core files will probably never be an issue for you.
In tcsh, you'd type
limit coredumpsize unlimited
As explained above the real question being asked here is how to enable core dumps on a system where they are not enabled. That question is answered here.
If you've come here hoping to learn how to generate a core dump for a hung process, the answer is
gcore <pid>
if gcore is not available on your system then
kill -ABRT <pid>
Don't use kill -SEGV as that will often invoke a signal handler making it harder to diagnose the stuck process
To check where the core dumps are generated, run:
sysctl kernel.core_pattern
or:
cat /proc/sys/kernel/core_pattern
where %e is the process name and %t the system time. You can change it in /etc/sysctl.conf and reloading by sysctl -p.
If the core files are not generated (test it by: sleep 10 & and killall -SIGSEGV sleep), check the limits by: ulimit -a.
If your core file size is limited, run:
ulimit -c unlimited
to make it unlimited.
Then test again, if the core dumping is successful, you will see “(core dumped)” after the segmentation fault indication as below:
Segmentation fault: 11 (core dumped)
See also: core dumped - but core file is not in current directory?
Ubuntu
In Ubuntu the core dumps are handled by Apport and can be located in /var/crash/. However, it is disabled by default in stable releases.
For more details, please check: Where do I find the core dump in Ubuntu?.
macOS
For macOS, see: How to generate core dumps in Mac OS X?
What I did at the end was attach gdb to the process before it crashed, and then when it got the segfault I executed the generate-core-file command. That forced generation of a core dump.
Maybe you could do it this way, this program is a demonstration of how to trap a segmentation fault and shells out to a debugger (this is the original code used under AIX) and prints the stack trace up to the point of a segmentation fault. You will need to change the sprintf variable to use gdb in the case of Linux.
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>
static void signal_handler(int);
static void dumpstack(void);
static void cleanup(void);
void init_signals(void);
void panic(const char *, ...);
struct sigaction sigact;
char *progname;
int main(int argc, char **argv) {
char *s;
progname = *(argv);
atexit(cleanup);
init_signals();
printf("About to seg fault by assigning zero to *s\n");
*s = 0;
sigemptyset(&sigact.sa_mask);
return 0;
}
void init_signals(void) {
sigact.sa_handler = signal_handler;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction(SIGINT, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGSEGV);
sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGBUS);
sigaction(SIGBUS, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGQUIT);
sigaction(SIGQUIT, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGHUP);
sigaction(SIGHUP, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGKILL);
sigaction(SIGKILL, &sigact, (struct sigaction *)NULL);
}
static void signal_handler(int sig) {
if (sig == SIGHUP) panic("FATAL: Program hanged up\n");
if (sig == SIGSEGV || sig == SIGBUS){
dumpstack();
panic("FATAL: %s Fault. Logged StackTrace\n", (sig == SIGSEGV) ? "Segmentation" : ((sig == SIGBUS) ? "Bus" : "Unknown"));
}
if (sig == SIGQUIT) panic("QUIT signal ended program\n");
if (sig == SIGKILL) panic("KILL signal ended program\n");
if (sig == SIGINT) ;
}
void panic(const char *fmt, ...) {
char buf[50];
va_list argptr;
va_start(argptr, fmt);
vsprintf(buf, fmt, argptr);
va_end(argptr);
fprintf(stderr, buf);
exit(-1);
}
static void dumpstack(void) {
/* Got this routine from http://www.whitefang.com/unix/faq_toc.html
** Section 6.5. Modified to redirect to file to prevent clutter
*/
/* This needs to be changed... */
char dbx[160];
sprintf(dbx, "echo 'where\ndetach' | dbx -a %d > %s.dump", getpid(), progname);
/* Change the dbx to gdb */
system(dbx);
return;
}
void cleanup(void) {
sigemptyset(&sigact.sa_mask);
/* Do any cleaning up chores here */
}
You may have to additionally add a parameter to get gdb to dump the core as shown here in this blog here.
There are more things that may influence the generation of a core dump. I encountered these:
the directory for the dump must be writable. By default this is the current directory of the process, but that may be changed by setting /proc/sys/kernel/core_pattern.
in some conditions, the kernel value in /proc/sys/fs/suid_dumpable may prevent the core to be generated.
There are more situations which may prevent the generation that are described in the man page - try man core.
For Ubuntu 14.04
Check core dump enabled:
ulimit -a
One of the lines should be :
core file size (blocks, -c) unlimited
If not :
gedit ~/.bashrc and add ulimit -c unlimited to end of file and save, re-run terminal.
Build your application with debug information :
In Makefile -O0 -g
Run application that create core dump (core dump file with name ‘core’ should be created near application_name file):
./application_name
Run under gdb:
gdb application_name core
In order to activate the core dump do the following:
In /etc/profile comment the line:
# ulimit -S -c 0 > /dev/null 2>&1
In /etc/security/limits.conf comment out the line:
* soft core 0
execute the cmd limit coredumpsize unlimited and check it with cmd limit:
# limit coredumpsize unlimited
# limit
cputime unlimited
filesize unlimited
datasize unlimited
stacksize 10240 kbytes
coredumpsize unlimited
memoryuse unlimited
vmemoryuse unlimited
descriptors 1024
memorylocked 32 kbytes
maxproc 528383
#
to check if the corefile gets written you can kill the relating process with cmd kill -s SEGV <PID> (should not be needed, just in case no core file gets written this can be used as a check):
# kill -s SEGV <PID>
Once the corefile has been written make sure to deactivate the coredump settings again in the relating files (1./2./3.) !
Ubuntu 19.04
All other answers themselves didn't help me. But the following sum up did the job
Create ~/.config/apport/settings with the following content:
[main]
unpackaged=true
(This tells apport to also write core dumps for custom apps)
check: ulimit -c. If it outputs 0, fix it with
ulimit -c unlimited
Just for in case restart apport:
sudo systemctl restart apport
Crash files are now written in /var/crash/. But you cannot use them with gdb. To use them with gdb, use
apport-unpack <location_of_report> <target_directory>
Further information:
Some answers suggest changing core_pattern. Be aware, that that file might get overwritten by the apport service on restarting.
Simply stopping apport did not do the job
The ulimit -c value might get changed automatically while you're trying other answers of the web. Be sure to check it regularly during setting up your core dump creation.
References:
https://stackoverflow.com/a/47481884/6702598
By default you will get a core file. Check to see that the current directory of the process is writable, or no core file will be created.
Better to turn on core dump programmatically using system call setrlimit.
example:
#include <sys/resource.h>
bool enable_core_dump(){
struct rlimit corelim;
corelim.rlim_cur = RLIM_INFINITY;
corelim.rlim_max = RLIM_INFINITY;
return (0 == setrlimit(RLIMIT_CORE, &corelim));
}
It's worth mentioning that if you have a systemd set up, then things are a little bit different. The set up typically would have the core files be piped, by means of core_pattern sysctl value, through systemd-coredump(8). The core file size rlimit would typically be configured as "unlimited" already.
It is then possible to retrieve the core dumps using coredumpctl(1).
The storage of core dumps, etc. is configured by coredump.conf(5). There are examples of how to get the core files in the coredumpctl man page, but in short, it would look like this:
Find the core file:
[vps#phoenix]~$ coredumpctl list test_me | tail -1
Sun 2019-01-20 11:17:33 CET 16163 1224 1224 11 present /home/vps/test_me
Get the core file:
[vps#phoenix]~$ coredumpctl -o test_me.core dump 16163
This is typically sufficient:
ulimit -c unlimited
Note this will not persist between ssh sections! To add persistence:
echo '* soft core unlimited' >> /etc/security/limits.conf
Now, if you're using Ubuntu, "apport" is probably running. Here's how to check:
sudo systemctl status apport.service
If it is, you'll probably find core dumps in one of these places:
/var/lib/apport/coredump
/var/crash
If you want to change the location of core dumps
Make sure that you have the permissions to create files and the directory exists in the directory you're sending a core dump to!
Here's an example. Note this will not persist across reboots:
sysctl -w kernel.core_pattern=/coredumps/core-%e-%s-%u-%g-%p-%t
mkdir /coredumps
Make sure that the process that's crashing has access to write to this. The easiest way would be an example like this:
chmod 777 /coredumps
Test that core dumps works
> crash.c
gcc -Wl,--defsym=main=0 crash.c
./a.out
==output== Segmentation fault (core dumped)
If it doesn't say "core dumped" above, something isn't working.

Resources