linux-api.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v10 0/9] proc: modernize proc to support multiple private instances
@ 2020-03-27 17:23 Alexey Gladkov
  2020-03-27 17:23 ` [PATCH v10 1/9] proc: rename struct proc_fs_info to proc_fs_opts Alexey Gladkov
                   ` (9 more replies)
  0 siblings, 10 replies; 33+ messages in thread
From: Alexey Gladkov @ 2020-03-27 17:23 UTC (permalink / raw)
  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

Preface:
--------
This is patchset v10 to modernize procfs and make it able to support multiple
private instances per the same pid namespace.

This patchset can be applied on top of:

git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git 4b871ce26ab2


Procfs modernization:
---------------------
Historically procfs was always tied to pid namespaces, during pid
namespace creation we internally create a procfs mount for it. However,
this has the effect that all new procfs mounts are just a mirror of the
internal one, any change, any mount option update, any new future
introduction will propagate to all other procfs mounts that are in the
same pid namespace.

This may have solved several use cases in that time. However today we
face new requirements, and making procfs able to support new private
instances inside same pid namespace seems a major point. If we want to
to introduce new features and security mechanisms we have to make sure
first that we do not break existing usecases. Supporting private procfs
instances will allow to support new features and behaviour without
propagating it to all other procfs mounts.

Today procfs is more of a burden especially to some Embedded, IoT,
sandbox, container use cases. In user space we are over-mounting null
or inaccessible files on top to hide files and information. If we want
to hide pids we have to create PID namespaces otherwise mount options
propagate to all other proc mounts, changing a mount option value in one
mount will propagate to all other proc mounts. If we want to introduce
new features, then they will propagate to all other mounts too, resulting
either maybe new useful functionality or maybe breaking stuff. We have
also to note that userspace should not workaround procfs, the kernel
should just provide a sane simple interface.

In this regard several developers and maintainers pointed out that
there are problems with procfs and it has to be modernized:

"Here's another one: split up and modernize /proc." by Andy Lutomirski [1]

Discussion about kernel pointer leaks:

"And yes, as Kees and Daniel mentioned, it's definitely not just dmesg.
In fact, the primary things tend to be /proc and /sys, not dmesg
itself." By Linus Torvalds [2]

Lot of other areas in the kernel and filesystems have been updated to be
able to support private instances, devpts is one major example [3].

Which will be used for:

1) Embedded systems and IoT: usually we have one supervisor for
apps, we have some lightweight sandbox support, however if we create
pid namespaces we have to manage 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, maybe use network namespaces for vlans
setups, but right now we only want mount namespaces, without all the
other complexity. We want procfs to behave more like a real file system,
and block access to inodes that belong to other users. The 'hidepid=' will
not work since it is a shared mount option.

2) Containers, sandboxes and Private instances of file systems - devpts case
Historically, lot of file systems inside Linux kernel view when instantiated
were just a mirror of an already created and mounted filesystem. This was the
case of devpts filesystem, it seems at that time the requirements were to
optimize things and reuse the same memory, etc. This design used to work but not
anymore with today's containers, IoT, hostile environments and all the privacy
challenges that Linux faces.

In that regards, devpts was updated so that each new mounts is a total
independent file system by the following patches:

"devpts: Make each mount of devpts an independent filesystem" by
Eric W. Biederman [3] [4]

3) 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/<pids>/ 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/<pids>/ but more importantly this will give desktop users a
generic and usuable way to specifiy which users should see all processes
and which user 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/<pid>/ is a Linux ABI using
filesystem syscalls. With this change all LSMs should be able to analyze
open/read/write/close... on /proc/<pid>/

4) This will allow to implement new features either in kernel or
userspace without having to worry about procfs.
In containers, sandboxes, etc we have workarounds to hide some /proc
inodes, this should be supported natively without doing extra complex
work, the kernel should be able to support sane options that work with
today and future Linux use cases.

5) Creation of new superblock with all procfs options for each procfs
mount will fix the ignoring of mount options. The problem is that the
second mount of procfs in the same pid namespace ignores the mount
options. The mount options are ignored without error until procfs is
remounted.

Before:

# 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

# 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

After:

# grep ^proc /proc/mounts
proc /proc proc rw,relatime,hidepid=ptraceable 0 0

# mount -o hidepid=invisible -t proc proc /tmp/proc

# grep ^proc /proc/mounts
proc /proc proc rw,relatime,hidepid=ptraceable 0 0
proc /tmp/proc proc rw,relatime,hidepid=invisible 0 0


Introduced changes:
-------------------
Each mount of procfs creates a separate procfs instance with its own
mount options.

This series adds few new mount options:

* New 'hidepid=ptraceable' or 'hidepid=4' mount option to show only ptraceable
processes in the procfs. This allows to support lightweight sandboxes in
Embedded Linux, also solves the case for LSM where now with this mount option,
we make sure that they have a ptrace path in procfs.

* 'subset=pid' that allows to hide non-pid inodes from procfs. It can be used
in containers and sandboxes, as these are already trying to hide and block
access to procfs inodes anyway.


ChangeLog:
----------
# v10:
* 'subset=pidfs' renamed to 'subset=pid' as suggested by Alexey Dobriyan.
* Include Reviewed-by tags.

# v9:
* Rebase on top of Eric W. Biederman's procfs changes.
* Add human readable values of 'hidepid' as suggested by Andy Lutomirski.

# v8:
* Started using RCU lock to clean dcache entries as suggested by Linus Torvalds.

# v7:
* 'pidonly=1' renamed to 'subset=pidfs' as suggested by Alexey Dobriyan.
* HIDEPID_* moved to uapi/ as they are user interface to mount().
  Suggested-by Alexey Dobriyan <adobriyan@gmail.com>

# v6:
* 'hidepid=' and 'gid=' mount options are moved from pid namespace to superblock.
* 'newinstance' mount option removed as suggested by Eric W. Biederman.
   Mount of procfs always creates a new instance.
* 'limit_pids' renamed to 'hidepid=3'.
* I took into account the comment of Linus Torvalds [7].
* Documentation added.

# v5:
* Fixed a bug that caused a problem with the Fedora boot.
* The 'pidonly' option is visible among the mount options.

# v2:
* Renamed mount options to 'newinstance' and 'pids='
   Suggested-by: Andy Lutomirski <luto@kernel.org>
* Fixed order of commit, Suggested-by: Andy Lutomirski <luto@kernel.org>
* Many bug fixes.

# v1:
* Removed 'unshared' mount option and replaced it with 'limit_pids'
   which is attached to the current procfs mount.
   Suggested-by Andy Lutomirski <luto@kernel.org>
* Do not fill dcache with pid entries that we can not ptrace.
* Many bug fixes.


References:
-----------
[1] https://lists.linuxfoundation.org/pipermail/ksummit-discuss/2017-January/004215.html
[2] http://www.openwall.com/lists/kernel-hardening/2017/10/05/5
[3] https://lwn.net/Articles/689539/
[4] http://lxr.free-electrons.com/source/Documentation/filesystems/devpts.txt?v=3.14
[5] https://lkml.org/lkml/2017/5/2/407
[6] https://lkml.org/lkml/2017/5/3/357
[7] https://lkml.org/lkml/2018/5/11/505


Alexey Gladkov (9):
  proc: rename struct proc_fs_info to proc_fs_opts
  proc: allow to mount many instances of proc in one pid namespace
  proc: move hide_pid, pid_gid from pid_namespace to proc_fs_info
  proc: instantiate only pids that we can ptrace on 'hidepid=4' mount
    option
  proc: add option to mount only a pids subset
  docs: proc: add documentation for "hidepid=4" and "subset=pid" options
    and new mount behavior
  proc: move hidepid values to uapi as they are user interface to mount
  proc: use human-readable values for hidehid
  proc: use named enums for better readability

 Documentation/filesystems/proc.txt |  93 ++++++++++++++++-----
 fs/proc/base.c                     |  48 +++++++----
 fs/proc/generic.c                  |   9 ++
 fs/proc/inode.c                    |  28 +++++--
 fs/proc/root.c                     | 128 +++++++++++++++++++++++------
 fs/proc/self.c                     |   6 +-
 fs/proc/thread_self.c              |   6 +-
 fs/proc_namespace.c                |  14 ++--
 include/linux/pid_namespace.h      |   8 --
 include/linux/proc_fs.h            |  22 +++++
 include/uapi/linux/proc_fs.h       |  13 +++
 11 files changed, 290 insertions(+), 85 deletions(-)
 create mode 100644 include/uapi/linux/proc_fs.h

-- 
2.25.2


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v10 1/9] proc: rename struct proc_fs_info to proc_fs_opts
  2020-03-27 17:23 [PATCH v10 0/9] proc: modernize proc to support multiple private instances Alexey Gladkov
@ 2020-03-27 17:23 ` Alexey Gladkov
  2020-03-27 17:23 ` [PATCH v10 2/9] proc: allow to mount many instances of proc in one pid namespace Alexey Gladkov
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 33+ messages in thread
From: Alexey Gladkov @ 2020-03-27 17:23 UTC (permalink / raw)
  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

Reviewed-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 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);
 	}
-- 
2.25.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v10 2/9] proc: allow to mount many instances of proc in one pid namespace
  2020-03-27 17:23 [PATCH v10 0/9] proc: modernize proc to support multiple private instances Alexey Gladkov
  2020-03-27 17:23 ` [PATCH v10 1/9] proc: rename struct proc_fs_info to proc_fs_opts Alexey Gladkov
@ 2020-03-27 17:23 ` Alexey Gladkov
  2020-04-02 15:31   ` Eric W. Biederman
  2020-03-27 17:23 ` [PATCH v10 3/9] proc: move hide_pid, pid_gid from pid_namespace to proc_fs_info Alexey Gladkov
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 33+ messages in thread
From: Alexey Gladkov @ 2020-03-27 17:23 UTC (permalink / raw)
  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

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/<pids>/ 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/<pids>/ 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/<pid>/ 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 suggested by Eric W. Biederman.

Reviewed-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 fs/proc/base.c          | 13 +++++++++----
 fs/proc/inode.c         |  4 ++--
 fs/proc/root.c          | 42 +++++++++++++++++++++++++----------------
 fs/proc/self.c          |  6 +++---
 fs/proc/thread_self.c   |  6 +++---
 include/linux/proc_fs.h | 12 ++++++++++++
 6 files changed, 55 insertions(+), 28 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index 74f948a6b621..3b9155a69ade 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -3301,6 +3301,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);
 
@@ -3308,7 +3309,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)
@@ -3372,6 +3374,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;
 
@@ -3379,13 +3382,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;
@@ -3599,6 +3602,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);
 
@@ -3609,7 +3613,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 1e730ea1dcd6..6e4c6728338b 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -167,8 +167,8 @@ void proc_invalidate_siblings_dcache(struct hlist_head *inodes, spinlock_t *lock
 
 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 2633f10446c3..b28adbb0b937 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;
@@ -92,7 +92,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;
 
@@ -106,6 +107,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
@@ -113,7 +115,7 @@ static int proc_fill_super(struct super_block *s, struct fs_context *fc)
 	 * top of it
 	 */
 	s->s_stack_depth = FILESYSTEM_MAX_STACK_DEPTH;
-	
+
 	/* procfs dentries and inodes don't require IO to create */
 	s->s_shrink.seeks = 0;
 
@@ -140,7 +142,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);
 
@@ -150,16 +153,14 @@ static int proc_reconfigure(struct fs_context *fc)
 
 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_nodev(fc, proc_fill_super);
 }
 
 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,9 +179,15 @@ static int proc_init_fs_context(struct fs_context *fc)
 	if (!ctx)
 		return -ENOMEM;
 
-	ctx->pid_ns = get_pid_ns(task_active_pid_ns(current));
+	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->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;
@@ -188,15 +195,18 @@ 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);
+	struct pid_namespace *ns = fs_info->pid_ns;
+
+	if (fs_info->proc_self)
+		dput(fs_info->proc_self);
+
+	if (fs_info->proc_thread_self)
+		dput(fs_info->proc_thread_self);
 
-	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);
 	kill_anon_super(sb);
 	put_pid_ns(ns);
+	kfree(fs_info);
 }
 
 static struct file_system_type proc_fs_type = {
diff --git a/fs/proc/self.c b/fs/proc/self.c
index 57c0a1047250..309301ac0136 100644
--- a/fs/proc/self.c
+++ b/fs/proc/self.c
@@ -36,10 +36,10 @@ 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;
-	
+
 	inode_lock(root_inode);
 	self = d_alloc_name(s->s_root, "self");
 	if (self) {
@@ -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/proc_fs.h b/include/linux/proc_fs.h
index 40a7982b7285..5920a4ecd71b 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -27,6 +27,17 @@ struct proc_ops {
 	unsigned long (*proc_get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
 };
 
+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)
+{
+	return sb->s_fs_info;
+}
+
 #ifdef CONFIG_PROC_FS
 
 typedef int (*proc_write_t)(struct file *, char *, size_t);
@@ -161,6 +172,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 proc_sb_info(inode->i_sb)->pid_ns;
 	return inode->i_sb->s_fs_info;
 }
 
-- 
2.25.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v10 3/9] proc: move hide_pid, pid_gid from pid_namespace to proc_fs_info
  2020-03-27 17:23 [PATCH v10 0/9] proc: modernize proc to support multiple private instances Alexey Gladkov
  2020-03-27 17:23 ` [PATCH v10 1/9] proc: rename struct proc_fs_info to proc_fs_opts Alexey Gladkov
  2020-03-27 17:23 ` [PATCH v10 2/9] proc: allow to mount many instances of proc in one pid namespace Alexey Gladkov
@ 2020-03-27 17:23 ` Alexey Gladkov
  2020-03-27 17:23 ` [PATCH v10 4/9] proc: instantiate only pids that we can ptrace on 'hidepid=4' mount option Alexey Gladkov
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 33+ messages in thread
From: Alexey Gladkov @ 2020-03-27 17:23 UTC (permalink / raw)
  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

Move hide_pid and pid_gid parameters inside procfs fs_info struct
instead of making them per pid namespace. Since we have a multiple
procfs instances per pid namespace we need to make sure that all
proc-specific parameters are also per-superblock.

Reviewed-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 fs/proc/base.c                | 18 +++++++++---------
 fs/proc/inode.c               |  9 ++++-----
 fs/proc/root.c                |  4 ++--
 include/linux/pid_namespace.h |  8 --------
 include/linux/proc_fs.h       |  9 +++++++++
 5 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index 3b9155a69ade..43a28907baf9 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -697,13 +697,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);
 }
@@ -711,18 +711,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
@@ -1897,7 +1897,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);
@@ -1907,7 +1907,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,
@@ -3402,7 +3402,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 6e4c6728338b..91fe4896fa85 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -168,12 +168,11 @@ void proc_invalidate_siblings_dcache(struct hlist_head *inodes, spinlock_t *lock
 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 b28adbb0b937..616e8976185c 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -85,9 +85,9 @@ static void proc_apply_options(struct super_block *s,
 	struct proc_fs_context *ctx = fc->fs_private;
 
 	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 4956e362e55e..028d7ba242c6 100644
--- a/include/linux/pid_namespace.h
+++ b/include/linux/pid_namespace.h
@@ -17,12 +17,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;
@@ -41,8 +35,6 @@ struct pid_namespace {
 #endif
 	struct user_namespace *user_ns;
 	struct ucounts *ucounts;
-	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 5920a4ecd71b..7d852dbca253 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -27,10 +27,19 @@ struct proc_ops {
 	unsigned long (*proc_get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
 };
 
+/* 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)
-- 
2.25.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v10 4/9] proc: instantiate only pids that we can ptrace on 'hidepid=4' mount option
  2020-03-27 17:23 [PATCH v10 0/9] proc: modernize proc to support multiple private instances Alexey Gladkov
                   ` (2 preceding siblings ...)
  2020-03-27 17:23 ` [PATCH v10 3/9] proc: move hide_pid, pid_gid from pid_namespace to proc_fs_info Alexey Gladkov
@ 2020-03-27 17:23 ` Alexey Gladkov
  2020-03-28 20:40   ` Kees Cook
  2020-03-27 17:23 ` [PATCH v10 5/9] proc: add option to mount only a pids subset Alexey Gladkov
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 33+ messages in thread
From: Alexey Gladkov @ 2020-03-27 17:23 UTC (permalink / raw)
  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

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 <keescook@chromium.org>
Cc: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Djalal Harouni <tixxdz@gmail.com>
Reviewed-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 fs/proc/base.c          | 15 +++++++++++++++
 fs/proc/root.c          | 13 ++++++++++---
 include/linux/proc_fs.h |  1 +
 3 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index 43a28907baf9..1ebe9eba48ea 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -701,6 +701,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 (fs_info->hide_pid == HIDEPID_NOT_PTRACEABLE)
+		return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
+
 	if (fs_info->hide_pid < hide_pid_min)
 		return true;
 	if (in_group_p(fs_info->pid_gid))
@@ -3319,7 +3327,14 @@ struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags)
 	if (!task)
 		goto out;
 
+	/* Limit procfs to only ptraceable tasks */
+	if (fs_info->hide_pid == HIDEPID_NOT_PTRACEABLE) {
+		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 616e8976185c..62eae22403d2 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -47,6 +47,14 @@ static const struct fs_parameter_spec proc_fs_parameters[] = {
 	{}
 };
 
+static inline int valid_hidepid(unsigned int value)
+{
+	return (value == HIDEPID_OFF ||
+		value == HIDEPID_NO_ACCESS ||
+		value == HIDEPID_INVISIBLE ||
+		value == HIDEPID_NOT_PTRACEABLE);
+}
+
 static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param)
 {
 	struct proc_fs_context *ctx = fc->fs_private;
@@ -63,10 +71,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 invalfc(fc, "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 7d852dbca253..21d19353fdc7 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -32,6 +32,7 @@ enum {
 	HIDEPID_OFF	  = 0,
 	HIDEPID_NO_ACCESS = 1,
 	HIDEPID_INVISIBLE = 2,
+	HIDEPID_NOT_PTRACEABLE = 4, /* Limit pids to only ptraceable pids */
 };
 
 struct proc_fs_info {
-- 
2.25.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v10 5/9] proc: add option to mount only a pids subset
  2020-03-27 17:23 [PATCH v10 0/9] proc: modernize proc to support multiple private instances Alexey Gladkov
                   ` (3 preceding siblings ...)
  2020-03-27 17:23 ` [PATCH v10 4/9] proc: instantiate only pids that we can ptrace on 'hidepid=4' mount option Alexey Gladkov
@ 2020-03-27 17:23 ` Alexey Gladkov
  2020-03-27 17:23 ` [PATCH v10 6/9] docs: proc: add documentation for "hidepid=4" and "subset=pid" options and new mount behavior Alexey Gladkov
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 33+ messages in thread
From: Alexey Gladkov @ 2020-03-27 17:23 UTC (permalink / raw)
  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

This allows to hide all files and directories in the procfs that are not
related to tasks.

Reviewed-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 fs/proc/generic.c       |  9 +++++++++
 fs/proc/inode.c         |  6 ++++++
 fs/proc/root.c          | 33 +++++++++++++++++++++++++++++++++
 include/linux/proc_fs.h |  7 +++++++
 4 files changed, 55 insertions(+)

diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 3faed94e4b65..ee5b6482009c 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -269,6 +269,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 (fs_info->pidonly == PROC_PIDONLY_ON)
+		return ERR_PTR(-ENOENT);
+
 	return proc_lookup_de(dir, dentry, PDE(dir));
 }
 
@@ -325,6 +330,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 (fs_info->pidonly == 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 91fe4896fa85..e6577ce6027b 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -173,6 +173,8 @@ static int proc_show_options(struct seq_file *seq, struct dentry *root)
 		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 (fs_info->pidonly != PROC_PIDONLY_OFF)
+		seq_printf(seq, ",subset=pid");
 
 	return 0;
 }
@@ -393,12 +395,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 proc_ops, proc_open) open;
 	typeof_member(struct proc_ops, proc_release) release;
 	struct pde_opener *pdeo;
 
+	if (fs_info->pidonly == PROC_PIDONLY_ON)
+		return -ENOENT;
+
 	/*
 	 * Ensure that
 	 * 1) PDE's ->release hook will be called no matter what
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 62eae22403d2..dbcd96f07c7a 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_fs_parameters[] = {
 	fsparam_u32("gid",	Opt_gid),
 	fsparam_u32("hidepid",	Opt_hidepid),
+	fsparam_string("subset",	Opt_subset),
 	{}
 };
 
@@ -55,6 +58,29 @@ static inline int valid_hidepid(unsigned int value)
 		value == HIDEPID_NOT_PTRACEABLE);
 }
 
+static 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, "pid")) {
+				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;
@@ -76,6 +102,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;
 	}
@@ -95,6 +126,8 @@ static void proc_apply_options(struct super_block *s,
 		ctx->fs_info->pid_gid = make_kgid(user_ns, ctx->gid);
 	if (ctx->mask & (1 << Opt_hidepid))
 		ctx->fs_info->hide_pid = ctx->hidepid;
+	if (ctx->mask & (1 << Opt_subset))
+		ctx->fs_info->pidonly = 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 21d19353fdc7..afd38cae2339 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -35,12 +35,19 @@ enum {
 	HIDEPID_NOT_PTRACEABLE = 4, /* Limit pids to only ptraceable pids */
 };
 
+/* definitions for proc mount option pidonly */
+enum {
+	PROC_PIDONLY_OFF = 0,
+	PROC_PIDONLY_ON  = 1,
+};
+
 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;
+	int pidonly;
 };
 
 static inline struct proc_fs_info *proc_sb_info(struct super_block *sb)
-- 
2.25.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v10 6/9] docs: proc: add documentation for "hidepid=4" and "subset=pid" options and new mount behavior
  2020-03-27 17:23 [PATCH v10 0/9] proc: modernize proc to support multiple private instances Alexey Gladkov
                   ` (4 preceding siblings ...)
  2020-03-27 17:23 ` [PATCH v10 5/9] proc: add option to mount only a pids subset Alexey Gladkov
@ 2020-03-27 17:23 ` Alexey Gladkov
  2020-03-27 17:23 ` [PATCH v10 7/9] proc: move hidepid values to uapi as they are user interface to mount Alexey Gladkov
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 33+ messages in thread
From: Alexey Gladkov @ 2020-03-27 17:23 UTC (permalink / raw)
  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

Reviewed-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 Documentation/filesystems/proc.txt | 53 ++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 99ca040e3f90..bd0e0ab85048 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/<pid>/ 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/<pid>/ 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/<pid>/ 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=pid 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
-- 
2.25.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v10 7/9] proc: move hidepid values to uapi as they are user interface to mount
  2020-03-27 17:23 [PATCH v10 0/9] proc: modernize proc to support multiple private instances Alexey Gladkov
                   ` (5 preceding siblings ...)
  2020-03-27 17:23 ` [PATCH v10 6/9] docs: proc: add documentation for "hidepid=4" and "subset=pid" options and new mount behavior Alexey Gladkov
@ 2020-03-27 17:23 ` Alexey Gladkov
  2020-03-28 20:41   ` Kees Cook
  2020-04-02 16:58   ` Eric W. Biederman
  2020-03-27 17:23 ` [PATCH v10 8/9] proc: use human-readable values for hidehid Alexey Gladkov
                   ` (2 subsequent siblings)
  9 siblings, 2 replies; 33+ messages in thread
From: Alexey Gladkov @ 2020-03-27 17:23 UTC (permalink / raw)
  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

Suggested-by: Alexey Dobriyan <adobriyan@gmail.com>
Reviewed-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 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 afd38cae2339..d259817ec913 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -7,6 +7,7 @@
 
 #include <linux/types.h>
 #include <linux/fs.h>
+#include <uapi/linux/proc_fs.h>
 
 struct proc_dir_entry;
 struct seq_file;
@@ -27,14 +28,6 @@ struct proc_ops {
 	unsigned long (*proc_get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
 };
 
-/* definitions for hide_pid field */
-enum {
-	HIDEPID_OFF	  = 0,
-	HIDEPID_NO_ACCESS = 1,
-	HIDEPID_INVISIBLE = 2,
-	HIDEPID_NOT_PTRACEABLE = 4, /* Limit pids to only ptraceable 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..dc6d717aa6ec
--- /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_PTRACEABLE = 4,
+};
+
+#endif
-- 
2.25.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v10 8/9] proc: use human-readable values for hidehid
  2020-03-27 17:23 [PATCH v10 0/9] proc: modernize proc to support multiple private instances Alexey Gladkov
                   ` (6 preceding siblings ...)
  2020-03-27 17:23 ` [PATCH v10 7/9] proc: move hidepid values to uapi as they are user interface to mount Alexey Gladkov
@ 2020-03-27 17:23 ` Alexey Gladkov
  2020-03-28 20:28   ` Kees Cook
                     ` (2 more replies)
  2020-03-27 17:23 ` [PATCH v10 9/9] proc: use named enums for better readability Alexey Gladkov
  2020-04-02 17:00 ` [PATCH v10 0/9] proc: modernize proc to support multiple private instances Eric W. Biederman
  9 siblings, 3 replies; 33+ messages in thread
From: Alexey Gladkov @ 2020-03-27 17:23 UTC (permalink / raw)
  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

The hidepid parameter values are becoming more and more and it becomes
difficult to remember what each new magic number means.

Suggested-by: Andy Lutomirski <luto@kernel.org>
Reviewed-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 Documentation/filesystems/proc.txt | 52 +++++++++++++++---------------
 fs/proc/inode.c                    | 13 +++++++-
 fs/proc/root.c                     | 36 +++++++++++++++++++--
 3 files changed, 71 insertions(+), 30 deletions(-)

diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index bd0e0ab85048..af47672cb2cb 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -2025,28 +2025,28 @@ The following mount options are supported:
 	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/<pid>/ directories
-(default).
-
-hidepid=1 means users may not access any /proc/<pid>/ directories but their
-own.  Sensitive files like cmdline, sched*, status are now protected against
-other users.  This makes it impossible to learn whether any user runs
-specific program (given the program doesn't reveal itself by its behaviour).
-As an additional bonus, as /proc/<pid>/cmdline is unaccessible for other users,
-poorly written programs passing sensitive information via program arguments are
-now protected against local eavesdroppers.
-
-hidepid=2 means hidepid=1 plus all /proc/<pid>/ will be fully invisible to other
-users.  It doesn't mean that it hides a fact whether a process with a specific
-pid value exists (it can be learned by other means, e.g. by "kill -0 $PID"),
-but it hides process' uid and gid, which may be learned by stat()'ing
-/proc/<pid>/ otherwise.  It greatly complicates an intruder's task of gathering
-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/<pid>/ directories
-that the caller can ptrace.
+hidepid=off or hidepid=0 means classic mode - everybody may access all
+/proc/<pid>/ directories (default).
+
+hidepid=noaccess or hidepid=1 means users may not access any /proc/<pid>/
+directories but their own.  Sensitive files like cmdline, sched*, status are now
+protected against other users.  This makes it impossible to learn whether any
+user runs specific program (given the program doesn't reveal itself by its
+behaviour).  As an additional bonus, as /proc/<pid>/cmdline is unaccessible for
+other users, poorly written programs passing sensitive information via program
+arguments are now protected against local eavesdroppers.
+
+hidepid=invisible or hidepid=2 means hidepid=noaccess plus all /proc/<pid>/ will
+be fully invisible to other users.  It doesn't mean that it hides a fact whether
+a process with a specific pid value exists (it can be learned by other means,
+e.g. by "kill -0 $PID"), but it hides process' uid and gid, which may be learned
+by stat()'ing /proc/<pid>/ otherwise.  It greatly complicates an intruder's task
+of gathering 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=ptraceable or hidepid=4 means that procfs should only contain
+/proc/<pid>/ 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
@@ -2093,8 +2093,8 @@ 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
+# mount -o hidepid=invisible -t proc proc /proc
+# mount -o hidepid=noaccess -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
+proc /proc proc rw,relatime,hidepid=invisible 0 0
+proc /tmp/proc proc rw,relatime,hidepid=noaccess 0 0
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index e6577ce6027b..f01fb4bed75c 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -165,6 +165,17 @@ void proc_invalidate_siblings_dcache(struct hlist_head *inodes, spinlock_t *lock
 		deactivate_super(old_sb);
 }
 
+static inline const char *hidepid2str(int v)
+{
+	switch (v) {
+		case HIDEPID_OFF: return "off";
+		case HIDEPID_NO_ACCESS: return "noaccess";
+		case HIDEPID_INVISIBLE: return "invisible";
+		case HIDEPID_NOT_PTRACEABLE: return "ptraceable";
+	}
+	BUG();
+}
+
 static int proc_show_options(struct seq_file *seq, struct dentry *root)
 {
 	struct proc_fs_info *fs_info = proc_sb_info(root->d_sb);
@@ -172,7 +183,7 @@ static int proc_show_options(struct seq_file *seq, struct dentry *root)
 	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);
+		seq_printf(seq, ",hidepid=%s", hidepid2str(fs_info->hide_pid));
 	if (fs_info->pidonly != PROC_PIDONLY_OFF)
 		seq_printf(seq, ",subset=pid");
 
diff --git a/fs/proc/root.c b/fs/proc/root.c
index dbcd96f07c7a..ba782d6e6197 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -45,7 +45,7 @@ enum proc_param {
 
 static const struct fs_parameter_spec proc_fs_parameters[] = {
 	fsparam_u32("gid",	Opt_gid),
-	fsparam_u32("hidepid",	Opt_hidepid),
+	fsparam_string("hidepid",	Opt_hidepid),
 	fsparam_string("subset",	Opt_subset),
 	{}
 };
@@ -58,6 +58,35 @@ static inline int valid_hidepid(unsigned int value)
 		value == HIDEPID_NOT_PTRACEABLE);
 }
 
+static int proc_parse_hidepid_param(struct fs_context *fc, struct fs_parameter *param)
+{
+	struct proc_fs_context *ctx = fc->fs_private;
+	struct fs_parameter_spec hidepid_u32_spec = fsparam_u32("hidepid", Opt_hidepid);
+	struct fs_parse_result result;
+	int base = (unsigned long)hidepid_u32_spec.data;
+
+	if (param->type != fs_value_is_string)
+		return invalf(fc, "proc: unexpected type of hidepid value\n");
+
+	if (!kstrtouint(param->string, base, &result.uint_32)) {
+		ctx->hidepid = result.uint_32;
+		return 0;
+	}
+
+	if (!strcmp(param->string, "off"))
+		ctx->hidepid = HIDEPID_OFF;
+	else if (!strcmp(param->string, "noaccess"))
+		ctx->hidepid = HIDEPID_NO_ACCESS;
+	else if (!strcmp(param->string, "invisible"))
+		ctx->hidepid = HIDEPID_INVISIBLE;
+	else if (!strcmp(param->string, "ptraceable"))
+		ctx->hidepid = HIDEPID_NOT_PTRACEABLE;
+	else
+		return invalf(fc, "proc: unknown value of hidepid - %s\n", param->string);
+
+	return 0;
+}
+
 static int proc_parse_subset_param(struct fs_context *fc, char *value)
 {
 	struct proc_fs_context *ctx = fc->fs_private;
@@ -97,9 +126,10 @@ static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param)
 		break;
 
 	case Opt_hidepid:
-		if (!valid_hidepid(result.uint_32))
+		if (proc_parse_hidepid_param(fc, param))
+			return -EINVAL;
+		if (!valid_hidepid(ctx->hidepid))
 			return invalf(fc, "proc: unknown value of hidepid.\n");
-		ctx->hidepid = result.uint_32;
 		break;
 
 	case Opt_subset:
-- 
2.25.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v10 9/9] proc: use named enums for better readability
  2020-03-27 17:23 [PATCH v10 0/9] proc: modernize proc to support multiple private instances Alexey Gladkov
                   ` (7 preceding siblings ...)
  2020-03-27 17:23 ` [PATCH v10 8/9] proc: use human-readable values for hidehid Alexey Gladkov
@ 2020-03-27 17:23 ` Alexey Gladkov
  2020-04-02 17:00 ` [PATCH v10 0/9] proc: modernize proc to support multiple private instances Eric W. Biederman
  9 siblings, 0 replies; 33+ messages in thread
From: Alexey Gladkov @ 2020-03-27 17:23 UTC (permalink / raw)
  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

Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Reviewed-by: Alexey Dobriyan <adobriyan@gmail.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 fs/proc/base.c               | 2 +-
 fs/proc/inode.c              | 2 +-
 fs/proc/root.c               | 4 ++--
 include/linux/proc_fs.h      | 6 +++---
 include/uapi/linux/proc_fs.h | 2 +-
 5 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index 1ebe9eba48ea..2f2f7b36c947 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -699,7 +699,7 @@ int proc_setattr(struct dentry *dentry, struct iattr *attr)
  */
 static bool has_pid_permissions(struct proc_fs_info *fs_info,
 				 struct task_struct *task,
-				 int hide_pid_min)
+				 enum proc_hidepid hide_pid_min)
 {
 	/*
 	 * If 'hidpid' mount option is set force a ptrace check,
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index f01fb4bed75c..77128bc36a05 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -165,7 +165,7 @@ void proc_invalidate_siblings_dcache(struct hlist_head *inodes, spinlock_t *lock
 		deactivate_super(old_sb);
 }
 
-static inline const char *hidepid2str(int v)
+static inline const char *hidepid2str(enum proc_hidepid v)
 {
 	switch (v) {
 		case HIDEPID_OFF: return "off";
diff --git a/fs/proc/root.c b/fs/proc/root.c
index ba782d6e6197..00f75d8ef32f 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -32,9 +32,9 @@
 struct proc_fs_context {
 	struct proc_fs_info	*fs_info;
 	unsigned int		mask;
-	int			hidepid;
+	enum proc_hidepid	hidepid;
 	int			gid;
-	int			pidonly;
+	enum proc_pidonly	pidonly;
 };
 
 enum proc_param {
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index d259817ec913..b9f7ecd7f61f 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -29,7 +29,7 @@ struct proc_ops {
 };
 
 /* definitions for proc mount option pidonly */
-enum {
+enum proc_pidonly {
 	PROC_PIDONLY_OFF = 0,
 	PROC_PIDONLY_ON  = 1,
 };
@@ -39,8 +39,8 @@ struct proc_fs_info {
 	struct dentry *proc_self;        /* For /proc/self */
 	struct dentry *proc_thread_self; /* For /proc/thread-self */
 	kgid_t pid_gid;
-	int hide_pid;
-	int pidonly;
+	enum proc_hidepid hide_pid;
+	enum proc_pidonly pidonly;
 };
 
 static inline struct proc_fs_info *proc_sb_info(struct super_block *sb)
diff --git a/include/uapi/linux/proc_fs.h b/include/uapi/linux/proc_fs.h
index dc6d717aa6ec..f5fe0e8dcfe4 100644
--- a/include/uapi/linux/proc_fs.h
+++ b/include/uapi/linux/proc_fs.h
@@ -3,7 +3,7 @@
 #define _UAPI_PROC_FS_H
 
 /* definitions for hide_pid field */
-enum {
+enum proc_hidepid {
 	HIDEPID_OFF            = 0,
 	HIDEPID_NO_ACCESS      = 1,
 	HIDEPID_INVISIBLE      = 2,
-- 
2.25.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: [PATCH v10 8/9] proc: use human-readable values for hidehid
  2020-03-27 17:23 ` [PATCH v10 8/9] proc: use human-readable values for hidehid Alexey Gladkov
@ 2020-03-28 20:28   ` Kees Cook
  2020-03-28 21:14     ` Alexey Gladkov
  2020-03-30 11:12   ` [PATCH v11 " Alexey Gladkov
  2020-04-02 16:05   ` [PATCH v10 " Eric W. Biederman
  2 siblings, 1 reply; 33+ messages in thread
From: Kees Cook @ 2020-03-28 20:28 UTC (permalink / raw)
  To: Alexey Gladkov
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, 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, Linus Torvalds,
	Oleg Nesterov

On Fri, Mar 27, 2020 at 06:23:30PM +0100, Alexey Gladkov wrote:
> The hidepid parameter values are becoming more and more and it becomes
> difficult to remember what each new magic number means.
> 
> Suggested-by: Andy Lutomirski <luto@kernel.org>
> Reviewed-by: Alexey Dobriyan <adobriyan@gmail.com>
> Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
> ---
>  Documentation/filesystems/proc.txt | 52 +++++++++++++++---------------
>  fs/proc/inode.c                    | 13 +++++++-
>  fs/proc/root.c                     | 36 +++++++++++++++++++--
>  3 files changed, 71 insertions(+), 30 deletions(-)
> 
> diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
> index bd0e0ab85048..af47672cb2cb 100644
> --- a/Documentation/filesystems/proc.txt
> +++ b/Documentation/filesystems/proc.txt
> @@ -2025,28 +2025,28 @@ The following mount options are supported:
>  	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/<pid>/ directories
> -(default).
> -
> -hidepid=1 means users may not access any /proc/<pid>/ directories but their
> -own.  Sensitive files like cmdline, sched*, status are now protected against
> -other users.  This makes it impossible to learn whether any user runs
> -specific program (given the program doesn't reveal itself by its behaviour).
> -As an additional bonus, as /proc/<pid>/cmdline is unaccessible for other users,
> -poorly written programs passing sensitive information via program arguments are
> -now protected against local eavesdroppers.
> -
> -hidepid=2 means hidepid=1 plus all /proc/<pid>/ will be fully invisible to other
> -users.  It doesn't mean that it hides a fact whether a process with a specific
> -pid value exists (it can be learned by other means, e.g. by "kill -0 $PID"),
> -but it hides process' uid and gid, which may be learned by stat()'ing
> -/proc/<pid>/ otherwise.  It greatly complicates an intruder's task of gathering
> -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/<pid>/ directories
> -that the caller can ptrace.
> +hidepid=off or hidepid=0 means classic mode - everybody may access all
> +/proc/<pid>/ directories (default).
> +
> +hidepid=noaccess or hidepid=1 means users may not access any /proc/<pid>/
> +directories but their own.  Sensitive files like cmdline, sched*, status are now
> +protected against other users.  This makes it impossible to learn whether any
> +user runs specific program (given the program doesn't reveal itself by its
> +behaviour).  As an additional bonus, as /proc/<pid>/cmdline is unaccessible for
> +other users, poorly written programs passing sensitive information via program
> +arguments are now protected against local eavesdroppers.
> +
> +hidepid=invisible or hidepid=2 means hidepid=noaccess plus all /proc/<pid>/ will
> +be fully invisible to other users.  It doesn't mean that it hides a fact whether
> +a process with a specific pid value exists (it can be learned by other means,
> +e.g. by "kill -0 $PID"), but it hides process' uid and gid, which may be learned
> +by stat()'ing /proc/<pid>/ otherwise.  It greatly complicates an intruder's task
> +of gathering 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=ptraceable or hidepid=4 means that procfs should only contain
> +/proc/<pid>/ 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
> @@ -2093,8 +2093,8 @@ 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
> +# mount -o hidepid=invisible -t proc proc /proc
> +# mount -o hidepid=noaccess -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
> +proc /proc proc rw,relatime,hidepid=invisible 0 0
> +proc /tmp/proc proc rw,relatime,hidepid=noaccess 0 0
> diff --git a/fs/proc/inode.c b/fs/proc/inode.c
> index e6577ce6027b..f01fb4bed75c 100644
> --- a/fs/proc/inode.c
> +++ b/fs/proc/inode.c
> @@ -165,6 +165,17 @@ void proc_invalidate_siblings_dcache(struct hlist_head *inodes, spinlock_t *lock
>  		deactivate_super(old_sb);
>  }
>  
> +static inline const char *hidepid2str(int v)
> +{
> +	switch (v) {
> +		case HIDEPID_OFF: return "off";
> +		case HIDEPID_NO_ACCESS: return "noaccess";
> +		case HIDEPID_INVISIBLE: return "invisible";
> +		case HIDEPID_NOT_PTRACEABLE: return "ptraceable";
> +	}
> +	BUG();

Please don't use BUG()[1]. Add a default case with a warn and return
"unknown":

	switch (v) {
	case HIDEPID_OFF: return "off";
	case HIDEPID_NO_ACCESS: return "noaccess";
	case HIDEPID_INVISIBLE: return "invisible";
	case HIDEPID_NOT_PTRACEABLE: return "ptraceable";
	default:
		WARN_ON_ONCE("bad hide_pid value: %d\n", v);
		return "unknown";
	}

[1] https://lore.kernel.org/lkml/202003141524.59C619B51A@keescook/

> +}
> +
>  static int proc_show_options(struct seq_file *seq, struct dentry *root)
>  {
>  	struct proc_fs_info *fs_info = proc_sb_info(root->d_sb);
> @@ -172,7 +183,7 @@ static int proc_show_options(struct seq_file *seq, struct dentry *root)
>  	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);
> +		seq_printf(seq, ",hidepid=%s", hidepid2str(fs_info->hide_pid));
>  	if (fs_info->pidonly != PROC_PIDONLY_OFF)
>  		seq_printf(seq, ",subset=pid");
>  
> diff --git a/fs/proc/root.c b/fs/proc/root.c
> index dbcd96f07c7a..ba782d6e6197 100644
> --- a/fs/proc/root.c
> +++ b/fs/proc/root.c
> @@ -45,7 +45,7 @@ enum proc_param {
>  
>  static const struct fs_parameter_spec proc_fs_parameters[] = {
>  	fsparam_u32("gid",	Opt_gid),
> -	fsparam_u32("hidepid",	Opt_hidepid),
> +	fsparam_string("hidepid",	Opt_hidepid),
>  	fsparam_string("subset",	Opt_subset),
>  	{}
>  };
> @@ -58,6 +58,35 @@ static inline int valid_hidepid(unsigned int value)
>  		value == HIDEPID_NOT_PTRACEABLE);
>  }
>  
> +static int proc_parse_hidepid_param(struct fs_context *fc, struct fs_parameter *param)
> +{
> +	struct proc_fs_context *ctx = fc->fs_private;
> +	struct fs_parameter_spec hidepid_u32_spec = fsparam_u32("hidepid", Opt_hidepid);
> +	struct fs_parse_result result;
> +	int base = (unsigned long)hidepid_u32_spec.data;
> +
> +	if (param->type != fs_value_is_string)
> +		return invalf(fc, "proc: unexpected type of hidepid value\n");
> +
> +	if (!kstrtouint(param->string, base, &result.uint_32)) {
> +		ctx->hidepid = result.uint_32;

This need to bounds-check the value with a call to valid_hidepid(), yes?

> +		return 0;
> +	}
> +
> +	if (!strcmp(param->string, "off"))
> +		ctx->hidepid = HIDEPID_OFF;
> +	else if (!strcmp(param->string, "noaccess"))
> +		ctx->hidepid = HIDEPID_NO_ACCESS;
> +	else if (!strcmp(param->string, "invisible"))
> +		ctx->hidepid = HIDEPID_INVISIBLE;
> +	else if (!strcmp(param->string, "ptraceable"))
> +		ctx->hidepid = HIDEPID_NOT_PTRACEABLE;
> +	else
> +		return invalf(fc, "proc: unknown value of hidepid - %s\n", param->string);
> +
> +	return 0;
> +}
> +
>  static int proc_parse_subset_param(struct fs_context *fc, char *value)
>  {
>  	struct proc_fs_context *ctx = fc->fs_private;
> @@ -97,9 +126,10 @@ static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param)
>  		break;
>  
>  	case Opt_hidepid:
> -		if (!valid_hidepid(result.uint_32))
> +		if (proc_parse_hidepid_param(fc, param))
> +			return -EINVAL;
> +		if (!valid_hidepid(ctx->hidepid))
>  			return invalf(fc, "proc: unknown value of hidepid.\n");
> -		ctx->hidepid = result.uint_32;
>  		break;
>  
>  	case Opt_subset:
> -- 
> 2.25.2
> 

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v10 4/9] proc: instantiate only pids that we can ptrace on 'hidepid=4' mount option
  2020-03-27 17:23 ` [PATCH v10 4/9] proc: instantiate only pids that we can ptrace on 'hidepid=4' mount option Alexey Gladkov
@ 2020-03-28 20:40   ` Kees Cook
  2020-03-28 21:23     ` Alexey Gladkov
  0 siblings, 1 reply; 33+ messages in thread
From: Kees Cook @ 2020-03-28 20:40 UTC (permalink / raw)
  To: Alexey Gladkov
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, 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, Linus Torvalds,
	Oleg Nesterov

On Fri, Mar 27, 2020 at 06:23:26PM +0100, Alexey Gladkov wrote:
> 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 <keescook@chromium.org>
> Cc: Andy Lutomirski <luto@kernel.org>
> Signed-off-by: Djalal Harouni <tixxdz@gmail.com>
> Reviewed-by: Alexey Dobriyan <adobriyan@gmail.com>
> Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
> ---
>  fs/proc/base.c          | 15 +++++++++++++++
>  fs/proc/root.c          | 13 ++++++++++---
>  include/linux/proc_fs.h |  1 +
>  3 files changed, 26 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/proc/base.c b/fs/proc/base.c
> index 43a28907baf9..1ebe9eba48ea 100644
> --- a/fs/proc/base.c
> +++ b/fs/proc/base.c
> @@ -701,6 +701,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 (fs_info->hide_pid == HIDEPID_NOT_PTRACEABLE)
> +		return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
> +
>  	if (fs_info->hide_pid < hide_pid_min)
>  		return true;
>  	if (in_group_p(fs_info->pid_gid))
> @@ -3319,7 +3327,14 @@ struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags)
>  	if (!task)
>  		goto out;
>  
> +	/* Limit procfs to only ptraceable tasks */
> +	if (fs_info->hide_pid == HIDEPID_NOT_PTRACEABLE) {
> +		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 616e8976185c..62eae22403d2 100644
> --- a/fs/proc/root.c
> +++ b/fs/proc/root.c
> @@ -47,6 +47,14 @@ static const struct fs_parameter_spec proc_fs_parameters[] = {
>  	{}
>  };
>  
> +static inline int valid_hidepid(unsigned int value)
> +{
> +	return (value == HIDEPID_OFF ||
> +		value == HIDEPID_NO_ACCESS ||
> +		value == HIDEPID_INVISIBLE ||
> +		value == HIDEPID_NOT_PTRACEABLE);

This likely easier to do with a ...MAX value? i.e.

	return (value < HIDEPID_OFF || value >= HIDEPID_MAX);

> +}
> +
>  static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param)
>  {
>  	struct proc_fs_context *ctx = fc->fs_private;
> @@ -63,10 +71,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 invalfc(fc, "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 7d852dbca253..21d19353fdc7 100644
> --- a/include/linux/proc_fs.h
> +++ b/include/linux/proc_fs.h
> @@ -32,6 +32,7 @@ enum {
>  	HIDEPID_OFF	  = 0,
>  	HIDEPID_NO_ACCESS = 1,
>  	HIDEPID_INVISIBLE = 2,
> +	HIDEPID_NOT_PTRACEABLE = 4, /* Limit pids to only ptraceable pids */

This isn't a bit field -- shouldn't this be "3"?

	...
	HIDEPID_NOT_PTRACEABLE = 3,
	HIDEPID_MAX

etc?

>  };
>  
>  struct proc_fs_info {
> -- 
> 2.25.2
> 

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v10 7/9] proc: move hidepid values to uapi as they are user interface to mount
  2020-03-27 17:23 ` [PATCH v10 7/9] proc: move hidepid values to uapi as they are user interface to mount Alexey Gladkov
@ 2020-03-28 20:41   ` Kees Cook
  2020-03-28 21:25     ` Alexey Gladkov
  2020-04-02 16:58   ` Eric W. Biederman
  1 sibling, 1 reply; 33+ messages in thread
From: Kees Cook @ 2020-03-28 20:41 UTC (permalink / raw)
  To: Alexey Gladkov
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, 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, Linus Torvalds,
	Oleg Nesterov

On Fri, Mar 27, 2020 at 06:23:29PM +0100, Alexey Gladkov wrote:
> Suggested-by: Alexey Dobriyan <adobriyan@gmail.com>
> Reviewed-by: Alexey Dobriyan <adobriyan@gmail.com>
> Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
> ---
>  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 afd38cae2339..d259817ec913 100644
> --- a/include/linux/proc_fs.h
> +++ b/include/linux/proc_fs.h
> @@ -7,6 +7,7 @@
>  
>  #include <linux/types.h>
>  #include <linux/fs.h>
> +#include <uapi/linux/proc_fs.h>
>  
>  struct proc_dir_entry;
>  struct seq_file;
> @@ -27,14 +28,6 @@ struct proc_ops {
>  	unsigned long (*proc_get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
>  };
>  
> -/* definitions for hide_pid field */
> -enum {
> -	HIDEPID_OFF	  = 0,
> -	HIDEPID_NO_ACCESS = 1,
> -	HIDEPID_INVISIBLE = 2,
> -	HIDEPID_NOT_PTRACEABLE = 4, /* Limit pids to only ptraceable 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..dc6d717aa6ec
> --- /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_PTRACEABLE = 4,
> +};
> +
> +#endif
> -- 
> 2.25.2
> 

Should the numeric values still be UAPI if there is string parsing now?

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v10 8/9] proc: use human-readable values for hidehid
  2020-03-28 20:28   ` Kees Cook
@ 2020-03-28 21:14     ` Alexey Gladkov
  2020-03-28 21:52       ` Kees Cook
  0 siblings, 1 reply; 33+ messages in thread
From: Alexey Gladkov @ 2020-03-28 21:14 UTC (permalink / raw)
  To: Kees Cook
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, Akinobu Mita, Alexander Viro,
	Alexey Dobriyan, 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, Linus Torvalds, Oleg Nesterov

On Sat, Mar 28, 2020 at 01:28:28PM -0700, Kees Cook wrote:
> On Fri, Mar 27, 2020 at 06:23:30PM +0100, Alexey Gladkov wrote:
> > The hidepid parameter values are becoming more and more and it becomes
> > difficult to remember what each new magic number means.
> > 
> > Suggested-by: Andy Lutomirski <luto@kernel.org>
> > Reviewed-by: Alexey Dobriyan <adobriyan@gmail.com>
> > Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
> > ---
> >  Documentation/filesystems/proc.txt | 52 +++++++++++++++---------------
> >  fs/proc/inode.c                    | 13 +++++++-
> >  fs/proc/root.c                     | 36 +++++++++++++++++++--
> >  3 files changed, 71 insertions(+), 30 deletions(-)
> > 
> > diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
> > index bd0e0ab85048..af47672cb2cb 100644
> > --- a/Documentation/filesystems/proc.txt
> > +++ b/Documentation/filesystems/proc.txt
> > @@ -2025,28 +2025,28 @@ The following mount options are supported:
> >  	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/<pid>/ directories
> > -(default).
> > -
> > -hidepid=1 means users may not access any /proc/<pid>/ directories but their
> > -own.  Sensitive files like cmdline, sched*, status are now protected against
> > -other users.  This makes it impossible to learn whether any user runs
> > -specific program (given the program doesn't reveal itself by its behaviour).
> > -As an additional bonus, as /proc/<pid>/cmdline is unaccessible for other users,
> > -poorly written programs passing sensitive information via program arguments are
> > -now protected against local eavesdroppers.
> > -
> > -hidepid=2 means hidepid=1 plus all /proc/<pid>/ will be fully invisible to other
> > -users.  It doesn't mean that it hides a fact whether a process with a specific
> > -pid value exists (it can be learned by other means, e.g. by "kill -0 $PID"),
> > -but it hides process' uid and gid, which may be learned by stat()'ing
> > -/proc/<pid>/ otherwise.  It greatly complicates an intruder's task of gathering
> > -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/<pid>/ directories
> > -that the caller can ptrace.
> > +hidepid=off or hidepid=0 means classic mode - everybody may access all
> > +/proc/<pid>/ directories (default).
> > +
> > +hidepid=noaccess or hidepid=1 means users may not access any /proc/<pid>/
> > +directories but their own.  Sensitive files like cmdline, sched*, status are now
> > +protected against other users.  This makes it impossible to learn whether any
> > +user runs specific program (given the program doesn't reveal itself by its
> > +behaviour).  As an additional bonus, as /proc/<pid>/cmdline is unaccessible for
> > +other users, poorly written programs passing sensitive information via program
> > +arguments are now protected against local eavesdroppers.
> > +
> > +hidepid=invisible or hidepid=2 means hidepid=noaccess plus all /proc/<pid>/ will
> > +be fully invisible to other users.  It doesn't mean that it hides a fact whether
> > +a process with a specific pid value exists (it can be learned by other means,
> > +e.g. by "kill -0 $PID"), but it hides process' uid and gid, which may be learned
> > +by stat()'ing /proc/<pid>/ otherwise.  It greatly complicates an intruder's task
> > +of gathering 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=ptraceable or hidepid=4 means that procfs should only contain
> > +/proc/<pid>/ 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
> > @@ -2093,8 +2093,8 @@ 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
> > +# mount -o hidepid=invisible -t proc proc /proc
> > +# mount -o hidepid=noaccess -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
> > +proc /proc proc rw,relatime,hidepid=invisible 0 0
> > +proc /tmp/proc proc rw,relatime,hidepid=noaccess 0 0
> > diff --git a/fs/proc/inode.c b/fs/proc/inode.c
> > index e6577ce6027b..f01fb4bed75c 100644
> > --- a/fs/proc/inode.c
> > +++ b/fs/proc/inode.c
> > @@ -165,6 +165,17 @@ void proc_invalidate_siblings_dcache(struct hlist_head *inodes, spinlock_t *lock
> >  		deactivate_super(old_sb);
> >  }
> >  
> > +static inline const char *hidepid2str(int v)
> > +{
> > +	switch (v) {
> > +		case HIDEPID_OFF: return "off";
> > +		case HIDEPID_NO_ACCESS: return "noaccess";
> > +		case HIDEPID_INVISIBLE: return "invisible";
> > +		case HIDEPID_NOT_PTRACEABLE: return "ptraceable";
> > +	}
> > +	BUG();
> 
> Please don't use BUG()[1]. Add a default case with a warn and return
> "unknown":
> 
> 	switch (v) {
> 	case HIDEPID_OFF: return "off";
> 	case HIDEPID_NO_ACCESS: return "noaccess";
> 	case HIDEPID_INVISIBLE: return "invisible";
> 	case HIDEPID_NOT_PTRACEABLE: return "ptraceable";
> 	default:
> 		WARN_ON_ONCE("bad hide_pid value: %d\n", v);
> 		return "unknown";
> 	}
> 
> [1] https://lore.kernel.org/lkml/202003141524.59C619B51A@keescook/

Make sense. I will change it.

> > +}
> > +
> >  static int proc_show_options(struct seq_file *seq, struct dentry *root)
> >  {
> >  	struct proc_fs_info *fs_info = proc_sb_info(root->d_sb);
> > @@ -172,7 +183,7 @@ static int proc_show_options(struct seq_file *seq, struct dentry *root)
> >  	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);
> > +		seq_printf(seq, ",hidepid=%s", hidepid2str(fs_info->hide_pid));
> >  	if (fs_info->pidonly != PROC_PIDONLY_OFF)
> >  		seq_printf(seq, ",subset=pid");
> >  
> > diff --git a/fs/proc/root.c b/fs/proc/root.c
> > index dbcd96f07c7a..ba782d6e6197 100644
> > --- a/fs/proc/root.c
> > +++ b/fs/proc/root.c
> > @@ -45,7 +45,7 @@ enum proc_param {
> >  
> >  static const struct fs_parameter_spec proc_fs_parameters[] = {
> >  	fsparam_u32("gid",	Opt_gid),
> > -	fsparam_u32("hidepid",	Opt_hidepid),
> > +	fsparam_string("hidepid",	Opt_hidepid),
> >  	fsparam_string("subset",	Opt_subset),
> >  	{}
> >  };
> > @@ -58,6 +58,35 @@ static inline int valid_hidepid(unsigned int value)
> >  		value == HIDEPID_NOT_PTRACEABLE);
> >  }
> >  
> > +static int proc_parse_hidepid_param(struct fs_context *fc, struct fs_parameter *param)
> > +{
> > +	struct proc_fs_context *ctx = fc->fs_private;
> > +	struct fs_parameter_spec hidepid_u32_spec = fsparam_u32("hidepid", Opt_hidepid);
> > +	struct fs_parse_result result;
> > +	int base = (unsigned long)hidepid_u32_spec.data;
> > +
> > +	if (param->type != fs_value_is_string)
> > +		return invalf(fc, "proc: unexpected type of hidepid value\n");
> > +
> > +	if (!kstrtouint(param->string, base, &result.uint_32)) {
> > +		ctx->hidepid = result.uint_32;
> 
> This need to bounds-check the value with a call to valid_hidepid(), yes?

The kstrtouint returns 0 on success and -ERANGE on overflow [1].

[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/lib/kstrtox.c#n217

> > +		return 0;
> > +	}
> > +
> > +	if (!strcmp(param->string, "off"))
> > +		ctx->hidepid = HIDEPID_OFF;
> > +	else if (!strcmp(param->string, "noaccess"))
> > +		ctx->hidepid = HIDEPID_NO_ACCESS;
> > +	else if (!strcmp(param->string, "invisible"))
> > +		ctx->hidepid = HIDEPID_INVISIBLE;
> > +	else if (!strcmp(param->string, "ptraceable"))
> > +		ctx->hidepid = HIDEPID_NOT_PTRACEABLE;
> > +	else
> > +		return invalf(fc, "proc: unknown value of hidepid - %s\n", param->string);
> > +
> > +	return 0;
> > +}
> > +
> >  static int proc_parse_subset_param(struct fs_context *fc, char *value)
> >  {
> >  	struct proc_fs_context *ctx = fc->fs_private;
> > @@ -97,9 +126,10 @@ static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param)
> >  		break;
> >  
> >  	case Opt_hidepid:
> > -		if (!valid_hidepid(result.uint_32))
> > +		if (proc_parse_hidepid_param(fc, param))
> > +			return -EINVAL;
> > +		if (!valid_hidepid(ctx->hidepid))
> >  			return invalf(fc, "proc: unknown value of hidepid.\n");
> > -		ctx->hidepid = result.uint_32;
> >  		break;
> >  
> >  	case Opt_subset:
> > -- 
> > 2.25.2
> > 
> 
> -- 
> Kees Cook
> 

-- 
Rgrds, legion


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v10 4/9] proc: instantiate only pids that we can ptrace on 'hidepid=4' mount option
  2020-03-28 20:40   ` Kees Cook
@ 2020-03-28 21:23     ` Alexey Gladkov
  0 siblings, 0 replies; 33+ messages in thread
From: Alexey Gladkov @ 2020-03-28 21:23 UTC (permalink / raw)
  To: Kees Cook
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, Akinobu Mita, Alexander Viro,
	Alexey Dobriyan, 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, Linus Torvalds, Oleg Nesterov

On Sat, Mar 28, 2020 at 01:40:03PM -0700, Kees Cook wrote:
> On Fri, Mar 27, 2020 at 06:23:26PM +0100, Alexey Gladkov wrote:
> > 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 <keescook@chromium.org>
> > Cc: Andy Lutomirski <luto@kernel.org>
> > Signed-off-by: Djalal Harouni <tixxdz@gmail.com>
> > Reviewed-by: Alexey Dobriyan <adobriyan@gmail.com>
> > Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
> > ---
> >  fs/proc/base.c          | 15 +++++++++++++++
> >  fs/proc/root.c          | 13 ++++++++++---
> >  include/linux/proc_fs.h |  1 +
> >  3 files changed, 26 insertions(+), 3 deletions(-)
> > 
> > diff --git a/fs/proc/base.c b/fs/proc/base.c
> > index 43a28907baf9..1ebe9eba48ea 100644
> > --- a/fs/proc/base.c
> > +++ b/fs/proc/base.c
> > @@ -701,6 +701,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 (fs_info->hide_pid == HIDEPID_NOT_PTRACEABLE)
> > +		return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
> > +
> >  	if (fs_info->hide_pid < hide_pid_min)
> >  		return true;
> >  	if (in_group_p(fs_info->pid_gid))
> > @@ -3319,7 +3327,14 @@ struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags)
> >  	if (!task)
> >  		goto out;
> >  
> > +	/* Limit procfs to only ptraceable tasks */
> > +	if (fs_info->hide_pid == HIDEPID_NOT_PTRACEABLE) {
> > +		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 616e8976185c..62eae22403d2 100644
> > --- a/fs/proc/root.c
> > +++ b/fs/proc/root.c
> > @@ -47,6 +47,14 @@ static const struct fs_parameter_spec proc_fs_parameters[] = {
> >  	{}
> >  };
> >  
> > +static inline int valid_hidepid(unsigned int value)
> > +{
> > +	return (value == HIDEPID_OFF ||
> > +		value == HIDEPID_NO_ACCESS ||
> > +		value == HIDEPID_INVISIBLE ||
> > +		value == HIDEPID_NOT_PTRACEABLE);
> 
> This likely easier to do with a ...MAX value? i.e.
> 
> 	return (value < HIDEPID_OFF || value >= HIDEPID_MAX);
> 
> > +}
> > +
> >  static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param)
> >  {
> >  	struct proc_fs_context *ctx = fc->fs_private;
> > @@ -63,10 +71,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 invalfc(fc, "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 7d852dbca253..21d19353fdc7 100644
> > --- a/include/linux/proc_fs.h
> > +++ b/include/linux/proc_fs.h
> > @@ -32,6 +32,7 @@ enum {
> >  	HIDEPID_OFF	  = 0,
> >  	HIDEPID_NO_ACCESS = 1,
> >  	HIDEPID_INVISIBLE = 2,
> > +	HIDEPID_NOT_PTRACEABLE = 4, /* Limit pids to only ptraceable pids */
> 
> This isn't a bit field -- shouldn't this be "3"?
> 
> 	...
> 	HIDEPID_NOT_PTRACEABLE = 3,
> 	HIDEPID_MAX
> 
> etc?

I decided to choose 4 so that if later we need to be able to make a mask.
I am not sure that this parameter will not have values that cannot be used
together. Since now these parameters are becoming part of the public api,
I decided to add flexibility.

-- 
Rgrds, legion


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v10 7/9] proc: move hidepid values to uapi as they are user interface to mount
  2020-03-28 20:41   ` Kees Cook
@ 2020-03-28 21:25     ` Alexey Gladkov
  2020-03-28 21:53       ` Kees Cook
  0 siblings, 1 reply; 33+ messages in thread
From: Alexey Gladkov @ 2020-03-28 21:25 UTC (permalink / raw)
  To: Kees Cook
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, Akinobu Mita, Alexander Viro,
	Alexey Dobriyan, 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, Linus Torvalds, Oleg Nesterov

On Sat, Mar 28, 2020 at 01:41:02PM -0700, Kees Cook wrote:
 > diff --git a/include/uapi/linux/proc_fs.h b/include/uapi/linux/proc_fs.h
> > new file mode 100644
> > index 000000000000..dc6d717aa6ec
> > --- /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_PTRACEABLE = 4,
> > +};
> > +
> > +#endif
> > -- 
> > 2.25.2
> > 
> 
> Should the numeric values still be UAPI if there is string parsing now?

I think yes, because these are still valid hidepid= values.

-- 
Rgrds, legion


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v10 8/9] proc: use human-readable values for hidehid
  2020-03-28 21:14     ` Alexey Gladkov
@ 2020-03-28 21:52       ` Kees Cook
  2020-03-28 22:54         ` Alexey Gladkov
  0 siblings, 1 reply; 33+ messages in thread
From: Kees Cook @ 2020-03-28 21:52 UTC (permalink / raw)
  To: Alexey Gladkov
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, Akinobu Mita, Alexander Viro,
	Alexey Dobriyan, 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, Linus Torvalds, Oleg Nesterov

On Sat, Mar 28, 2020 at 10:14:53PM +0100, Alexey Gladkov wrote:
> On Sat, Mar 28, 2020 at 01:28:28PM -0700, Kees Cook wrote:
> > On Fri, Mar 27, 2020 at 06:23:30PM +0100, Alexey Gladkov wrote:
> > > [...]
> > > +	if (!kstrtouint(param->string, base, &result.uint_32)) {
> > > +		ctx->hidepid = result.uint_32;
> > 
> > This need to bounds-check the value with a call to valid_hidepid(), yes?
> 
> The kstrtouint returns 0 on success and -ERANGE on overflow [1].

No, I mean, hidepid cannot be just any uint32 value. It must be in the
enum. Is that checked somewhere else? It looked like the call to
valid_hidepid() was removed.

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v10 7/9] proc: move hidepid values to uapi as they are user interface to mount
  2020-03-28 21:25     ` Alexey Gladkov
@ 2020-03-28 21:53       ` Kees Cook
  2020-03-28 23:00         ` Alexey Gladkov
  0 siblings, 1 reply; 33+ messages in thread
From: Kees Cook @ 2020-03-28 21:53 UTC (permalink / raw)
  To: Alexey Gladkov
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, Akinobu Mita, Alexander Viro,
	Alexey Dobriyan, 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, Linus Torvalds, Oleg Nesterov

On Sat, Mar 28, 2020 at 10:25:47PM +0100, Alexey Gladkov wrote:
> On Sat, Mar 28, 2020 at 01:41:02PM -0700, Kees Cook wrote:
>  > diff --git a/include/uapi/linux/proc_fs.h b/include/uapi/linux/proc_fs.h
> > > new file mode 100644
> > > index 000000000000..dc6d717aa6ec
> > > --- /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_PTRACEABLE = 4,
> > > +};
> > > +
> > > +#endif
> > > -- 
> > > 2.25.2
> > > 
> > 
> > Should the numeric values still be UAPI if there is string parsing now?
> 
> I think yes, because these are still valid hidepid= values.

But if we don't expose the values, we can do whatever we like with
future numbers (e.g. the "is this a value or a bit field?" question).

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v10 8/9] proc: use human-readable values for hidehid
  2020-03-28 21:52       ` Kees Cook
@ 2020-03-28 22:54         ` Alexey Gladkov
  0 siblings, 0 replies; 33+ messages in thread
From: Alexey Gladkov @ 2020-03-28 22:54 UTC (permalink / raw)
  To: Kees Cook
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, Akinobu Mita, Alexander Viro,
	Alexey Dobriyan, 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, Linus Torvalds, Oleg Nesterov

On Sat, Mar 28, 2020 at 02:52:55PM -0700, Kees Cook wrote:
> On Sat, Mar 28, 2020 at 10:14:53PM +0100, Alexey Gladkov wrote:
> > On Sat, Mar 28, 2020 at 01:28:28PM -0700, Kees Cook wrote:
> > > On Fri, Mar 27, 2020 at 06:23:30PM +0100, Alexey Gladkov wrote:
> > > > [...]
> > > > +	if (!kstrtouint(param->string, base, &result.uint_32)) {
> > > > +		ctx->hidepid = result.uint_32;
> > > 
> > > This need to bounds-check the value with a call to valid_hidepid(), yes?
> > 
> > The kstrtouint returns 0 on success and -ERANGE on overflow [1].
> 
> No, I mean, hidepid cannot be just any uint32 value. It must be in the
> enum. Is that checked somewhere else? It looked like the call to
> valid_hidepid() was removed.

The valid_hidepid() is called after parsing the hidepid parameter value.
Yes, it can be called inside this condition.

-- 
Rgrds, legion


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v10 7/9] proc: move hidepid values to uapi as they are user interface to mount
  2020-03-28 21:53       ` Kees Cook
@ 2020-03-28 23:00         ` Alexey Gladkov
  2020-03-29  3:17           ` Kees Cook
  0 siblings, 1 reply; 33+ messages in thread
From: Alexey Gladkov @ 2020-03-28 23:00 UTC (permalink / raw)
  To: Kees Cook
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, Akinobu Mita, Alexander Viro,
	Alexey Dobriyan, 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, Linus Torvalds, Oleg Nesterov

On Sat, Mar 28, 2020 at 02:53:49PM -0700, Kees Cook wrote:
> > > > +/* definitions for hide_pid field */
> > > > +enum {
> > > > +	HIDEPID_OFF            = 0,
> > > > +	HIDEPID_NO_ACCESS      = 1,
> > > > +	HIDEPID_INVISIBLE      = 2,
> > > > +	HIDEPID_NOT_PTRACEABLE = 4,
> > > > +};
> > > Should the numeric values still be UAPI if there is string parsing now?
> > 
> > I think yes, because these are still valid hidepid= values.
> 
> But if we don't expose the values, we can do whatever we like with
> future numbers (e.g. the "is this a value or a bit field?" question).

Alexey Dobriyan suggested to put these parameters into the UAPI and it
makes sense because these are user parameters.

-- 
Rgrds, legion


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v10 7/9] proc: move hidepid values to uapi as they are user interface to mount
  2020-03-28 23:00         ` Alexey Gladkov
@ 2020-03-29  3:17           ` Kees Cook
  0 siblings, 0 replies; 33+ messages in thread
From: Kees Cook @ 2020-03-29  3:17 UTC (permalink / raw)
  To: Alexey Gladkov
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, Akinobu Mita, Alexander Viro,
	Alexey Dobriyan, 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, Linus Torvalds, Oleg Nesterov

On Sun, Mar 29, 2020 at 12:00:46AM +0100, Alexey Gladkov wrote:
> On Sat, Mar 28, 2020 at 02:53:49PM -0700, Kees Cook wrote:
> > > > > +/* definitions for hide_pid field */
> > > > > +enum {
> > > > > +	HIDEPID_OFF            = 0,
> > > > > +	HIDEPID_NO_ACCESS      = 1,
> > > > > +	HIDEPID_INVISIBLE      = 2,
> > > > > +	HIDEPID_NOT_PTRACEABLE = 4,
> > > > > +};
> > > > Should the numeric values still be UAPI if there is string parsing now?
> > > 
> > > I think yes, because these are still valid hidepid= values.
> > 
> > But if we don't expose the values, we can do whatever we like with
> > future numbers (e.g. the "is this a value or a bit field?" question).
> 
> Alexey Dobriyan suggested to put these parameters into the UAPI and it
> makes sense because these are user parameters.

Okidokey. :) Anyway, ignore my HIDEPID_MAX idea then, since this could
become a bitfield. Just checking for individual bits is the way to go
for now. Sorry for the noise.

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v11 8/9] proc: use human-readable values for hidehid
  2020-03-27 17:23 ` [PATCH v10 8/9] proc: use human-readable values for hidehid Alexey Gladkov
  2020-03-28 20:28   ` Kees Cook
@ 2020-03-30 11:12   ` Alexey Gladkov
  2020-03-30 18:33     ` Kees Cook
  2020-04-02 16:11     ` Jann Horn
  2020-04-02 16:05   ` [PATCH v10 " Eric W. Biederman
  2 siblings, 2 replies; 33+ messages in thread
From: Alexey Gladkov @ 2020-03-30 11:12 UTC (permalink / raw)
  To: LKML
  Cc: Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, 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

The hidepid parameter values are becoming more and more and it becomes
difficult to remember what each new magic number means.

Suggested-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 Documentation/filesystems/proc.txt | 52 +++++++++++++++---------------
 fs/proc/inode.c                    | 15 ++++++++-
 fs/proc/root.c                     | 36 +++++++++++++++++++--
 3 files changed, 73 insertions(+), 30 deletions(-)

diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index bd0e0ab85048..af47672cb2cb 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -2025,28 +2025,28 @@ The following mount options are supported:
 	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/<pid>/ directories
-(default).
-
-hidepid=1 means users may not access any /proc/<pid>/ directories but their
-own.  Sensitive files like cmdline, sched*, status are now protected against
-other users.  This makes it impossible to learn whether any user runs
-specific program (given the program doesn't reveal itself by its behaviour).
-As an additional bonus, as /proc/<pid>/cmdline is unaccessible for other users,
-poorly written programs passing sensitive information via program arguments are
-now protected against local eavesdroppers.
-
-hidepid=2 means hidepid=1 plus all /proc/<pid>/ will be fully invisible to other
-users.  It doesn't mean that it hides a fact whether a process with a specific
-pid value exists (it can be learned by other means, e.g. by "kill -0 $PID"),
-but it hides process' uid and gid, which may be learned by stat()'ing
-/proc/<pid>/ otherwise.  It greatly complicates an intruder's task of gathering
-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/<pid>/ directories
-that the caller can ptrace.
+hidepid=off or hidepid=0 means classic mode - everybody may access all
+/proc/<pid>/ directories (default).
+
+hidepid=noaccess or hidepid=1 means users may not access any /proc/<pid>/
+directories but their own.  Sensitive files like cmdline, sched*, status are now
+protected against other users.  This makes it impossible to learn whether any
+user runs specific program (given the program doesn't reveal itself by its
+behaviour).  As an additional bonus, as /proc/<pid>/cmdline is unaccessible for
+other users, poorly written programs passing sensitive information via program
+arguments are now protected against local eavesdroppers.
+
+hidepid=invisible or hidepid=2 means hidepid=noaccess plus all /proc/<pid>/ will
+be fully invisible to other users.  It doesn't mean that it hides a fact whether
+a process with a specific pid value exists (it can be learned by other means,
+e.g. by "kill -0 $PID"), but it hides process' uid and gid, which may be learned
+by stat()'ing /proc/<pid>/ otherwise.  It greatly complicates an intruder's task
+of gathering 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=ptraceable or hidepid=4 means that procfs should only contain
+/proc/<pid>/ 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
@@ -2093,8 +2093,8 @@ 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
+# mount -o hidepid=invisible -t proc proc /proc
+# mount -o hidepid=noaccess -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
+proc /proc proc rw,relatime,hidepid=invisible 0 0
+proc /tmp/proc proc rw,relatime,hidepid=noaccess 0 0
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index e6577ce6027b..d38a9e592352 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -24,6 +24,7 @@
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/mount.h>
+#include <linux/bug.h>
 
 #include <linux/uaccess.h>
 
@@ -165,6 +166,18 @@ void proc_invalidate_siblings_dcache(struct hlist_head *inodes, spinlock_t *lock
 		deactivate_super(old_sb);
 }
 
+static inline const char *hidepid2str(int v)
+{
+	switch (v) {
+		case HIDEPID_OFF: return "off";
+		case HIDEPID_NO_ACCESS: return "noaccess";
+		case HIDEPID_INVISIBLE: return "invisible";
+		case HIDEPID_NOT_PTRACEABLE: return "ptraceable";
+	}
+	WARN_ONCE(1, "bad hide_pid value: %d\n", v);
+	return "unknown";
+}
+
 static int proc_show_options(struct seq_file *seq, struct dentry *root)
 {
 	struct proc_fs_info *fs_info = proc_sb_info(root->d_sb);
@@ -172,7 +185,7 @@ static int proc_show_options(struct seq_file *seq, struct dentry *root)
 	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);
+		seq_printf(seq, ",hidepid=%s", hidepid2str(fs_info->hide_pid));
 	if (fs_info->pidonly != PROC_PIDONLY_OFF)
 		seq_printf(seq, ",subset=pid");
 
diff --git a/fs/proc/root.c b/fs/proc/root.c
index dbcd96f07c7a..ba782d6e6197 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -45,7 +45,7 @@ enum proc_param {
 
 static const struct fs_parameter_spec proc_fs_parameters[] = {
 	fsparam_u32("gid",	Opt_gid),
-	fsparam_u32("hidepid",	Opt_hidepid),
+	fsparam_string("hidepid",	Opt_hidepid),
 	fsparam_string("subset",	Opt_subset),
 	{}
 };
@@ -58,6 +58,35 @@ static inline int valid_hidepid(unsigned int value)
 		value == HIDEPID_NOT_PTRACEABLE);
 }
 
+static int proc_parse_hidepid_param(struct fs_context *fc, struct fs_parameter *param)
+{
+	struct proc_fs_context *ctx = fc->fs_private;
+	struct fs_parameter_spec hidepid_u32_spec = fsparam_u32("hidepid", Opt_hidepid);
+	struct fs_parse_result result;
+	int base = (unsigned long)hidepid_u32_spec.data;
+
+	if (param->type != fs_value_is_string)
+		return invalf(fc, "proc: unexpected type of hidepid value\n");
+
+	if (!kstrtouint(param->string, base, &result.uint_32)) {
+		ctx->hidepid = result.uint_32;
+		return 0;
+	}
+
+	if (!strcmp(param->string, "off"))
+		ctx->hidepid = HIDEPID_OFF;
+	else if (!strcmp(param->string, "noaccess"))
+		ctx->hidepid = HIDEPID_NO_ACCESS;
+	else if (!strcmp(param->string, "invisible"))
+		ctx->hidepid = HIDEPID_INVISIBLE;
+	else if (!strcmp(param->string, "ptraceable"))
+		ctx->hidepid = HIDEPID_NOT_PTRACEABLE;
+	else
+		return invalf(fc, "proc: unknown value of hidepid - %s\n", param->string);
+
+	return 0;
+}
+
 static int proc_parse_subset_param(struct fs_context *fc, char *value)
 {
 	struct proc_fs_context *ctx = fc->fs_private;
@@ -97,9 +126,10 @@ static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param)
 		break;
 
 	case Opt_hidepid:
-		if (!valid_hidepid(result.uint_32))
+		if (proc_parse_hidepid_param(fc, param))
+			return -EINVAL;
+		if (!valid_hidepid(ctx->hidepid))
 			return invalf(fc, "proc: unknown value of hidepid.\n");
-		ctx->hidepid = result.uint_32;
 		break;
 
 	case Opt_subset:
-- 
2.25.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: [PATCH v11 8/9] proc: use human-readable values for hidehid
  2020-03-30 11:12   ` [PATCH v11 " Alexey Gladkov
@ 2020-03-30 18:33     ` Kees Cook
  2020-04-02 16:11     ` Jann Horn
  1 sibling, 0 replies; 33+ messages in thread
From: Kees Cook @ 2020-03-30 18:33 UTC (permalink / raw)
  To: Alexey Gladkov
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, 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, Linus Torvalds,
	Oleg Nesterov

On Mon, Mar 30, 2020 at 01:12:35PM +0200, Alexey Gladkov wrote:
> The hidepid parameter values are becoming more and more and it becomes
> difficult to remember what each new magic number means.
> 
> Suggested-by: Andy Lutomirski <luto@kernel.org>
> Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
> ---
>  Documentation/filesystems/proc.txt | 52 +++++++++++++++---------------
>  fs/proc/inode.c                    | 15 ++++++++-
>  fs/proc/root.c                     | 36 +++++++++++++++++++--
>  3 files changed, 73 insertions(+), 30 deletions(-)
> 
> diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
> index bd0e0ab85048..af47672cb2cb 100644
> --- a/Documentation/filesystems/proc.txt
> +++ b/Documentation/filesystems/proc.txt
> @@ -2025,28 +2025,28 @@ The following mount options are supported:
>  	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/<pid>/ directories
> -(default).
> -
> -hidepid=1 means users may not access any /proc/<pid>/ directories but their
> -own.  Sensitive files like cmdline, sched*, status are now protected against
> -other users.  This makes it impossible to learn whether any user runs
> -specific program (given the program doesn't reveal itself by its behaviour).
> -As an additional bonus, as /proc/<pid>/cmdline is unaccessible for other users,
> -poorly written programs passing sensitive information via program arguments are
> -now protected against local eavesdroppers.
> -
> -hidepid=2 means hidepid=1 plus all /proc/<pid>/ will be fully invisible to other
> -users.  It doesn't mean that it hides a fact whether a process with a specific
> -pid value exists (it can be learned by other means, e.g. by "kill -0 $PID"),
> -but it hides process' uid and gid, which may be learned by stat()'ing
> -/proc/<pid>/ otherwise.  It greatly complicates an intruder's task of gathering
> -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/<pid>/ directories
> -that the caller can ptrace.
> +hidepid=off or hidepid=0 means classic mode - everybody may access all
> +/proc/<pid>/ directories (default).
> +
> +hidepid=noaccess or hidepid=1 means users may not access any /proc/<pid>/
> +directories but their own.  Sensitive files like cmdline, sched*, status are now
> +protected against other users.  This makes it impossible to learn whether any
> +user runs specific program (given the program doesn't reveal itself by its
> +behaviour).  As an additional bonus, as /proc/<pid>/cmdline is unaccessible for
> +other users, poorly written programs passing sensitive information via program
> +arguments are now protected against local eavesdroppers.
> +
> +hidepid=invisible or hidepid=2 means hidepid=noaccess plus all /proc/<pid>/ will
> +be fully invisible to other users.  It doesn't mean that it hides a fact whether
> +a process with a specific pid value exists (it can be learned by other means,
> +e.g. by "kill -0 $PID"), but it hides process' uid and gid, which may be learned
> +by stat()'ing /proc/<pid>/ otherwise.  It greatly complicates an intruder's task
> +of gathering 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=ptraceable or hidepid=4 means that procfs should only contain
> +/proc/<pid>/ 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
> @@ -2093,8 +2093,8 @@ 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
> +# mount -o hidepid=invisible -t proc proc /proc
> +# mount -o hidepid=noaccess -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
> +proc /proc proc rw,relatime,hidepid=invisible 0 0
> +proc /tmp/proc proc rw,relatime,hidepid=noaccess 0 0
> diff --git a/fs/proc/inode.c b/fs/proc/inode.c
> index e6577ce6027b..d38a9e592352 100644
> --- a/fs/proc/inode.c
> +++ b/fs/proc/inode.c
> @@ -24,6 +24,7 @@
>  #include <linux/seq_file.h>
>  #include <linux/slab.h>
>  #include <linux/mount.h>
> +#include <linux/bug.h>
>  
>  #include <linux/uaccess.h>
>  
> @@ -165,6 +166,18 @@ void proc_invalidate_siblings_dcache(struct hlist_head *inodes, spinlock_t *lock
>  		deactivate_super(old_sb);
>  }
>  
> +static inline const char *hidepid2str(int v)
> +{
> +	switch (v) {
> +		case HIDEPID_OFF: return "off";
> +		case HIDEPID_NO_ACCESS: return "noaccess";
> +		case HIDEPID_INVISIBLE: return "invisible";
> +		case HIDEPID_NOT_PTRACEABLE: return "ptraceable";
> +	}
> +	WARN_ONCE(1, "bad hide_pid value: %d\n", v);
> +	return "unknown";
> +}
> +
>  static int proc_show_options(struct seq_file *seq, struct dentry *root)
>  {
>  	struct proc_fs_info *fs_info = proc_sb_info(root->d_sb);
> @@ -172,7 +185,7 @@ static int proc_show_options(struct seq_file *seq, struct dentry *root)
>  	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);
> +		seq_printf(seq, ",hidepid=%s", hidepid2str(fs_info->hide_pid));
>  	if (fs_info->pidonly != PROC_PIDONLY_OFF)
>  		seq_printf(seq, ",subset=pid");
>  
> diff --git a/fs/proc/root.c b/fs/proc/root.c
> index dbcd96f07c7a..ba782d6e6197 100644
> --- a/fs/proc/root.c
> +++ b/fs/proc/root.c
> @@ -45,7 +45,7 @@ enum proc_param {
>  
>  static const struct fs_parameter_spec proc_fs_parameters[] = {
>  	fsparam_u32("gid",	Opt_gid),
> -	fsparam_u32("hidepid",	Opt_hidepid),
> +	fsparam_string("hidepid",	Opt_hidepid),
>  	fsparam_string("subset",	Opt_subset),
>  	{}
>  };
> @@ -58,6 +58,35 @@ static inline int valid_hidepid(unsigned int value)
>  		value == HIDEPID_NOT_PTRACEABLE);
>  }
>  
> +static int proc_parse_hidepid_param(struct fs_context *fc, struct fs_parameter *param)
> +{
> +	struct proc_fs_context *ctx = fc->fs_private;
> +	struct fs_parameter_spec hidepid_u32_spec = fsparam_u32("hidepid", Opt_hidepid);
> +	struct fs_parse_result result;
> +	int base = (unsigned long)hidepid_u32_spec.data;
> +
> +	if (param->type != fs_value_is_string)
> +		return invalf(fc, "proc: unexpected type of hidepid value\n");
> +
> +	if (!kstrtouint(param->string, base, &result.uint_32)) {
> +		ctx->hidepid = result.uint_32;

If it were me, I'd put this valid_hidepid() test inside here, then the
parsing really is entirely done by this function. Otherwise, the
validation is spread into proc_parse_param() which seems weird.

But either way:

Reviewed-by: Kees Cook <keescook@chromium.org>

-Kees

> +		return 0;
> +	}
> +
> +	if (!strcmp(param->string, "off"))
> +		ctx->hidepid = HIDEPID_OFF;
> +	else if (!strcmp(param->string, "noaccess"))
> +		ctx->hidepid = HIDEPID_NO_ACCESS;
> +	else if (!strcmp(param->string, "invisible"))
> +		ctx->hidepid = HIDEPID_INVISIBLE;
> +	else if (!strcmp(param->string, "ptraceable"))
> +		ctx->hidepid = HIDEPID_NOT_PTRACEABLE;
> +	else
> +		return invalf(fc, "proc: unknown value of hidepid - %s\n", param->string);
> +
> +	return 0;
> +}
> +
>  static int proc_parse_subset_param(struct fs_context *fc, char *value)
>  {
>  	struct proc_fs_context *ctx = fc->fs_private;
> @@ -97,9 +126,10 @@ static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param)
>  		break;
>  
>  	case Opt_hidepid:
> -		if (!valid_hidepid(result.uint_32))
> +		if (proc_parse_hidepid_param(fc, param))
> +			return -EINVAL;
> +		if (!valid_hidepid(ctx->hidepid))
>  			return invalf(fc, "proc: unknown value of hidepid.\n");
> -		ctx->hidepid = result.uint_32;
>  		break;
>  
>  	case Opt_subset:
> -- 
> 2.25.2
> 

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v10 2/9] proc: allow to mount many instances of proc in one pid namespace
  2020-03-27 17:23 ` [PATCH v10 2/9] proc: allow to mount many instances of proc in one pid namespace Alexey Gladkov
@ 2020-04-02 15:31   ` Eric W. Biederman
  2020-04-02 16:32     ` Alexey Gladkov
  0 siblings, 1 reply; 33+ messages in thread
From: Eric W. Biederman @ 2020-04-02 15:31 UTC (permalink / raw)
  To: Alexey Gladkov
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, Akinobu Mita, Alexander Viro,
	Alexey Dobriyan, Alexey Gladkov, Andrew Morton, Andy Lutomirski,
	Daniel Micay, Djalal Harouni, Dmitry V . Levin,
	Greg Kroah-Hartman, Ingo Molnar, J . Bruce Fields, Jeff Layton,
	Jonathan Corbet, Kees Cook, Linus Torvalds, Oleg Nesterov


> diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
> index 40a7982b7285..5920a4ecd71b 100644
> --- a/include/linux/proc_fs.h
> +++ b/include/linux/proc_fs.h
> @@ -27,6 +27,17 @@ struct proc_ops {
>  	unsigned long (*proc_get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
>  };
>  
> +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 */
> +};

Minor nit.

I have not seen a patch where you remove proc_self and proc_thread_self
from struct pid_namepace.

Ideally it would have been in this patch.  But as it won't break
anyone's bisection can you please have a follow up patch that removes
those fields?

Thank you,
Eric



> +
> +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);
> @@ -161,6 +172,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 proc_sb_info(inode->i_sb)->pid_ns;
>  	return inode->i_sb->s_fs_info;
>  }

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v10 8/9] proc: use human-readable values for hidehid
  2020-03-27 17:23 ` [PATCH v10 8/9] proc: use human-readable values for hidehid Alexey Gladkov
  2020-03-28 20:28   ` Kees Cook
  2020-03-30 11:12   ` [PATCH v11 " Alexey Gladkov
@ 2020-04-02 16:05   ` Eric W. Biederman
  2020-04-02 16:51     ` Alexey Gladkov
  2020-04-09 14:32     ` Alexey Gladkov
  2 siblings, 2 replies; 33+ messages in thread
From: Eric W. Biederman @ 2020-04-02 16:05 UTC (permalink / raw)
  To: Alexey Gladkov
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, Akinobu Mita, Alexander Viro,
	Alexey Dobriyan, Alexey Gladkov, Andrew Morton, Andy Lutomirski,
	Daniel Micay, Djalal Harouni, Dmitry V . Levin,
	Greg Kroah-Hartman, Ingo Molnar, J . Bruce Fields, Jeff Layton,
	Jonathan Corbet, Kees Cook, Linus Torvalds, Oleg Nesterov,
	David Howells

Alexey Gladkov <gladkov.alexey@gmail.com> writes:

> The hidepid parameter values are becoming more and more and it becomes
> difficult to remember what each new magic number means.

In principle I like this change.  In practice I think you have just
broken ABI compatiblity with the new mount ABI.

In particular the following line seems broken.

> diff --git a/fs/proc/root.c b/fs/proc/root.c
> index dbcd96f07c7a..ba782d6e6197 100644
> --- a/fs/proc/root.c
> +++ b/fs/proc/root.c
> @@ -45,7 +45,7 @@ enum proc_param {
>  
>  static const struct fs_parameter_spec proc_fs_parameters[] = {
>  	fsparam_u32("gid",	Opt_gid),
> -	fsparam_u32("hidepid",	Opt_hidepid),
> +	fsparam_string("hidepid",	Opt_hidepid),
>  	fsparam_string("subset",	Opt_subset),
>  	{}
>  };

As I read fs_parser.c fs_param_is_u32 handles string inputs and turns them
into numbers, and it handles binary numbers.  However fs_param_is_string
appears to only handle strings.  It appears to have not capacity to turn
raw binary numbers into strings.

So I think we probably need to fix fs_param_is_string to raw binary
numbers before we can safely make this change to fs/proc/root.c

David am I reading the fs_parser.c code correctly?  If I am are you ok
with a change like the above?

Eric

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v11 8/9] proc: use human-readable values for hidehid
  2020-03-30 11:12   ` [PATCH v11 " Alexey Gladkov
  2020-03-30 18:33     ` Kees Cook
@ 2020-04-02 16:11     ` Jann Horn
  1 sibling, 0 replies; 33+ messages in thread
From: Jann Horn @ 2020-04-02 16:11 UTC (permalink / raw)
  To: Alexey Gladkov
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, 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

On Mon, Mar 30, 2020 at 1:13 PM Alexey Gladkov <gladkov.alexey@gmail.com> wrote:
> The hidepid parameter values are becoming more and more and it becomes
> difficult to remember what each new magic number means.

nit: subject line says "hidehid"

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v10 2/9] proc: allow to mount many instances of proc in one pid namespace
  2020-04-02 15:31   ` Eric W. Biederman
@ 2020-04-02 16:32     ` Alexey Gladkov
  0 siblings, 0 replies; 33+ messages in thread
From: Alexey Gladkov @ 2020-04-02 16:32 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, Akinobu Mita, Alexander Viro,
	Alexey Dobriyan, Andrew Morton, Andy Lutomirski, Daniel Micay,
	Djalal Harouni, Dmitry V . Levin, Greg Kroah-Hartman,
	Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
	Kees Cook, Linus Torvalds, Oleg Nesterov

On Thu, Apr 02, 2020 at 10:31:48AM -0500, Eric W. Biederman wrote:
> 
> > diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
> > index 40a7982b7285..5920a4ecd71b 100644
> > --- a/include/linux/proc_fs.h
> > +++ b/include/linux/proc_fs.h
> > @@ -27,6 +27,17 @@ struct proc_ops {
> >  	unsigned long (*proc_get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
> >  };
> >  
> > +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 */
> > +};
> 
> Minor nit.
> 
> I have not seen a patch where you remove proc_self and proc_thread_self
> from struct pid_namepace.
> 
> Ideally it would have been in this patch.  But as it won't break
> anyone's bisection can you please have a follow up patch that removes
> those fields?

Yep. I miss that. I will make v11 to address this and other nits.

-- 
Rgrds, legion


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v10 8/9] proc: use human-readable values for hidehid
  2020-04-02 16:05   ` [PATCH v10 " Eric W. Biederman
@ 2020-04-02 16:51     ` Alexey Gladkov
  2020-04-02 17:04       ` Eric W. Biederman
  2020-04-09 14:32     ` Alexey Gladkov
  1 sibling, 1 reply; 33+ messages in thread
From: Alexey Gladkov @ 2020-04-02 16:51 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, Akinobu Mita, Alexander Viro,
	Alexey Dobriyan, Andrew Morton, Andy Lutomirski, Daniel Micay,
	Djalal Harouni, Dmitry V . Levin, Greg Kroah-Hartman,
	Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
	Kees Cook, Linus Torvalds, Oleg Nesterov, David Howells

On Thu, Apr 02, 2020 at 11:05:21AM -0500, Eric W. Biederman wrote:
> Alexey Gladkov <gladkov.alexey@gmail.com> writes:
> 
> > The hidepid parameter values are becoming more and more and it becomes
> > difficult to remember what each new magic number means.
> 
> In principle I like this change.  In practice I think you have just
> broken ABI compatiblity with the new mount ABI.
> 
> In particular the following line seems broken.
> 
> > diff --git a/fs/proc/root.c b/fs/proc/root.c
> > index dbcd96f07c7a..ba782d6e6197 100644
> > --- a/fs/proc/root.c
> > +++ b/fs/proc/root.c
> > @@ -45,7 +45,7 @@ enum proc_param {
> >  
> >  static const struct fs_parameter_spec proc_fs_parameters[] = {
> >  	fsparam_u32("gid",	Opt_gid),
> > -	fsparam_u32("hidepid",	Opt_hidepid),
> > +	fsparam_string("hidepid",	Opt_hidepid),
> >  	fsparam_string("subset",	Opt_subset),
> >  	{}
> >  };
> 
> As I read fs_parser.c fs_param_is_u32 handles string inputs and turns them
> into numbers, and it handles binary numbers.  However fs_param_is_string
> appears to only handle strings.  It appears to have not capacity to turn
> raw binary numbers into strings.

I use result only with hidepid_u32_spec and nobody modifies param->string.
I do not use internal functions here.

I don’t follow how a raw number can get here ?

> So I think we probably need to fix fs_param_is_string to raw binary
> numbers before we can safely make this change to fs/proc/root.c
> 
> David am I reading the fs_parser.c code correctly?  If I am are you ok
> with a change like the above?
> 
> Eric
> 

-- 
Rgrds, legion


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v10 7/9] proc: move hidepid values to uapi as they are user interface to mount
  2020-03-27 17:23 ` [PATCH v10 7/9] proc: move hidepid values to uapi as they are user interface to mount Alexey Gladkov
  2020-03-28 20:41   ` Kees Cook
@ 2020-04-02 16:58   ` Eric W. Biederman
  2020-04-03 23:59     ` Kees Cook
  1 sibling, 1 reply; 33+ messages in thread
From: Eric W. Biederman @ 2020-04-02 16:58 UTC (permalink / raw)
  To: Alexey Gladkov
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, Akinobu Mita, Alexander Viro,
	Alexey Dobriyan, Alexey Gladkov, Andrew Morton, Andy Lutomirski,
	Daniel Micay, Djalal Harouni, Dmitry V . Levin,
	Greg Kroah-Hartman, Ingo Molnar, J . Bruce Fields, Jeff Layton,
	Jonathan Corbet, Kees Cook, Linus Torvalds, Oleg Nesterov


I will just say that I do not understand exporting this to the uapi
headers.  Why do we want to export the enumeration names?

I understand that the values are uapi.  This looks like it will make it
difficult to make changes that rename enumeration values to make
the code more readable.

Given that this patchset goes immediately to using string enumerated
values, I also don't understand the point of exporting
HIDEPID_NOT_PTRACEABLE.  I don't think we need to ever let
people use the numeric value.

My sense is that if we are switching to string values we should
just leave the existing numeric values as backwards compatiblity
and not do anything to make them easier to use.

Eric


Alexey Gladkov <gladkov.alexey@gmail.com> writes:

> Suggested-by: Alexey Dobriyan <adobriyan@gmail.com>
> Reviewed-by: Alexey Dobriyan <adobriyan@gmail.com>
> Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
> ---
>  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 afd38cae2339..d259817ec913 100644
> --- a/include/linux/proc_fs.h
> +++ b/include/linux/proc_fs.h
> @@ -7,6 +7,7 @@
>  
>  #include <linux/types.h>
>  #include <linux/fs.h>
> +#include <uapi/linux/proc_fs.h>
>  
>  struct proc_dir_entry;
>  struct seq_file;
> @@ -27,14 +28,6 @@ struct proc_ops {
>  	unsigned long (*proc_get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
>  };
>  
> -/* definitions for hide_pid field */
> -enum {
> -	HIDEPID_OFF	  = 0,
> -	HIDEPID_NO_ACCESS = 1,
> -	HIDEPID_INVISIBLE = 2,
> -	HIDEPID_NOT_PTRACEABLE = 4, /* Limit pids to only ptraceable 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..dc6d717aa6ec
> --- /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_PTRACEABLE = 4,
> +};
> +
> +#endif

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v10 0/9] proc: modernize proc to support multiple private instances
  2020-03-27 17:23 [PATCH v10 0/9] proc: modernize proc to support multiple private instances Alexey Gladkov
                   ` (8 preceding siblings ...)
  2020-03-27 17:23 ` [PATCH v10 9/9] proc: use named enums for better readability Alexey Gladkov
@ 2020-04-02 17:00 ` Eric W. Biederman
  9 siblings, 0 replies; 33+ messages in thread
From: Eric W. Biederman @ 2020-04-02 17:00 UTC (permalink / raw)
  To: Alexey Gladkov
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, Akinobu Mita, Alexander Viro,
	Alexey Dobriyan, Alexey Gladkov, Andrew Morton, Andy Lutomirski,
	Daniel Micay, Djalal Harouni, Dmitry V . Levin,
	Greg Kroah-Hartman, Ingo Molnar, J . Bruce Fields, Jeff Layton,
	Jonathan Corbet, Kees Cook, Linus Torvalds, Oleg Nesterov


Overall this patchset looks good.

I have found a couple of nits.  The biggest is the potential ABI change.
I would be surprised if someone is using the new mount ABI so changing
that may not be a regression.  But it is worth a close look.

One way or another I will ensure we get this in linux-next after the
merge window closes.

Eric

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v10 8/9] proc: use human-readable values for hidehid
  2020-04-02 16:51     ` Alexey Gladkov
@ 2020-04-02 17:04       ` Eric W. Biederman
  0 siblings, 0 replies; 33+ messages in thread
From: Eric W. Biederman @ 2020-04-02 17:04 UTC (permalink / raw)
  To: Alexey Gladkov
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, Akinobu Mita, Alexander Viro,
	Alexey Dobriyan, Andrew Morton, Andy Lutomirski, Daniel Micay,
	Djalal Harouni, Dmitry V . Levin, Greg Kroah-Hartman,
	Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
	Kees Cook, Linus Torvalds, Oleg Nesterov, David Howells

Alexey Gladkov <gladkov.alexey@gmail.com> writes:

> On Thu, Apr 02, 2020 at 11:05:21AM -0500, Eric W. Biederman wrote:
>> Alexey Gladkov <gladkov.alexey@gmail.com> writes:
>> 
>> > The hidepid parameter values are becoming more and more and it becomes
>> > difficult to remember what each new magic number means.
>> 
>> In principle I like this change.  In practice I think you have just
>> broken ABI compatiblity with the new mount ABI.
>> 
>> In particular the following line seems broken.
>> 
>> > diff --git a/fs/proc/root.c b/fs/proc/root.c
>> > index dbcd96f07c7a..ba782d6e6197 100644
>> > --- a/fs/proc/root.c
>> > +++ b/fs/proc/root.c
>> > @@ -45,7 +45,7 @@ enum proc_param {
>> >  
>> >  static const struct fs_parameter_spec proc_fs_parameters[] = {
>> >  	fsparam_u32("gid",	Opt_gid),
>> > -	fsparam_u32("hidepid",	Opt_hidepid),
>> > +	fsparam_string("hidepid",	Opt_hidepid),
>> >  	fsparam_string("subset",	Opt_subset),
>> >  	{}
>> >  };
>> 
>> As I read fs_parser.c fs_param_is_u32 handles string inputs and turns them
>> into numbers, and it handles binary numbers.  However fs_param_is_string
>> appears to only handle strings.  It appears to have not capacity to turn
>> raw binary numbers into strings.
>
> I use result only with hidepid_u32_spec and nobody modifies param->string.
> I do not use internal functions here.
>
> I don’t follow how a raw number can get here ?

I may be wrong but last I looked you can input raw numbers using the new
mount api.   I have most of the details paged out at the moment,
but I believe that is why when you set a parameter in the new mount api
it takes a type.

>> So I think we probably need to fix fs_param_is_string to raw binary
>> numbers before we can safely make this change to fs/proc/root.c
>> 
>> David am I reading the fs_parser.c code correctly?  If I am are you ok
>> with a change like the above?

Eric

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v10 7/9] proc: move hidepid values to uapi as they are user interface to mount
  2020-04-02 16:58   ` Eric W. Biederman
@ 2020-04-03 23:59     ` Kees Cook
  0 siblings, 0 replies; 33+ messages in thread
From: Kees Cook @ 2020-04-03 23:59 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Alexey Gladkov, LKML, Kernel Hardening, Linux API,
	Linux FS Devel, Linux Security Module, Akinobu Mita,
	Alexander Viro, Alexey Dobriyan, Alexey Gladkov, Andrew Morton,
	Andy Lutomirski, Daniel Micay, Djalal Harouni, Dmitry V . Levin,
	Greg Kroah-Hartman, Ingo Molnar, J . Bruce Fields, Jeff Layton,
	Jonathan Corbet, Linus Torvalds, Oleg Nesterov

On Thu, Apr 02, 2020 at 11:58:28AM -0500, Eric W. Biederman wrote:
> 
> I will just say that I do not understand exporting this to the uapi
> headers.  Why do we want to export the enumeration names?
> 
> I understand that the values are uapi.  This looks like it will make it
> difficult to make changes that rename enumeration values to make
> the code more readable.
> 
> Given that this patchset goes immediately to using string enumerated
> values, I also don't understand the point of exporting
> HIDEPID_NOT_PTRACEABLE.  I don't think we need to ever let
> people use the numeric value.
> 
> My sense is that if we are switching to string values we should
> just leave the existing numeric values as backwards compatiblity
> and not do anything to make them easier to use.

Yeah, that's what I had suggested too. Let's not export this to UAPI.

-Kees

> 
> Eric
> 
> 
> Alexey Gladkov <gladkov.alexey@gmail.com> writes:
> 
> > Suggested-by: Alexey Dobriyan <adobriyan@gmail.com>
> > Reviewed-by: Alexey Dobriyan <adobriyan@gmail.com>
> > Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
> > ---
> >  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 afd38cae2339..d259817ec913 100644
> > --- a/include/linux/proc_fs.h
> > +++ b/include/linux/proc_fs.h
> > @@ -7,6 +7,7 @@
> >  
> >  #include <linux/types.h>
> >  #include <linux/fs.h>
> > +#include <uapi/linux/proc_fs.h>
> >  
> >  struct proc_dir_entry;
> >  struct seq_file;
> > @@ -27,14 +28,6 @@ struct proc_ops {
> >  	unsigned long (*proc_get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
> >  };
> >  
> > -/* definitions for hide_pid field */
> > -enum {
> > -	HIDEPID_OFF	  = 0,
> > -	HIDEPID_NO_ACCESS = 1,
> > -	HIDEPID_INVISIBLE = 2,
> > -	HIDEPID_NOT_PTRACEABLE = 4, /* Limit pids to only ptraceable 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..dc6d717aa6ec
> > --- /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_PTRACEABLE = 4,
> > +};
> > +
> > +#endif

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v10 8/9] proc: use human-readable values for hidehid
  2020-04-02 16:05   ` [PATCH v10 " Eric W. Biederman
  2020-04-02 16:51     ` Alexey Gladkov
@ 2020-04-09 14:32     ` Alexey Gladkov
  1 sibling, 0 replies; 33+ messages in thread
From: Alexey Gladkov @ 2020-04-09 14:32 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, Akinobu Mita, Alexander Viro,
	Alexey Dobriyan, Andrew Morton, Andy Lutomirski, Daniel Micay,
	Djalal Harouni, Dmitry V . Levin, Greg Kroah-Hartman,
	Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
	Kees Cook, Linus Torvalds, Oleg Nesterov, David Howells

On Thu, Apr 02, 2020 at 11:05:21AM -0500, Eric W. Biederman wrote:
> Alexey Gladkov <gladkov.alexey@gmail.com> writes:
> 
> > The hidepid parameter values are becoming more and more and it becomes
> > difficult to remember what each new magic number means.
> 
> In principle I like this change.  In practice I think you have just
> broken ABI compatiblity with the new mount ABI.
> 
> In particular the following line seems broken.
> 
> > diff --git a/fs/proc/root.c b/fs/proc/root.c
> > index dbcd96f07c7a..ba782d6e6197 100644
> > --- a/fs/proc/root.c
> > +++ b/fs/proc/root.c
> > @@ -45,7 +45,7 @@ enum proc_param {
> >  
> >  static const struct fs_parameter_spec proc_fs_parameters[] = {
> >  	fsparam_u32("gid",	Opt_gid),
> > -	fsparam_u32("hidepid",	Opt_hidepid),
> > +	fsparam_string("hidepid",	Opt_hidepid),
> >  	fsparam_string("subset",	Opt_subset),
> >  	{}
> >  };
> 
> As I read fs_parser.c fs_param_is_u32 handles string inputs and turns them
> into numbers, and it handles binary numbers.

Yes, you can use: fsconfig(fsfd, FSCONFIG_SET_BINARY, ...); but in this
case the type of parameter will be fs_value_is_blob [1]. This kind of
parameters is handled by fs_param_is_blob(). The fs_param_is_u32 can
handle only parametes with fs_value_is_string type [2].

Am I missing something?

[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/fsopen.c#n405
[2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/fs_parser.c#n215

> However fs_param_is_string
> appears to only handle strings.  It appears to have not capacity to turn
> raw binary numbers into strings.
> 
> So I think we probably need to fix fs_param_is_string to raw binary
> numbers before we can safely make this change to fs/proc/root.c
> 
> David am I reading the fs_parser.c code correctly?  If I am are you ok
> with a change like the above?
> 
> Eric
> 

-- 
Rgrds, legion


^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2020-04-09 14:33 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-27 17:23 [PATCH v10 0/9] proc: modernize proc to support multiple private instances Alexey Gladkov
2020-03-27 17:23 ` [PATCH v10 1/9] proc: rename struct proc_fs_info to proc_fs_opts Alexey Gladkov
2020-03-27 17:23 ` [PATCH v10 2/9] proc: allow to mount many instances of proc in one pid namespace Alexey Gladkov
2020-04-02 15:31   ` Eric W. Biederman
2020-04-02 16:32     ` Alexey Gladkov
2020-03-27 17:23 ` [PATCH v10 3/9] proc: move hide_pid, pid_gid from pid_namespace to proc_fs_info Alexey Gladkov
2020-03-27 17:23 ` [PATCH v10 4/9] proc: instantiate only pids that we can ptrace on 'hidepid=4' mount option Alexey Gladkov
2020-03-28 20:40   ` Kees Cook
2020-03-28 21:23     ` Alexey Gladkov
2020-03-27 17:23 ` [PATCH v10 5/9] proc: add option to mount only a pids subset Alexey Gladkov
2020-03-27 17:23 ` [PATCH v10 6/9] docs: proc: add documentation for "hidepid=4" and "subset=pid" options and new mount behavior Alexey Gladkov
2020-03-27 17:23 ` [PATCH v10 7/9] proc: move hidepid values to uapi as they are user interface to mount Alexey Gladkov
2020-03-28 20:41   ` Kees Cook
2020-03-28 21:25     ` Alexey Gladkov
2020-03-28 21:53       ` Kees Cook
2020-03-28 23:00         ` Alexey Gladkov
2020-03-29  3:17           ` Kees Cook
2020-04-02 16:58   ` Eric W. Biederman
2020-04-03 23:59     ` Kees Cook
2020-03-27 17:23 ` [PATCH v10 8/9] proc: use human-readable values for hidehid Alexey Gladkov
2020-03-28 20:28   ` Kees Cook
2020-03-28 21:14     ` Alexey Gladkov
2020-03-28 21:52       ` Kees Cook
2020-03-28 22:54         ` Alexey Gladkov
2020-03-30 11:12   ` [PATCH v11 " Alexey Gladkov
2020-03-30 18:33     ` Kees Cook
2020-04-02 16:11     ` Jann Horn
2020-04-02 16:05   ` [PATCH v10 " Eric W. Biederman
2020-04-02 16:51     ` Alexey Gladkov
2020-04-02 17:04       ` Eric W. Biederman
2020-04-09 14:32     ` Alexey Gladkov
2020-03-27 17:23 ` [PATCH v10 9/9] proc: use named enums for better readability Alexey Gladkov
2020-04-02 17:00 ` [PATCH v10 0/9] proc: modernize proc to support multiple private instances Eric W. Biederman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).