Procmail opens $HOME/.procmailrc before dropping setuid permissions
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
procmail (Ubuntu) |
Confirmed
|
Low
|
Unassigned |
Bug Description
Ubuntu release: Ubuntu 8.04.3 LTS (Hardy)
Package version: 3.22-16ubuntu3
Procmail is installed setuid root and opens the user's
$HOME/.procmailrc before dropping root permissions.
This is both a bug and a security issue, especially since
procmail makes no attempt to not follow symlinks and
so on when doing the open().
(This is a bug because there are situations, such as
NFS-mounted user home directories with restricted
permissions, where opening a file as root will fail but
opening the file as the user will succeed.)
Verification: 'strace -u <user> -- /usr/bin/procmail -t -Y </tmp/sample-mail'
and watch the order that syscalls are done in. (If you want
to see this in the wild as real mail delivery happens, you'll
need to use SystemTap.) My trace says:
[....]
umask(077) = 077
open("/
stat64(
open("/
setuid32(2315) = 0
Changed in procmail (Ubuntu): | |
status: | Invalid → New |
Changed in procmail (Ubuntu): | |
status: | Incomplete → Confirmed |
assignee: | Kees Cook (kees) → nobody |
Thanks for this report! As it turns out, this is just procmail attempting to work around the exact issue (strict NFS). If it were to actually open the rc file as root, it would close it and reopen after dropping privileges:
/* delay_setid, rctype, dowarning) rctype, dowarning; setid&& privileged& & /* if we can setid now and we haven't yet, */ privileged= =priv_DONTNEED| |!stat( buf,&stbuf) )) /* and we either don't */ setid&& privileged) /* if we're not supposed to delay */ 0>bopen( buf)) /* and try again */
* if we happen to be still running as root, and the rcfile
* is mounted on a secure NFS-partition, we might not be able
* to access it, so check if we can stat it or don't need any
* sgid privileges, if yes, drop all privs and set uid to
* the recipient beforehand
*/
static int tryopen(
const int delay_setid,
{ struct stat stbuf;
if(!delay_
(
setids(); /* need the privileges or it's accessible, then setid now */
if(0>bopen(buf)) /* try opening the rcfile */
{ if(dowarning)
rerr: readerr(buf);
return 0;
}
if(!delay_
{ closerc(); /* and we haven't changed yet, then close it, */
setids(); /* transmogrify to prevent peeking, */
if(
goto rerr; /* they couldn't read it, so it was bogus */
}
Note the "closerc()" attempt above.