From 5815e821a322fede231e3ee374da3cde5eb2fa24 Mon Sep 17 00:00:00 2001 From: Samuel FORESTIER Date: Sun, 28 Apr 2024 11:27:51 +0200 Subject: [PATCH] proc: checks system security policy before trying to get personalities 096972f7 and fc8f593b introduces task personalities retrieval to fix incorrect /proc files info in some cases. Linux governs access to personalities based on system ptrace policy, which may be restricted by an LSM (e.g. Yama). This patch implements a simple check for "Yama ptrace scope" kernel value to make sure ptrace usage is allowed, and prevent access from containers to proc files with "Permission denied" error if not. > closes #636 (follow-up to #553 and #609). Signed-off-by: Samuel FORESTIER --- src/proc_fuse.c | 15 ++++++++++++--- src/utils.c | 41 +++++++++++++++++++++++++++++++++++++++++ src/utils.h | 7 +++++++ 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/proc_fuse.c b/src/proc_fuse.c index 1049e72d..d0e2580c 100644 --- a/src/proc_fuse.c +++ b/src/proc_fuse.c @@ -145,8 +145,11 @@ __lxcfs_fuse_ops int proc_getattr(const char *path, struct stat *sb) strcmp(path, "/proc/swaps") == 0 || strcmp(path, "/proc/loadavg") == 0 || strcmp(path, "/proc/slabinfo") == 0) { - if (liblxcfs_functional()) + if (liblxcfs_functional()) { + if (!is_ptrace_allowed()) + return log_error(-EACCES, RESTRICTED_YAMA_PTRACE_POLICY); sb->st_size = get_procfile_size_with_personality(path); + } else sb->st_size = get_procfile_size(path); sb->st_mode = S_IFREG | 00444; @@ -206,8 +209,11 @@ __lxcfs_fuse_ops int proc_open(const char *path, struct fuse_file_info *fi) info->type = type; - if (liblxcfs_functional()) + if (liblxcfs_functional()) { + if (!is_ptrace_allowed()) + return log_error(-EACCES, RESTRICTED_YAMA_PTRACE_POLICY); info->buflen = get_procfile_size_with_personality(path) + BUF_RESERVE_SIZE; + } else info->buflen = get_procfile_size(path) + BUF_RESERVE_SIZE; @@ -1646,8 +1652,11 @@ __lxcfs_fuse_ops int proc_read(const char *path, char *buf, size_t size, return read_file_fuse_with_offset(LXC_TYPE_PROC_MEMINFO_PATH, buf, size, offset, f); case LXC_TYPE_PROC_CPUINFO: - if (liblxcfs_functional()) + if (liblxcfs_functional()) { + if (!is_ptrace_allowed()) + return log_error(-EACCES, RESTRICTED_YAMA_PTRACE_POLICY); return proc_read_with_personality(&proc_cpuinfo_read, buf, size, offset, fi); + } return read_file_fuse_with_offset(LXC_TYPE_PROC_CPUINFO_PATH, buf, size, offset, f); diff --git a/src/utils.c b/src/utils.c index ab665f74..5231013a 100644 --- a/src/utils.c +++ b/src/utils.c @@ -691,3 +691,44 @@ int get_task_personality(pid_t pid, __u32 *personality) return ret; } + +/* + This function checks whether system security policy (i.e. Yama LSM) allows ptrace usages. + This is required as accessing task personalities (see `get_task_personality` above) may be restricted by a ptrace + access mode check (see PROC(5)). +*/ +bool is_ptrace_allowed(void) +{ + static int yama_ptrace_scope = -1; + + __u32 buf_u32; + __do_close int fd = -EBADF; + int ret = -1; + char buf[INTTYPE_TO_STRLEN(uint32_t)]; + + /* Yama ptrace scope is not yet known (cache is empty) */ + if (yama_ptrace_scope == -1) { + /* assume default policy if we can't retrieve info below */ + yama_ptrace_scope = YAMA_SCOPE_RELATIONAL; + + fd = open(SYS_FS_KERNEL_YAMA_PTRACE_SCOPE, O_RDONLY | O_CLOEXEC); + if (fd >= 0) { + ret = read_nointr(fd, buf, sizeof(buf) - 1); + if (ret >= 0) { + buf[ret] = '\0'; + if (safe_uint32(buf, &buf_u32, 16) < 0) + return log_error(true, "Failed to convert Yama ptrace scope %s\n", buf); + + yama_ptrace_scope = buf_u32; + } else { + lxcfs_error("Failed to read Yama ptrace scope: %s.\n", strerror(errno)); + } + } else if (errno == -ENOENT) { + /* in this very case, Yama may not be enabled at all */ + yama_ptrace_scope = YAMA_SCOPE_DISABLED; + } + } + + /* consider ptrace is allowed when Yama scope is lower than "no-attach" mode */ + return (yama_ptrace_scope < YAMA_SCOPE_NO_ATTACH); +} diff --git a/src/utils.h b/src/utils.h index 7ed021a9..f254044b 100644 --- a/src/utils.h +++ b/src/utils.h @@ -25,6 +25,12 @@ #define SEND_CREDS_NOTSK 1 #define SEND_CREDS_FAIL 2 +#define SYS_FS_KERNEL_YAMA_PTRACE_SCOPE "/sys/kernel/yama/ptrace_scope" +#define YAMA_SCOPE_DISABLED 0 +#define YAMA_SCOPE_RELATIONAL 1 +#define YAMA_SCOPE_NO_ATTACH 3 +#define RESTRICTED_YAMA_PTRACE_POLICY "Due to restricted Yama ptrace policy, reading proc files from containers is not permitted" + struct file_info; __attribute__((__format__(__printf__, 4, 5))) extern char *must_strcat(char **src, size_t *sz, size_t *asz, const char *format, ...); @@ -77,6 +83,7 @@ static inline bool file_exists(const char *f) extern char *read_file_at(int dfd, const char *fnam, unsigned int o_flags); extern int get_task_personality(pid_t pid, __u32 *personality); +extern bool is_ptrace_allowed(void); extern int get_host_personality(__u32 *personality); #endif /* __LXCFS_UTILS_H */