Timo Sirainen wrote: > > > Looks like once a process has called setuid(), no-one except root can > > > ptrace() it. I don't see this mentioned very clearly in any man page > > > though (*BSD, Linux). > > > > my ptrace(2) page on debian woody says this: > > > > ERRORS > > EPERM The specified process cannot be traced. This could be because > > the parent has insufficient privileges; non-root processes cannot > > trace processes that they cannot send signals to or those > > running setuid/setgid programs, for obvious reasons. > > Alternatively, the process may already be being traced, or be > > init (pid 1). > > You mean the "running setuid/setgid programs"? How is setuid/setgid > program defined? I've always thought it was just the +s bit attached to > the file. When does the setuidness get cleared; after fork(), exec*(), > or ..? Is that standardized somewhere? The behaviour of programs with setuid/setgid bits is that executing such a program with exec*() results in euid/egid being set to the owner/group of the file. The effects persist until the program revokes those privileges with setuid(), seteuid() etc, or it executes another setuid/setgid program; executing a non-setgid program doesn't revoke the privileges. However, for the purpose of checking permissions for certain "unsafe" operations (e.g. ptrace()), Linux uses a slightly broader definition. It includes processes where uid != euid, but also those processes for which this was previously true but isn't now. IOW, a process running a setuid program remains untraceable even after it drops privileges, as it might still have access to privileged resources (e.g. descriptors) or have privileged data in memory. IIRC, this state ends when exec*() is called (for a non setuid program) after any excess privileges have been revoked. This should ensure that no privileged data remains in memory (exec*() completely replaces the process' memory space, except for the environment/argv page), although it's up to the programmer to ensure that any privileged resources which would survive exec*() (e.g. descriptors) are released first. Basically, the intention is that you can only trace "normal" processes, i.e. those which you own completely and have always owned completely; in case of doubt, permission is refused. However, the "abnormal" status must get revoked eventually, otherwise (almost) all non-root processes would be abnormal, as they ultimately inherit from an initial process (e.g. login, telnetd, sshd) which started as root then changed its ownership to that of the user. In 2.4.20, the actual permission checks for ptrace() are (from kernel/ptrace.c): if (task->pid <= 1) goto bad; if (task == current) goto bad; if (!task->mm) goto bad; if(((current->uid != task->euid) || (current->uid != task->suid) || (current->uid != task->uid) || (current->gid != task->egid) || (current->gid != task->sgid) || (!cap_issubset(task->cap_permitted, current->cap_permitted)) || (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE)) goto bad; rmb(); if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE)) goto bad; /* the same process cannot be attached many times */ if (task->ptrace & PT_PTRACED) goto bad; However, much of the logic is hidden by the use of task->mm->dumpable; IIRC, this determines whether a process can generate core dump, which has many of the same security considerations as ptrace(). Examination of kernel/sys.c indicates a number of places where this flag is cleared (mostly where various uids/gids differ). AFAICT, your original comment (that this isn't mentioned clearly in any man page) is correct. The above description comes from a mixture of comments made in various mailing lists and personal experience. -- Glynn Clements <glynn.clementsat_private>
This archive was generated by hypermail 2b30 : Sat Jan 11 2003 - 12:17:24 PST