From patchwork Sat Jan 25 13:05:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11351577 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 B2BD31395 for ; Sat, 25 Jan 2020 13:07:17 +0000 (UTC) Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.kernel.org (Postfix) with SMTP id 21ED92077C for ; Sat, 25 Jan 2020 13:07:16 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 21ED92077C Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=kernel-hardening-return-17604-patchwork-kernel-hardening=patchwork.kernel.org@lists.openwall.com Received: (qmail 11462 invoked by uid 550); 25 Jan 2020 13:06:58 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Received: (qmail 11267 invoked from network); 25 Jan 2020 13:06:54 -0000 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 , Stephen Rothwell Subject: [PATCH v7 01/11] proc: Rename struct proc_fs_info to proc_fs_opts Date: Sat, 25 Jan 2020 14:05:31 +0100 Message-Id: <20200125130541.450409-2-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200125130541.450409-1-gladkov.alexey@gmail.com> References: <20200125130541.450409-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 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 Sat Jan 25 13:05:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11351593 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 A21171398 for ; Sat, 25 Jan 2020 13:07:30 +0000 (UTC) Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.kernel.org (Postfix) with SMTP id DE59C2071E for ; Sat, 25 Jan 2020 13:07:29 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DE59C2071E Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=kernel-hardening-return-17606-patchwork-kernel-hardening=patchwork.kernel.org@lists.openwall.com Received: (qmail 11555 invoked by uid 550); 25 Jan 2020 13:06:59 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Received: (qmail 11326 invoked from network); 25 Jan 2020 13:06:55 -0000 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 , Stephen Rothwell Subject: [PATCH v7 02/11] proc: add proc_fs_info struct to store proc information Date: Sat, 25 Jan 2020 14:05:32 +0100 Message-Id: <20200125130541.450409-3-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200125130541.450409-1-gladkov.alexey@gmail.com> References: <20200125130541.450409-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 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 Sat Jan 25 13:05:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11351583 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 08C061398 for ; Sat, 25 Jan 2020 13:07:24 +0000 (UTC) Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.kernel.org (Postfix) with SMTP id 3D2A32071E for ; Sat, 25 Jan 2020 13:07:23 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 3D2A32071E Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=kernel-hardening-return-17605-patchwork-kernel-hardening=patchwork.kernel.org@lists.openwall.com Received: (qmail 11495 invoked by uid 550); 25 Jan 2020 13:06:58 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Received: (qmail 11389 invoked from network); 25 Jan 2020 13:06:56 -0000 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 , Stephen Rothwell Subject: [PATCH v7 03/11] proc: move /proc/{self|thread-self} dentries to proc_fs_info Date: Sat, 25 Jan 2020 14:05:33 +0100 Message-Id: <20200125130541.450409-4-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200125130541.450409-1-gladkov.alexey@gmail.com> References: <20200125130541.450409-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 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 Sat Jan 25 13:05:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11351605 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 76E341398 for ; Sat, 25 Jan 2020 13:07:38 +0000 (UTC) Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.kernel.org (Postfix) with SMTP id 9A20D2077C for ; Sat, 25 Jan 2020 13:07:37 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9A20D2077C Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=kernel-hardening-return-17607-patchwork-kernel-hardening=patchwork.kernel.org@lists.openwall.com Received: (qmail 11588 invoked by uid 550); 25 Jan 2020 13:07:00 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Received: (qmail 11460 invoked from network); 25 Jan 2020 13:06:57 -0000 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 , Stephen Rothwell Subject: [PATCH v7 04/11] proc: move hide_pid, pid_gid from pid_namespace to proc_fs_info Date: Sat, 25 Jan 2020 14:05:34 +0100 Message-Id: <20200125130541.450409-5-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200125130541.450409-1-gladkov.alexey@gmail.com> References: <20200125130541.450409-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 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 Sat Jan 25 13:05:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11351617 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 A61F41395 for ; Sat, 25 Jan 2020 13:07:45 +0000 (UTC) Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.kernel.org (Postfix) with SMTP id 0B9222071E for ; Sat, 25 Jan 2020 13:07:44 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0B9222071E Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=kernel-hardening-return-17608-patchwork-kernel-hardening=patchwork.kernel.org@lists.openwall.com Received: (qmail 12079 invoked by uid 550); 25 Jan 2020 13:07:06 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Received: (qmail 12005 invoked from network); 25 Jan 2020 13:07:05 -0000 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 , Stephen Rothwell Subject: [PATCH v7 05/11] proc: add helpers to set and get proc hidepid and gid mount options Date: Sat, 25 Jan 2020 14:05:35 +0100 Message-Id: <20200125130541.450409-6-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200125130541.450409-1-gladkov.alexey@gmail.com> References: <20200125130541.450409-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 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 Sat Jan 25 13:05:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11351619 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 548FB1398 for ; Sat, 25 Jan 2020 13:07:53 +0000 (UTC) Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.kernel.org (Postfix) with SMTP id 904EC2071E for ; Sat, 25 Jan 2020 13:07:52 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 904EC2071E Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=kernel-hardening-return-17609-patchwork-kernel-hardening=patchwork.kernel.org@lists.openwall.com Received: (qmail 12161 invoked by uid 550); 25 Jan 2020 13:07:07 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Received: (qmail 12006 invoked from network); 25 Jan 2020 13:07:05 -0000 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 , Stephen Rothwell Subject: [PATCH v7 06/11] proc: support mounting procfs instances inside same pid namespace Date: Sat, 25 Jan 2020 14:05:36 +0100 Message-Id: <20200125130541.450409-7-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200125130541.450409-1-gladkov.alexey@gmail.com> References: <20200125130541.450409-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 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 Sat Jan 25 13:05:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11351623 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 22E0D1395 for ; Sat, 25 Jan 2020 13:08:11 +0000 (UTC) Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.kernel.org (Postfix) with SMTP id 602742071A for ; Sat, 25 Jan 2020 13:08:10 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 602742071A Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=kernel-hardening-return-17611-patchwork-kernel-hardening=patchwork.kernel.org@lists.openwall.com Received: (qmail 13366 invoked by uid 550); 25 Jan 2020 13:07:11 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Received: (qmail 12070 invoked from network); 25 Jan 2020 13:07:06 -0000 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 , Stephen Rothwell Subject: [PATCH v7 07/11] proc: flush task dcache entries from all procfs instances Date: Sat, 25 Jan 2020 14:05:37 +0100 Message-Id: <20200125130541.450409-8-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200125130541.450409-1-gladkov.alexey@gmail.com> References: <20200125130541.450409-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 This allows to flush dcache entries of a task on multiple procfs mounts per pid namespace. Cc: Kees Cook Cc: Andy Lutomirski Signed-off-by: Djalal Harouni Signed-off-by: Alexey Gladkov --- fs/proc/base.c | 23 ++++++++++++++----- fs/proc/root.c | 14 ++++++++++++ include/linux/pid_namespace.h | 42 +++++++++++++++++++++++++++++++++++ include/linux/proc_fs.h | 2 ++ 4 files changed, 76 insertions(+), 5 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 4ccb280a3e79..f4f1bcb28603 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,27 @@ void proc_flush_task(struct task_struct *task) int i; struct pid *pid, *tgid; struct upid *upid; + struct pid_namespace *pid_ns; + 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); + + pid_ns = upid->ns; + + pidns_proc_lock_shared(pid_ns); + list_for_each_entry(fs_info, &pid_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); + } + pidns_proc_unlock_shared(pid_ns); + + mnt_root = pid_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..3bb8df360cf7 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -112,6 +112,12 @@ static int proc_fill_super(struct super_block *s, struct fs_context *fc) proc_apply_options(ctx->fs_info, fc, pid_ns, current_user_ns()); + ctx->fs_info->m_super = s; + + pidns_proc_lock(pid_ns); + list_add_tail(&ctx->fs_info->pidns_entry, &pid_ns->proc_mounts); + pidns_proc_unlock(pid_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; s->s_flags |= SB_NODIRATIME | SB_NOSUID | SB_NOEXEC; @@ -215,6 +221,11 @@ static void proc_kill_sb(struct super_block *sb) dput(fs_info->proc_self); if (fs_info->proc_thread_self) dput(fs_info->proc_thread_self); + + pidns_proc_lock(fs_info->pid_ns); + list_del(&fs_info->pidns_entry); + pidns_proc_unlock(fs_info->pid_ns); + kill_anon_super(sb); put_pid_ns(fs_info->pid_ns); kfree(fs_info); @@ -336,6 +347,9 @@ int pid_ns_prepare_proc(struct pid_namespace *ns) ctx->fs_info->pid_ns = ns; } + init_rwsem(&ns->rw_proc_mounts); + INIT_LIST_HEAD(&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..297b39604312 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 */ + struct rw_semaphore rw_proc_mounts; + struct list_head proc_mounts; /* list of separated procfs mounts */ #endif #ifdef CONFIG_BSD_PROCESS_ACCT struct fs_pin *bacct; @@ -90,4 +92,44 @@ extern struct pid_namespace *task_active_pid_ns(struct task_struct *tsk); void pidhash_init(void); void pid_idr_init(void); +#ifdef CONFIG_PROC_FS +static inline void pidns_proc_lock(struct pid_namespace *pid_ns) +{ + down_write(&pid_ns->rw_proc_mounts); +} + +static inline void pidns_proc_unlock(struct pid_namespace *pid_ns) +{ + up_write(&pid_ns->rw_proc_mounts); +} + +static inline void pidns_proc_lock_shared(struct pid_namespace *pid_ns) +{ + down_read(&pid_ns->rw_proc_mounts); +} + +static inline void pidns_proc_unlock_shared(struct pid_namespace *pid_ns) +{ + up_read(&pid_ns->rw_proc_mounts); +} +#else /* !CONFIG_PROC_FS */ + +static inline void pidns_proc_lock(struct pid_namespace *pid_ns) +{ +} + +static inline void pidns_proc_unlock(struct pid_namespace *pid_ns) +{ +} + +static inline void pidns_proc_lock_shared(struct pid_namespace *pid_ns) +{ +} + +static inline void pidns_proc_unlock_shared(struct pid_namespace *pid_ns) +{ +} + +#endif /* CONFIG_PROC_FS */ + #endif /* _LINUX_PID_NS_H */ 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 Sat Jan 25 13:05:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11351621 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 2235C1395 for ; Sat, 25 Jan 2020 13:08:02 +0000 (UTC) Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.kernel.org (Postfix) with SMTP id 80F0C2071E for ; Sat, 25 Jan 2020 13:08:01 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 80F0C2071E Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=kernel-hardening-return-17610-patchwork-kernel-hardening=patchwork.kernel.org@lists.openwall.com Received: (qmail 12193 invoked by uid 550); 25 Jan 2020 13:07:08 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Received: (qmail 12076 invoked from network); 25 Jan 2020 13:07:06 -0000 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 , Stephen Rothwell Subject: [PATCH v7 08/11] proc: instantiate only pids that we can ptrace on 'hidepid=4' mount option Date: Sat, 25 Jan 2020 14:05:38 +0100 Message-Id: <20200125130541.450409-9-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200125130541.450409-1-gladkov.alexey@gmail.com> References: <20200125130541.450409-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 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 f4f1bcb28603..b55d205a7f6e 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))) @@ -3274,7 +3282,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 3bb8df360cf7..57276cb65528 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 Sat Jan 25 13:05:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11351625 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 589AF1395 for ; Sat, 25 Jan 2020 13:08:21 +0000 (UTC) Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.kernel.org (Postfix) with SMTP id 8B7B02071A for ; Sat, 25 Jan 2020 13:08:20 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 8B7B02071A Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=kernel-hardening-return-17612-patchwork-kernel-hardening=patchwork.kernel.org@lists.openwall.com Received: (qmail 13575 invoked by uid 550); 25 Jan 2020 13:07:11 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Received: (qmail 12192 invoked from network); 25 Jan 2020 13:07:08 -0000 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 , Stephen Rothwell Subject: [PATCH v7 09/11] proc: add option to mount only a pids subset Date: Sat, 25 Jan 2020 14:05:39 +0100 Message-Id: <20200125130541.450409-10-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200125130541.450409-1-gladkov.alexey@gmail.com> References: <20200125130541.450409-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 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 57276cb65528..8e8d5c930e32 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 Sat Jan 25 13:05:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11351627 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 639A91398 for ; Sat, 25 Jan 2020 13:08:31 +0000 (UTC) Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.kernel.org (Postfix) with SMTP id C50EE2071A for ; Sat, 25 Jan 2020 13:08:30 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C50EE2071A Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=kernel-hardening-return-17613-patchwork-kernel-hardening=patchwork.kernel.org@lists.openwall.com Received: (qmail 13604 invoked by uid 550); 25 Jan 2020 13:07:12 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Received: (qmail 12118 invoked from network); 25 Jan 2020 13:07:07 -0000 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 , Stephen Rothwell Subject: [PATCH v7 10/11] docs: proc: add documentation for "hidepid=4" and "subset=pidfs" options and new mount behavior Date: Sat, 25 Jan 2020 14:05:40 +0100 Message-Id: <20200125130541.450409-11-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200125130541.450409-1-gladkov.alexey@gmail.com> References: <20200125130541.450409-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 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 Sat Jan 25 13:05:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Gladkov X-Patchwork-Id: 11351629 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 255111398 for ; Sat, 25 Jan 2020 13:08:41 +0000 (UTC) Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.kernel.org (Postfix) with SMTP id 85B302071E for ; Sat, 25 Jan 2020 13:08:40 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 85B302071E Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=kernel-hardening-return-17614-patchwork-kernel-hardening=patchwork.kernel.org@lists.openwall.com Received: (qmail 13619 invoked by uid 550); 25 Jan 2020 13:07:13 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Received: (qmail 12117 invoked from network); 25 Jan 2020 13:07:07 -0000 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 , Stephen Rothwell Subject: [PATCH v7 11/11] proc: Move hidepid values to uapi as they are user interface to mount Date: Sat, 25 Jan 2020 14:05:41 +0100 Message-Id: <20200125130541.450409-12-gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200125130541.450409-1-gladkov.alexey@gmail.com> References: <20200125130541.450409-1-gladkov.alexey@gmail.com> MIME-Version: 1.0 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