The same problem prevents the program from opening /proc/self/mem.
It is unusual for a setuid root program to have less permission than the
same program without setuid!
The problem is due to the following test in fs/proc/inode.c:
if (ino == PROC_PID_INO || p->dumpable) {
inode->i_uid = p->euid;
inode->i_gid = p->egid;
}
When this condition is not satisfied, inode->i_uid and inode->i_gid are
both set to zero.
I understand the need for this test even in the "exe" case: otherwise, a
program that's switching its euid all the time (like a file server that
doesn't know about fsuid) could inadvertantly give access to a file (the
executable) which may not be reachable to ordinary users by any other
means.
It seems to me that everything referenced through /proc/self should be
accessible to the process, though the same information, fetched through
/proc/<pid>, may be denied to other processes.
The following patch implements this:
--- linux/fs/proc/base.c.orig Sat Jun 1 04:15:22 1996
+++ linux/fs/proc/base.c Sat Jun 1 04:13:46 1996
@@ -57,7 +57,7 @@
for_each_task(p) {
if (p->pid == pid) {
- if (p->dumpable || ino == PROC_PID_INO) {
+ if (p->dumpable || p == current || ino == PROC_PID_INO) {
inode->i_uid = p->euid;
inode->i_gid = p->gid;
}
--- linux/fs/proc/inode.c.orig Sat Jun 1 01:52:25 1996
+++ linux/fs/proc/inode.c Sat Jun 1 04:14:16 1996
@@ -193,7 +193,7 @@
return;
}
ino &= 0x0000ffff;
- if (ino == PROC_PID_INO || p->dumpable) {
+ if (ino == PROC_PID_INO || p->dumpable || p == current) {
inode->i_uid = p->euid;
inode->i_gid = p->egid;
}
BTW, there is some duplication between proc_read_inode,
proc_pid_fill_inode and proc_get_inode for /proc/<pid>/*. The
permissions, reference counts and operations are set by proc_read_inode,
and then overwritten by proc_get_inode (which uses the proc_dir_entry
structure). proc_pid_fill_inode then changes the user and group ids,
ignoring the values chosen by proc_read_inode. (That had me confused
for a while).
I would be inclined to delete parts of proc_read_inode, leaving the
settings in the proc_dir_entry structures.
There is some conflict: proc_read_inode sets the reference count for
/proc/<pid> to 4, but then (somehow) the directory's reference count
comes out as 3. The directory link counts are generally wrong, due to
conflicting calculations. For example, /proc has a reference count of
5 (it should be much larger). /proc/net has a reference count of 2,
despite proc_register and proc_register_dynamic going to all the effort
of counting the links. There are others, too.
Enjoy,
-- Jamie