Project

General

Profile

Bug #864

at(1) should not popen /usr/bin/pwd

Added by Rich Lowe over 9 years ago. Updated about 9 years ago.

Status:
Resolved
Priority:
Normal
Assignee:
-
Category:
cmd - userland programs
Start date:
2011-03-29
Due date:
% Done:

0%

Estimated time:
Difficulty:
Medium
Tags:
needs-triage
Gerrit CR:

Description

For some reason I can't currently fathom, at(1) popens /usr/bin/pwd

It opens a pipe, forks, and in the child setuid's to the real user, then popens /usr/bin/pwd and writes the result back up the pipe to the parent. It's vaguely possible that there's a good reason for this, but I'm not at the moment seeing it.

At the very least, I can't come up with a reason it could not just call getcwd(3C) in the child.

History

#1

Updated by Roland Mainz over 9 years ago

I have no clue what this code does... but... maybe the intention of the code was/is to get the physical path (e.g. pwd -P) instead of the logical path name returned by |getcwd()|.
Example:
The ksh/bash "pwd" builtin returns the logical path name while the external /usr/bin/pwd utilitz returns the physical path name:
$ cd /usr/lib/32/32/32/
$ pwd
/usr/lib/32/32/32
$ /usr/bin/pwd
/usr/lib

#2

Updated by Rich Lowe over 9 years ago

getcwd(3C) returns the physical pathname too, so there'd be no difference here. I think it's just ancient code.

The SunOS-compat libbc getcwd() uses "pwd" too (most unsafely), Gordon thinks possibly to get some special-cased behaviour of the old SunOS pwd relating to the old automounter. Perhaps they have the same reasons (though at is from AT&T, and libbc from Berkeley)

#3

Updated by Roland Mainz over 9 years ago

Rich Lowe wrote:

getcwd(3C) returns the physical pathname too, so there'd be no difference here. I think it's just ancient code.

Mhhh... I am still wondering why it explicitly uses /usr/bin/pwd as external process. |getcwd()| is a quite old function in libc and somehow I am wondering why noone complained about the extra process |fork()| if it would be unneccesary...

#4

Updated by Rich Lowe over 9 years ago

Well, if the code existed on 4, libc would be forking for it too, so there'd be no savings. Special casing of the old automount behaviour (the BSD automount behaviour, with /tmp_mnt/ or whatever it was) would probably be seen as a feature.

There should be no difference in, for eg, behaviour in a directory to which you don't have permission to read or enter after the setuid.

#5

Updated by Gary Mills over 9 years ago

  • Difficulty set to Medium
  • Tags set to needs-triage

The `at' command runs setuid root. It has to determine
the user's CWD so that it can later execute the at job from
the same directory. It runs /usr/bin/pwd in a pipe to obtain
this information. The `getcwd()' function also runs `pwd'
in a pipe, expecting /usr/bin to be in the PATH. This is
harmless unless it's run by root with the user setting PATH.
It's not safe when called by `at' as root. `at' seems to be
secure now. I see no way to improve the code, and no reason
to change it.

I'd recommend closing this bug report.

#6

Updated by Rich Lowe over 9 years ago

Gary Mills wrote:

The `at' command runs setuid root. It has to determine
the user's CWD so that it can later execute the at job from
the same directory. It runs /usr/bin/pwd in a pipe to obtain
this information. The `getcwd()' function also runs `pwd'
in a pipe, expecting /usr/bin to be in the PATH.

You're looking at the wrong getcwd(). The SunOS compat getcwd() behaves as you describe, the real getcwd() is a system call.

(src/lib/libbc is the SunOS compat library, the real C library is src/lib/libc)

#7

Updated by Gary Mills over 9 years ago

Yes, I was looking at the wrong getcwd(). With the right
one, changes are possible. Even the fork() is no longer
needed, as long as getcwd() runs as the user to handle the
NFS case. Something like this might work:

realusr = getuid();
(void) setuid(realusr);
getcwd(dirbuf, sizeof(dirbuf));
(void) setuid(0);
#8

Updated by Gary Mills over 9 years ago

Of course I meant to set only the effective UID, like this:

realusr = getuid();
(void) seteuid(realusr);
getcwd(dirbuf, sizeof(dirbuf));
(void) seteuid(0);
#9

Updated by Gordon Ross about 9 years ago

  • Status changed from New to Resolved

changeset: 13372:dd80b2e7fda4
tag: tip
user: Gary Mills <>
date: Sun May 15 13:49:21 2011 -0500
description:
864 at(1) should not popen /usr/bin/pwd
Reviewed by: Garrett D'Amore <>
Reviewed by: Albert Lee <>
Approved by: Gordon Ross <>

Also available in: Atom PDF