summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2016-02-16 10:03:46 +0100
committerAlexander Larsson <alexl@redhat.com>2016-02-16 10:03:46 +0100
commit5d5f8e96145cc399bff0363f7ca529000fc669d0 (patch)
tree01ddfedd08617634e9e188e43f694fa22eaa66ef
parent5422cd3952801c9815242bedc7afc20cfac6acc8 (diff)
downloadbubblewrap-5d5f8e96145cc399bff0363f7ca529000fc669d0.tar.gz
Break out bind_mount() to separate file
-rw-r--r--Makefile.am2
-rw-r--r--bind-mount.c282
-rw-r--r--bind-mount.h34
-rw-r--r--build-root.c262
4 files changed, 320 insertions, 260 deletions
diff --git a/Makefile.am b/Makefile.am
index dbe0c1a..6b8ec98 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,6 +8,8 @@ bin_PROGRAMS = build-root
build_root_SOURCES = \
build-root.c \
+ bind-mount.h \
+ bind-mount.c \
network.h \
network.c \
utils.h \
diff --git a/bind-mount.c b/bind-mount.c
new file mode 100644
index 0000000..7a9f6ed
--- /dev/null
+++ b/bind-mount.c
@@ -0,0 +1,282 @@
+/* build-root
+ * Copyright (C) 2016 Alexander Larsson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "config.h"
+
+#include <sys/mount.h>
+
+#include "utils.h"
+#include "bind-mount.h"
+
+static char *
+skip_line (char *line)
+{
+ while (*line != 0 && *line != '\n')
+ line++;
+
+ if (*line == '\n')
+ line++;
+
+ return line;
+}
+
+static char *
+skip_token (char *line, bool eat_whitespace)
+{
+ while (*line != ' ' && *line != '\n')
+ line++;
+
+ if (eat_whitespace && *line == ' ')
+ line++;
+
+ return line;
+}
+
+static char *
+unescape_mountpoint (const char *escaped, ssize_t len)
+{
+ char *unescaped, *res;
+ const char *end;
+
+ if (len < 0)
+ len = strlen (escaped);
+ end = escaped + len;
+
+ unescaped = res = xmalloc (len + 1);
+ while (escaped < end)
+ {
+ if (*escaped == '\\')
+ {
+ *unescaped++ =
+ ((escaped[1] - '0') << 6) |
+ ((escaped[2] - '0') << 3) |
+ ((escaped[3] - '0') << 0);
+ escaped += 4;
+ }
+ else
+ *unescaped++ = *escaped++;
+ }
+ *unescaped = 0;
+ return res;
+}
+
+static char *
+get_mountinfo (int proc_fd,
+ const char *mountpoint)
+{
+ char *line_mountpoint, *line_mountpoint_end;
+ cleanup_free char *mountinfo = NULL;
+ cleanup_free char *free_me = NULL;
+ char *line, *line_start;
+ char *res = NULL;
+ int i;
+
+ if (mountpoint[0] != '/')
+ {
+ cleanup_free char *cwd = getcwd (NULL, 0);
+ if (cwd == NULL)
+ die_oom ();
+
+ mountpoint = free_me = strconcat3 (cwd, "/", mountpoint);
+ }
+
+ mountinfo = load_file_at (proc_fd, "/self/mountinfo");
+ if (mountinfo == NULL)
+ return NULL;
+
+ line = mountinfo;
+
+ while (*line != 0)
+ {
+ cleanup_free char *unescaped = NULL;
+
+ line_start = line;
+ for (i = 0; i < 4; i++)
+ line = skip_token (line, TRUE);
+ line_mountpoint = line;
+ line = skip_token (line, FALSE);
+ line_mountpoint_end = line;
+ line = skip_line (line);
+
+ unescaped = unescape_mountpoint (line_mountpoint, line_mountpoint_end - line_mountpoint);
+ if (strcmp (mountpoint, unescaped) == 0)
+ {
+ res = line_start;
+ line[-1] = 0;
+ break;
+ }
+ }
+
+ if (res)
+ return xstrdup (res);
+ return NULL;
+}
+
+static unsigned long
+get_mountflags (int proc_fd,
+ const char *mountpoint)
+{
+ cleanup_free char *line = NULL;
+ char *token, *end_token;
+ int i;
+ unsigned long flags = 0;
+ static const struct { int flag; char *name; } flags_data[] = {
+ { 0, "rw" },
+ { MS_RDONLY, "ro" },
+ { MS_NOSUID, "nosuid" },
+ { MS_NODEV, "nodev" },
+ { MS_NOEXEC, "noexec" },
+ { MS_NOATIME, "noatime" },
+ { MS_NODIRATIME, "nodiratime" },
+ { MS_RELATIME, "relatime" },
+ { 0, NULL }
+ };
+
+ line = get_mountinfo (proc_fd, mountpoint);
+ if (line == NULL)
+ return 0;
+
+ token = line;
+ for (i = 0; i < 5; i++)
+ token = skip_token (token, TRUE);
+
+ end_token = skip_token (token, FALSE);
+ *end_token = 0;
+
+ do {
+ end_token = strchr (token, ',');
+ if (end_token != NULL)
+ *end_token = 0;
+
+ for (i = 0; flags_data[i].name != NULL; i++)
+ {
+ if (strcmp (token, flags_data[i].name) == 0)
+ flags |= flags_data[i].flag;
+ }
+
+ if (end_token)
+ token = end_token + 1;
+ else
+ token = NULL;
+ } while (token != NULL);
+
+ return flags;
+}
+
+
+static char **
+get_submounts (int proc_fd,
+ const char *parent_mount)
+{
+ char *mountpoint, *mountpoint_end;
+ char **submounts;
+ int i, n_submounts, submounts_size;
+ cleanup_free char *mountinfo = NULL;
+ char *line;
+
+ mountinfo = load_file_at (proc_fd, "self/mountinfo");
+ if (mountinfo == NULL)
+ return NULL;
+
+ submounts_size = 8;
+ n_submounts = 0;
+ submounts = xmalloc (sizeof (char *) * submounts_size);
+
+ line = mountinfo;
+
+ while (*line != 0)
+ {
+ cleanup_free char *unescaped = NULL;
+ for (i = 0; i < 4; i++)
+ line = skip_token (line, TRUE);
+ mountpoint = line;
+ line = skip_token (line, FALSE);
+ mountpoint_end = line;
+ line = skip_line (line);
+ *mountpoint_end = 0;
+
+ unescaped = unescape_mountpoint (mountpoint, -1);
+
+ if (*unescaped == '/' &&
+ has_prefix (unescaped + 1, parent_mount) &&
+ *(unescaped + 1 + strlen (parent_mount)) == '/')
+ {
+ if (n_submounts + 1 >= submounts_size)
+ {
+ submounts_size *= 2;
+ submounts = xrealloc (submounts, sizeof (char *) * submounts_size);
+ }
+ submounts[n_submounts++] = xstrdup (unescaped + 1);
+ }
+ }
+
+ submounts[n_submounts] = NULL;
+
+ return submounts;
+}
+
+int
+bind_mount (int proc_fd,
+ const char *src,
+ const char *dest,
+ bind_option_t options)
+{
+ bool readonly = (options & BIND_READONLY) != 0;
+ bool private = (options & BIND_PRIVATE) != 0;
+ bool devices = (options & BIND_DEVICES) != 0;
+ bool recursive = (options & BIND_RECURSIVE) != 0;
+ unsigned long current_flags;
+ int i;
+
+ if (mount (src, dest, NULL, MS_MGC_VAL|MS_BIND|(recursive?MS_REC:0), NULL) != 0)
+ return 1;
+
+ if (private)
+ {
+ if (mount ("none", dest,
+ NULL, MS_REC|MS_PRIVATE, NULL) != 0)
+ return 2;
+ }
+
+ current_flags = get_mountflags (proc_fd, dest);
+
+ if (mount ("none", dest,
+ NULL, MS_MGC_VAL|MS_BIND|MS_REMOUNT|current_flags|(devices?0:MS_NODEV)|MS_NOSUID|(readonly?MS_RDONLY:0), NULL) != 0)
+ return 3;
+
+ /* We need to work around the fact that a bind mount does not apply the flags, so we need to manually
+ * apply the flags to all submounts in the recursive case.
+ * Note: This does not apply the flags to mounts which are later propagated into this namespace.
+ */
+ if (recursive)
+ {
+ cleanup_strv char **submounts = get_submounts (proc_fd, dest);
+ if (submounts == NULL)
+ return 4;
+
+ for (i = 0; submounts[i] != NULL; i++)
+ {
+ current_flags = get_mountflags (proc_fd, submounts[i]);
+ if (mount ("none", submounts[i],
+ NULL, MS_MGC_VAL|MS_BIND|MS_REMOUNT|current_flags|(devices?0:MS_NODEV)|MS_NOSUID|(readonly?MS_RDONLY:0), NULL) != 0)
+ return 5;
+ }
+ }
+
+ return 0;
+}
diff --git a/bind-mount.h b/bind-mount.h
new file mode 100644
index 0000000..430a520
--- /dev/null
+++ b/bind-mount.h
@@ -0,0 +1,34 @@
+/* build-root
+ * Copyright (C) 2016 Alexander Larsson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __MOUNTS_H__
+#define __MOUNTS_H__
+
+typedef enum {
+ BIND_READONLY = (1<<0),
+ BIND_PRIVATE = (1<<1),
+ BIND_DEVICES = (1<<2),
+ BIND_RECURSIVE = (1<<3),
+} bind_option_t;
+
+int bind_mount (int proc_fd,
+ const char *src,
+ const char *dest,
+ bind_option_t options);
+
+#endif /* __MOUNTS_H__ */
diff --git a/build-root.c b/build-root.c
index a48e66d..d0540a0 100644
--- a/build-root.c
+++ b/build-root.c
@@ -30,6 +30,7 @@
#include "utils.h"
#include "network.h"
+#include "bind-mount.h"
/* Globals to avoid having to use getuid(), since the uid/gid changes during runtime */
static uid_t uid;
@@ -48,265 +49,6 @@ usage ()
exit (1);
}
-typedef enum {
- BIND_READONLY = (1<<0),
- BIND_PRIVATE = (1<<1),
- BIND_DEVICES = (1<<2),
- BIND_RECURSIVE = (1<<3),
-} bind_option_t;
-
-static char *
-skip_line (char *line)
-{
- while (*line != 0 && *line != '\n')
- line++;
-
- if (*line == '\n')
- line++;
-
- return line;
-}
-
-static char *
-skip_token (char *line, bool eat_whitespace)
-{
- while (*line != ' ' && *line != '\n')
- line++;
-
- if (eat_whitespace && *line == ' ')
- line++;
-
- return line;
-}
-
-static char *
-unescape_mountpoint (const char *escaped, ssize_t len)
-{
- char *unescaped, *res;
- const char *end;
-
- if (len < 0)
- len = strlen (escaped);
- end = escaped + len;
-
- unescaped = res = xmalloc (len + 1);
- while (escaped < end)
- {
- if (*escaped == '\\')
- {
- *unescaped++ =
- ((escaped[1] - '0') << 6) |
- ((escaped[2] - '0') << 3) |
- ((escaped[3] - '0') << 0);
- escaped += 4;
- }
- else
- *unescaped++ = *escaped++;
- }
- *unescaped = 0;
- return res;
-}
-
-static char *
-get_mountinfo (const char *mountpoint)
-{
- char *line_mountpoint, *line_mountpoint_end;
- cleanup_free char *mountinfo = NULL;
- cleanup_free char *free_me = NULL;
- char *line, *line_start;
- char *res = NULL;
- int i;
-
- if (mountpoint[0] != '/')
- {
- cleanup_free char *cwd = getcwd (NULL, 0);
- if (cwd == NULL)
- die_oom ();
-
- mountpoint = free_me = strconcat3 (cwd, "/", mountpoint);
- }
-
- mountinfo = load_file_at (proc_fd, "/self/mountinfo");
- if (mountinfo == NULL)
- return NULL;
-
- line = mountinfo;
-
- while (*line != 0)
- {
- cleanup_free char *unescaped = NULL;
-
- line_start = line;
- for (i = 0; i < 4; i++)
- line = skip_token (line, TRUE);
- line_mountpoint = line;
- line = skip_token (line, FALSE);
- line_mountpoint_end = line;
- line = skip_line (line);
-
- unescaped = unescape_mountpoint (line_mountpoint, line_mountpoint_end - line_mountpoint);
- if (strcmp (mountpoint, unescaped) == 0)
- {
- res = line_start;
- line[-1] = 0;
- break;
- }
- }
-
- if (res)
- return xstrdup (res);
- return NULL;
-}
-
-static unsigned long
-get_mountflags (const char *mountpoint)
-{
- cleanup_free char *line = NULL;
- char *token, *end_token;
- int i;
- unsigned long flags = 0;
- static const struct { int flag; char *name; } flags_data[] = {
- { 0, "rw" },
- { MS_RDONLY, "ro" },
- { MS_NOSUID, "nosuid" },
- { MS_NODEV, "nodev" },
- { MS_NOEXEC, "noexec" },
- { MS_NOATIME, "noatime" },
- { MS_NODIRATIME, "nodiratime" },
- { MS_RELATIME, "relatime" },
- { 0, NULL }
- };
-
- line = get_mountinfo (mountpoint);
- if (line == NULL)
- return 0;
-
- token = line;
- for (i = 0; i < 5; i++)
- token = skip_token (token, TRUE);
-
- end_token = skip_token (token, FALSE);
- *end_token = 0;
-
- do {
- end_token = strchr (token, ',');
- if (end_token != NULL)
- *end_token = 0;
-
- for (i = 0; flags_data[i].name != NULL; i++)
- {
- if (strcmp (token, flags_data[i].name) == 0)
- flags |= flags_data[i].flag;
- }
-
- if (end_token)
- token = end_token + 1;
- else
- token = NULL;
- } while (token != NULL);
-
- return flags;
-}
-
-
-static char **
-get_submounts (const char *parent_mount)
-{
- char *mountpoint, *mountpoint_end;
- char **submounts;
- int i, n_submounts, submounts_size;
- cleanup_free char *mountinfo = NULL;
- char *line;
-
- mountinfo = load_file_at (proc_fd, "self/mountinfo");
- if (mountinfo == NULL)
- return NULL;
-
- submounts_size = 8;
- n_submounts = 0;
- submounts = xmalloc (sizeof (char *) * submounts_size);
-
- line = mountinfo;
-
- while (*line != 0)
- {
- cleanup_free char *unescaped = NULL;
- for (i = 0; i < 4; i++)
- line = skip_token (line, TRUE);
- mountpoint = line;
- line = skip_token (line, FALSE);
- mountpoint_end = line;
- line = skip_line (line);
- *mountpoint_end = 0;
-
- unescaped = unescape_mountpoint (mountpoint, -1);
-
- if (*unescaped == '/' &&
- has_prefix (unescaped + 1, parent_mount) &&
- *(unescaped + 1 + strlen (parent_mount)) == '/')
- {
- if (n_submounts + 1 >= submounts_size)
- {
- submounts_size *= 2;
- submounts = xrealloc (submounts, sizeof (char *) * submounts_size);
- }
- submounts[n_submounts++] = xstrdup (unescaped + 1);
- }
- }
-
- submounts[n_submounts] = NULL;
-
- return submounts;
-}
-
-static int
-bind_mount (const char *src, const char *dest, bind_option_t options)
-{
- bool readonly = (options & BIND_READONLY) != 0;
- bool private = (options & BIND_PRIVATE) != 0;
- bool devices = (options & BIND_DEVICES) != 0;
- bool recursive = (options & BIND_RECURSIVE) != 0;
- unsigned long current_flags;
- int i;
-
- if (mount (src, dest, NULL, MS_MGC_VAL|MS_BIND|(recursive?MS_REC:0), NULL) != 0)
- return 1;
-
- if (private)
- {
- if (mount ("none", dest,
- NULL, MS_REC|MS_PRIVATE, NULL) != 0)
- return 2;
- }
-
- current_flags = get_mountflags (dest);
-
- if (mount ("none", dest,
- NULL, MS_MGC_VAL|MS_BIND|MS_REMOUNT|current_flags|(devices?0:MS_NODEV)|MS_NOSUID|(readonly?MS_RDONLY:0), NULL) != 0)
- return 3;
-
- /* We need to work around the fact that a bind mount does not apply the flags, so we need to manually
- * apply the flags to all submounts in the recursive case.
- * Note: This does not apply the flags to mounts which are later propagated into this namespace.
- */
- if (recursive)
- {
- cleanup_strv char **submounts = get_submounts (dest);
- if (submounts == NULL)
- return 4;
-
- for (i = 0; submounts[i] != NULL; i++)
- {
- current_flags = get_mountflags (submounts[i]);
- if (mount ("none", submounts[i],
- NULL, MS_MGC_VAL|MS_BIND|MS_REMOUNT|current_flags|(devices?0:MS_NODEV)|MS_NOSUID|(readonly?MS_RDONLY:0), NULL) != 0)
- return 5;
- }
- }
-
- return 0;
-}
-
static void
block_sigchild (void)
{
@@ -818,7 +560,7 @@ main (int argc,
case SETUP_BIND_MOUNT:
if (mkdir_with_parents (dest, 0755, TRUE) != 0)
die_with_error ("Can't mkdir parents of %s", op->dest);
- if (bind_mount (source, dest, BIND_RECURSIVE) != 0)
+ if (bind_mount (proc_fd, source, dest, BIND_RECURSIVE) != 0)
die_with_error ("Can't bind mount %s on %s", op->source, op->dest);
break;
default: