Open Bug 845738 Opened 11 years ago Updated 2 months ago

In the context of bug 845736, implement ability for SupervisorChild process to launch unprivileged subprocesses

Categories

(Core :: General, defect)

x86_64
Linux
defect

Tracking

()

People

(Reporter: cjones, Unassigned)

References

(Depends on 1 open bug)

Details

Attachments

(1 file, 1 obsolete file)

Rough sketch

 protocol PSupervisor {
   child opens PContent as child;

System process Open()s PContent, on parent side Supervisor gets request and spawns new subprocess.  Do the rebind-to-new-thread hack, except across a new process.  At fork() set[ug]id(UNPRIVILEGED) and use seccomp to forbid the set[ug]id() syscalls.

There's a more complex impl but don't want to go there.  Need to flesh out.
In a bit more detail, with less sickness-addled brain

 1. System process calls PContent::Open() to create a new content channel.  This creates a ContentParent in the system process, and sends a message to create ContentChild (temporarily!) in the supervisor process.

 2. The supervisor process forks/execs a new subprocess.  This process inherits the create PContent fd, and we remap to the magic process channel fd number.

 3. The forked process (still with high privileges) setuid/setgid's itself down to nobody.  Same code that we already run.

 4. The content process Open()s its channel normally, binding it to the new content-process main thread.
We don't have to jump through these hoops for launching nested processes, because they're already running with the nobody privileges we want them to have.
No longer depends on: b2g-seccomp
I would propose a different process model, so that we can share our model with desktop firefox.
I believe that as long as the content processes are sandboxed, we are not exposed to any additional threat (risk analysis pending).


The new model would remove the need for setuid(), basically.

- b2g (parent process) and content-processes would run as the same, non-privileged UID (required)
- b2g would query another process ("supervisor", running as root/privileged user) for privileged operations such as reboot/update/etc as per bug 845736)
- we remove SetCurrentProcessPrivileges entirely (no more setuid() !)
- we require SetCurrentProcessSandbox (provides same security as the setuid "sandbox" and more)

This model is IMO clean, simple, and works on b2g desktop and firefox desktop as well.

Schematic:

[Supervisor  (root)]
   |
   | (IPC / bug 845736)
   |
[b2g "parent" (nobody)]
   |                  \
   | (IPDL)            \ (IPDL)
   |                    --------------------
   |                                        \
   |                                         \
[Sandboxed Content Process (nobody)]    [Sandboxed Content Process (nobody)] ...

Notes:
- b2g may or may not be forked+setuid+exec'd from Supervisor. It may also just be started by init. Does not matter.
- Content Processes may or may not be forked from b2g. It may also be started by Supervisor or init. Does not matter. If not started by b2g, a default, template process ("preallocated process") will the first-started process and forked from instead. Since b2g already provides this functionality as well, this is probably not an issue for either startup method.
- b2g desktop/firefox desktop do not have a supervisor.
FYI: b2g process works as system server and needs to run as system privilege.
as per IRC (comment 4):
yes - and even system needs additional filesystem privileges to access all the hw (starting by /dev/input/* which is root:input 660 and system's gid is only system)

Whichever user is used, we'd therefore need to modify either the filesystem owners/attributes either/and the hardcoded user/groups from Android/bionic.

We also discussed that, the mediaserver is automatically restarted by init when b2g dies, so using init to start b2g (even as a diff. user) is a good idea.
Assignee: nobody → jhector
I am currently working on the supervisor implementation. I dropped the privileges of b2g to system and I am stuck right now at the setuid()/setgid() part in nuwa after it did the fork. 

I have discussed the options a little with :kang on irc, which lead to the following:
(1) b2g drops its UID to system during startup, when nuwa forked, nuwa will then get back root with the help of the EUID. After nuwa is forked, b2g will drop its EUID to system as well so that there is no way to recover root beyond that point. Nuwa is now root and therefore able to call setuid/setgid in its forks. Like so:

b2g (system)
|
|
+---- nuwa (root)
       |
       +----- app (app_uid)
       |

(2) this option is bascially the idea proposed in Comment #1

(3) b2g drops all privileges to system (including EUID) and tells supervisor to fork nuwa with root privileges and does a exec("plugin-container -nuwa") (like b2g does right now), from there b2g and nuwa share an IPC connection and everything goes as usual

(4) kernel patch to setuid/setgid from kernel space

Option (4) is probably not considerable, since it is kind of hard to implement it and maintain it, but I wrote it down just to give you guys all options that came up.

I don't like (1) so much because when b2g is exploited between startup and before nuwa is created, the attacker will be able to recover root privileges. But developer couldn't rely on root in b2g any more. It would be the easiest to implement.

Option (2) would basically replace nuwa since supervisor would be the new nuwa, there is probably to much going on in nuwa to implement that in the supervisor (supervisor should be low in memory)

I am in favor of option (3) since we don't expose any risk during start of b2g and fork of nuwa.

What do you guys think? Keep in mind that we try to keep the memory usage low, since the end product will only have 128 MB of RAM.

Option (1) is probably the option with the lowest memory usage.
Flags: needinfo?(cyu)
I think the basic requirement is that we keep memory usage low. I would say (1) is the route I'd like to take. Please be noted that the b2g loader (but 977026) work has landed. You might need to take it into consideration when implementing PSupervisor. Maybe we make b2g loader the supervisor process and then forks b2g and Nuwa processes.
Flags: needinfo?(cyu)
See Also: → 977026
So with the landing of b2gloader, this can be solved a lot better.
The way I did it right now is somewhat similar to (1) but there is no point in time where b2g can gain root again after it dropped its privileges to system:system.

b2gloader starts as root, fork()s and now we have (nuwa) running as root and b2g process. In the b2g main() (b2g_main()) function we add b2g to some groups and drop with setresuid() to system. Later b2g will send the message to nuwa to become nuwa and from there it goes the usual way.
Assignee: julian.r.hector → nobody
Severity: normal → S3
Attachment #9386922 - Attachment is obsolete: true
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: