On 10/11/2014 12:06 AM, Steven J. Long wrote:
> On Sun, Oct 05, 2014, Zac Medico wrote:
>> On 10/02/2014 07:32 PM, Steven J. Long wrote:
>>> On Tue, Sep 30, 2014, Zac Medico wrote:
>>>>> On Mon, Sep 29, 2014, Zac Medico wrote:
>>>>>> We control the shell code that launches the requested command, so we can
>>>>>> save the environment after the requested command completes (using a
>>>>>> modified version of our existing environment persistence code).
>>>>>
> <snip>
>>>> You're thinking in terms of a SUID helper like sudo. The implementation
>>>> that I've been suggesting does not involve a SUID helper.
>>>
>>> No, I'm thinking in terms of "a process with elevated privileges" running
>>> "a specific command"; whether that first process is started by us or not,
>>> is irrelevant to whether it can get the environment from a child process
>>> we have no control over, after it "completes".
>>
>> You're assuming that we have no control over the child process, which
>> would be true with a SUID helper like sudo (in the absence of a wrapper
>> script, see below) that is only designed to run a specific command and
>> then exit without saving the enviroment.
>
> I've already agreed you can run a shell command that you control: that's
> equivalent to running a process whose code you control.
>
>> However, imagine a helper that is designed to run a requested shell
>> command and then save the environment before it exits. It could be done
>> with sudo if you simply required that the first argument to sudo be a
>> wrapper script that executes the requested command and then saves the
>> environment. For example, consider the following usage:
>>
>> sudo /foo/bar/wrapper.sh <requested shell command with arguments>
>
>> If the sudo command is constructed shown above, then wrapper.sh can load
>> an arbitrary environment, execute the requested shell command with
>> arguments, and then save the resulting environment afterwards.
>
> What command exactly? Since after any external it runs, which I thought was
> the whole point of this, it can't get the resultant env. You're in the
> same situation, only you're discussing a shell command as opposed to a
> "privileged process".
>
> I'm just trying to get at which env exactly you think you're getting.
The shell env consists of shell variables and functions.
Maybe it helps if I explain it in terms of existing ebuild phases that
are already supported. For example, pkg_setup runs as root, and the
ebuild's shell enviroment is saved. This environment contains the ebuild
functions and variables as well as the functions and variables of the
eclasses it inherits. When the src_unpack phase is called, it runs as
the "portage" user, and it's able to load the environment from
pkg_setup. So, we have two phases sharing/mutating the same shell
environment, yet they run as different users with different privileges.
The pkg_setup/src_unpack environment sharing is very similar to the
environment sharing that I have suggested for esudo. You can consider
them to be practically identical, except that esudo will allow an
unprivileged phase to launch a privileged shell with a shared
environment, using basically the same mechanics that allow pkg_setup and
src_unpack to share the same environment.
>>> Sure it can save its own, but since it's a generic "run any command" helper,
>>> it can't do much more than give us back what we gave it, unless you're
>>> talking about echoing back settings, in the manner of gpg et al, which
>>> by definition is not about the saved env. That's why we have to use that
>>> format in the first place; because the env setting must be done by the
>>> process which wants to use it (have it inherited for child processes),
>>> for the same reason: a child process can never affect the parent env.
>>
>> We could implement esudo so that it will insert wrapper.sh into the sudo
>> arguments, so that the caller doesn't have to know anything about the
>> wrapper.sh implementation details. For example:
>
>> esudo <requested shell command with arguments>
>
> So that's going to call the listener with a string to eval(gack) and the
> listener will then launch a bash process to evaluate the line, correct?
>
> Given that this is ebuild context, that's likely going to be a process
> that loads the env saved before the call, in order to have access to the
> functions and metadata declared in the ebuild. And then evaluates the
> line given (which sets off all sorts of alarm-bells).
Right.
> In the typical case that's just going to be an external we could have
> called anyway. In the case pertinent to this discussion, there is some
> sort of env-setting going on. But not from externals, unless of the
> gpg-ilk such that we can load any variable settings they give us, or
> they write out to a file we can source; iow not from 99% of externals.
>
> Presumably the shell line (I'd guess a call to a saved function in env)
> is going to export settings back to the env, which will be saved by the
> usual mechanism.
>
> Is that about right?
Right. Maybe I should have read your this part of your email before I
wrote the pkg_setup/src_unpack example above, because it seems like your
getting the idea now.
>> So, the privilege escalation mechanism is indeed irrelevant, as long as
>> there's some opportunity to insert a wrapper script that runs with
>> escalated privileges, allowing it to load/save the environment at the
>> appropriate time during shell execution.
>
> Yeah we just run a shell script (as a privileged user). Which can save its
> own env off for sure; just not the env from some external it happens to
> run, which is usually the functional aspect of a shell script. It could
> run something like gpg et al which give an env return, as I described before.
>>>> Instead, IPC
>>>> would be used to request that the privileged parent process launch a new
>>>> privileged process on behalf of esudo. In this context, unless the esudo
>>>> implementation provides explicit support for environment inheritance,
>>>> the new privileged process will not inherit any environment from the
>>>> environment where esudo was called.
>>>
>>> Well, assuming that were the implementation, that explains why you'd want
>>> to save the env off, so that the privileged helper can access it. It still
>>> sounds like more work in the long run in terms of what's happening, but
>>> regardless: it doesn't get you the resultant env from the child command.
>>
>> Except that it is possible to save the resultant env from the child
>> command, using a wrapper as described above.
>
> No, you haven't convinced me of that at all. It's certainly possible to save
> the env from a command whose _code you control_, as I stated *upfront*. But
> not from some random command you don't. Running it from shell doesn't get
> round that, and if you save the resultant env, you're just doing what I
> said before, in the context of a "privileged process".
I've been talking about the *shell* environment (sorry, thought it would
be obvious). When speaking about the writing of ebuilds and eclasses,
generally "the environment" means the "shell environment" which consists
of shell variables and functions.
> If that's all you mean, then fair enough. Presumably there is some interest
> in elevated shell scripts running specific commands and then exporting to
> the env, as opposed to just running a specific command to access a device,
> say.
Sure, there may be some interest in it. I can practically already hear
people asking "why can't we use esudo to call a shell function from the
ebuild env". The answer would be that we didn't design it that way, not
that it wasn't possible.
>>> But like I said, that's of dubious utility in any case. I think we should
>>> just forget about it.
>>
>> It may have dubious utility, but it's still possible, nonetheless.
>
> Nope, show me the flow of execution and convince me: you haven't yet. It
> shouldn't be hard, a -> b -> c with ids that make sense, and a line
> indicating foo=bar and show how it flows back to the caller. (Each is a
> separate process.) It'd take 5 minutes to work out on a bit of paper,
> for you.
>
> All you've demonstrated so far, is that it's possible to run a script.
Does the pkg_setup/src_unpack example that I've given above clarify it
for you?
>>>> The IPC implementation that I've suggested does not involve an SUID
>>>> helper, so it is much more secure. Security would rely on the permission
>>>> bits of the named pipes that are used to implement IPC.
>>>
>>> I see, so presumably there's a fifo pair, that only the portage user can
>>> access (likely at dir level too), one read-only? On the other end of which
>>> you have a waiting process, ie a daemon, in the classic sense, with root
>>> privilege, so it can run any command as any user, with any set of caps
>>> required. If you're using IPC to request a process with privilege be
>>> launched, something's got to be listening to the other end.
>>
>> Yes, this is how ebuild helpers like has_version and best_version
>> already work. The IPC system can easily be extended to handle privilege
>> escalation commands.
>>
>>> I don't see how that's "more secure", but then I don't really care how you
>>> implement it, either ;) It's certainly less deps, I guess.
>>
>> Well, a named pipe that is only readable/writable by a specific user is
>> inherently more secure that a SUID binary that can be executed by any user.
>
> Who said it can be executed by any user? That would be foolish; my point
> ("borrow a suid helper") was you use the same file perms you're using above
> for the fifo, for the executable, at least in terms of effect: only the
> portage uid has access to the dir, only the portage gid can run the binary,
> which is suid root.
Generally sudo is installed with a+x, and I thought that you had
suggested that we use sudo. Anyway, I think we should focus this
discussion on the environment loading/saving. The privilege escalation
mechanism can be considered as an irrelevant implementation detail.
> See: _same_ access control (kernel-fs), no difference in terms of security,
> *much* less effort in general terms.
>
> That can additionally be configured by sudo, much the same as the admin can
> configure any command they like via sudo, should they have it installed. But
> it doesn't have to be: it's just a suid helper you install along with your
> package, that has specific permissions on the directory and the executable,
> which the helper checks, much like ssh checks perms on ~/.ssh.
>
> I accept, however, that you have the below already running, and have no wish
> to influence your implementation decision in-situ. Just to verify that
> what you're talking about seems reasonable.
>
> If above you mean that your named-pipe/listener is inherently more secure
> than sudo, forgive me for demurring. As well argue that every daemon is
> inherently more secure than sudo, simply because they're not suid.
>
> I'd gone on the helper as I wasn't sure sudo can do caps, and it seems to
> me you're going to want a bit of extra stuff like fs and network namespaces
> which are simple enough in C.
>
>> Well, the daemon is already there listening for commands such as
>> has_version and best_version. Extending it to handle privilege
>> escalation would be fairly easy. The overhead involved is negligible.
>> For things like has_version and best_version, the daemon approach is
>> actually much more efficient than the alternatives, since the daemon has
>> access to relatively long-lived database instances that would otherwise
>> have to be instantiated for each has_version/best_version call.
>
> Yeah fair enough.
>
>>> And as above, it cannot get us the env after randomcmd completes, but
>>> that's orthogonal, since nothing can, and programs aren't written
>>> to output to their env, since the parent can't access it.
>>
>> Again, a wrapper script like wrapper.sh described above would have
>> access to the resultant env.
>
> Only of _itself_, same as "code we control" in prior mails.
>
> If that suffices, then fair enough; but it's not the mythical "run external
> command as privileged user and get resultant env" that was presented
> at the start of this. Since that doesn't exist, unless you get into debug
> facilities, and afaic that really would be Doing It Wrong.
I'm sorry I wasn't more clear that I was speaking about the *shell*
environment. Again, I thought it would be obvious to the audience here.
>> What I have in mind is the existing IPC system that portage already uses
>> to implement commands like has_version and best_version.
>
> So the back-end process running the database queries is already privileged;
> or would be, or is a helper?
>
>>> Though from what I've seen even Linux-specific projects just
>>> exec the command, after setting privileges, namespace etc as
>>> appropriate, from a suid helper.
>>
>> An SUID helper would certainly work. However, given the existing IPC
>> infrastructure, I would use IPC.
>
> Yeah it's always tempting to integrate everything. It always seems to
> make so much sense, the bits are right there..
>
>> The portage user/group is already a possible attack vector:
>>
>> https://bugs.gentoo.org/show_bug.cgi?id=149062
>>
>> For this reason, it's very important not to grant access to this
>> user/group to untrusted users.
>
> In which case, the suid helper seems even more appropriate to my tired
> old eyes. Still, good luck with whichever way you go.
For the purposes of this discussion, it's best that the privilege
escalation mechanism be considered an irrelevant implementation detail.
--
Thanks,
Zac