2016-02-17 11:54:21 +01:00
|
|
|
/* bubblewrap
|
2016-02-16 10:03:46 +01:00
|
|
|
* Copyright (C) 2016 Alexander Larsson
|
2021-08-31 11:54:10 +01:00
|
|
|
* SPDX-License-Identifier: LGPL-2.0-or-later
|
2016-02-16 10:03:46 +01:00
|
|
|
*
|
|
|
|
|
* 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_token (char *line, bool eat_whitespace)
|
|
|
|
|
{
|
|
|
|
|
while (*line != ' ' && *line != '\n')
|
|
|
|
|
line++;
|
|
|
|
|
|
|
|
|
|
if (eat_whitespace && *line == ' ')
|
|
|
|
|
line++;
|
|
|
|
|
|
|
|
|
|
return line;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
unescape_inline (char *escaped)
|
2016-02-16 10:03:46 +01:00
|
|
|
{
|
|
|
|
|
char *unescaped, *res;
|
|
|
|
|
const char *end;
|
|
|
|
|
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
res = escaped;
|
|
|
|
|
end = escaped + strlen (escaped);
|
2016-02-16 10:03:46 +01:00
|
|
|
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
unescaped = escaped;
|
2016-02-16 10:03:46 +01:00
|
|
|
while (escaped < end)
|
|
|
|
|
{
|
|
|
|
|
if (*escaped == '\\')
|
|
|
|
|
{
|
|
|
|
|
*unescaped++ =
|
2016-05-13 10:18:14 +02:00
|
|
|
((escaped[1] - '0') << 6) |
|
|
|
|
|
((escaped[2] - '0') << 3) |
|
|
|
|
|
((escaped[3] - '0') << 0);
|
2016-02-16 10:03:46 +01:00
|
|
|
escaped += 4;
|
|
|
|
|
}
|
|
|
|
|
else
|
2016-05-13 10:18:14 +02:00
|
|
|
{
|
|
|
|
|
*unescaped++ = *escaped++;
|
|
|
|
|
}
|
2016-02-16 10:03:46 +01:00
|
|
|
}
|
|
|
|
|
*unescaped = 0;
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
static bool
|
|
|
|
|
match_token (const char *token, const char *token_end, const char *str)
|
2016-02-16 10:03:46 +01:00
|
|
|
{
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
while (token != token_end && *token == *str)
|
2016-02-16 10:03:46 +01:00
|
|
|
{
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
token++;
|
|
|
|
|
str++;
|
2016-02-16 10:03:46 +01:00
|
|
|
}
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
if (token == token_end)
|
|
|
|
|
return *str == 0;
|
2016-02-16 10:03:46 +01:00
|
|
|
|
2024-10-03 18:01:45 +01:00
|
|
|
return false;
|
2016-02-16 10:03:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unsigned long
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
decode_mountoptions (const char *options)
|
2016-02-16 10:03:46 +01:00
|
|
|
{
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
const char *token, *end_token;
|
2016-02-16 10:03:46 +01:00
|
|
|
int i;
|
|
|
|
|
unsigned long flags = 0;
|
2016-05-13 10:18:14 +02:00
|
|
|
static const struct { int flag;
|
2021-08-31 13:11:54 +01:00
|
|
|
const char *name;
|
2016-05-13 10:18:14 +02:00
|
|
|
} flags_data[] = {
|
2016-02-16 10:03:46 +01:00
|
|
|
{ 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 }
|
|
|
|
|
};
|
|
|
|
|
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
token = options;
|
2016-05-13 10:18:14 +02:00
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
end_token = strchr (token, ',');
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
if (end_token == NULL)
|
|
|
|
|
end_token = token + strlen (token);
|
2016-02-16 10:03:46 +01:00
|
|
|
|
2016-05-13 10:18:14 +02:00
|
|
|
for (i = 0; flags_data[i].name != NULL; i++)
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
{
|
|
|
|
|
if (match_token (token, end_token, flags_data[i].name))
|
|
|
|
|
{
|
|
|
|
|
flags |= flags_data[i].flag;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-02-16 10:03:46 +01:00
|
|
|
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
if (*end_token != 0)
|
2016-05-13 10:18:14 +02:00
|
|
|
token = end_token + 1;
|
|
|
|
|
else
|
|
|
|
|
token = NULL;
|
|
|
|
|
}
|
|
|
|
|
while (token != NULL);
|
2016-02-16 10:03:46 +01:00
|
|
|
|
|
|
|
|
return flags;
|
|
|
|
|
}
|
|
|
|
|
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
typedef struct MountInfo MountInfo;
|
|
|
|
|
struct MountInfo {
|
|
|
|
|
char *mountpoint;
|
|
|
|
|
unsigned long options;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef MountInfo *MountTab;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
mount_tab_free (MountTab tab)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; tab[i].mountpoint != NULL; i++)
|
|
|
|
|
free (tab[i].mountpoint);
|
|
|
|
|
free (tab);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
cleanup_mount_tabp (void *p)
|
|
|
|
|
{
|
|
|
|
|
void **pp = (void **) p;
|
|
|
|
|
|
|
|
|
|
if (*pp)
|
|
|
|
|
mount_tab_free ((MountTab)*pp);
|
|
|
|
|
}
|
2016-02-16 10:03:46 +01:00
|
|
|
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
#define cleanup_mount_tab __attribute__((cleanup (cleanup_mount_tabp)))
|
|
|
|
|
|
|
|
|
|
typedef struct MountInfoLine MountInfoLine;
|
|
|
|
|
struct MountInfoLine {
|
|
|
|
|
const char *mountpoint;
|
|
|
|
|
const char *options;
|
|
|
|
|
bool covered;
|
|
|
|
|
int id;
|
|
|
|
|
int parent_id;
|
|
|
|
|
MountInfoLine *first_child;
|
|
|
|
|
MountInfoLine *next_sibling;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static unsigned int
|
|
|
|
|
count_lines (const char *data)
|
|
|
|
|
{
|
|
|
|
|
unsigned int count = 0;
|
|
|
|
|
const char *p = data;
|
|
|
|
|
|
|
|
|
|
while (*p != 0)
|
|
|
|
|
{
|
|
|
|
|
if (*p == '\n')
|
|
|
|
|
count++;
|
|
|
|
|
p++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If missing final newline, add one */
|
|
|
|
|
if (p > data && *(p-1) != '\n')
|
|
|
|
|
count++;
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
count_mounts (MountInfoLine *line)
|
|
|
|
|
{
|
|
|
|
|
MountInfoLine *child;
|
|
|
|
|
int res = 0;
|
|
|
|
|
|
|
|
|
|
if (!line->covered)
|
|
|
|
|
res += 1;
|
|
|
|
|
|
|
|
|
|
child = line->first_child;
|
|
|
|
|
while (child != NULL)
|
|
|
|
|
{
|
|
|
|
|
res += count_mounts (child);
|
|
|
|
|
child = child->next_sibling;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static MountInfo *
|
|
|
|
|
collect_mounts (MountInfo *info, MountInfoLine *line)
|
|
|
|
|
{
|
|
|
|
|
MountInfoLine *child;
|
|
|
|
|
|
|
|
|
|
if (!line->covered)
|
|
|
|
|
{
|
|
|
|
|
info->mountpoint = xstrdup (line->mountpoint);
|
|
|
|
|
info->options = decode_mountoptions (line->options);
|
|
|
|
|
info ++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
child = line->first_child;
|
|
|
|
|
while (child != NULL)
|
|
|
|
|
{
|
|
|
|
|
info = collect_mounts (info, child);
|
|
|
|
|
child = child->next_sibling;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static MountTab
|
|
|
|
|
parse_mountinfo (int proc_fd,
|
|
|
|
|
const char *root_mount)
|
2016-02-16 10:03:46 +01:00
|
|
|
{
|
|
|
|
|
cleanup_free char *mountinfo = NULL;
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
cleanup_free MountInfoLine *lines = NULL;
|
|
|
|
|
cleanup_free MountInfoLine **by_id = NULL;
|
|
|
|
|
cleanup_mount_tab MountTab mount_tab = NULL;
|
|
|
|
|
MountInfo *end_tab;
|
|
|
|
|
int n_mounts;
|
2016-02-16 10:03:46 +01:00
|
|
|
char *line;
|
2023-02-28 21:22:37 +01:00
|
|
|
unsigned int i;
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
int max_id;
|
|
|
|
|
unsigned int n_lines;
|
|
|
|
|
int root;
|
2016-02-16 10:03:46 +01:00
|
|
|
|
|
|
|
|
mountinfo = load_file_at (proc_fd, "self/mountinfo");
|
|
|
|
|
if (mountinfo == NULL)
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
die_with_error ("Can't open /proc/self/mountinfo");
|
2016-02-16 10:03:46 +01:00
|
|
|
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
n_lines = count_lines (mountinfo);
|
2023-02-28 21:44:33 +01:00
|
|
|
lines = xcalloc (n_lines, sizeof (MountInfoLine));
|
2016-02-16 10:03:46 +01:00
|
|
|
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
max_id = 0;
|
2016-02-16 10:03:46 +01:00
|
|
|
line = mountinfo;
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
i = 0;
|
|
|
|
|
root = -1;
|
2016-02-16 10:03:46 +01:00
|
|
|
while (*line != 0)
|
|
|
|
|
{
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
int rc, consumed = 0;
|
|
|
|
|
unsigned int maj, min;
|
|
|
|
|
char *end;
|
|
|
|
|
char *rest;
|
|
|
|
|
char *mountpoint;
|
|
|
|
|
char *mountpoint_end;
|
|
|
|
|
char *options;
|
|
|
|
|
char *options_end;
|
|
|
|
|
char *next_line;
|
|
|
|
|
|
|
|
|
|
assert (i < n_lines);
|
|
|
|
|
|
|
|
|
|
end = strchr (line, '\n');
|
|
|
|
|
if (end != NULL)
|
|
|
|
|
{
|
|
|
|
|
*end = 0;
|
|
|
|
|
next_line = end + 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
next_line = line + strlen (line);
|
|
|
|
|
|
|
|
|
|
rc = sscanf (line, "%d %d %u:%u %n", &lines[i].id, &lines[i].parent_id, &maj, &min, &consumed);
|
|
|
|
|
if (rc != 4)
|
|
|
|
|
die ("Can't parse mountinfo line");
|
|
|
|
|
rest = line + consumed;
|
|
|
|
|
|
2024-10-03 18:01:45 +01:00
|
|
|
rest = skip_token (rest, true); /* mountroot */
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
mountpoint = rest;
|
2024-10-03 18:01:45 +01:00
|
|
|
rest = skip_token (rest, false); /* mountpoint */
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
mountpoint_end = rest++;
|
|
|
|
|
options = rest;
|
2024-10-03 18:01:45 +01:00
|
|
|
rest = skip_token (rest, false); /* vfs options */
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
options_end = rest;
|
|
|
|
|
|
2016-02-16 10:03:46 +01:00
|
|
|
*mountpoint_end = 0;
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
lines[i].mountpoint = unescape_inline (mountpoint);
|
|
|
|
|
|
|
|
|
|
*options_end = 0;
|
|
|
|
|
lines[i].options = options;
|
|
|
|
|
|
|
|
|
|
if (lines[i].id > max_id)
|
|
|
|
|
max_id = lines[i].id;
|
|
|
|
|
if (lines[i].parent_id > max_id)
|
|
|
|
|
max_id = lines[i].parent_id;
|
|
|
|
|
|
|
|
|
|
if (path_equal (lines[i].mountpoint, root_mount))
|
|
|
|
|
root = i;
|
|
|
|
|
|
|
|
|
|
i++;
|
|
|
|
|
line = next_line;
|
|
|
|
|
}
|
|
|
|
|
assert (i == n_lines);
|
|
|
|
|
|
|
|
|
|
if (root == -1)
|
|
|
|
|
{
|
2023-02-28 21:44:33 +01:00
|
|
|
mount_tab = xcalloc (1, sizeof (MountInfo));
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
return steal_pointer (&mount_tab);
|
|
|
|
|
}
|
2016-02-16 10:03:46 +01:00
|
|
|
|
2023-02-28 21:44:33 +01:00
|
|
|
by_id = xcalloc (max_id + 1, sizeof (MountInfoLine*));
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
for (i = 0; i < n_lines; i++)
|
|
|
|
|
by_id[lines[i].id] = &lines[i];
|
2016-02-16 10:03:46 +01:00
|
|
|
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
for (i = 0; i < n_lines; i++)
|
|
|
|
|
{
|
|
|
|
|
MountInfoLine *this = &lines[i];
|
|
|
|
|
MountInfoLine *parent = by_id[this->parent_id];
|
|
|
|
|
MountInfoLine **to_sibling;
|
|
|
|
|
MountInfoLine *sibling;
|
2024-10-03 18:01:45 +01:00
|
|
|
bool covered = false;
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
|
|
|
|
|
if (!has_path_prefix (this->mountpoint, root_mount))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (parent == NULL)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (strcmp (parent->mountpoint, this->mountpoint) == 0)
|
2024-10-03 18:01:45 +01:00
|
|
|
parent->covered = true;
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
|
|
|
|
|
to_sibling = &parent->first_child;
|
|
|
|
|
sibling = parent->first_child;
|
|
|
|
|
while (sibling != NULL)
|
2016-02-16 10:03:46 +01:00
|
|
|
{
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
/* If this mountpoint is a path prefix of the sibling,
|
|
|
|
|
* say this->mp=/foo/bar and sibling->mp=/foo, then it is
|
|
|
|
|
* covered by the sibling, and we drop it. */
|
|
|
|
|
if (has_path_prefix (this->mountpoint, sibling->mountpoint))
|
2016-02-16 10:03:46 +01:00
|
|
|
{
|
2024-10-03 18:01:45 +01:00
|
|
|
covered = true;
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
break;
|
2016-02-16 10:03:46 +01:00
|
|
|
}
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
|
|
|
|
|
/* If the sibling is a path prefix of this mount point,
|
|
|
|
|
* say this->mp=/foo and sibling->mp=/foo/bar, then the sibling
|
|
|
|
|
* is covered, and we drop it.
|
|
|
|
|
*/
|
|
|
|
|
if (has_path_prefix (sibling->mountpoint, this->mountpoint))
|
|
|
|
|
*to_sibling = sibling->next_sibling;
|
|
|
|
|
else
|
|
|
|
|
to_sibling = &sibling->next_sibling;
|
|
|
|
|
sibling = sibling->next_sibling;
|
2016-02-16 10:03:46 +01:00
|
|
|
}
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
|
|
|
|
|
if (covered)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
*to_sibling = this;
|
2016-02-16 10:03:46 +01:00
|
|
|
}
|
|
|
|
|
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
n_mounts = count_mounts (&lines[root]);
|
2023-02-28 21:44:33 +01:00
|
|
|
mount_tab = xcalloc (n_mounts + 1, sizeof (MountInfo));
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
|
|
|
|
|
end_tab = collect_mounts (&mount_tab[0], &lines[root]);
|
|
|
|
|
assert (end_tab == &mount_tab[n_mounts]);
|
2016-02-16 10:03:46 +01:00
|
|
|
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
return steal_pointer (&mount_tab);
|
2016-02-16 10:03:46 +01:00
|
|
|
}
|
|
|
|
|
|
2021-06-21 16:55:52 +01:00
|
|
|
bind_mount_result
|
2016-05-13 10:18:14 +02:00
|
|
|
bind_mount (int proc_fd,
|
|
|
|
|
const char *src,
|
|
|
|
|
const char *dest,
|
2022-02-08 19:04:55 +00:00
|
|
|
bind_option_t options,
|
|
|
|
|
char **failing_path)
|
2016-02-16 10:03:46 +01:00
|
|
|
{
|
|
|
|
|
bool readonly = (options & BIND_READONLY) != 0;
|
|
|
|
|
bool devices = (options & BIND_DEVICES) != 0;
|
|
|
|
|
bool recursive = (options & BIND_RECURSIVE) != 0;
|
2016-03-07 19:14:30 +01:00
|
|
|
unsigned long current_flags, new_flags;
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
cleanup_mount_tab MountTab mount_tab = NULL;
|
2016-11-22 11:43:56 +01:00
|
|
|
cleanup_free char *resolved_dest = NULL;
|
2021-02-16 13:46:10 +01:00
|
|
|
cleanup_free char *dest_proc = NULL;
|
|
|
|
|
cleanup_free char *oldroot_dest_proc = NULL;
|
|
|
|
|
cleanup_free char *kernel_case_combination = NULL;
|
|
|
|
|
cleanup_fd int dest_fd = -1;
|
2016-02-16 10:03:46 +01:00
|
|
|
int i;
|
|
|
|
|
|
2016-08-12 12:15:28 +02:00
|
|
|
if (src)
|
|
|
|
|
{
|
2020-05-18 21:20:43 +00:00
|
|
|
if (mount (src, dest, NULL, MS_SILENT | MS_BIND | (recursive ? MS_REC : 0), NULL) != 0)
|
2021-06-21 16:55:52 +01:00
|
|
|
return BIND_MOUNT_ERROR_MOUNT;
|
2016-08-12 12:15:28 +02:00
|
|
|
}
|
2016-02-16 10:03:46 +01:00
|
|
|
|
2016-11-22 11:43:56 +01:00
|
|
|
/* The mount operation will resolve any symlinks in the destination
|
|
|
|
|
path, so to find it in the mount table we need to do that too. */
|
|
|
|
|
resolved_dest = realpath (dest, NULL);
|
2016-12-13 13:56:23 +01:00
|
|
|
if (resolved_dest == NULL)
|
2021-06-21 16:55:52 +01:00
|
|
|
return BIND_MOUNT_ERROR_REALPATH_DEST;
|
2016-11-22 11:43:56 +01:00
|
|
|
|
2024-10-03 17:24:25 +01:00
|
|
|
dest_fd = TEMP_FAILURE_RETRY (open (resolved_dest, O_PATH | O_CLOEXEC));
|
2021-02-16 13:46:10 +01:00
|
|
|
if (dest_fd < 0)
|
2022-02-08 19:04:55 +00:00
|
|
|
{
|
|
|
|
|
if (failing_path != NULL)
|
|
|
|
|
*failing_path = steal_pointer (&resolved_dest);
|
|
|
|
|
|
|
|
|
|
return BIND_MOUNT_ERROR_REOPEN_DEST;
|
|
|
|
|
}
|
2021-02-16 13:46:10 +01:00
|
|
|
|
|
|
|
|
/* If we are in a case-insensitive filesystem, mountinfo might contain a
|
|
|
|
|
* different case combination of the path we requested to mount.
|
|
|
|
|
* This is due to the fact that the kernel, as of the beginning of 2021,
|
|
|
|
|
* populates mountinfo with whatever case combination first appeared in the
|
|
|
|
|
* dcache; kernel developers plan to change this in future so that it
|
|
|
|
|
* reflects the on-disk encoding instead.
|
|
|
|
|
* To avoid throwing an error when this happens, we use readlink() result
|
|
|
|
|
* instead of the provided @root_mount, so that we can compare the mountinfo
|
|
|
|
|
* entries with the same case combination that the kernel is expected to
|
|
|
|
|
* use. */
|
|
|
|
|
dest_proc = xasprintf ("/proc/self/fd/%d", dest_fd);
|
|
|
|
|
oldroot_dest_proc = get_oldroot_path (dest_proc);
|
|
|
|
|
kernel_case_combination = readlink_malloc (oldroot_dest_proc);
|
|
|
|
|
if (kernel_case_combination == NULL)
|
2022-02-08 19:04:55 +00:00
|
|
|
{
|
|
|
|
|
if (failing_path != NULL)
|
|
|
|
|
*failing_path = steal_pointer (&resolved_dest);
|
|
|
|
|
|
|
|
|
|
return BIND_MOUNT_ERROR_READLINK_DEST_PROC_FD;
|
|
|
|
|
}
|
2021-02-16 13:46:10 +01:00
|
|
|
|
|
|
|
|
mount_tab = parse_mountinfo (proc_fd, kernel_case_combination);
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
if (mount_tab[0].mountpoint == NULL)
|
|
|
|
|
{
|
2022-02-08 19:04:55 +00:00
|
|
|
if (failing_path != NULL)
|
|
|
|
|
*failing_path = steal_pointer (&kernel_case_combination);
|
|
|
|
|
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
errno = EINVAL;
|
2021-06-21 16:55:52 +01:00
|
|
|
return BIND_MOUNT_ERROR_FIND_DEST_MOUNT;
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
}
|
2016-02-16 10:03:46 +01:00
|
|
|
|
2021-02-16 13:46:10 +01:00
|
|
|
assert (path_equal (mount_tab[0].mountpoint, kernel_case_combination));
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
current_flags = mount_tab[0].options;
|
2016-05-13 10:18:14 +02:00
|
|
|
new_flags = current_flags | (devices ? 0 : MS_NODEV) | MS_NOSUID | (readonly ? MS_RDONLY : 0);
|
2016-03-07 19:14:30 +01:00
|
|
|
if (new_flags != current_flags &&
|
2016-11-22 11:43:56 +01:00
|
|
|
mount ("none", resolved_dest,
|
2020-05-18 21:20:43 +00:00
|
|
|
NULL, MS_SILENT | MS_BIND | MS_REMOUNT | new_flags, NULL) != 0)
|
2022-02-08 19:04:55 +00:00
|
|
|
{
|
|
|
|
|
if (failing_path != NULL)
|
|
|
|
|
*failing_path = steal_pointer (&resolved_dest);
|
|
|
|
|
|
|
|
|
|
return BIND_MOUNT_ERROR_REMOUNT_DEST;
|
|
|
|
|
}
|
2016-02-16 10:03:46 +01:00
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
|
{
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
for (i = 1; mount_tab[i].mountpoint != NULL; i++)
|
2016-02-16 10:03:46 +01:00
|
|
|
{
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
current_flags = mount_tab[i].options;
|
2016-05-13 10:18:14 +02:00
|
|
|
new_flags = current_flags | (devices ? 0 : MS_NODEV) | MS_NOSUID | (readonly ? MS_RDONLY : 0);
|
2016-03-07 19:14:30 +01:00
|
|
|
if (new_flags != current_flags &&
|
bind-mounts: Fix handling of covered mountpoints
Its not uncommon for mountpoints to cover other mountpoints, for instance
if /a/b is mounted first, then /a/b or /a can be mounted again effectively
making the old /a/b unreachable. This happens sometimes on the host
system, but it happens also often in the context of bubblewrap
where you migth do something like:
bwrap --bind / / --bind /my/foo /foo
In this case, we're covering whatever is on /foo on the host with
different content, and if /foo had submount under it these will be
covered.
There is a problem with bind mounts and covered mountpoints though.
Bubblewrap always does recursive bind-mounts (because a non-recursive
bind-mount could expose content that was otherwise covered), and the
linux recursive bind mount doesn't let you modify flags (such as
adding readonly). So we have to first bind-mount, and then change the
flags for the destination and all the submounts under it.
The existing naive implementation of submount enumeration in
bubblewrap also returns the covered mount points, and when we try
to change the flags on these we run into issues, because mount()
can't find the pathnames.
This implementation does a more thorough parsing of the mountinfo
file, looking at the "mount id" and "parent mount id" to reconstruct
exactly which mountpoints that are accessible.
This fixes https://github.com/projectatomic/bubblewrap/issues/14
Closes: #118
Approved by: alexlarsson
2016-11-10 20:50:53 +01:00
|
|
|
mount ("none", mount_tab[i].mountpoint,
|
2020-05-18 21:20:43 +00:00
|
|
|
NULL, MS_SILENT | MS_BIND | MS_REMOUNT | new_flags, NULL) != 0)
|
2016-03-07 19:26:05 +01:00
|
|
|
{
|
|
|
|
|
/* If we can't read the mountpoint we can't remount it, but that should
|
|
|
|
|
be safe to ignore because its not something the user can access. */
|
|
|
|
|
if (errno != EACCES)
|
2022-02-08 19:04:55 +00:00
|
|
|
{
|
|
|
|
|
if (failing_path != NULL)
|
|
|
|
|
*failing_path = xstrdup (mount_tab[i].mountpoint);
|
|
|
|
|
|
|
|
|
|
return BIND_MOUNT_ERROR_REMOUNT_SUBMOUNT;
|
|
|
|
|
}
|
2016-03-07 19:26:05 +01:00
|
|
|
}
|
2016-02-16 10:03:46 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-21 16:55:52 +01:00
|
|
|
return BIND_MOUNT_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-23 18:56:38 +01:00
|
|
|
/**
|
|
|
|
|
* Return a string representing bind_mount_result, like strerror().
|
|
|
|
|
* If want_errno_p is non-NULL, *want_errno_p is used to indicate whether
|
|
|
|
|
* it would make sense to print strerror(saved_errno).
|
|
|
|
|
*/
|
2022-02-08 19:04:55 +00:00
|
|
|
static char *
|
2021-06-23 18:56:38 +01:00
|
|
|
bind_mount_result_to_string (bind_mount_result res,
|
2022-02-08 19:04:55 +00:00
|
|
|
const char *failing_path,
|
2021-06-23 18:56:38 +01:00
|
|
|
bool *want_errno_p)
|
2021-06-21 16:55:52 +01:00
|
|
|
{
|
2022-02-08 19:04:55 +00:00
|
|
|
char *string = NULL;
|
2024-10-03 18:01:45 +01:00
|
|
|
bool want_errno = true;
|
2021-06-21 16:55:52 +01:00
|
|
|
|
|
|
|
|
switch (res)
|
|
|
|
|
{
|
|
|
|
|
case BIND_MOUNT_ERROR_MOUNT:
|
2022-02-08 19:04:55 +00:00
|
|
|
string = xstrdup ("Unable to mount source on destination");
|
2021-06-21 16:55:52 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BIND_MOUNT_ERROR_REALPATH_DEST:
|
2022-02-08 19:04:55 +00:00
|
|
|
string = xstrdup ("realpath(destination)");
|
2021-06-21 16:55:52 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BIND_MOUNT_ERROR_REOPEN_DEST:
|
2022-02-08 19:04:55 +00:00
|
|
|
string = xasprintf ("open(\"%s\", O_PATH)", failing_path);
|
2021-06-21 16:55:52 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BIND_MOUNT_ERROR_READLINK_DEST_PROC_FD:
|
2022-02-08 19:04:55 +00:00
|
|
|
string = xasprintf ("readlink(/proc/self/fd/N) for \"%s\"", failing_path);
|
2021-06-21 16:55:52 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BIND_MOUNT_ERROR_FIND_DEST_MOUNT:
|
2022-02-08 19:04:55 +00:00
|
|
|
string = xasprintf ("Unable to find \"%s\" in mount table", failing_path);
|
2024-10-03 18:01:45 +01:00
|
|
|
want_errno = false;
|
2021-06-21 16:55:52 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BIND_MOUNT_ERROR_REMOUNT_DEST:
|
2022-02-08 19:04:55 +00:00
|
|
|
string = xasprintf ("Unable to remount destination \"%s\" with correct flags",
|
|
|
|
|
failing_path);
|
2021-06-21 16:55:52 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BIND_MOUNT_ERROR_REMOUNT_SUBMOUNT:
|
2022-02-08 19:04:55 +00:00
|
|
|
string = xasprintf ("Unable to apply mount flags: remount \"%s\"",
|
|
|
|
|
failing_path);
|
2021-06-21 16:55:52 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BIND_MOUNT_SUCCESS:
|
2022-02-08 19:04:55 +00:00
|
|
|
string = xstrdup ("Success");
|
2021-06-23 18:56:38 +01:00
|
|
|
break;
|
|
|
|
|
|
2021-06-21 16:55:52 +01:00
|
|
|
default:
|
2022-02-08 19:04:55 +00:00
|
|
|
string = xstrdup ("(unknown/invalid bind_mount_result)");
|
2021-06-21 16:55:52 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-23 18:56:38 +01:00
|
|
|
if (want_errno_p != NULL)
|
|
|
|
|
*want_errno_p = want_errno;
|
|
|
|
|
|
|
|
|
|
return string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
die_with_bind_result (bind_mount_result res,
|
|
|
|
|
int saved_errno,
|
2022-02-08 19:04:55 +00:00
|
|
|
const char *failing_path,
|
2021-06-23 18:56:38 +01:00
|
|
|
const char *format,
|
|
|
|
|
...)
|
|
|
|
|
{
|
|
|
|
|
va_list args;
|
2024-10-03 18:01:45 +01:00
|
|
|
bool want_errno = true;
|
2022-02-08 19:04:55 +00:00
|
|
|
char *message;
|
2021-06-23 18:56:38 +01:00
|
|
|
|
2024-08-01 13:37:10 +01:00
|
|
|
if (bwrap_level_prefix)
|
|
|
|
|
fprintf (stderr, "<%d>", LOG_ERR);
|
|
|
|
|
|
2021-06-23 18:56:38 +01:00
|
|
|
fprintf (stderr, "bwrap: ");
|
|
|
|
|
|
|
|
|
|
va_start (args, format);
|
|
|
|
|
vfprintf (stderr, format, args);
|
|
|
|
|
va_end (args);
|
|
|
|
|
|
2022-02-08 19:04:55 +00:00
|
|
|
message = bind_mount_result_to_string (res, failing_path, &want_errno);
|
|
|
|
|
fprintf (stderr, ": %s", message);
|
|
|
|
|
/* message is leaked, but we're exiting unsuccessfully anyway, so ignore */
|
2021-06-23 18:56:38 +01:00
|
|
|
|
2021-06-21 16:55:52 +01:00
|
|
|
if (want_errno)
|
2024-01-03 15:30:07 +00:00
|
|
|
{
|
|
|
|
|
switch (res)
|
|
|
|
|
{
|
|
|
|
|
case BIND_MOUNT_ERROR_MOUNT:
|
|
|
|
|
case BIND_MOUNT_ERROR_REMOUNT_DEST:
|
|
|
|
|
case BIND_MOUNT_ERROR_REMOUNT_SUBMOUNT:
|
|
|
|
|
fprintf (stderr, ": %s", mount_strerror (saved_errno));
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BIND_MOUNT_ERROR_REALPATH_DEST:
|
|
|
|
|
case BIND_MOUNT_ERROR_REOPEN_DEST:
|
|
|
|
|
case BIND_MOUNT_ERROR_READLINK_DEST_PROC_FD:
|
|
|
|
|
case BIND_MOUNT_ERROR_FIND_DEST_MOUNT:
|
|
|
|
|
case BIND_MOUNT_SUCCESS:
|
|
|
|
|
default:
|
|
|
|
|
fprintf (stderr, ": %s", strerror (saved_errno));
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-21 16:55:52 +01:00
|
|
|
|
|
|
|
|
fprintf (stderr, "\n");
|
|
|
|
|
exit (1);
|
2016-02-16 10:03:46 +01:00
|
|
|
}
|