]> git.proxmox.com Git - mirror_lxcfs.git/commitdiff
bindings: handle shared pidns
authorHongbo Yin <yinhongbo@bytedance.com>
Tue, 22 Oct 2019 08:41:55 +0000 (16:41 +0800)
committerHongbo Yin <yinhongbo@bytedance.com>
Mon, 16 Dec 2019 08:38:01 +0000 (16:38 +0800)
Signed-off-by: Hongbo Yin <yinhongbo@bytedance.com>
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
Signed-off-by: Hongbo Yin <yinhongbo@bytedance.com>
Makefile.am
bindings.c
memory_utils.h [new file with mode: 0644]

index ce88ac94780a5cf10c1ab1a9243df652190fdbc9..13fb1e3a5ed6e86d37bef0241ae4d1a5c34b87d8 100644 (file)
@@ -14,17 +14,19 @@ AM_CFLAGS += -DRUNTIME_PATH=\"$(RUNTIME_PATH)\"
 
 liblxcfs_la_SOURCES = bindings.c bindings.h \
                      cpuset.c \
+                     memory_utils.h \
                      sysfs_fuse.c sysfs_fuse.h
 liblxcfs_la_CFLAGS = $(AM_CFLAGS)
 liblxcfs_la_LDFLAGS = $(AM_CFLAGS) -module -avoid-version -shared
 
 liblxcfstest_la_SOURCES = bindings.c bindings.h \
                          cpuset.c \
+                         memory_utils.h \
                          sysfs_fuse.c sysfs_fuse.h
 liblxcfstest_la_CFLAGS = $(AM_CFLAGS) -DRELOADTEST
 liblxcfstest_la_LDFLAGS = $(AM_CFLAGS) -module -avoid-version -shared
 
-noinst_HEADERS = bindings.h macro.h sysfs_fuse.h
+noinst_HEADERS = bindings.h macro.h memory_utils.h sysfs_fuse.h
 
 sodir=$(libdir)
 lxcfs_LTLIBRARIES = liblxcfs.la
index 18119555893623f0d9c84abd2018feb7c77f9abc..4c6eaf73c992d265fd37ec72f4724d040a33e261 100644 (file)
@@ -38,7 +38,8 @@
 #include <sys/vfs.h>
 
 #include "bindings.h"
-#include "config.h" // for VERSION
+#include "memory_utils.h"
+#include "config.h"
 
 /* Define pivot_root() if missing from the C library */
 #ifndef HAVE_PIVOT_ROOT
@@ -662,6 +663,87 @@ static char *slurp_file(const char *from, int fd)
        return contents;
 }
 
+static int preserve_ns(const int pid, const char *ns)
+{
+       int ret;
+/* 5 /proc + 21 /int_as_str + 3 /ns + 20 /NS_NAME + 1 \0 */
+#define __NS_PATH_LEN 50
+       char path[__NS_PATH_LEN];
+
+       /* This way we can use this function to also check whether namespaces
+        * are supported by the kernel by passing in the NULL or the empty
+        * string.
+        */
+       ret = snprintf(path, __NS_PATH_LEN, "/proc/%d/ns%s%s", pid,
+                      !ns || strcmp(ns, "") == 0 ? "" : "/",
+                      !ns || strcmp(ns, "") == 0 ? "" : ns);
+       if (ret < 0 || (size_t)ret >= __NS_PATH_LEN) {
+               errno = EFBIG;
+               return -1;
+       }
+
+       return open(path, O_RDONLY | O_CLOEXEC);
+}
+
+/**
+ * in_same_namespace - Check whether two processes are in the same namespace.
+ * @pid1 - PID of the first process.
+ * @pid2 - PID of the second process.
+ * @ns   - Name of the namespace to check. Must correspond to one of the names
+ *         for the namespaces as shown in /proc/<pid/ns/
+ *
+ * If the two processes are not in the same namespace returns an fd to the
+ * namespace of the second process identified by @pid2. If the two processes are
+ * in the same namespace returns -EINVAL, -1 if an error occurred.
+ */
+static int in_same_namespace(pid_t pid1, pid_t pid2, const char *ns)
+{
+       __do_close_prot_errno int ns_fd1 = -1, ns_fd2 = -1;
+       int ret = -1;
+       struct stat ns_st1, ns_st2;
+
+       ns_fd1 = preserve_ns(pid1, ns);
+       if (ns_fd1 < 0) {
+               /* The kernel does not support this namespace. This is not an
+                * error.
+                */
+               if (errno == ENOENT)
+                       return -EINVAL;
+
+               return -1;
+       }
+
+       ns_fd2 = preserve_ns(pid2, ns);
+       if (ns_fd2 < 0)
+               return -1;
+
+       ret = fstat(ns_fd1, &ns_st1);
+       if (ret < 0)
+               return -1;
+
+       ret = fstat(ns_fd2, &ns_st2);
+       if (ret < 0)
+               return -1;
+
+       /* processes are in the same namespace */
+       if ((ns_st1.st_dev == ns_st2.st_dev) && (ns_st1.st_ino == ns_st2.st_ino))
+               return -EINVAL;
+
+       /* processes are in different namespaces */
+       return move_fd(ns_fd2);
+}
+
+static bool is_shared_pidns(pid_t pid)
+{
+       if (pid != 1)
+               return false;
+
+       if (in_same_ns(pid, getpid(), "pid") == -EINVAL)
+               return true;
+
+       return false;
+}
+
 static bool write_string(const char *fnam, const char *string, int fd)
 {
        FILE *f;
@@ -1963,7 +2045,7 @@ int cg_getattr(const char *path, struct stat *sb)
        }
 
        pid_t initpid = lookup_initpid_in_store(fc->pid);
-       if (initpid <= 0)
+       if (initpid <= 0 || is_shared_pidns(initpid))
                initpid = fc->pid;
        /* check that cgcopy is either a child cgroup of cgdir, or listed in its keys.
         * Then check that caller's cgroup is under path if last is a child
@@ -2048,7 +2130,7 @@ int cg_opendir(const char *path, struct fuse_file_info *fi)
        }
 
        pid_t initpid = lookup_initpid_in_store(fc->pid);
-       if (initpid <= 0)
+       if (initpid <= 0 || is_shared_pidns(initpid))
                initpid = fc->pid;
        if (cgroup) {
                if (!caller_may_see_dir(initpid, controller, cgroup))
@@ -2108,7 +2190,7 @@ int cg_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset
        }
 
        pid_t initpid = lookup_initpid_in_store(fc->pid);
-       if (initpid <= 0)
+       if (initpid <= 0 || is_shared_pidns(initpid))
                initpid = fc->pid;
        if (!caller_is_in_ancestor(initpid, d->controller, d->cgroup, &nextcg)) {
                if (nextcg) {
@@ -2219,7 +2301,7 @@ int cg_open(const char *path, struct fuse_file_info *fi)
        free_key(k);
 
        pid_t initpid = lookup_initpid_in_store(fc->pid);
-       if (initpid <= 0)
+       if (initpid <= 0 || is_shared_pidns(initpid))
                initpid = fc->pid;
        if (!caller_may_see_dir(initpid, controller, path1)) {
                ret = -ENOENT;
@@ -2297,7 +2379,7 @@ int cg_access(const char *path, int mode)
        free_key(k);
 
        pid_t initpid = lookup_initpid_in_store(fc->pid);
-       if (initpid <= 0)
+       if (initpid <= 0 || is_shared_pidns(initpid))
                initpid = fc->pid;
        if (!caller_may_see_dir(initpid, controller, path1)) {
                ret = -ENOENT;
@@ -3188,7 +3270,7 @@ int cg_mkdir(const char *path, mode_t mode)
                path1 = cgdir;
 
        pid_t initpid = lookup_initpid_in_store(fc->pid);
-       if (initpid <= 0)
+       if (initpid <= 0 || is_shared_pidns(initpid))
                initpid = fc->pid;
        if (!caller_is_in_ancestor(initpid, controller, path1, &next)) {
                if (!next)
@@ -3246,7 +3328,7 @@ int cg_rmdir(const char *path)
        }
 
        pid_t initpid = lookup_initpid_in_store(fc->pid);
-       if (initpid <= 0)
+       if (initpid <= 0 || is_shared_pidns(initpid))
                initpid = fc->pid;
        if (!caller_is_in_ancestor(initpid, controller, cgroup, &next)) {
                if (!last || (next && (strcmp(next, last) == 0)))
@@ -3450,7 +3532,7 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset,
        }
 
        pid_t initpid = lookup_initpid_in_store(fc->pid);
-       if (initpid <= 0)
+       if (initpid <= 0 || is_shared_pidns(initpid))
                initpid = fc->pid;
        cg = get_pid_cgroup(initpid, "memory");
        if (!cg)
@@ -3797,7 +3879,7 @@ static int proc_cpuinfo_read(char *buf, size_t size, off_t offset,
        }
 
        pid_t initpid = lookup_initpid_in_store(fc->pid);
-       if (initpid <= 0)
+       if (initpid <= 0 || is_shared_pidns(initpid))
                initpid = fc->pid;
        cg = get_pid_cgroup(initpid, "cpuset");
        if (!cg)
@@ -5245,7 +5327,7 @@ static int proc_diskstats_read(char *buf, size_t size, off_t offset,
        }
 
        pid_t initpid = lookup_initpid_in_store(fc->pid);
-       if (initpid <= 0)
+       if (initpid <= 0 || is_shared_pidns(initpid))
                initpid = fc->pid;
        cg = get_pid_cgroup(initpid, "blkio");
        if (!cg)
@@ -5367,7 +5449,7 @@ static int proc_swaps_read(char *buf, size_t size, off_t offset,
        }
 
        pid_t initpid = lookup_initpid_in_store(fc->pid);
-       if (initpid <= 0)
+       if (initpid <= 0 || is_shared_pidns(initpid))
                initpid = fc->pid;
        cg = get_pid_cgroup(initpid, "memory");
        if (!cg)
@@ -5729,7 +5811,7 @@ static int proc_loadavg_read(char *buf, size_t size, off_t offset,
                return read_file("/proc/loadavg", buf, size, d);
 
        initpid = lookup_initpid_in_store(fc->pid);
-       if (initpid <= 0)
+       if (initpid <= 0 || is_shared_pidns(initpid))
                initpid = fc->pid;
        cg = get_pid_cgroup(initpid, "cpu");
        if (!cg)
diff --git a/memory_utils.h b/memory_utils.h
new file mode 100644 (file)
index 0000000..73e04fc
--- /dev/null
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#ifndef __LXCFS_MEMORY_UTILS_H
+#define __LXCFS_MEMORY_UTILS_H
+
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "macro.h"
+
+static inline void __auto_free__(void *p)
+{
+       free(*(void **)p);
+}
+
+static inline void __auto_fclose__(FILE **f)
+{
+       if (*f)
+               fclose(*f);
+}
+
+static inline void __auto_closedir__(DIR **d)
+{
+       if (*d)
+               closedir(*d);
+}
+
+#define close_prot_errno_disarm(fd) \
+       if (fd >= 0) {              \
+               int _e_ = errno;    \
+               close(fd);          \
+               errno = _e_;        \
+               fd = -EBADF;        \
+       }
+
+#define free_disarm(ptr)       \
+       ({                     \
+               free(ptr);     \
+               move_ptr(ptr); \
+       })
+
+static inline void __auto_close__(int *fd)
+{
+       close_prot_errno_disarm(*fd);
+}
+
+#define __do_close_prot_errno __attribute__((__cleanup__(__auto_close__)))
+#define __do_free __attribute__((__cleanup__(__auto_free__)))
+#define __do_fclose __attribute__((__cleanup__(__auto_fclose__)))
+#define __do_closedir __attribute__((__cleanup__(__auto_closedir__)))
+
+#define move_ptr(ptr)                                 \
+       ({                                            \
+               typeof(ptr) __internal_ptr__ = (ptr); \
+               (ptr) = NULL;                         \
+               __internal_ptr__;                     \
+       })
+
+#define move_fd(fd)                         \
+       ({                                  \
+               int __internal_fd__ = (fd); \
+               (fd) = -EBADF;              \
+               __internal_fd__;            \
+       })
+
+#endif /* __LXCFS_MEMORY_UTILS_H */