Why is gdb requiring root permission to debug user programs? - linux

I have been using gdb quite successfully for a while, but I recently upgraded my version of Ubuntu, and now it seems that I can only get gdb to successfully run my program if I run as root. That is,
~ % gdb -q sleep -ex 'run 60'
Reading symbols from /bin/sleep...(no debugging symbols found)...done.
Starting program: /bin/sleep 60
tcsh: Permission denied.
During startup program exited with code 1.
(gdb)
fails, whereas
~ % sudo gdb -q sleep -ex 'run 60'
Reading symbols from /bin/sleep...(no debugging symbols found)...done.
Starting program: /bin/sleep 60
Running .tcshrc
warning: no loadable sections found in added symbol-file system-supplied DSO at 0x7ffff7ffa000
^C
Program received signal SIGINT, Interrupt.
0x00007ffff7adada0 in __nanosleep_nocancel () at ../sysdeps/unix/syscall-template.S:82
82 ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb)
works. One clue is that in the first case, the gdb startup doesn't run my .tcshrc file, whereas in the second case it does.
It seems that this is a simple permissions issue, which I must have fixed at one time, because in the past, I have never needed to run gdb as root. After much googling, however, I wasn't able to find what I might have done (if I did in fact do something). One possible fix - set ptrace permissions - didn't seem to work.
Is there something that needs to be done to allow gdb to run programs without root privileges? I know in OSX, gdb has to be codesigned. Is there something similar for Ubuntu/Linux?

here are some ideas for debugging the gdb problem. comments aren't really feasible for such things, so I put them into an answer.
try the -n option to make sure no init file is loaded.
use the echo program instead of sleep 60 to make debugging simpler (the SIGINT thing in your example is probably specific to the sleep program.
run gdb -batch and put the rest into ~/.gdbinit:
file /bin/echo
run
add set verbose on.
don't forget to clean up ~/.gdbinit when done.

I changed my login shell to bash and gdb no longer needs root permission to debug. Here is the latest :
My .gdbinit file:
(bash) ~ % more .gdbinit
show environment SHELL
file /bin/echo
run 'running .gdbinit'
(bash) ~ %
and the results of running gdb :
(bash) ~ % gdb -q -batch
SHELL = /bin/bash
running .gdbinit
[Inferior 1 (process 3174) exited normally]
(bash) ~ %
I still don't understand why tcsh didn't work, though, and am curious to know. So if anyone has a possible explanation, please comment.

This isn't a complete answer, but things are becoming clearer. The tip above was very helpful. I created the following .gdbinit file
show environment SHELL
file /bin/echo
run 'Goodbye'
and the results were interesting. If SHELL=/usr/tcsh, I get a permissions error, i.e.
~ % setenv SHELL /bin/tcsh
~ % gdb -q -batch
SHELL = /bin/tcsh
tcsh: Permission denied.
/home/calhoun/.gdbinit:12: Error in sourced command file:
During startup program exited with code 1.
Unsetting the shell variable works :
~ % unsetenv SHELL
~ % gdb -q -batch
Environment variable "SHELL" not defined.
Goodbye
[Inferior 1 (process 6992) exited normally]
In this case, run uses /bin/sh to expand the argument list. Setting SHELL to /bin/bash or /bin/dash will use those shells to expand the argument list, e.g.
~ % setenv SHELL /bin/bash
~ % gdb -q -batch
SHELL = /bin/bash
warning: no loadable sections found in added symbol-file system-supplied DSO at 0x7ffff7ffa000
Goodbye
[Inferior 1 (process 7280) exited normally]
Oddly, the "no loadable sections' error only happens when the shell variable is explicitly set. Another mystery.
Why /bin/tcsh doesn't work is still baffling. In my case, the permissions on /bin/tcsh are
~ % ls -lh /bin/tcsh
lrwxrwxrwx 1 root root 13 Oct 14 2011 /bin/tcsh -> /usr/bin/tcsh
~ % ls -lh /usr/bin/tcsh
-rwxr-xr-x 1 root root 382K Oct 14 2011 /usr/bin/tcsh
The problem could also be something in my .tcshrc file that is causing the shell to crash in this non-interactive mode.

Check if your program has executable privileges.
ls -l .
-rw-r--r-- 1 opt opt 30010 Aug 16 16:13 test
Something like 'test' maybe caused that when you debug it.

I specified Linux in the launch.json file, via the LaunchCompleteCommand...
MS has 3 different ways to specify the CPU... Windows, Linux or OSx
From https://code.visualstudio.com/docs/cpp/launch-json-reference
"launchCompleteCommand": "exec-run",
"linux": {
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb"
},
In my launch.json file, this LaunchCompleteCommand section was pasted in after the setupCommands section.

I faced this issue before, and files from /usr/bin/gdb* didn't have execution permissions. This happened after I have installed peda, pwndbg and gef.
# chmod +x /usr/bin/gdb-*

I had the same problem and the reason was that someone had set the sticky bit in the gdb executable:
cruiz> ls -l /usr/bin/gdb
-rwsr-sr-x 1 root root 4190760 2010-05-05 07:55 /usr/bin/gdb*
I changed it (chmod 755 /usr/bin/gdb) and now it works.
Before:
cruiz> gdb
...
(gdb) shell
csh: Permission denied.
After the change:
cruiz> gdb
(gdb) shell
cruiz>

Related

How to enable debugging for all bash scripts at system-wide level [duplicate]

This question already has answers here:
bash recursive xtrace
(2 answers)
Closed 11 months ago.
I have a linux system that uses lots of bash scripts as the bootup scripts. I want to print all the bash statements that are being executed in order to debug some issue. How can I do that at system-wide level?
I had the following as init in my system :
$ls -la /init
lrwxrwxrwx. 1 root root 20 Feb 10 04:46 /init -> /lib/systemd/systemd
I replaced init with a script like below :
#!/bin/bash
set -x
/lib/systemd/systemd
but no prints.
Download bash sources, change https://github.com/bminor/bash/blob/f3a35a2d601a55f337f8ca02a541f8c033682247/flags.c#L88 to echo_command_at_execute = 1. echo_command_at_execute might be reset somewhere later, in reset_shell_flags() and with change_flag('x', 0) - make echo_command_at_execute const and remove all assignments to it. Recompile and install. Create sh -> bash symlinks appriopriate for your system.
Note, that some scripts may parse stderr output of some shell programs. This modification may result in unstable system.
Copy /bin/bash to for example /bin/bash2, and similar with sh. Create an executable script:
#!/bin/bash2
/bin/bash2 -x "$#"
Repeat the process for sh. The paths have to be absolute.
Note, that for initrd you will have to regenerate it and include the copied executables and the scripts in the image. the copied executables in the image. Research your distribution specific ways about generating initrd.
I give an idea that do not confirm:
mv /bin/bash /bin/bashx
vi /bin/bash
/bin/bashx -x $#

Shell script doesn't exit if output redirected to logger

I was looking for a way to route the output of my shell scripts to syslog, and found this article, which suggests putting the following line at the top of the script:
exec 1> >(logger -s -t $(basename $0)) 2>&1
I've tried this with the following simple script:
#!/bin/bash
exec 1> >(logger -s -t $(basename $0)) 2>&1
echo "testing"
exit 0
When I run this script from the shell, I do indeed get the message in the syslog, but the script doesn't seem to return--in order to continue interacting with the shell, I need to hit Enter or send a SIGINT signal. What's going on here? FWIW, I'm mostly using this to log the results of cron jobs, so in the wild I probably don't need it to work properly in an interactive shell session, but I'm nervous using something I don't really understand in production. I am mostly worried about spawning a bunch of processes that don't terminate cleanly.
I've tested this on Ubuntu 15.10, Ubuntu 16.04, and OSX, all with the same result.
Cutting a long story short: the shell script does exit and so does the logger — there isn't actually a problem — but the output from the logger lead to confusion.
Converting comments into an answer.
Superficially, given the symptoms you describe, what's going on is that Bash isn't exiting until all its child processes exit. You could try exec >/dev/null 2>&1 before exit 0 to see if that stops the logger — basically, the redirection closes its inputs, so it should terminate, allowing the script to exit.
However, when I try your script (bash logtest.sh) on macOS Sierra 10.12.2 (though I'd not expect it to change in earlier versions), the command exits promptly and produces a log message on the terminal like this (I use Osiris JL: as my prompt):
Osiris JL: bash logtest.sh
Osiris JL: Dec 26 12:23:50 logtest.sh[6623] <Notice>: testing
Osiris JL: ps
PID TTY TIME CMD
71792 ttys000 0:00.25 -bash
534 ttys002 0:00.57 -bash
543 ttys003 0:01.71 -bash
558 ttys004 0:00.44 -bash
Osiris JL:
I hit return on the blank line and got the prompt before the ps command.
Note that the message from logger arrived after the prompt.
When I ran bash logtest.sh (where logtest.sh contained your script), the only key I hit was the return to enter the command (which the shell read before running the command). I then got a prompt, the output from logger, and a blank line with the terminal waiting for input. That's normal. The logger was not still running — I could check that in other windows.
Try typing ls instead of just hitting return. The shell is waiting for input. It wrote its prompt, but the logger output confused the on-screen layout. For me, I got:
Osiris JL: bash logtest.sh
Osiris JL: Dec 26 13:28:28 logtest.sh[7133] <Notice>: testing
ls
README.md ix37.sql mq13.c sh11.o
Safe lib mq13.dSYM so-4018-8770
Untracked ll89 oddascevendesc so-4018-8770.c
ci11 ll89.cpp oddascevendesc.c so-4018-8770.dSYM
ci11.c ll89.dSYM oddascevendesc.dSYM sops
ci11.dSYM ll97 rav73 src
data ll97.c rav73.c tf17
doc ll97.dSYM rav73.dSYM tf17.cpp
es.se-36764 logtest.sh rd11 tf17.dSYM
etc mac-clock-get-time rd11.c tf19
fa37.sh mac-clock-get-time.c rd11.dSYM tf19.c
fileswap.sh mac-clock-get-time.dSYM rn53 tf19.dSYM
gm11 makefile rn53.c x-paste.c
gm11.c matrot13 rn53.dSYM xc19
gm11.dSYM matrot13.c sh11 xc19.c
inc matrot13.dSYM sh11.c xc19.dSYM
infile mq13 sh11.dSYM
Osiris JL:

docker ubuntu container: shell linked to bash still starts shell

Alright guys, so I try to install rvm in a docker container based on ubuntu:14.04. During the process, I discovered that some people do something like this to ensure docker commands are also run with the bash:
RUN ln -fs /bin/bash /bin/sh
Now The weirdness happens and I hope someone of you can explain it to me:
→ docker run -it --rm d81ff50de1ce /bin/bash
root#e93a877ab3dc:/# ls -lah /bin
....
lrwxrwxrwx 1 root root 9 Mar 1 16:15 sh -> /bin/bash
lrwxrwxrwx 1 root root 9 Mar 1 16:15 sh.distrib -> /bin/bash
...
root#e93a877ab3dc:/# /bin/sh
sh-4.3# echo $0
/bin/sh
Can someone explain what's going on here? I know I could just prefix my commands in the dockerfile w/ bash -c, but I would like to understand what is happening here and if possible still ditch the bash -c prefix in the dockerfile.
Thanks a lot,
Robin
It's because bash has a compatibility mode where it tries to emulate sh if it is started via the name sh, as the manpage says:
If bash is invoked with the name sh, it tries to mimic the startup
behavior of historical versions of sh as closely as possible, while
conforming to the POSIX standard as well. When invoked as an
interactive login shell, or a non-interactive shell with the --login
option, it first attempts to read and execute commands from
/etc/profile and ~/.profile, in that order. The --noprofile option
may be used to inhibit this behavior. When invoked as an interactive
shell with the name sh, bash looks for the variable ENV, expands its
value if it is defined, and uses the expanded value as the name of a
file to read and execute. Since a shell invoked as sh does not
attempt to read and execute commands from any other startup files, the
--rcfile option has no effect. A non-interactive shell invoked with the name sh does not attempt to read any other startup files. When
invoked as sh, bash enters posix mode after the startup files are
read.

Busybox init does not start /etc/init.d/rcS

I'm trying to build embedded system using buildroot. Everything seems to work. All modules are starting, the system is stable. The problem is that /etc/init.d/rcS does not start during initialization of the system. If I run it manually everything is OK. I have it in my inittab file.
# /etc/inittab
#
# Copyright (C) 2001 Erik Andersen <andersen#codepoet.org>
#
# Note: BusyBox init doesn't support runlevels. The runlevels field is
# completely ignored by BusyBox init. If you want runlevels, use
# sysvinit.
#
# Format for each entry: <id>:<runlevels>:<action>:<process>
#
# id == tty to run on, or empty for /dev/console
# runlevels == ignored
# action == one of sysinit, respawn, askfirst, wait, and once
# process == program to run
# Startup the system
null::sysinit:/bin/mount -t proc proc /proc
null::sysinit:/bin/mount -o remount,rw /
null::sysinit:/bin/mkdir -p /dev/pts
null::sysinit:/bin/mkdir -p /dev/shm
null::sysinit:/bin/mount -a
null::sysinit:/bin/hostname -F /etc/hostname
# now run any rc scripts
::sysinit:/etc/init.d/rcS
# Put a getty on the serial port
ttyFIQ0::respawn:/sbin/getty -L -n ttyFIQ0 115200 vt100 # GENERIC_SERIAL
# Stuff to do for the 3-finger salute
::ctrlaltdel:/sbin/reboot
# Stuff to do before rebooting
null::shutdown:/etc/init.d/rcK
null::shutdown:/bin/umount -a -r
null::shutdown:/sbin/swapoff -a
Any idea what could be wrong?
/bin/init needs to be on your filesystem.
/bin/sh needs to be on your filesystem.
/etc/init.d/rcS needs to be executable and have #!/bin/sh as its first line.
Init
Are you sure you where invoking Busybox init? What was the kernel command line? If no init= option was supplied to the the kernel, the kernel will look for an executable at /init.
For instance, if your busybox binary resides in /bin/busybox, you need to create the following symlink :
ln -s /bin/busybox /init
If you want your init to reside in /sbin, to comply with the inittab, also create a symlink there. Note that the kernel will not respect init= setting if you don't mount root and your busybox only runs in an initramfs.
ln -s /bin/busybox /sbin/init
Inittab
Also, you could try not using an inittab. The things you try to run from inittab, might very well fit in rcS and any descendant scripts. From the same source you found your example inittab:
# Note: BusyBox init works just fine without an inittab. If no inittab is
# found, it has the following default behavior:
# ::sysinit:/etc/init.d/rcS
# ::askfirst:/bin/sh
# ::ctrlaltdel:/sbin/reboot
# ::shutdown:/sbin/swapoff -a
# ::shutdown:/bin/umount -a -r
# ::restart:/sbin/init
# tty2::askfirst:/bin/sh
# tty3::askfirst:/bin/sh
# tty4::askfirst:/bin/sh
rcS
Make sure /etc/init.d/rcS is executable:
chmod +x chroot chroot /bin/busybox
And try with:
#!/bin/busybox sh
echo "Hello world!"
Please note that this sentence can get buried between kernel log messages, so you might want to pass the quiet kernel command line option to see if it appears.
Busybox symlinks
Are the symlinks installed into the file system or not? If not it is not a disaster. Make sure that /etc/init.d/rcS starts with:
#!/bin/busybox sh
mkdir -pv /sbin
/bin/busybox --install -s
In addition to the scripts themselves being executable and having a correct shebang line, the kernel also needs to be compiled with the CONFIG_BINFMT_SCRIPT option enabled.
CONFIG_BINFMT_SCRIPT:
Say Y here if you want to execute interpreted scripts starting with
#! followed by the path to an interpreter.
You can build this support as a module; however, until that module
gets loaded, you cannot run scripts. Thus, if you want to load this
module from an initramfs, the portion of the initramfs before loading
this module must consist of compiled binaries only.
Most systems will not boot if you say M or N here. If unsure, say Y.
Without this option, you may receive the error message can't run '/etc/init.d/rcS': Exec format error.
From the information given, everything looks correct.
Some things to try:
Check ownership of your rcS script.
Comment out everything from rcS, and add something very simple:
echo "This worked" > /tmp/test
There might be something in your script related to a startup race condition that is causing it to exit. Also curious if your script is starting syslogd.

/bin/bash giving a segmentation fault upon startup

I am getting a segmentation fault from bash when I try to SSH to a remote server (running RHEL 4.4.5-6). After providing my credentials, the SSH client spits back the "Last login: ..." information, and then just hangs.
Out of curiosity, I pressed Ctrl-C and was able to get to a bash prompt. However, it's not the "usual" prompt that I see (it usually has my username, the server hostname, etc).
login as: xxxxxxx
xxxxx#xxxx's password:
Last login: Fri Mar 30 14:33:41 2012 from xxx.xx.xx.xxx
-bash-4.1$ echo $0
-bash
-bash-4.1$
I tried to run /bin/bash from GDB. After a medium-sized wait time, I finally got a SIGSEGV error:
(gdb) run
Starting program: /bin/bash
Program received signal SIGSEGV, Segmentation fault.
0x08067ab5 in yyparse ()
(gdb)
The last (significant) changes that I've made to the system was installing GNU screen (using yum install screen). Screen seemed to hang as well when I tried to start it (I'm assuming because it tried running bash, and got the same segfault).
Edit:
I tried running rpm -V:
-bash-4.1$ rpm -V bash
-bash-4.1$
Here are my .bash* files:
.bashrc:
# .bashrc
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
.bash_profile:
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
.bash_logout:
# ~/.bash_logout
.bash_history is quite long. I erased it, tried logging in again, and got the same results.
You're recursively sourcing your .bashrc from inside itself, which in a short test here does indeed lead to a segmentation fault. Removing that part from your .bashrc should hopefully fix the problem.

Resources