summaryrefslogtreecommitdiff
path: root/README
blob: e0d0852a9b5dfbf5e42432cee9d44caa8f5dfbcd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
THIS PROJECT IS REPLACED BY BUBBLEWRAP
--------------------------------------

Please see:
https://github.com/projectatomic/bubblewrap

THIS PROJECT IS REPLACED BY BUBBLEWRAP
--------------------------------------


Historical README follows:


Summary
-------

This tool allows regular (non-root) users to call chroot(2), create
Linux bind mounts, and use some Linux container features.  It's
primarily intended for use by build systems.

Contributing
------------

Currently, linux-user-chroot reuses
the https://mail.gnome.org/mailman/listinfo/ostree-list
mailing list.

Please send patches there.

Why is this useful?
-------------------

There are a few well-known approaches for software build roots:
 
 - Set up a chroot as root, then chroot in, and become non-root
   This is the model currently used by both rpm and dpkg.
   The problem with this is that if you want to build *two* packages
   where B depends on A, then the `%post` type scripts from A run
   as root, and hence need to be fully trusted.
 - Use `LD_PRELOAD` emulation
   This is implemented by https://github.com/wrpseudo/pseudo
   The problem with this is that it's a speed hit, and maintaining
   that sort of emulation is a long-term maintenance pain.
 - Don't do any chrooting, use environment variables
   This is implemented by `jhbuild`.  The problem with this is there
   are a *lot* of these, and it's really easy to get "host contamination",
   where we silently pick up `/usr/include/foo.h` instead of the one
   from the root.

What linux-user-chroot does is a variant of the first, except instead
of using root-owned files for the chroot, you simply make the chroot
data as non-root, and run `%post` type scripts as non-root too.

This works because we believe linux-user-chroot is secure; see below.

Security
--------

**** IMPORTANT NOTE ****

Installing this tool accessible to all users increases their ability
to perform local, authenticated denial of service attacks.  One
mitigation against this is to ensure the tool is only executable by
certain users.

**** IMPORTANT NOTE ****

The historical reason Unix doesn't allow chroot(2) as non-root is
because of setuid binaries.  It's trivial to use chroot to create a
hostile environment, then execute a setuid binary to subvert it.

Since then, the Linux kernel has gained a per-process mode
that disables setuid binaries, called `PR_SET_NO_NEW_PRIVS`:

https://lwn.net/Articles/478062/

While this tool itself is setuid, it enables that mode, thus ensuring
any other setuid binaries (including recursive invocations of this
tool) cannot be exploited.

However, this tool also allows creating bind mounts, which currently
have no resource controls and occupy kernel memory.  This is why this
tool is not intended to be installed by default and accessible to all
users.

Abilities granted
-----------------

However in order to make a usable system, it's not quite enough to be
able to call chroot(2).  A lot of Unix software expects
e.g. /dev/null, and Linux /proc is also fairly widely used.  So
this tool also allows creating Linux "bind mounts".  This is how
one can expose the "host" /dev inside the chroot.  Also, this tool
allows mounting procfs.

In addition, this tool exposes several of the Linux "unshare"
capabilities such as:

  * CLONE_NEWNET - create a new, empty networking stack.  Because
    the child process won't have the privilges to manipulate the
    network, this will result in no networking (including loopback)
    which ensures that e.g. the build process isn't downloading more
    code.

  * CLONE_NEWPID - create a new PID namespace.  For example, if the
    build script runs some test scripts that start processes, "pidof"
    won't accidentally pick up a similarly-named process outside of
    the root.

  * CLONE_NEWIPC - get a new SysV IPC namespace.  This is just further
    isolation.

See "man 2 clone" for more information.

Additionally, the 2015.1 release of linux-user-chroot also gained
support for seccomp, which is a strong way to restrict what system
calls build systems can use.

Example usage
-------------

Note here all files are owned by the user.

$ mkdir -p /path/to/my/chroot/usr/src/project
$ linux-user-chroot \
   --seccomp-profile-version 0 \
   --unshare-pid --unshare-net --unshare-pid \
   --mount-proc /proc --mount-bind /dev /dev \
   --mount-bind /home/user/source/project /usr/src/project \
   /path/to/my/chroot /bin/sh

Here we're creating a bind mount inside the chroot to outside.  This
helps avoid copying files around.

Installing
----------

This binary can be installed in two modes:

1) uwsr-xr-x  root:root - Executable by everyone
2) uwsr-x---  root:somegroup - Executable only by somegroup

Programs using linux-user-chroot
--------------------------------

 - https://github.com/CodethinkLabs/sandboxlib
 - https://git.gnome.org/browse/gnome-continuous/ uses it for builds

Related projects
----------------

Google's Bazel system has a similar tool:

https://github.com/google/bazel/blob/master/src/main/tools/namespace-sandbox.c

(Noted by the sandboxlib/README.rst list of related projects)