If your glibc is reasonably current, and devpts is set up correctly, there should be no need to invoke the pt_chown
helper at all.
You might be running into a known/potential issue removing setuid-root from pt_chown
.
grantpt()
supported devfs
from glibc-2.7, changes were made in glibc-2.11 though so that rather than explicitly checking for DEVFS_SUPER_MAGIC
, it checks instead to see if it needs to do any work before attempting chown()
or falling back to invoking pt_chown
.
From glibc-2.17/sysdeps/unix/grantpt.c
...
uid_t uid = __getuid ();
if (st.st_uid != uid)
{
if (__chown (buf, uid, st.st_gid) < 0)
goto helper;
}
...
A similar stanza is used to check the gid and the permissions.
The catch is that the uid, gid and mode must match expectations (you, tty, and exactly 620; confirm with /usr/libexec/pt_chown --help
). If not, chown()
(which would require capabilities CAP_CHOWN, CAP_FOWNER of the calling binary/process) is attempted, and if that fails, the pt_chown
external helper (which must be setuid-root) is attempted. In order for pt_chown
to be able to use capabilities it (and hence your glibc) must have been compiled with HAVE_LIBCAP
. However, it seems that pt_chown
is (as of glibc-2.17, and as you noted though you haven't stated the version) hard-coded to want geteuid()==0
regardless of HAVE_LIBCAP
, relevant code from glibc-2.17/login/programs/pt_chown.c
:
...
if (argc == 1 && euid == 0)
{
#ifdef HAVE_LIBCAP
/* Drop privileges. */
if (uid != euid)
...
#endif
/* Normal invocation of this program is with no arguments and
with privileges. */
return do_pt_chown ();
}
...
/* Check if we are properly installed. */
if (euid != 0)
error (FAIL_EXEC, 0, gettext ("needs to be installed setuid `root'"));
(Expecting geteuid()==0
before attempting to use capabilities doesn't seem to be really in the spirit of capabilities, I'd go with logging a bug on this one.)
A potential workaround might be to give CAP_CHOWN, CAP_FOWNER to the affected programs, but I really don't recommend that since you cannot restrict that to ptys of course.
If that doesn't help you solve it, patching sshd
and screen
is slightly less disagreeable than patching glibc. Since the problem lies within glibc though, a cleaner approach would be selective use of DLL injection to implement a dummy grantpt()
.
I don't think the permission denied is necessarily talking about the traditional permissions bits (rwx..), rather I'd be suspicious of something like SELinux or AppArmor which might be denying your process access.
I do not have access to a ArchLinux system but there is something similar under Fedora that is discussed here in this Fedora Wiki topic: Features/SELinuxDenyPtrace.
Here they're blocking access to ptrace through SELinux, so you might want to try disabling either SELinux or AppArmor is ArchLinux happens to be using either.
What your attempting worked for me
I tried you code on my Fedora 19 system and other than needing to install some addtional debuginfo RPMs it worked as you'd expect it to.
Example
Compiled your code.
$ gcc -g test.c
Ran the resulting binary in gdb
.
$ gdb a.out
GNU gdb (GDB) Fedora 7.6.1-46.fc19
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/saml/tst/106912/a.out...done.
(gdb) break main
Breakpoint 1 at 0x40053f: file test.c, line 4.
(gdb) run
Starting program: /home/saml/tst/106912/a.out
Breakpoint 1, main (argc=1, argv=0x7fffffffd698) at test.c:4
4 printf("1\n");
Missing separate debuginfos, use: debuginfo-install glibc-2.17-20.fc19.x86_64
(gdb) quit
A debugging session is active.
Inferior 1 [process 13341] will be killed.
Quit anyway? (y or n) y
The debugger complained that I was missing the debuginfos for glibc so I installed them.
$ sudo debuginfo-install glibc-2.17-20.fc19.x86_64
Now when I re-run gdb
.
$ gdb a.out
GNU gdb (GDB) Fedora 7.6.1-46.fc19
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/saml/tst/106912/a.out...done.
(gdb) break main
Breakpoint 1 at 0x40053f: file test.c, line 4.
(gdb) run
Starting program: /home/saml/tst/106912/a.out
Breakpoint 1, main (argc=1, argv=0x7fffffffd698) at test.c:4
4 printf("1\n");
(gdb)
Best Answer
You can only debug a setuid or setgid program if the debugger is running as root. The kernel won't let you call
ptrace
on a program running with extra privileges. If it did, you would be able to make the program execute anything, which would effectively mean you could e.g. run a root shell by calling a debugger on/bin/su
.If you run Gdb as root, you'll be able to run your program, but you'll only be observing its behavior when run by root.
If you need to debug the program when it's not started by root, start the program outside Gdb, make it pause in some fashion before getting to the troublesome part, and
attach
the process inside Gdb (at 1234
where 1234 is the process ID).