github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/cmd/libsnap-confine-private/cgroup-support.c (about) 1 /* 2 * Copyright (C) 2019 Canonical Ltd 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 3 as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 * 16 */ 17 18 // For AT_EMPTY_PATH and O_PATH 19 #define _GNU_SOURCE 20 21 #include "cgroup-support.h" 22 23 #include <errno.h> 24 #include <stdio.h> 25 #include <string.h> 26 #include <sys/stat.h> 27 #include <sys/types.h> 28 #include <sys/vfs.h> 29 #include <unistd.h> 30 31 #include "cleanup-funcs.h" 32 #include "string-utils.h" 33 #include "utils.h" 34 35 void sc_cgroup_create_and_join(const char *parent, const char *name, pid_t pid) { 36 int parent_fd SC_CLEANUP(sc_cleanup_close) = -1; 37 parent_fd = open(parent, O_PATH | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); 38 if (parent_fd < 0) { 39 die("cannot open cgroup hierarchy %s", parent); 40 } 41 // Since we may be running from a setuid but not setgid executable, switch 42 // to the effective group to root so that the mkdirat call creates a cgroup 43 // that is always owned by root.root. 44 sc_identity old = sc_set_effective_identity(sc_root_group_identity()); 45 if (mkdirat(parent_fd, name, 0755) < 0 && errno != EEXIST) { 46 die("cannot create cgroup hierarchy %s/%s", parent, name); 47 } 48 (void)sc_set_effective_identity(old); 49 int hierarchy_fd SC_CLEANUP(sc_cleanup_close) = -1; 50 hierarchy_fd = openat(parent_fd, name, O_PATH | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); 51 if (hierarchy_fd < 0) { 52 die("cannot open cgroup hierarchy %s/%s", parent, name); 53 } 54 // Open the cgroup.procs file. 55 int procs_fd SC_CLEANUP(sc_cleanup_close) = -1; 56 procs_fd = openat(hierarchy_fd, "cgroup.procs", O_WRONLY | O_NOFOLLOW | O_CLOEXEC); 57 if (procs_fd < 0) { 58 die("cannot open file %s/%s/cgroup.procs", parent, name); 59 } 60 // Write the process (task) number to the procs file. Linux task IDs are 61 // limited to 2^29 so a long int is enough to represent it. 62 // See include/linux/threads.h in the kernel source tree for details. 63 char buf[22] = {0}; // 2^64 base10 + 2 for NUL and '-' for long 64 int n = sc_must_snprintf(buf, sizeof buf, "%ld", (long)pid); 65 if (write(procs_fd, buf, n) < n) { 66 die("cannot move process %ld to cgroup hierarchy %s/%s", (long)pid, parent, name); 67 } 68 debug("moved process %ld to cgroup hierarchy %s/%s", (long)pid, parent, name); 69 } 70 71 static const char *cgroup_dir = "/sys/fs/cgroup"; 72 73 // from statfs(2) 74 #ifndef CGRUOP2_SUPER_MAGIC 75 #define CGROUP2_SUPER_MAGIC 0x63677270 76 #endif 77 78 // Detect if we are running in cgroup v2 unified mode (as opposed to 79 // hybrid or legacy) The algorithm is described in 80 // https://systemd.io/CGROUP_DELEGATION.html 81 bool sc_cgroup_is_v2() { 82 static bool did_warn = false; 83 struct statfs buf; 84 85 if (statfs(cgroup_dir, &buf) != 0) { 86 if (errno == ENOENT) { 87 return false; 88 } 89 die("cannot statfs %s", cgroup_dir); 90 } 91 if (buf.f_type == CGROUP2_SUPER_MAGIC) { 92 if (!did_warn) { 93 fprintf(stderr, "WARNING: cgroup v2 is not fully supported yet, proceeding with partial confinement\n"); 94 did_warn = true; 95 } 96 return true; 97 } 98 return false; 99 }