mirror of
https://github.com/token2/snapd.git
synced 2026-03-13 11:15:47 -07:00
cmd/snap-confine: skip device cgroup setup when running inside a container (#13859)
* cmd/libsnap-confine-private: helper for detecting if executing inside a container Add a helper which attempts to detect if the current process is executing inside a container environment. Specifically, look for /run/systemd/container and check whether it is non empty. Signed-off-by: Maciej Borzecki <maciej.borzecki@canonical.com> * cmd/snap-confine: do not setup device cgroup if running inside a container Do not set up a device cgroup filter, if we're running inside the container. The rationale is that the container environment has already shut down device access sufficiently, and especially if running in unprivileged container, we may not be able to set it up correctly anyway. Signed-off-by: Maciej Borzecki <maciej.borzecki@canonical.com> * cmd/snap-confine: allow reading of /run/systemd/container Allow snap-confine to read /run/system/container to implement container execution check. Signed-off-by: Maciej Borzecki <maciej.borzecki@canonical.com> * cmd/snap-confine: use strnlen for sc_is_container Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com> --------- Signed-off-by: Maciej Borzecki <maciej.borzecki@canonical.com> Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com> Co-authored-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
This commit is contained in:
@@ -146,6 +146,13 @@ static void my_chdir(const char *path)
|
||||
}
|
||||
}
|
||||
|
||||
static void my_unlink(const char *path)
|
||||
{
|
||||
if (unlink(path) != 0 && errno != ENOENT) {
|
||||
die("cannot unlink: %s", path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the rest of testing in a ephemeral directory.
|
||||
*
|
||||
@@ -222,6 +229,37 @@ static void test_sc_nonfatal_mkpath__absolute(void)
|
||||
_test_sc_nonfatal_mkpath(dirname, subdirname);
|
||||
}
|
||||
|
||||
static void test_sc_is_container__empty(void)
|
||||
{
|
||||
g_test_in_ephemeral_dir();
|
||||
g_test_queue_destroy((GDestroyNotify) my_unlink, "container");
|
||||
g_assert_true(g_file_set_contents("container", "", -1, NULL));
|
||||
g_assert_false(_sc_is_in_container("container"));
|
||||
}
|
||||
|
||||
static void test_sc_is_container__lxc(void)
|
||||
{
|
||||
g_test_in_ephemeral_dir();
|
||||
g_test_queue_destroy((GDestroyNotify) my_unlink, "container");
|
||||
g_assert_true(g_file_set_contents("container", "lxc", -1, NULL));
|
||||
g_assert_true(_sc_is_in_container("container"));
|
||||
}
|
||||
|
||||
static void test_sc_is_container__lxc_with_newline(void)
|
||||
{
|
||||
g_test_in_ephemeral_dir();
|
||||
g_test_queue_destroy((GDestroyNotify) my_unlink, "container");
|
||||
g_assert_true(g_file_set_contents("container", "lxc\n", -1, NULL));
|
||||
g_assert_true(_sc_is_in_container("container"));
|
||||
}
|
||||
|
||||
static void test_sc_is_container__no_file(void)
|
||||
{
|
||||
g_test_in_ephemeral_dir();
|
||||
g_test_queue_destroy((GDestroyNotify) my_unlink, "container");
|
||||
g_assert_false(_sc_is_in_container("container"));
|
||||
}
|
||||
|
||||
static void __attribute__((constructor)) init(void)
|
||||
{
|
||||
g_test_add_func("/utils/parse_bool", test_parse_bool);
|
||||
@@ -232,4 +270,12 @@ static void __attribute__((constructor)) init(void)
|
||||
test_sc_nonfatal_mkpath__relative);
|
||||
g_test_add_func("/utils/sc_nonfatal_mkpath/absolute",
|
||||
test_sc_nonfatal_mkpath__absolute);
|
||||
g_test_add_func("/utils/sc_is_in_container/empty",
|
||||
test_sc_is_container__empty);
|
||||
g_test_add_func("/utils/sc_is_in_container/no_file",
|
||||
test_sc_is_container__no_file);
|
||||
g_test_add_func("/utils/sc_is_in_container/lxc",
|
||||
test_sc_is_container__lxc);
|
||||
g_test_add_func("/utils/sc_is_in_container/lxc_newline",
|
||||
test_sc_is_container__lxc_with_newline);
|
||||
}
|
||||
|
||||
@@ -261,3 +261,44 @@ bool sc_wait_for_file(const char *path, size_t timeout_sec)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *run_systemd_container = "/run/systemd/container";
|
||||
|
||||
static bool _sc_is_in_container(const char *p)
|
||||
{
|
||||
// see what systemd-detect-virt --container does in, see:
|
||||
// https://github.com/systemd/systemd/blob/5dcd6b1d55a1cfe247621d70f0e25d020de6e0ed/src/basic/virt.c#L749-L755
|
||||
// https://systemd.io/CONTAINER_INTERFACE/
|
||||
FILE *in SC_CLEANUP(sc_cleanup_file) = fopen(p, "r");
|
||||
if (in == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char container[128] = { 0 };
|
||||
|
||||
if (fgets(container, sizeof(container), in) == NULL) {
|
||||
/* nothing read or other error? */
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t r = strnlen(container, sizeof container);
|
||||
// TODO add sc_str_chomp()?
|
||||
if (r > 0 && container[r - 1] == '\n') {
|
||||
/* replace trailing newline */
|
||||
container[r - 1] = 0;
|
||||
r--;
|
||||
}
|
||||
|
||||
if (r == 0) {
|
||||
/* empty or just a newline */
|
||||
return false;
|
||||
}
|
||||
|
||||
debug("detected container environment: %s", container);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sc_is_in_container(void)
|
||||
{
|
||||
return _sc_is_in_container(run_systemd_container);
|
||||
}
|
||||
|
||||
@@ -49,6 +49,11 @@ bool sc_is_debug_enabled(void);
|
||||
**/
|
||||
bool sc_is_reexec_enabled(void);
|
||||
|
||||
/**
|
||||
* Return true if executing inside a container.
|
||||
**/
|
||||
bool sc_is_in_container(void);
|
||||
|
||||
/**
|
||||
* sc_identity describes the user performing certain operation.
|
||||
*
|
||||
|
||||
@@ -120,6 +120,9 @@
|
||||
# To find if apparmor is enabled
|
||||
/sys/module/apparmor/parameters/enabled r,
|
||||
|
||||
# For detecting if we're in a container
|
||||
/run/systemd/container r,
|
||||
|
||||
# Don't allow changing profile to unconfined or profiles that start with
|
||||
# '/'. Use 'unsafe' to support snap-exec on armhf and its reliance on
|
||||
# the environment for determining the capabilities of the architecture.
|
||||
|
||||
@@ -733,10 +733,13 @@ static void enter_non_classic_execution_environment(sc_invocation *inv,
|
||||
// device cgroup by itself.
|
||||
struct sc_device_cgroup_options cgdevopts = { false, false };
|
||||
sc_get_device_cgroup_setup(inv, &cgdevopts);
|
||||
bool in_container = sc_is_in_container();
|
||||
if (cgdevopts.self_managed) {
|
||||
debug("device cgroup is self-managed by the snap");
|
||||
} else if (cgdevopts.non_strict) {
|
||||
debug("device cgroup skipped, snap in non-strict confinement");
|
||||
} else if (in_container) {
|
||||
debug("device cgroup skipped, executing inside a container");
|
||||
} else {
|
||||
sc_device_cgroup_mode mode = device_cgroup_mode_for_snap(inv);
|
||||
sc_setup_device_cgroup(inv->security_tag, mode);
|
||||
|
||||
Reference in New Issue
Block a user