From patchwork Mon Feb 10 15:05:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11373449 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3BCCC921 for ; Mon, 10 Feb 2020 15:06:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 26CAF2085B for ; Mon, 10 Feb 2020 15:06:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729090AbgBJPGG (ORCPT ); Mon, 10 Feb 2020 10:06:06 -0500 Received: from monster.unsafe.ru ([5.9.28.80]:53742 "EHLO mail.unsafe.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729026AbgBJPGG (ORCPT ); Mon, 10 Feb 2020 10:06:06 -0500 Received: from comp-core-i7-2640m-0182e6.redhat.com (nat-pool-brq-t.redhat.com [213.175.37.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.unsafe.ru (Postfix) with ESMTPSA id ECF28C61B02; Mon, 10 Feb 2020 15:06:01 +0000 (UTC) From: Alexey Gladkov To: LKML , Kernel Hardening , Linux API , Linux FS Devel , Linux Security Module Cc: Akinobu Mita , Alexander Viro , Alexey Dobriyan , Alexey Gladkov , Andrew Morton , Andy Lutomirski , Daniel Micay , Djalal Harouni , "Dmitry V . Levin" , "Eric W . Biederman" , Greg Kroah-Hartman , Ingo Molnar , "J . Bruce Fields" , Jeff Layton , Jonathan Corbet , Kees Cook , Linus Torvalds , Oleg Nesterov , Solar Designer Subject: [PATCH v8 01/11] proc: Rename struct proc_fs_info to proc_fs_opts Date: Mon, 10 Feb 2020 16:05:09 +0100 Message-Id: <20200210150519.538333-2-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com> References: <20200210150519.538333-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: Signed-off-by: Alexey Gladkov --- fs/proc_namespace.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c index 273ee82d8aa9..9a8b624bc3db 100644 --- a/fs/proc_namespace.c +++ b/fs/proc_namespace.c @@ -37,23 +37,23 @@ static __poll_t mounts_poll(struct file *file, poll_table *wait) return res; } -struct proc_fs_info { +struct proc_fs_opts { int flag; const char *str; }; static int show_sb_opts(struct seq_file *m, struct super_block *sb) { - static const struct proc_fs_info fs_info[] = { + static const struct proc_fs_opts fs_opts[] = { { SB_SYNCHRONOUS, ",sync" }, { SB_DIRSYNC, ",dirsync" }, { SB_MANDLOCK, ",mand" }, { SB_LAZYTIME, ",lazytime" }, { 0, NULL } }; - const struct proc_fs_info *fs_infop; + const struct proc_fs_opts *fs_infop; - for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { + for (fs_infop = fs_opts; fs_infop->flag; fs_infop++) { if (sb->s_flags & fs_infop->flag) seq_puts(m, fs_infop->str); } @@ -63,7 +63,7 @@ static int show_sb_opts(struct seq_file *m, struct super_block *sb) static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt) { - static const struct proc_fs_info mnt_info[] = { + static const struct proc_fs_opts mnt_opts[] = { { MNT_NOSUID, ",nosuid" }, { MNT_NODEV, ",nodev" }, { MNT_NOEXEC, ",noexec" }, @@ -72,9 +72,9 @@ static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt) { MNT_RELATIME, ",relatime" }, { 0, NULL } }; - const struct proc_fs_info *fs_infop; + const struct proc_fs_opts *fs_infop; - for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) { + for (fs_infop = mnt_opts; fs_infop->flag; fs_infop++) { if (mnt->mnt_flags & fs_infop->flag) seq_puts(m, fs_infop->str); } From patchwork Mon Feb 10 15:05:10 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11373501 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AC8401395 for ; Mon, 10 Feb 2020 15:06:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 812C820714 for ; Mon, 10 Feb 2020 15:06:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729133AbgBJPGH (ORCPT ); Mon, 10 Feb 2020 10:06:07 -0500 Received: from monster.unsafe.ru ([5.9.28.80]:53774 "EHLO mail.unsafe.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729081AbgBJPGH (ORCPT ); Mon, 10 Feb 2020 10:06:07 -0500 Received: from comp-core-i7-2640m-0182e6.redhat.com (nat-pool-brq-t.redhat.com [213.175.37.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.unsafe.ru (Postfix) with ESMTPSA id 107D5C61B1A; Mon, 10 Feb 2020 15:06:04 +0000 (UTC) From: Alexey Gladkov To: LKML , Kernel Hardening , Linux API , Linux FS Devel , Linux Security Module Cc: Akinobu Mita , Alexander Viro , Alexey Dobriyan , Alexey Gladkov , Andrew Morton , Andy Lutomirski , Daniel Micay , Djalal Harouni , "Dmitry V . Levin" , "Eric W . Biederman" , Greg Kroah-Hartman , Ingo Molnar , "J . Bruce Fields" , Jeff Layton , Jonathan Corbet , Kees Cook , Linus Torvalds , Oleg Nesterov , Solar Designer Subject: [PATCH v8 02/11] proc: add proc_fs_info struct to store proc information Date: Mon, 10 Feb 2020 16:05:10 +0100 Message-Id: <20200210150519.538333-3-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com> References: <20200210150519.538333-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: This is a preparation patch that adds proc_fs_info to be able to store different procfs options and informations. Right now some mount options are stored inside the pid namespace which makes it hard to change or modernize procfs without affecting pid namespaces. Plus we do want to treat proc as more of a real mount point and filesystem. procfs is part of Linux API where it offers some features using filesystem syscalls and in order to support some features where we are able to have multiple instances of procfs, each one with its mount options inside the same pid namespace, we have to separate these procfs instances. This is the same feature that was also added to other Linux interfaces like devpts in order to support containers, sandboxes, and to have multiple instances of devpts filesystem [1]. [1] https://elixir.bootlin.com/linux/v3.4/source/Documentation/filesystems/devpts.txt Cc: Kees Cook Suggested-by: Andy Lutomirski Signed-off-by: Djalal Harouni Signed-off-by: Alexey Gladkov --- fs/locks.c | 6 +++-- fs/proc/base.c | 8 +++++-- fs/proc/inode.c | 4 ++-- fs/proc/root.c | 49 +++++++++++++++++++++++++++-------------- include/linux/proc_fs.h | 11 ++++++++- 5 files changed, 54 insertions(+), 24 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 6970f55daf54..21200e3005e4 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -2795,7 +2795,8 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, { struct inode *inode = NULL; unsigned int fl_pid; - struct pid_namespace *proc_pidns = file_inode(f->file)->i_sb->s_fs_info; + struct proc_fs_info *fs_info = proc_sb_info(file_inode(f->file)->i_sb); + struct pid_namespace *proc_pidns = fs_info->pid_ns; fl_pid = locks_translate_pid(fl, proc_pidns); /* @@ -2873,7 +2874,8 @@ static int locks_show(struct seq_file *f, void *v) { struct locks_iterator *iter = f->private; struct file_lock *fl, *bfl; - struct pid_namespace *proc_pidns = file_inode(f->file)->i_sb->s_fs_info; + struct proc_fs_info *fs_info = proc_sb_info(file_inode(f->file)->i_sb); + struct pid_namespace *proc_pidns = fs_info->pid_ns; fl = hlist_entry(v, struct file_lock, fl_link); diff --git a/fs/proc/base.c b/fs/proc/base.c index ebea9501afb8..672e71c52dbd 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -3243,6 +3243,7 @@ struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags) { struct task_struct *task; unsigned tgid; + struct proc_fs_info *fs_info; struct pid_namespace *ns; struct dentry *result = ERR_PTR(-ENOENT); @@ -3250,7 +3251,8 @@ struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags) if (tgid == ~0U) goto out; - ns = dentry->d_sb->s_fs_info; + fs_info = proc_sb_info(dentry->d_sb); + ns = fs_info->pid_ns; rcu_read_lock(); task = find_task_by_pid_ns(tgid, ns); if (task) @@ -3538,6 +3540,7 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry struct task_struct *task; struct task_struct *leader = get_proc_task(dir); unsigned tid; + struct proc_fs_info *fs_info; struct pid_namespace *ns; struct dentry *result = ERR_PTR(-ENOENT); @@ -3548,7 +3551,8 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry if (tid == ~0U) goto out; - ns = dentry->d_sb->s_fs_info; + fs_info = proc_sb_info(dentry->d_sb); + ns = fs_info->pid_ns; rcu_read_lock(); task = find_task_by_pid_ns(tid, ns); if (task) diff --git a/fs/proc/inode.c b/fs/proc/inode.c index dbe43a50caf2..b631608dfbcc 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -104,8 +104,8 @@ void __init proc_init_kmemcache(void) static int proc_show_options(struct seq_file *seq, struct dentry *root) { - struct super_block *sb = root->d_sb; - struct pid_namespace *pid = sb->s_fs_info; + struct proc_fs_info *fs_info = proc_sb_info(root->d_sb); + struct pid_namespace *pid = fs_info->pid_ns; if (!gid_eq(pid->pid_gid, GLOBAL_ROOT_GID)) seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, pid->pid_gid)); diff --git a/fs/proc/root.c b/fs/proc/root.c index 0b7c8dffc9ae..d449f095f0f7 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -30,7 +30,7 @@ #include "internal.h" struct proc_fs_context { - struct pid_namespace *pid_ns; + struct proc_fs_info *fs_info; unsigned int mask; int hidepid; int gid; @@ -97,7 +97,8 @@ static void proc_apply_options(struct super_block *s, static int proc_fill_super(struct super_block *s, struct fs_context *fc) { - struct pid_namespace *pid_ns = get_pid_ns(s->s_fs_info); + struct proc_fs_context *ctx = fc->fs_private; + struct pid_namespace *pid_ns = get_pid_ns(ctx->fs_info->pid_ns); struct inode *root_inode; int ret; @@ -145,7 +146,8 @@ static int proc_fill_super(struct super_block *s, struct fs_context *fc) static int proc_reconfigure(struct fs_context *fc) { struct super_block *sb = fc->root->d_sb; - struct pid_namespace *pid = sb->s_fs_info; + struct proc_fs_info *fs_info = proc_sb_info(sb); + struct pid_namespace *pid = fs_info->pid_ns; sync_filesystem(sb); @@ -157,14 +159,14 @@ static int proc_get_tree(struct fs_context *fc) { struct proc_fs_context *ctx = fc->fs_private; - return get_tree_keyed(fc, proc_fill_super, ctx->pid_ns); + return get_tree_keyed(fc, proc_fill_super, ctx->fs_info); } static void proc_fs_context_free(struct fs_context *fc) { struct proc_fs_context *ctx = fc->fs_private; - put_pid_ns(ctx->pid_ns); + put_pid_ns(ctx->fs_info->pid_ns); kfree(ctx); } @@ -178,14 +180,27 @@ static const struct fs_context_operations proc_fs_context_ops = { static int proc_init_fs_context(struct fs_context *fc) { struct proc_fs_context *ctx; + struct pid_namespace *pid_ns; ctx = kzalloc(sizeof(struct proc_fs_context), GFP_KERNEL); if (!ctx) return -ENOMEM; - ctx->pid_ns = get_pid_ns(task_active_pid_ns(current)); + pid_ns = get_pid_ns(task_active_pid_ns(current)); + + if (!pid_ns->proc_mnt) { + ctx->fs_info = kzalloc(sizeof(struct proc_fs_info), GFP_KERNEL); + if (!ctx->fs_info) { + kfree(ctx); + return -ENOMEM; + } + ctx->fs_info->pid_ns = pid_ns; + } else { + ctx->fs_info = proc_sb_info(pid_ns->proc_mnt->mnt_sb); + } + put_user_ns(fc->user_ns); - fc->user_ns = get_user_ns(ctx->pid_ns->user_ns); + fc->user_ns = get_user_ns(ctx->fs_info->pid_ns->user_ns); fc->fs_private = ctx; fc->ops = &proc_fs_context_ops; return 0; @@ -193,15 +208,15 @@ static int proc_init_fs_context(struct fs_context *fc) static void proc_kill_sb(struct super_block *sb) { - struct pid_namespace *ns; + struct proc_fs_info *fs_info = proc_sb_info(sb); - ns = (struct pid_namespace *)sb->s_fs_info; - if (ns->proc_self) - dput(ns->proc_self); - if (ns->proc_thread_self) - dput(ns->proc_thread_self); + if (fs_info->pid_ns->proc_self) + dput(fs_info->pid_ns->proc_self); + if (fs_info->pid_ns->proc_thread_self) + dput(fs_info->pid_ns->proc_thread_self); kill_anon_super(sb); - put_pid_ns(ns); + put_pid_ns(fs_info->pid_ns); + kfree(fs_info); } static struct file_system_type proc_fs_type = { @@ -314,10 +329,10 @@ int pid_ns_prepare_proc(struct pid_namespace *ns) } ctx = fc->fs_private; - if (ctx->pid_ns != ns) { - put_pid_ns(ctx->pid_ns); + if (ctx->fs_info->pid_ns != ns) { + put_pid_ns(ctx->fs_info->pid_ns); get_pid_ns(ns); - ctx->pid_ns = ns; + ctx->fs_info->pid_ns = ns; } mnt = fc_mount(fc); diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index a705aa2d03f9..2d79489e55aa 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -12,6 +12,15 @@ struct proc_dir_entry; struct seq_file; struct seq_operations; +struct proc_fs_info { + struct pid_namespace *pid_ns; +}; + +static inline struct proc_fs_info *proc_sb_info(struct super_block *sb) +{ + return sb->s_fs_info; +} + #ifdef CONFIG_PROC_FS typedef int (*proc_write_t)(struct file *, char *, size_t); @@ -146,7 +155,7 @@ int open_related_ns(struct ns_common *ns, /* get the associated pid namespace for a file in procfs */ static inline struct pid_namespace *proc_pid_ns(const struct inode *inode) { - return inode->i_sb->s_fs_info; + return proc_sb_info(inode->i_sb)->pid_ns; } #endif /* _LINUX_PROC_FS_H */ From patchwork Mon Feb 10 15:05:11 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11373457 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 145CA921 for ; Mon, 10 Feb 2020 15:06:13 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id EBD9D20842 for ; Mon, 10 Feb 2020 15:06:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729161AbgBJPGJ (ORCPT ); Mon, 10 Feb 2020 10:06:09 -0500 Received: from monster.unsafe.ru ([5.9.28.80]:53828 "EHLO mail.unsafe.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729098AbgBJPGI (ORCPT ); Mon, 10 Feb 2020 10:06:08 -0500 Received: from comp-core-i7-2640m-0182e6.redhat.com (nat-pool-brq-t.redhat.com [213.175.37.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.unsafe.ru (Postfix) with ESMTPSA id AF60FC61B1C; Mon, 10 Feb 2020 15:06:05 +0000 (UTC) From: Alexey Gladkov To: LKML , Kernel Hardening , Linux API , Linux FS Devel , Linux Security Module Cc: Akinobu Mita , Alexander Viro , Alexey Dobriyan , Alexey Gladkov , Andrew Morton , Andy Lutomirski , Daniel Micay , Djalal Harouni , "Dmitry V . Levin" , "Eric W . Biederman" , Greg Kroah-Hartman , Ingo Molnar , "J . Bruce Fields" , Jeff Layton , Jonathan Corbet , Kees Cook , Linus Torvalds , Oleg Nesterov , Solar Designer Subject: [PATCH v8 03/11] proc: move /proc/{self|thread-self} dentries to proc_fs_info Date: Mon, 10 Feb 2020 16:05:11 +0100 Message-Id: <20200210150519.538333-4-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com> References: <20200210150519.538333-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: This is a preparation patch that moves /proc/{self|thread-self} dentries to be stored inside procfs fs_info struct instead of making them per pid namespace. Since we want to support multiple procfs instances we need to make sure that these dentries are also per-superblock instead of per-pidns, unmounting a private procfs won't clash with other procfs mounts. Cc: Kees Cook Cc: Andy Lutomirski Signed-off-by: Djalal Harouni Signed-off-by: Alexey Gladkov --- fs/proc/base.c | 5 +++-- fs/proc/root.c | 8 ++++---- fs/proc/self.c | 4 ++-- fs/proc/thread_self.c | 6 +++--- include/linux/pid_namespace.h | 4 +--- include/linux/proc_fs.h | 2 ++ 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 672e71c52dbd..1eb366ad8b06 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -3316,6 +3316,7 @@ static struct tgid_iter next_tgid(struct pid_namespace *ns, struct tgid_iter ite int proc_pid_readdir(struct file *file, struct dir_context *ctx) { struct tgid_iter iter; + struct proc_fs_info *fs_info = proc_sb_info(file_inode(file)->i_sb); struct pid_namespace *ns = proc_pid_ns(file_inode(file)); loff_t pos = ctx->pos; @@ -3323,13 +3324,13 @@ int proc_pid_readdir(struct file *file, struct dir_context *ctx) return 0; if (pos == TGID_OFFSET - 2) { - struct inode *inode = d_inode(ns->proc_self); + struct inode *inode = d_inode(fs_info->proc_self); if (!dir_emit(ctx, "self", 4, inode->i_ino, DT_LNK)) return 0; ctx->pos = pos = pos + 1; } if (pos == TGID_OFFSET - 1) { - struct inode *inode = d_inode(ns->proc_thread_self); + struct inode *inode = d_inode(fs_info->proc_thread_self); if (!dir_emit(ctx, "thread-self", 11, inode->i_ino, DT_LNK)) return 0; ctx->pos = pos = pos + 1; diff --git a/fs/proc/root.c b/fs/proc/root.c index d449f095f0f7..637e26cc795e 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -210,10 +210,10 @@ static void proc_kill_sb(struct super_block *sb) { struct proc_fs_info *fs_info = proc_sb_info(sb); - if (fs_info->pid_ns->proc_self) - dput(fs_info->pid_ns->proc_self); - if (fs_info->pid_ns->proc_thread_self) - dput(fs_info->pid_ns->proc_thread_self); + if (fs_info->proc_self) + dput(fs_info->proc_self); + if (fs_info->proc_thread_self) + dput(fs_info->proc_thread_self); kill_anon_super(sb); put_pid_ns(fs_info->pid_ns); kfree(fs_info); diff --git a/fs/proc/self.c b/fs/proc/self.c index 57c0a1047250..846fc2b7c8a8 100644 --- a/fs/proc/self.c +++ b/fs/proc/self.c @@ -36,7 +36,7 @@ static unsigned self_inum __ro_after_init; int proc_setup_self(struct super_block *s) { struct inode *root_inode = d_inode(s->s_root); - struct pid_namespace *ns = proc_pid_ns(root_inode); + struct proc_fs_info *fs_info = proc_sb_info(s); struct dentry *self; int ret = -ENOMEM; @@ -62,7 +62,7 @@ int proc_setup_self(struct super_block *s) if (ret) pr_err("proc_fill_super: can't allocate /proc/self\n"); else - ns->proc_self = self; + fs_info->proc_self = self; return ret; } diff --git a/fs/proc/thread_self.c b/fs/proc/thread_self.c index f61ae53533f5..2493cbbdfa6f 100644 --- a/fs/proc/thread_self.c +++ b/fs/proc/thread_self.c @@ -36,7 +36,7 @@ static unsigned thread_self_inum __ro_after_init; int proc_setup_thread_self(struct super_block *s) { struct inode *root_inode = d_inode(s->s_root); - struct pid_namespace *ns = proc_pid_ns(root_inode); + struct proc_fs_info *fs_info = proc_sb_info(s); struct dentry *thread_self; int ret = -ENOMEM; @@ -60,9 +60,9 @@ int proc_setup_thread_self(struct super_block *s) inode_unlock(root_inode); if (ret) - pr_err("proc_fill_super: can't allocate /proc/thread_self\n"); + pr_err("proc_fill_super: can't allocate /proc/thread-self\n"); else - ns->proc_thread_self = thread_self; + fs_info->proc_thread_self = thread_self; return ret; } diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h index 49538b172483..f91a8bf6e09e 100644 --- a/include/linux/pid_namespace.h +++ b/include/linux/pid_namespace.h @@ -31,9 +31,7 @@ struct pid_namespace { unsigned int level; struct pid_namespace *parent; #ifdef CONFIG_PROC_FS - struct vfsmount *proc_mnt; - struct dentry *proc_self; - struct dentry *proc_thread_self; + struct vfsmount *proc_mnt; /* Internal proc mounted during each new pidns */ #endif #ifdef CONFIG_BSD_PROCESS_ACCT struct fs_pin *bacct; diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 2d79489e55aa..59162988998e 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -14,6 +14,8 @@ struct seq_operations; struct proc_fs_info { struct pid_namespace *pid_ns; + struct dentry *proc_self; /* For /proc/self */ + struct dentry *proc_thread_self; /* For /proc/thread-self */ }; static inline struct proc_fs_info *proc_sb_info(struct super_block *sb) From patchwork Mon Feb 10 15:05:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11373497 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7316B1820 for ; Mon, 10 Feb 2020 15:06:48 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 56238208C3 for ; Mon, 10 Feb 2020 15:06:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729202AbgBJPGN (ORCPT ); Mon, 10 Feb 2020 10:06:13 -0500 Received: from monster.unsafe.ru ([5.9.28.80]:53774 "EHLO mail.unsafe.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729098AbgBJPGM (ORCPT ); Mon, 10 Feb 2020 10:06:12 -0500 Received: from comp-core-i7-2640m-0182e6.redhat.com (nat-pool-brq-t.redhat.com [213.175.37.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.unsafe.ru (Postfix) with ESMTPSA id D75FDC61B1E; Mon, 10 Feb 2020 15:06:07 +0000 (UTC) From: Alexey Gladkov To: LKML , Kernel Hardening , Linux API , Linux FS Devel , Linux Security Module Cc: Akinobu Mita , Alexander Viro , Alexey Dobriyan , Alexey Gladkov , Andrew Morton , Andy Lutomirski , Daniel Micay , Djalal Harouni , "Dmitry V . Levin" , "Eric W . Biederman" , Greg Kroah-Hartman , Ingo Molnar , "J . Bruce Fields" , Jeff Layton , Jonathan Corbet , Kees Cook , Linus Torvalds , Oleg Nesterov , Solar Designer Subject: [PATCH v8 04/11] proc: move hide_pid, pid_gid from pid_namespace to proc_fs_info Date: Mon, 10 Feb 2020 16:05:12 +0100 Message-Id: <20200210150519.538333-5-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com> References: <20200210150519.538333-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: This is a preparation patch that moves hide_pid and pid_gid parameters to be stored inside procfs fs_info struct instead of making them per pid namespace. Since we want to support multiple procfs instances we need to make sure that all proc-specific parameters are also per-superblock. Signed-off-by: Alexey Gladkov --- fs/proc/base.c | 18 +++++++++--------- fs/proc/inode.c | 9 ++++----- fs/proc/root.c | 10 ++++++++-- include/linux/pid_namespace.h | 8 -------- include/linux/proc_fs.h | 9 +++++++++ 5 files changed, 30 insertions(+), 24 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 1eb366ad8b06..caca1929fee1 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -695,13 +695,13 @@ int proc_setattr(struct dentry *dentry, struct iattr *attr) * May current process learn task's sched/cmdline info (for hide_pid_min=1) * or euid/egid (for hide_pid_min=2)? */ -static bool has_pid_permissions(struct pid_namespace *pid, +static bool has_pid_permissions(struct proc_fs_info *fs_info, struct task_struct *task, int hide_pid_min) { - if (pid->hide_pid < hide_pid_min) + if (fs_info->hide_pid < hide_pid_min) return true; - if (in_group_p(pid->pid_gid)) + if (in_group_p(fs_info->pid_gid)) return true; return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); } @@ -709,18 +709,18 @@ static bool has_pid_permissions(struct pid_namespace *pid, static int proc_pid_permission(struct inode *inode, int mask) { - struct pid_namespace *pid = proc_pid_ns(inode); + struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb); struct task_struct *task; bool has_perms; task = get_proc_task(inode); if (!task) return -ESRCH; - has_perms = has_pid_permissions(pid, task, HIDEPID_NO_ACCESS); + has_perms = has_pid_permissions(fs_info, task, HIDEPID_NO_ACCESS); put_task_struct(task); if (!has_perms) { - if (pid->hide_pid == HIDEPID_INVISIBLE) { + if (fs_info->hide_pid == HIDEPID_INVISIBLE) { /* * Let's make getdents(), stat(), and open() * consistent with each other. If a process @@ -1784,7 +1784,7 @@ int pid_getattr(const struct path *path, struct kstat *stat, u32 request_mask, unsigned int query_flags) { struct inode *inode = d_inode(path->dentry); - struct pid_namespace *pid = proc_pid_ns(inode); + struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb); struct task_struct *task; generic_fillattr(inode, stat); @@ -1794,7 +1794,7 @@ int pid_getattr(const struct path *path, struct kstat *stat, rcu_read_lock(); task = pid_task(proc_pid(inode), PIDTYPE_PID); if (task) { - if (!has_pid_permissions(pid, task, HIDEPID_INVISIBLE)) { + if (!has_pid_permissions(fs_info, task, HIDEPID_INVISIBLE)) { rcu_read_unlock(); /* * This doesn't prevent learning whether PID exists, @@ -3344,7 +3344,7 @@ int proc_pid_readdir(struct file *file, struct dir_context *ctx) unsigned int len; cond_resched(); - if (!has_pid_permissions(ns, iter.task, HIDEPID_INVISIBLE)) + if (!has_pid_permissions(fs_info, iter.task, HIDEPID_INVISIBLE)) continue; len = snprintf(name, sizeof(name), "%u", iter.tgid); diff --git a/fs/proc/inode.c b/fs/proc/inode.c index b631608dfbcc..b90c233e5968 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -105,12 +105,11 @@ void __init proc_init_kmemcache(void) static int proc_show_options(struct seq_file *seq, struct dentry *root) { struct proc_fs_info *fs_info = proc_sb_info(root->d_sb); - struct pid_namespace *pid = fs_info->pid_ns; - if (!gid_eq(pid->pid_gid, GLOBAL_ROOT_GID)) - seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, pid->pid_gid)); - if (pid->hide_pid != HIDEPID_OFF) - seq_printf(seq, ",hidepid=%u", pid->hide_pid); + if (!gid_eq(fs_info->pid_gid, GLOBAL_ROOT_GID)) + seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, fs_info->pid_gid)); + if (fs_info->hide_pid != HIDEPID_OFF) + seq_printf(seq, ",hidepid=%u", fs_info->hide_pid); return 0; } diff --git a/fs/proc/root.c b/fs/proc/root.c index 637e26cc795e..1ca47d446aa4 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -89,10 +89,16 @@ static void proc_apply_options(struct super_block *s, { struct proc_fs_context *ctx = fc->fs_private; + if (pid_ns->proc_mnt) { + struct proc_fs_info *fs_info = proc_sb_info(pid_ns->proc_mnt->mnt_sb); + ctx->fs_info->pid_gid = fs_info->pid_gid; + ctx->fs_info->hide_pid = fs_info->hide_pid; + } + if (ctx->mask & (1 << Opt_gid)) - pid_ns->pid_gid = make_kgid(user_ns, ctx->gid); + ctx->fs_info->pid_gid = make_kgid(user_ns, ctx->gid); if (ctx->mask & (1 << Opt_hidepid)) - pid_ns->hide_pid = ctx->hidepid; + ctx->fs_info->hide_pid = ctx->hidepid; } static int proc_fill_super(struct super_block *s, struct fs_context *fc) diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h index f91a8bf6e09e..66f47f1afe0d 100644 --- a/include/linux/pid_namespace.h +++ b/include/linux/pid_namespace.h @@ -15,12 +15,6 @@ struct fs_pin; -enum { /* definitions for pid_namespace's hide_pid field */ - HIDEPID_OFF = 0, - HIDEPID_NO_ACCESS = 1, - HIDEPID_INVISIBLE = 2, -}; - struct pid_namespace { struct kref kref; struct idr idr; @@ -39,8 +33,6 @@ struct pid_namespace { struct user_namespace *user_ns; struct ucounts *ucounts; struct work_struct proc_work; - kgid_t pid_gid; - int hide_pid; int reboot; /* group exit code if this pidns was rebooted */ struct ns_common ns; } __randomize_layout; diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 59162988998e..5f0b1b7e4271 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -12,10 +12,19 @@ struct proc_dir_entry; struct seq_file; struct seq_operations; +/* definitions for hide_pid field */ +enum { + HIDEPID_OFF = 0, + HIDEPID_NO_ACCESS = 1, + HIDEPID_INVISIBLE = 2, +}; + struct proc_fs_info { struct pid_namespace *pid_ns; struct dentry *proc_self; /* For /proc/self */ struct dentry *proc_thread_self; /* For /proc/thread-self */ + kgid_t pid_gid; + int hide_pid; }; static inline struct proc_fs_info *proc_sb_info(struct super_block *sb) From patchwork Mon Feb 10 15:05:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11373489 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 141AA921 for ; Mon, 10 Feb 2020 15:06:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id F3E5520714 for ; Mon, 10 Feb 2020 15:06:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729242AbgBJPGP (ORCPT ); Mon, 10 Feb 2020 10:06:15 -0500 Received: from monster.unsafe.ru ([5.9.28.80]:54006 "EHLO mail.unsafe.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729199AbgBJPGP (ORCPT ); Mon, 10 Feb 2020 10:06:15 -0500 Received: from comp-core-i7-2640m-0182e6.redhat.com (nat-pool-brq-t.redhat.com [213.175.37.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.unsafe.ru (Postfix) with ESMTPSA id 62359C61B20; Mon, 10 Feb 2020 15:06:10 +0000 (UTC) From: Alexey Gladkov To: LKML , Kernel Hardening , Linux API , Linux FS Devel , Linux Security Module Cc: Akinobu Mita , Alexander Viro , Alexey Dobriyan , Alexey Gladkov , Andrew Morton , Andy Lutomirski , Daniel Micay , Djalal Harouni , "Dmitry V . Levin" , "Eric W . Biederman" , Greg Kroah-Hartman , Ingo Molnar , "J . Bruce Fields" , Jeff Layton , Jonathan Corbet , Kees Cook , Linus Torvalds , Oleg Nesterov , Solar Designer Subject: [PATCH v8 05/11] proc: add helpers to set and get proc hidepid and gid mount options Date: Mon, 10 Feb 2020 16:05:13 +0100 Message-Id: <20200210150519.538333-6-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com> References: <20200210150519.538333-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: This is a cleaning patch to add helpers to set and get proc mount options instead of directly using them. This make it easy to track what's happening and easy to update in future. Cc: Kees Cook Cc: Andy Lutomirski Signed-off-by: Djalal Harouni Signed-off-by: Alexey Gladkov --- fs/proc/base.c | 6 +++--- fs/proc/inode.c | 11 +++++++---- fs/proc/internal.h | 20 ++++++++++++++++++++ fs/proc/root.c | 8 ++++---- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index caca1929fee1..4ccb280a3e79 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -699,9 +699,9 @@ static bool has_pid_permissions(struct proc_fs_info *fs_info, struct task_struct *task, int hide_pid_min) { - if (fs_info->hide_pid < hide_pid_min) + if (proc_fs_hide_pid(fs_info) < hide_pid_min) return true; - if (in_group_p(fs_info->pid_gid)) + if (in_group_p(proc_fs_pid_gid(fs_info))) return true; return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); } @@ -720,7 +720,7 @@ static int proc_pid_permission(struct inode *inode, int mask) put_task_struct(task); if (!has_perms) { - if (fs_info->hide_pid == HIDEPID_INVISIBLE) { + if (proc_fs_hide_pid(fs_info) == HIDEPID_INVISIBLE) { /* * Let's make getdents(), stat(), and open() * consistent with each other. If a process diff --git a/fs/proc/inode.c b/fs/proc/inode.c index b90c233e5968..70b722fb8811 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -105,11 +105,14 @@ void __init proc_init_kmemcache(void) static int proc_show_options(struct seq_file *seq, struct dentry *root) { struct proc_fs_info *fs_info = proc_sb_info(root->d_sb); + int hidepid = proc_fs_hide_pid(fs_info); + kgid_t gid = proc_fs_pid_gid(fs_info); - if (!gid_eq(fs_info->pid_gid, GLOBAL_ROOT_GID)) - seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, fs_info->pid_gid)); - if (fs_info->hide_pid != HIDEPID_OFF) - seq_printf(seq, ",hidepid=%u", fs_info->hide_pid); + if (!gid_eq(gid, GLOBAL_ROOT_GID)) + seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, gid)); + + if (hidepid != HIDEPID_OFF) + seq_printf(seq, ",hidepid=%u", hidepid); return 0; } diff --git a/fs/proc/internal.h b/fs/proc/internal.h index cd0c8d5ce9a1..ff2f274b2e0d 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -121,6 +121,26 @@ static inline struct task_struct *get_proc_task(const struct inode *inode) return get_pid_task(proc_pid(inode), PIDTYPE_PID); } +static inline void proc_fs_set_hide_pid(struct proc_fs_info *fs_info, int hide_pid) +{ + fs_info->hide_pid = hide_pid; +} + +static inline void proc_fs_set_pid_gid(struct proc_fs_info *fs_info, kgid_t gid) +{ + fs_info->pid_gid = gid; +} + +static inline int proc_fs_hide_pid(struct proc_fs_info *fs_info) +{ + return fs_info->hide_pid; +} + +static inline kgid_t proc_fs_pid_gid(struct proc_fs_info *fs_info) +{ + return fs_info->pid_gid; +} + void task_dump_owner(struct task_struct *task, umode_t mode, kuid_t *ruid, kgid_t *rgid); diff --git a/fs/proc/root.c b/fs/proc/root.c index 1ca47d446aa4..efd76c004e86 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -91,14 +91,14 @@ static void proc_apply_options(struct super_block *s, if (pid_ns->proc_mnt) { struct proc_fs_info *fs_info = proc_sb_info(pid_ns->proc_mnt->mnt_sb); - ctx->fs_info->pid_gid = fs_info->pid_gid; - ctx->fs_info->hide_pid = fs_info->hide_pid; + proc_fs_set_pid_gid(ctx->fs_info, proc_fs_pid_gid(fs_info)); + proc_fs_set_hide_pid(ctx->fs_info, proc_fs_hide_pid(fs_info)); } if (ctx->mask & (1 << Opt_gid)) - ctx->fs_info->pid_gid = make_kgid(user_ns, ctx->gid); + proc_fs_set_pid_gid(ctx->fs_info, make_kgid(user_ns, ctx->gid)); if (ctx->mask & (1 << Opt_hidepid)) - ctx->fs_info->hide_pid = ctx->hidepid; + proc_fs_set_hide_pid(ctx->fs_info, ctx->hidepid); } static int proc_fill_super(struct super_block *s, struct fs_context *fc) From patchwork Mon Feb 10 15:05:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11373491 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B3BC8921 for ; Mon, 10 Feb 2020 15:06:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 954892080C for ; Mon, 10 Feb 2020 15:06:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729232AbgBJPGP (ORCPT ); Mon, 10 Feb 2020 10:06:15 -0500 Received: from monster.unsafe.ru ([5.9.28.80]:54062 "EHLO mail.unsafe.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729207AbgBJPGP (ORCPT ); Mon, 10 Feb 2020 10:06:15 -0500 Received: from comp-core-i7-2640m-0182e6.redhat.com (nat-pool-brq-t.redhat.com [213.175.37.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.unsafe.ru (Postfix) with ESMTPSA id EDF07C61AB0; Mon, 10 Feb 2020 15:06:11 +0000 (UTC) From: Alexey Gladkov To: LKML , Kernel Hardening , Linux API , Linux FS Devel , Linux Security Module Cc: Akinobu Mita , Alexander Viro , Alexey Dobriyan , Alexey Gladkov , Andrew Morton , Andy Lutomirski , Daniel Micay , Djalal Harouni , "Dmitry V . Levin" , "Eric W . Biederman" , Greg Kroah-Hartman , Ingo Molnar , "J . Bruce Fields" , Jeff Layton , Jonathan Corbet , Kees Cook , Linus Torvalds , Oleg Nesterov , Solar Designer Subject: [PATCH v8 06/11] proc: support mounting procfs instances inside same pid namespace Date: Mon, 10 Feb 2020 16:05:14 +0100 Message-Id: <20200210150519.538333-7-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com> References: <20200210150519.538333-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: This patch allows to have multiple procfs instances inside the same pid namespace. The aim here is lightweight sandboxes, and to allow that we have to modernize procfs internals. 1) The main aim of this work is to have on embedded systems one supervisor for apps. Right now we have some lightweight sandbox support, however if we create pid namespacess we have to manages all the processes inside too, where our goal is to be able to run a bunch of apps each one inside its own mount namespace without being able to notice each other. We only want to use mount namespaces, and we want procfs to behave more like a real mount point. 2) Linux Security Modules have multiple ptrace paths inside some subsystems, however inside procfs, the implementation does not guarantee that the ptrace() check which triggers the security_ptrace_check() hook will always run. We have the 'hidepid' mount option that can be used to force the ptrace_may_access() check inside has_pid_permissions() to run. The problem is that 'hidepid' is per pid namespace and not attached to the mount point, any remount or modification of 'hidepid' will propagate to all other procfs mounts. This also does not allow to support Yama LSM easily in desktop and user sessions. Yama ptrace scope which restricts ptrace and some other syscalls to be allowed only on inferiors, can be updated to have a per-task context, where the context will be inherited during fork(), clone() and preserved across execve(). If we support multiple private procfs instances, then we may force the ptrace_may_access() on /proc// to always run inside that new procfs instances. This will allow to specifiy on user sessions if we should populate procfs with pids that the user can ptrace or not. By using Yama ptrace scope, some restricted users will only be able to see inferiors inside /proc, they won't even be able to see their other processes. Some software like Chromium, Firefox's crash handler, Wine and others are already using Yama to restrict which processes can be ptracable. With this change this will give the possibility to restrict /proc// but more importantly this will give desktop users a generic and usuable way to specifiy which users should see all processes and which users can not. Side notes: * This covers the lack of seccomp where it is not able to parse arguments, it is easy to install a seccomp filter on direct syscalls that operate on pids, however /proc// is a Linux ABI using filesystem syscalls. With this change LSMs should be able to analyze open/read/write/close... In the new patchset version I removed the 'newinstance' option as Eric W. Biederman suggested. Cc: Kees Cook Cc: "Eric W. Biederman" Signed-off-by: Alexey Gladkov --- fs/proc/root.c | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/fs/proc/root.c b/fs/proc/root.c index efd76c004e86..5d5cba4c899b 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -82,7 +82,7 @@ static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param) return 0; } -static void proc_apply_options(struct super_block *s, +static void proc_apply_options(struct proc_fs_info *fs_info, struct fs_context *fc, struct pid_namespace *pid_ns, struct user_namespace *user_ns) @@ -90,15 +90,17 @@ static void proc_apply_options(struct super_block *s, struct proc_fs_context *ctx = fc->fs_private; if (pid_ns->proc_mnt) { - struct proc_fs_info *fs_info = proc_sb_info(pid_ns->proc_mnt->mnt_sb); - proc_fs_set_pid_gid(ctx->fs_info, proc_fs_pid_gid(fs_info)); - proc_fs_set_hide_pid(ctx->fs_info, proc_fs_hide_pid(fs_info)); + struct proc_fs_info *pidns_fs_info = proc_sb_info(pid_ns->proc_mnt->mnt_sb); + + proc_fs_set_pid_gid(fs_info, proc_fs_pid_gid(pidns_fs_info)); + proc_fs_set_hide_pid(fs_info, proc_fs_hide_pid(pidns_fs_info)); } if (ctx->mask & (1 << Opt_gid)) - proc_fs_set_pid_gid(ctx->fs_info, make_kgid(user_ns, ctx->gid)); + proc_fs_set_pid_gid(fs_info, make_kgid(user_ns, ctx->gid)); + if (ctx->mask & (1 << Opt_hidepid)) - proc_fs_set_hide_pid(ctx->fs_info, ctx->hidepid); + proc_fs_set_hide_pid(fs_info, ctx->hidepid); } static int proc_fill_super(struct super_block *s, struct fs_context *fc) @@ -108,7 +110,7 @@ static int proc_fill_super(struct super_block *s, struct fs_context *fc) struct inode *root_inode; int ret; - proc_apply_options(s, fc, pid_ns, current_user_ns()); + proc_apply_options(ctx->fs_info, fc, pid_ns, current_user_ns()); /* User space would break if executables or devices appear on proc */ s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NOEXEC | SB_I_NODEV; @@ -118,6 +120,7 @@ static int proc_fill_super(struct super_block *s, struct fs_context *fc) s->s_magic = PROC_SUPER_MAGIC; s->s_op = &proc_sops; s->s_time_gran = 1; + s->s_fs_info = ctx->fs_info; /* * procfs isn't actually a stacking filesystem; however, there is @@ -157,15 +160,13 @@ static int proc_reconfigure(struct fs_context *fc) sync_filesystem(sb); - proc_apply_options(sb, fc, pid, current_user_ns()); + proc_apply_options(fs_info, fc, pid, current_user_ns()); return 0; } static int proc_get_tree(struct fs_context *fc) { - struct proc_fs_context *ctx = fc->fs_private; - - return get_tree_keyed(fc, proc_fill_super, ctx->fs_info); + return get_tree_nodev(fc, proc_fill_super); } static void proc_fs_context_free(struct fs_context *fc) @@ -186,25 +187,19 @@ static const struct fs_context_operations proc_fs_context_ops = { static int proc_init_fs_context(struct fs_context *fc) { struct proc_fs_context *ctx; - struct pid_namespace *pid_ns; ctx = kzalloc(sizeof(struct proc_fs_context), GFP_KERNEL); if (!ctx) return -ENOMEM; - pid_ns = get_pid_ns(task_active_pid_ns(current)); - - if (!pid_ns->proc_mnt) { - ctx->fs_info = kzalloc(sizeof(struct proc_fs_info), GFP_KERNEL); - if (!ctx->fs_info) { - kfree(ctx); - return -ENOMEM; - } - ctx->fs_info->pid_ns = pid_ns; - } else { - ctx->fs_info = proc_sb_info(pid_ns->proc_mnt->mnt_sb); + ctx->fs_info = kzalloc(sizeof(struct proc_fs_info), GFP_KERNEL); + if (!ctx->fs_info) { + kfree(ctx); + return -ENOMEM; } + ctx->fs_info->pid_ns = get_pid_ns(task_active_pid_ns(current)); + put_user_ns(fc->user_ns); fc->user_ns = get_user_ns(ctx->fs_info->pid_ns->user_ns); fc->fs_private = ctx; From patchwork Mon Feb 10 15:05:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11373483 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 80BED921 for ; Mon, 10 Feb 2020 15:06:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 61A6E2080C for ; Mon, 10 Feb 2020 15:06:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729287AbgBJPGS (ORCPT ); Mon, 10 Feb 2020 10:06:18 -0500 Received: from monster.unsafe.ru ([5.9.28.80]:54120 "EHLO mail.unsafe.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729230AbgBJPGR (ORCPT ); Mon, 10 Feb 2020 10:06:17 -0500 Received: from comp-core-i7-2640m-0182e6.redhat.com (nat-pool-brq-t.redhat.com [213.175.37.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.unsafe.ru (Postfix) with ESMTPSA id 52C9AC61B22; Mon, 10 Feb 2020 15:06:14 +0000 (UTC) From: Alexey Gladkov To: LKML , Kernel Hardening , Linux API , Linux FS Devel , Linux Security Module Cc: Akinobu Mita , Alexander Viro , Alexey Dobriyan , Alexey Gladkov , Andrew Morton , Andy Lutomirski , Daniel Micay , Djalal Harouni , "Dmitry V . Levin" , "Eric W . Biederman" , Greg Kroah-Hartman , Ingo Molnar , "J . Bruce Fields" , Jeff Layton , Jonathan Corbet , Kees Cook , Linus Torvalds , Oleg Nesterov , Solar Designer Subject: [PATCH v8 07/11] proc: flush task dcache entries from all procfs instances Date: Mon, 10 Feb 2020 16:05:15 +0100 Message-Id: <20200210150519.538333-8-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com> References: <20200210150519.538333-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: This allows to flush dcache entries of a task on multiple procfs mounts per pid namespace. The RCU lock is used because the number of reads at the task exit time is much larger than the number of procfs mounts. Cc: Kees Cook Cc: Andy Lutomirski Signed-off-by: Djalal Harouni Suggested-by: Linus Torvalds Signed-off-by: Alexey Gladkov --- fs/proc/base.c | 20 +++++++++++++++----- fs/proc/root.c | 27 ++++++++++++++++++++++++++- include/linux/pid_namespace.h | 2 ++ include/linux/proc_fs.h | 2 ++ 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 4ccb280a3e79..24b7c620ded3 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -3133,7 +3133,7 @@ static const struct inode_operations proc_tgid_base_inode_operations = { .permission = proc_pid_permission, }; -static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid) +static void proc_flush_task_mnt_root(struct dentry *mnt_root, pid_t pid, pid_t tgid) { struct dentry *dentry, *leader, *dir; char buf[10 + 1]; @@ -3142,7 +3142,7 @@ static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid) name.name = buf; name.len = snprintf(buf, sizeof(buf), "%u", pid); /* no ->d_hash() rejects on procfs */ - dentry = d_hash_and_lookup(mnt->mnt_root, &name); + dentry = d_hash_and_lookup(mnt_root, &name); if (dentry) { d_invalidate(dentry); dput(dentry); @@ -3153,7 +3153,7 @@ static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid) name.name = buf; name.len = snprintf(buf, sizeof(buf), "%u", tgid); - leader = d_hash_and_lookup(mnt->mnt_root, &name); + leader = d_hash_and_lookup(mnt_root, &name); if (!leader) goto out; @@ -3208,14 +3208,24 @@ void proc_flush_task(struct task_struct *task) int i; struct pid *pid, *tgid; struct upid *upid; + struct dentry *mnt_root; + struct proc_fs_info *fs_info; pid = task_pid(task); tgid = task_tgid(task); for (i = 0; i <= pid->level; i++) { upid = &pid->numbers[i]; - proc_flush_task_mnt(upid->ns->proc_mnt, upid->nr, - tgid->numbers[i].nr); + + rcu_read_lock(); + list_for_each_entry_rcu(fs_info, &upid->ns->proc_mounts, pidns_entry) { + mnt_root = fs_info->m_super->s_root; + proc_flush_task_mnt_root(mnt_root, upid->nr, tgid->numbers[i].nr); + } + rcu_read_unlock(); + + mnt_root = upid->ns->proc_mnt->mnt_root; + proc_flush_task_mnt_root(mnt_root, upid->nr, tgid->numbers[i].nr); } } diff --git a/fs/proc/root.c b/fs/proc/root.c index 5d5cba4c899b..e2bb015da1a8 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -149,7 +149,22 @@ static int proc_fill_super(struct super_block *s, struct fs_context *fc) if (ret) { return ret; } - return proc_setup_thread_self(s); + + ret = proc_setup_thread_self(s); + if (ret) { + return ret; + } + + /* + * back reference to flush dcache entries at process exit time. + */ + ctx->fs_info->m_super = s; + + spin_lock(&pid_ns->proc_mounts_lock); + list_add_tail_rcu(&ctx->fs_info->pidns_entry, &pid_ns->proc_mounts); + spin_unlock(&pid_ns->proc_mounts_lock); + + return 0; } static int proc_reconfigure(struct fs_context *fc) @@ -211,10 +226,17 @@ static void proc_kill_sb(struct super_block *sb) { struct proc_fs_info *fs_info = proc_sb_info(sb); + spin_lock(&fs_info->pid_ns->proc_mounts_lock); + list_del_rcu(&fs_info->pidns_entry); + spin_unlock(&fs_info->pid_ns->proc_mounts_lock); + + synchronize_rcu(); + if (fs_info->proc_self) dput(fs_info->proc_self); if (fs_info->proc_thread_self) dput(fs_info->proc_thread_self); + kill_anon_super(sb); put_pid_ns(fs_info->pid_ns); kfree(fs_info); @@ -336,6 +358,9 @@ int pid_ns_prepare_proc(struct pid_namespace *ns) ctx->fs_info->pid_ns = ns; } + spin_lock_init(&ns->proc_mounts_lock); + INIT_LIST_HEAD_RCU(&ns->proc_mounts); + mnt = fc_mount(fc); put_fs_context(fc); if (IS_ERR(mnt)) diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h index 66f47f1afe0d..c36af1dfd862 100644 --- a/include/linux/pid_namespace.h +++ b/include/linux/pid_namespace.h @@ -26,6 +26,8 @@ struct pid_namespace { struct pid_namespace *parent; #ifdef CONFIG_PROC_FS struct vfsmount *proc_mnt; /* Internal proc mounted during each new pidns */ + spinlock_t proc_mounts_lock; + struct list_head proc_mounts; /* list of separated procfs mounts */ #endif #ifdef CONFIG_BSD_PROCESS_ACCT struct fs_pin *bacct; diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 5f0b1b7e4271..f307940f8311 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -20,6 +20,8 @@ enum { }; struct proc_fs_info { + struct list_head pidns_entry; /* Node in procfs_mounts of a pidns */ + struct super_block *m_super; struct pid_namespace *pid_ns; struct dentry *proc_self; /* For /proc/self */ struct dentry *proc_thread_self; /* For /proc/thread-self */ From patchwork Mon Feb 10 15:05:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11373481 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D6441186E for ; Mon, 10 Feb 2020 15:06:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C126E208C3 for ; Mon, 10 Feb 2020 15:06:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729310AbgBJPGV (ORCPT ); Mon, 10 Feb 2020 10:06:21 -0500 Received: from monster.unsafe.ru ([5.9.28.80]:54164 "EHLO mail.unsafe.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729283AbgBJPGU (ORCPT ); Mon, 10 Feb 2020 10:06:20 -0500 Received: from comp-core-i7-2640m-0182e6.redhat.com (nat-pool-brq-t.redhat.com [213.175.37.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.unsafe.ru (Postfix) with ESMTPSA id B9BAFC61B1A; Mon, 10 Feb 2020 15:06:16 +0000 (UTC) From: Alexey Gladkov To: LKML , Kernel Hardening , Linux API , Linux FS Devel , Linux Security Module Cc: Akinobu Mita , Alexander Viro , Alexey Dobriyan , Alexey Gladkov , Andrew Morton , Andy Lutomirski , Daniel Micay , Djalal Harouni , "Dmitry V . Levin" , "Eric W . Biederman" , Greg Kroah-Hartman , Ingo Molnar , "J . Bruce Fields" , Jeff Layton , Jonathan Corbet , Kees Cook , Linus Torvalds , Oleg Nesterov , Solar Designer Subject: [PATCH v8 08/11] proc: instantiate only pids that we can ptrace on 'hidepid=4' mount option Date: Mon, 10 Feb 2020 16:05:16 +0100 Message-Id: <20200210150519.538333-9-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com> References: <20200210150519.538333-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: If "hidepid=4" mount option is set then do not instantiate pids that we can not ptrace. "hidepid=4" means that procfs should only contain pids that the caller can ptrace. Cc: Kees Cook Cc: Andy Lutomirski Signed-off-by: Djalal Harouni Signed-off-by: Alexey Gladkov --- fs/proc/base.c | 15 +++++++++++++++ fs/proc/root.c | 14 +++++++++++--- include/linux/proc_fs.h | 1 + 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 24b7c620ded3..49937d54e745 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -699,6 +699,14 @@ static bool has_pid_permissions(struct proc_fs_info *fs_info, struct task_struct *task, int hide_pid_min) { + /* + * If 'hidpid' mount option is set force a ptrace check, + * we indicate that we are using a filesystem syscall + * by passing PTRACE_MODE_READ_FSCREDS + */ + if (proc_fs_hide_pid(fs_info) == HIDEPID_NOT_PTRACABLE) + return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); + if (proc_fs_hide_pid(fs_info) < hide_pid_min) return true; if (in_group_p(proc_fs_pid_gid(fs_info))) @@ -3271,7 +3279,14 @@ struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags) if (!task) goto out; + /* Limit procfs to only ptracable tasks */ + if (proc_fs_hide_pid(fs_info) == HIDEPID_NOT_PTRACABLE) { + if (!has_pid_permissions(fs_info, task, HIDEPID_NO_ACCESS)) + goto out_put_task; + } + result = proc_pid_instantiate(dentry, task, NULL); +out_put_task: put_task_struct(task); out: return result; diff --git a/fs/proc/root.c b/fs/proc/root.c index e2bb015da1a8..5e27bb31f125 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -52,6 +52,15 @@ static const struct fs_parameter_description proc_fs_parameters = { .specs = proc_param_specs, }; +static inline int +valid_hidepid(unsigned int value) +{ + return (value == HIDEPID_OFF || + value == HIDEPID_NO_ACCESS || + value == HIDEPID_INVISIBLE || + value == HIDEPID_NOT_PTRACABLE); +} + static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param) { struct proc_fs_context *ctx = fc->fs_private; @@ -68,10 +77,9 @@ static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param) break; case Opt_hidepid: + if (!valid_hidepid(result.uint_32)) + return invalf(fc, "proc: unknown value of hidepid.\n"); ctx->hidepid = result.uint_32; - if (ctx->hidepid < HIDEPID_OFF || - ctx->hidepid > HIDEPID_INVISIBLE) - return invalf(fc, "proc: hidepid value must be between 0 and 2.\n"); break; default: diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index f307940f8311..6822548405a7 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -17,6 +17,7 @@ enum { HIDEPID_OFF = 0, HIDEPID_NO_ACCESS = 1, HIDEPID_INVISIBLE = 2, + HIDEPID_NOT_PTRACABLE = 4, /* Limit pids to only ptracable pids */ }; struct proc_fs_info { From patchwork Mon Feb 10 15:05:17 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11373475 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 988741820 for ; Mon, 10 Feb 2020 15:06:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 7BD9521734 for ; Mon, 10 Feb 2020 15:06:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729333AbgBJPGX (ORCPT ); Mon, 10 Feb 2020 10:06:23 -0500 Received: from monster.unsafe.ru ([5.9.28.80]:54120 "EHLO mail.unsafe.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729306AbgBJPGW (ORCPT ); Mon, 10 Feb 2020 10:06:22 -0500 Received: from comp-core-i7-2640m-0182e6.redhat.com (nat-pool-brq-t.redhat.com [213.175.37.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.unsafe.ru (Postfix) with ESMTPSA id 6FD06C61B1B; Mon, 10 Feb 2020 15:06:19 +0000 (UTC) From: Alexey Gladkov To: LKML , Kernel Hardening , Linux API , Linux FS Devel , Linux Security Module Cc: Akinobu Mita , Alexander Viro , Alexey Dobriyan , Alexey Gladkov , Andrew Morton , Andy Lutomirski , Daniel Micay , Djalal Harouni , "Dmitry V . Levin" , "Eric W . Biederman" , Greg Kroah-Hartman , Ingo Molnar , "J . Bruce Fields" , Jeff Layton , Jonathan Corbet , Kees Cook , Linus Torvalds , Oleg Nesterov , Solar Designer Subject: [PATCH v8 09/11] proc: add option to mount only a pids subset Date: Mon, 10 Feb 2020 16:05:17 +0100 Message-Id: <20200210150519.538333-10-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com> References: <20200210150519.538333-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: This allows to hide all files and directories in the procfs that are not related to tasks. Signed-off-by: Alexey Gladkov --- fs/proc/generic.c | 9 +++++++++ fs/proc/inode.c | 7 +++++++ fs/proc/internal.h | 10 ++++++++++ fs/proc/root.c | 36 ++++++++++++++++++++++++++++++++++++ include/linux/proc_fs.h | 7 +++++++ 5 files changed, 69 insertions(+) diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 64e9ee1b129e..6f6517d63053 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -267,6 +267,11 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry, struct dentry *proc_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { + struct proc_fs_info *fs_info = proc_sb_info(dir->i_sb); + + if (proc_fs_pidonly(fs_info) == PROC_PIDONLY_ON) + return ERR_PTR(-ENOENT); + return proc_lookup_de(dir, dentry, PDE(dir)); } @@ -323,6 +328,10 @@ int proc_readdir_de(struct file *file, struct dir_context *ctx, int proc_readdir(struct file *file, struct dir_context *ctx) { struct inode *inode = file_inode(file); + struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb); + + if (proc_fs_pidonly(fs_info) == PROC_PIDONLY_ON) + return 1; return proc_readdir_de(file, ctx, PDE(inode)); } diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 70b722fb8811..f35eef117775 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -114,6 +114,9 @@ static int proc_show_options(struct seq_file *seq, struct dentry *root) if (hidepid != HIDEPID_OFF) seq_printf(seq, ",hidepid=%u", hidepid); + if (proc_fs_pidonly(fs_info) != PROC_PIDONLY_OFF) + seq_printf(seq, ",subset=pidfs"); + return 0; } @@ -333,12 +336,16 @@ proc_reg_get_unmapped_area(struct file *file, unsigned long orig_addr, static int proc_reg_open(struct inode *inode, struct file *file) { + struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb); struct proc_dir_entry *pde = PDE(inode); int rv = 0; typeof_member(struct file_operations, open) open; typeof_member(struct file_operations, release) release; struct pde_opener *pdeo; + if (proc_fs_pidonly(fs_info) == PROC_PIDONLY_ON) + return -ENOENT; + /* * Ensure that * 1) PDE's ->release hook will be called no matter what diff --git a/fs/proc/internal.h b/fs/proc/internal.h index ff2f274b2e0d..e2c729267317 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -126,6 +126,11 @@ static inline void proc_fs_set_hide_pid(struct proc_fs_info *fs_info, int hide_p fs_info->hide_pid = hide_pid; } +static inline void proc_fs_set_pidonly(struct proc_fs_info *fs_info, int value) +{ + fs_info->pidonly = value; +} + static inline void proc_fs_set_pid_gid(struct proc_fs_info *fs_info, kgid_t gid) { fs_info->pid_gid = gid; @@ -141,6 +146,11 @@ static inline kgid_t proc_fs_pid_gid(struct proc_fs_info *fs_info) return fs_info->pid_gid; } +static inline int proc_fs_pidonly(struct proc_fs_info *fs_info) +{ + return fs_info->pidonly; +} + void task_dump_owner(struct task_struct *task, umode_t mode, kuid_t *ruid, kgid_t *rgid); diff --git a/fs/proc/root.c b/fs/proc/root.c index 5e27bb31f125..4dce77639c2b 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -34,16 +34,19 @@ struct proc_fs_context { unsigned int mask; int hidepid; int gid; + int pidonly; }; enum proc_param { Opt_gid, Opt_hidepid, + Opt_subset, }; static const struct fs_parameter_spec proc_param_specs[] = { fsparam_u32("gid", Opt_gid), fsparam_u32("hidepid", Opt_hidepid), + fsparam_string("subset", Opt_subset), {} }; @@ -61,6 +64,30 @@ valid_hidepid(unsigned int value) value == HIDEPID_NOT_PTRACABLE); } +static inline int +proc_parse_subset_param(struct fs_context *fc, char *value) +{ + struct proc_fs_context *ctx = fc->fs_private; + + while (value) { + char *ptr = strchr(value, ','); + + if (ptr != NULL) + *ptr++ = '\0'; + + if (*value != '\0') { + if (!strcmp(value, "pidfs")) { + ctx->pidonly = PROC_PIDONLY_ON; + } else { + return invalf(fc, "proc: unsupported subset option - %s\n", value); + } + } + value = ptr; + } + + return 0; +} + static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param) { struct proc_fs_context *ctx = fc->fs_private; @@ -82,6 +109,11 @@ static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param) ctx->hidepid = result.uint_32; break; + case Opt_subset: + if (proc_parse_subset_param(fc, param->string) < 0) + return -EINVAL; + break; + default: return -EINVAL; } @@ -102,6 +134,7 @@ static void proc_apply_options(struct proc_fs_info *fs_info, proc_fs_set_pid_gid(fs_info, proc_fs_pid_gid(pidns_fs_info)); proc_fs_set_hide_pid(fs_info, proc_fs_hide_pid(pidns_fs_info)); + proc_fs_set_pidonly(fs_info, proc_fs_pidonly(pidns_fs_info)); } if (ctx->mask & (1 << Opt_gid)) @@ -109,6 +142,9 @@ static void proc_apply_options(struct proc_fs_info *fs_info, if (ctx->mask & (1 << Opt_hidepid)) proc_fs_set_hide_pid(fs_info, ctx->hidepid); + + if (ctx->mask & (1 << Opt_subset)) + proc_fs_set_pidonly(fs_info, ctx->pidonly); } static int proc_fill_super(struct super_block *s, struct fs_context *fc) diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 6822548405a7..3ad0a47c3556 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -20,6 +20,12 @@ enum { HIDEPID_NOT_PTRACABLE = 4, /* Limit pids to only ptracable pids */ }; +/* definitions for proc mount option pidonly */ +enum { + PROC_PIDONLY_OFF = 0, + PROC_PIDONLY_ON = 1, +}; + struct proc_fs_info { struct list_head pidns_entry; /* Node in procfs_mounts of a pidns */ struct super_block *m_super; @@ -28,6 +34,7 @@ struct proc_fs_info { struct dentry *proc_thread_self; /* For /proc/thread-self */ kgid_t pid_gid; int hide_pid; + int pidonly; }; static inline struct proc_fs_info *proc_sb_info(struct super_block *sb) From patchwork Mon Feb 10 15:05:18 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11373463 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id F144A921 for ; Mon, 10 Feb 2020 15:06:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id DCBC82080C for ; Mon, 10 Feb 2020 15:06:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729354AbgBJPGZ (ORCPT ); Mon, 10 Feb 2020 10:06:25 -0500 Received: from monster.unsafe.ru ([5.9.28.80]:54266 "EHLO mail.unsafe.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729283AbgBJPGZ (ORCPT ); Mon, 10 Feb 2020 10:06:25 -0500 Received: from comp-core-i7-2640m-0182e6.redhat.com (nat-pool-brq-t.redhat.com [213.175.37.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.unsafe.ru (Postfix) with ESMTPSA id 1FBE2C61B1E; Mon, 10 Feb 2020 15:06:22 +0000 (UTC) From: Alexey Gladkov To: LKML , Kernel Hardening , Linux API , Linux FS Devel , Linux Security Module Cc: Akinobu Mita , Alexander Viro , Alexey Dobriyan , Alexey Gladkov , Andrew Morton , Andy Lutomirski , Daniel Micay , Djalal Harouni , "Dmitry V . Levin" , "Eric W . Biederman" , Greg Kroah-Hartman , Ingo Molnar , "J . Bruce Fields" , Jeff Layton , Jonathan Corbet , Kees Cook , Linus Torvalds , Oleg Nesterov , Solar Designer Subject: [PATCH v8 10/11] docs: proc: add documentation for "hidepid=4" and "subset=pidfs" options and new mount behavior Date: Mon, 10 Feb 2020 16:05:18 +0100 Message-Id: <20200210150519.538333-11-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com> References: <20200210150519.538333-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: Signed-off-by: Alexey Gladkov --- Documentation/filesystems/proc.txt | 53 ++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index 99ca040e3f90..4741fd092f36 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -50,6 +50,8 @@ Table of Contents 4 Configuring procfs 4.1 Mount options + 5 Filesystem behavior + ------------------------------------------------------------------------------ Preface ------------------------------------------------------------------------------ @@ -2021,6 +2023,7 @@ The following mount options are supported: hidepid= Set /proc// access mode. gid= Set the group authorized to learn processes information. + subset= Show only the specified subset of procfs. hidepid=0 means classic mode - everybody may access all /proc// directories (default). @@ -2042,6 +2045,56 @@ information about running processes, whether some daemon runs with elevated privileges, whether other user runs some sensitive program, whether other users run any program at all, etc. +hidepid=4 means that procfs should only contain /proc// directories +that the caller can ptrace. + gid= defines a group authorized to learn processes information otherwise prohibited by hidepid=. If you use some daemon like identd which needs to learn information about processes information, just add identd to this group. + +subset=pidfs hides all top level files and directories in the procfs that +are not related to tasks. + +------------------------------------------------------------------------------ +5 Filesystem behavior +------------------------------------------------------------------------------ + +Originally, before the advent of pid namepsace, procfs was a global file +system. It means that there was only one procfs instance in the system. + +When pid namespace was added, a separate procfs instance was mounted in +each pid namespace. So, procfs mount options are global among all +mountpoints within the same namespace. + +# grep ^proc /proc/mounts +proc /proc proc rw,relatime,hidepid=2 0 0 + +# strace -e mount mount -o hidepid=1 -t proc proc /tmp/proc +mount("proc", "/tmp/proc", "proc", 0, "hidepid=1") = 0 ++++ exited with 0 +++ + +# grep ^proc /proc/mounts +proc /proc proc rw,relatime,hidepid=2 0 0 +proc /tmp/proc proc rw,relatime,hidepid=2 0 0 + +and only after remounting procfs mount options will change at all +mountpoints. + +# mount -o remount,hidepid=1 -t proc proc /tmp/proc + +# grep ^proc /proc/mounts +proc /proc proc rw,relatime,hidepid=1 0 0 +proc /tmp/proc proc rw,relatime,hidepid=1 0 0 + +This behavior is different from the behavior of other filesystems. + +The new procfs behavior is more like other filesystems. Each procfs mount +creates a new procfs instance. Mount options affect own procfs instance. +It means that it became possible to have several procfs instances +displaying tasks with different filtering options in one pid namespace. + +# mount -o hidepid=2 -t proc proc /proc +# mount -o hidepid=1 -t proc proc /tmp/proc +# grep ^proc /proc/mounts +proc /proc proc rw,relatime,hidepid=2 0 0 +proc /tmp/proc proc rw,relatime,hidepid=1 0 0 From patchwork Mon Feb 10 15:05:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11373471 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0F337921 for ; Mon, 10 Feb 2020 15:06:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id EDBD72080C for ; Mon, 10 Feb 2020 15:06:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729385AbgBJPG3 (ORCPT ); Mon, 10 Feb 2020 10:06:29 -0500 Received: from monster.unsafe.ru ([5.9.28.80]:54352 "EHLO mail.unsafe.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729360AbgBJPG2 (ORCPT ); Mon, 10 Feb 2020 10:06:28 -0500 Received: from comp-core-i7-2640m-0182e6.redhat.com (nat-pool-brq-t.redhat.com [213.175.37.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.unsafe.ru (Postfix) with ESMTPSA id 0A217C61B1C; Mon, 10 Feb 2020 15:06:25 +0000 (UTC) From: Alexey Gladkov To: LKML , Kernel Hardening , Linux API , Linux FS Devel , Linux Security Module Cc: Akinobu Mita , Alexander Viro , Alexey Dobriyan , Alexey Gladkov , Andrew Morton , Andy Lutomirski , Daniel Micay , Djalal Harouni , "Dmitry V . Levin" , "Eric W . Biederman" , Greg Kroah-Hartman , Ingo Molnar , "J . Bruce Fields" , Jeff Layton , Jonathan Corbet , Kees Cook , Linus Torvalds , Oleg Nesterov , Solar Designer Subject: [PATCH v8 11/11] proc: Move hidepid values to uapi as they are user interface to mount Date: Mon, 10 Feb 2020 16:05:19 +0100 Message-Id: <20200210150519.538333-12-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com> References: <20200210150519.538333-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: Suggested-by: Alexey Dobriyan Signed-off-by: Alexey Gladkov --- include/linux/proc_fs.h | 9 +-------- include/uapi/linux/proc_fs.h | 13 +++++++++++++ 2 files changed, 14 insertions(+), 8 deletions(-) create mode 100644 include/uapi/linux/proc_fs.h diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 3ad0a47c3556..f2b4a411d371 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -7,19 +7,12 @@ #include #include +#include struct proc_dir_entry; struct seq_file; struct seq_operations; -/* definitions for hide_pid field */ -enum { - HIDEPID_OFF = 0, - HIDEPID_NO_ACCESS = 1, - HIDEPID_INVISIBLE = 2, - HIDEPID_NOT_PTRACABLE = 4, /* Limit pids to only ptracable pids */ -}; - /* definitions for proc mount option pidonly */ enum { PROC_PIDONLY_OFF = 0, diff --git a/include/uapi/linux/proc_fs.h b/include/uapi/linux/proc_fs.h new file mode 100644 index 000000000000..1e3374efffe2 --- /dev/null +++ b/include/uapi/linux/proc_fs.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_PROC_FS_H +#define _UAPI_PROC_FS_H + +/* definitions for hide_pid field */ +enum { + HIDEPID_OFF = 0, + HIDEPID_NO_ACCESS = 1, + HIDEPID_INVISIBLE = 2, + HIDEPID_NOT_PTRACABLE = 4, +}; + +#endif