]> git.proxmox.com Git - mirror_lxc.git/commitdiff
apparmor: prefer /proc/.../attr/apparmor/current over legacy interface
authorAleksa Sarai <cyphar@cyphar.com>
Fri, 19 Feb 2021 09:45:37 +0000 (20:45 +1100)
committerAleksa Sarai <cyphar@cyphar.com>
Fri, 19 Feb 2021 09:53:50 +0000 (20:53 +1100)
It turns out that since Linux 5.1 there are now per-LSM subdirectories
for major LSMs, which users are recommended to use over the "legacy"
top-level /proc/$pid/attr/... files[1]:

> Process attributes associated with “major” security modules should be
> accessed and maintained using the special files in /proc/.../attr. A
> security module may maintain a module specific subdirectory there,
> named after the module. /proc/.../attr/smack is provided by the Smack
> security module and contains all its special files. The files directly
> in /proc/.../attr remain as legacy interfaces for modules that provide
> subdirectories.

AppArmor has had such a directory since Linux 5.8[2], and it turns out
that with certain CONFIG_LSM configurations you can end up with AppArmor
files not being accessible from the legacy interface. Arch Linux
recently added BPF as one of the enabled LSM in their configuration, and
this broke runc[3] and LXC.

The solution is to first try to use /proc/$pid/attr/apparmor/current and
fall back to /proc/$pid/attr/current if the former is not available.

[1]: https://www.kernel.org/doc/html/latest/admin-guide/LSM/index.html
[2]: Linux 5.8 ; commit 6413f852ce08 ("apparmor: add proc subdir to attrs")
[3]: https://github.com/opencontainers/runc/issues/2801

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
src/lxc/lsm/apparmor.c
src/lxc/macro.h

index c563b4931643cd255e1060eb93ef2ce97594e7cb..b4c0569a939051fdf645c4c26461d6316449e238 100644 (file)
@@ -404,15 +404,28 @@ static int __apparmor_process_label_open(struct lsm_ops *ops, pid_t pid, int o_f
        if (on_exec)
                TRACE("On-exec not supported with AppArmor");
 
+       /* first try the apparmor subdir */
+       ret = snprintf(path, LXC_LSMATTRLEN, "/proc/%d/attr/apparmor/current", pid);
+       if (ret < 0 || ret >= LXC_LSMATTRLEN)
+               return -1;
+
+       labelfd = open(path, o_flags);
+       if (labelfd >= 0)
+               return labelfd;
+       else if (errno != ENOENT)
+               goto error;
+
+       /* fallback to legacy global attr directory */
        ret = snprintf(path, LXC_LSMATTRLEN, "/proc/%d/attr/current", pid);
        if (ret < 0 || ret >= LXC_LSMATTRLEN)
                return -1;
 
        labelfd = open(path, o_flags);
-       if (labelfd < 0)
-               return log_error_errno(-errno, errno, "Unable to open AppArmor LSM label file descriptor");
+       if (labelfd >= 0)
+               return labelfd;
 
-       return labelfd;
+error:
+       return log_error_errno(-errno, errno, "Unable to open AppArmor LSM label file descriptor");
 }
 
 static char *apparmor_process_label_get(struct lsm_ops *ops, pid_t pid)
@@ -439,14 +452,16 @@ static char *apparmor_process_label_get_at(struct lsm_ops *ops, int fd_pid)
        __do_free char *label = NULL;
        size_t len;
 
-       label = read_file_at(fd_pid, "attr/current", PROTECT_OPEN, PROTECT_LOOKUP_BENEATH);
+       /* first try the apparmor subdir, then fall back to legacy interface */
+       label = read_file_at(fd_pid, "attr/apparmor/current", PROTECT_OPEN, PROTECT_LOOKUP_BENEATH);
+       if (!label && errno == ENOENT)
+               label = read_file_at(fd_pid, "attr/current", PROTECT_OPEN, PROTECT_LOOKUP_BENEATH);
        if (!label)
                return log_error_errno(NULL, errno, "Failed to get AppArmor context");
 
        len = strcspn(label, "\n \t");
        if (len)
                label[len] = '\0';
-
        return move_ptr(label);
 }
 
index f6ac8c45f6cfa41c3a61ee804de6c9a3a66b8f35..d802849eecbdadfd4b72d370c112ea142104df7a 100644 (file)
  *               +
  * /attr/        = 6
  *               +
+ * /apparmor/    = 10
+ *               +
  * /current      = 8
  *               +
  * \0            = 1
  */
-#define LXC_LSMATTRLEN (6 + INTTYPE_TO_STRLEN(pid_t) + 6 + 8 + 1)
+#define LXC_LSMATTRLEN (6 + INTTYPE_TO_STRLEN(pid_t) + 6 + 10 + 8 + 1)
 
 /* MAX_NS_PROC_NAME = MAX_NS_PROC_NAME
  *                  +