namespace.c revision 6b46ea73e3b1d8a1e65f58ac04772821bd4a72fb
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering This file is part of systemd.
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering Copyright 2010 Lennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering systemd is free software; you can redistribute it and/or modify it
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering under the terms of the GNU Lesser General Public License as published by
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering (at your option) any later version.
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering systemd is distributed in the hope that it will be useful, but
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering Lesser General Public License for more details.
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering You should have received a copy of the GNU Lesser General Public License
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
3ed08c446cfaaae2b234fdfeb0c34ab6b4748c3eLennart Poettering /* This is ordered by priority! */
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringtypedef struct BindMount {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic int append_mounts(BindMount **p, char **strv, MountMode mode) {
bb99a35a873c35e80b0b47fe045081022660374dLennart Poettering (*p)->ignore = false;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if ((mode == INACCESSIBLE || mode == READONLY) && (*i)[0] == '-') {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic int mount_path_compare(const void *a, const void *b) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering const BindMount *p = a, *q = b;
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering /* If the paths are equal, check the mode */
d0bbc21caa6e68693a47db60c93e99422bf2a858Lennart Poettering /* If the paths are not equal, then order prefixes first */
d0bbc21caa6e68693a47db60c93e99422bf2a858Lennart Poetteringstatic void drop_duplicates(BindMount *m, unsigned *n) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering for (f = m, t = m, previous = NULL; f < m+*n; f++) {
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering /* The first one wins */
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering if (previous && path_equal(f->path, previous->path))
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering r = mount(what, m->path, NULL, MS_BIND|MS_REC, NULL);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering log_debug("Successfully mounted %s to %s", what, m->path);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (m->mode != INACCESSIBLE && m->mode != READONLY)
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering r = mount(NULL, m->path, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_REC, NULL);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering if (r < 0 && !(m->ignore && errno == ENOENT))
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering m = mounts = (BindMount *) alloca(n * sizeof(BindMount));
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering r = append_mounts(&m, read_write_dirs, READWRITE);
9058851be7821edac08c1fa7ecafe5cba9ab9022Lennart Poettering r = append_mounts(&m, read_only_dirs, READONLY);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering r = append_mounts(&m, inaccessible_dirs, INACCESSIBLE);
29abad107f8610e73b2fc091216040b579c75453Zbigniew Jędrzejewski-Szmek qsort(mounts, n, sizeof(BindMount), mount_path_compare);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering /* Remount / as SLAVE so that nothing now mounted in the namespace
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering shows up in the parent */
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering r = apply_mount(m, tmp_dir, var_tmp_dir);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering /* Remount / as the desired mode */
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (mount(NULL, "/", NULL, mount_flags | MS_REC, NULL) < 0) {
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart Poetteringstatic int setup_one_tmp_dir(const char *id, const char *prefix, char **path) {
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart Poettering /* We include the boot id in the directory so that after a
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart Poettering * reboot we can easily identify obsolete directories. */
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering x = strjoin(prefix, "/systemd-private-", sd_id128_to_string(boot_id, bid), "-", id, "-XXXXXX", NULL);
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poetteringint setup_tmp_dirs(const char *id, char **tmp_dir, char **var_tmp_dir) {
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering r = setup_one_tmp_dir(id, "/var/tmp", &b);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringint setup_netns(int netns_storage_socket[2]) {
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering /* We use the passed socketpair as a storage buffer for our
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering * namespace reference fd. Whatever process runs this first
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering * shall create a new namespace, all others should just join
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering * it. To serialize that we use a file lock on the socket
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering * It's a bit crazy, but hey, works great! */
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering if (lockf(netns_storage_socket[0], F_LOCK, 0) < 0)
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering if (recvmsg(netns_storage_socket[0], &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC) < 0) {
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering /* Nothing stored yet, so let's create a new namespace */
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering netns = open("/proc/self/ns/net", O_RDONLY|O_CLOEXEC|O_NOCTTY);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering /* Yay, found something, so let's join the namespace */
4cd9a9d9ecf3a8835e21930f3215a5f5b74144beLennart Poettering for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) {
6e5abe1564070a760196b97031eca9cf5e95e8a2Zbigniew Jędrzejewski-Szmek if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
6e5abe1564070a760196b97031eca9cf5e95e8a2Zbigniew Jędrzejewski-Szmek assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int)));
6e5abe1564070a760196b97031eca9cf5e95e8a2Zbigniew Jędrzejewski-Szmek netns = *(int*) CMSG_DATA(cmsg);
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering memcpy(CMSG_DATA(cmsg), &netns, sizeof(int));
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering if (sendmsg(netns_storage_socket[1], &mh, MSG_DONTWAIT|MSG_NOSIGNAL) < 0) {