* [PATCH v9 1/8] proc: rename struct proc_fs_info to proc_fs_opts
From: Alexey Gladkov @ 2020-03-15 15:25 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
In-Reply-To: <cover.1584285253.git.gladkov.alexey@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.1
^ permalink raw reply related
* [PATCH v9 0/8] proc: modernize proc to support multiple private instances
From: Alexey Gladkov @ 2020-03-15 15:25 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
Greetings!
Preface:
--------
This is patchset v9 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 58a45d79571a
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=pidfs' 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:
----------
# 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 (8):
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=pidfs"
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
Documentation/filesystems/proc.txt | 93 ++++++++++++++++-----
fs/proc/base.c | 46 ++++++++---
fs/proc/generic.c | 9 +++
fs/proc/inode.c | 28 +++++--
fs/proc/root.c | 126 +++++++++++++++++++++++------
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, 288 insertions(+), 83 deletions(-)
create mode 100644 include/uapi/linux/proc_fs.h
--
2.25.1
^ permalink raw reply
* [PATCH v9 3/8] proc: move hide_pid, pid_gid from pid_namespace to proc_fs_info
From: Alexey Gladkov @ 2020-03-15 15:25 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
In-Reply-To: <cover.1584285253.git.gladkov.alexey@gmail.com>
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.
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 9d2e425338c8..984b97bb634b 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.1
^ permalink raw reply related
* [PATCH v9 4/8] proc: instantiate only pids that we can ptrace on 'hidepid=4' mount option
From: Alexey Gladkov @ 2020-03-15 15:25 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
In-Reply-To: <cover.1584285253.git.gladkov.alexey@gmail.com>
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>
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 984b97bb634b..a836979e42fe 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.1
^ permalink raw reply related
* [PATCH v9 8/8] proc: use human-readable values for hidehid
From: Alexey Gladkov @ 2020-03-15 15:25 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
In-Reply-To: <cover.1584285253.git.gladkov.alexey@gmail.com>
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 | 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 4741fd092f36..27830a93464b 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 c1dbcf2b96db..a462fd111719 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=pidfs");
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 07c309529628..42f3ee05c584 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.1
^ permalink raw reply related
* [PATCH v9 7/8] proc: move hidepid values to uapi as they are user interface to mount
From: Alexey Gladkov @ 2020-03-15 15:25 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
In-Reply-To: <cover.1584285253.git.gladkov.alexey@gmail.com>
Suggested-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.1
^ permalink raw reply related
* [PATCH v9 6/8] docs: proc: add documentation for "hidepid=4" and "subset=pidfs" options and new mount behavior
From: Alexey Gladkov @ 2020-03-15 15:25 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
In-Reply-To: <cover.1584285253.git.gladkov.alexey@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..4741fd092f36 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -50,6 +50,8 @@ Table of Contents
4 Configuring procfs
4.1 Mount options
+ 5 Filesystem behavior
+
------------------------------------------------------------------------------
Preface
------------------------------------------------------------------------------
@@ -2021,6 +2023,7 @@ The following mount options are supported:
hidepid= Set /proc/<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=pidfs hides all top level files and directories in the procfs that
+are not related to tasks.
+
+------------------------------------------------------------------------------
+5 Filesystem behavior
+------------------------------------------------------------------------------
+
+Originally, before the advent of pid namepsace, procfs was a global file
+system. It means that there was only one procfs instance in the system.
+
+When pid namespace was added, a separate procfs instance was mounted in
+each pid namespace. So, procfs mount options are global among all
+mountpoints within the same namespace.
+
+# grep ^proc /proc/mounts
+proc /proc proc rw,relatime,hidepid=2 0 0
+
+# strace -e mount mount -o hidepid=1 -t proc proc /tmp/proc
+mount("proc", "/tmp/proc", "proc", 0, "hidepid=1") = 0
++++ exited with 0 +++
+
+# grep ^proc /proc/mounts
+proc /proc proc rw,relatime,hidepid=2 0 0
+proc /tmp/proc proc rw,relatime,hidepid=2 0 0
+
+and only after remounting procfs mount options will change at all
+mountpoints.
+
+# mount -o remount,hidepid=1 -t proc proc /tmp/proc
+
+# grep ^proc /proc/mounts
+proc /proc proc rw,relatime,hidepid=1 0 0
+proc /tmp/proc proc rw,relatime,hidepid=1 0 0
+
+This behavior is different from the behavior of other filesystems.
+
+The new procfs behavior is more like other filesystems. Each procfs mount
+creates a new procfs instance. Mount options affect own procfs instance.
+It means that it became possible to have several procfs instances
+displaying tasks with different filtering options in one pid namespace.
+
+# mount -o hidepid=2 -t proc proc /proc
+# mount -o hidepid=1 -t proc proc /tmp/proc
+# grep ^proc /proc/mounts
+proc /proc proc rw,relatime,hidepid=2 0 0
+proc /tmp/proc proc rw,relatime,hidepid=1 0 0
--
2.25.1
^ permalink raw reply related
* [PATCH v9 5/8] proc: add option to mount only a pids subset
From: Alexey Gladkov @ 2020-03-15 15:25 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
In-Reply-To: <cover.1584285253.git.gladkov.alexey@gmail.com>
This allows to hide all files and directories in the procfs that are not
related to tasks.
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..c1dbcf2b96db 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=pidfs");
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..07c309529628 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, "pidfs")) {
+ ctx->pidonly = PROC_PIDONLY_ON;
+ } else {
+ return invalf(fc, "proc: unsupported subset option - %s\n", value);
+ }
+ }
+ value = ptr;
+ }
+
+ return 0;
+}
+
static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param)
{
struct proc_fs_context *ctx = fc->fs_private;
@@ -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.1
^ permalink raw reply related
* [PATCH v9 2/8] proc: allow to mount many instances of proc in one pid namespace
From: Alexey Gladkov @ 2020-03-15 15:25 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
In-Reply-To: <cover.1584285253.git.gladkov.alexey@gmail.com>
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.
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 e7efe9d6f3d6..9d2e425338c8 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.1
^ permalink raw reply related
* Re: [PATCH 01/14] VFS: Add additional RESOLVE_* flags [ver #18]
From: Jeremy Allison @ 2020-03-13 18:35 UTC (permalink / raw)
To: Al Viro
Cc: Aleksa Sarai, Stefan Metzmacher, Linus Torvalds, David Howells,
Ian Kent, Miklos Szeredi, Christian Brauner, Jann Horn,
Darrick J. Wong, Karel Zak, jlayton, Linux API, linux-fsdevel,
LSM List, Linux Kernel Mailing List, Ralph Böhme,
Volker Lendecke
In-Reply-To: <20200313182844.GO23230@ZenIV.linux.org.uk>
On Fri, Mar 13, 2020 at 06:28:44PM +0000, Al Viro wrote:
> On Fri, Mar 13, 2020 at 08:59:01PM +1100, Aleksa Sarai wrote:
> > On 2020-03-12, Stefan Metzmacher <metze@samba.org> wrote:
> > > Am 12.03.20 um 17:24 schrieb Linus Torvalds:
> > > > But yes, if we have a major package like samba use it, then by all
> > > > means let's add linkat2(). How many things are we talking about? We
> > > > have a number of system calls that do *not* take flags, but do do
> > > > pathname walking. I'm thinking things like "mkdirat()"?)
> > >
> > > I haven't looked them up in detail yet.
> > > Jeremy can you provide a list?
> > >
> > > Do you think we could route some of them like mkdirat() and mknodat()
> > > via openat2() instead of creating new syscalls?
> >
> > I have heard some folks asking for a way to create a directory and get a
> > handle to it atomically -- so arguably this is something that could be
> > inside openat2()'s feature set (O_MKDIR?). But I'm not sure how popular
> > of an idea this is.
>
> For fuck sake, *NO*!
>
> We don't need any more multiplexors from hell. mkdir() and open() have
> deeply different interpretation of pathnames (and anyone who asks for
> e.g. traversals of dangling symlinks on mkdir() is insane). Don't try to
> mix those; even O_TMPFILE had been a mistake.
>
> Folks, we'd paid very dearly for the atomic_open() merge. We are _still_
> paying for it - and keep finding bugs induced by the convoluted horrors
> in that thing (see yesterday pull from vfs.git#fixes for the latest crop).
> I hope to get into more or less sane shape (part - this cycle, with
> followups in the next one), but the last thing we need is more complexity
> in the area.
Can we disentangle the laudable desire to keep kernel internals
simple (which I completely agree with :-) from the desire to
keep user-space interfaces simple ?
Having some way of doing a mkdir() that returns an open fd
on the new directory *is* a very useful thing for many applications,
but I really don't care how the kernel implements it. We have so much
Linux-specific code already that one more thing won't matter :-).
^ permalink raw reply
* Re: [PATCH 01/14] VFS: Add additional RESOLVE_* flags [ver #18]
From: Al Viro @ 2020-03-13 18:28 UTC (permalink / raw)
To: Aleksa Sarai
Cc: Stefan Metzmacher, Linus Torvalds, David Howells, Ian Kent,
Miklos Szeredi, Christian Brauner, Jann Horn, Darrick J. Wong,
Karel Zak, jlayton, Linux API, linux-fsdevel, LSM List,
Linux Kernel Mailing List, Jeremy Allison, Ralph Böhme,
Volker Lendecke
In-Reply-To: <20200313095901.tdv4vl7envypgqfz@yavin>
On Fri, Mar 13, 2020 at 08:59:01PM +1100, Aleksa Sarai wrote:
> On 2020-03-12, Stefan Metzmacher <metze@samba.org> wrote:
> > Am 12.03.20 um 17:24 schrieb Linus Torvalds:
> > > But yes, if we have a major package like samba use it, then by all
> > > means let's add linkat2(). How many things are we talking about? We
> > > have a number of system calls that do *not* take flags, but do do
> > > pathname walking. I'm thinking things like "mkdirat()"?)
> >
> > I haven't looked them up in detail yet.
> > Jeremy can you provide a list?
> >
> > Do you think we could route some of them like mkdirat() and mknodat()
> > via openat2() instead of creating new syscalls?
>
> I have heard some folks asking for a way to create a directory and get a
> handle to it atomically -- so arguably this is something that could be
> inside openat2()'s feature set (O_MKDIR?). But I'm not sure how popular
> of an idea this is.
For fuck sake, *NO*!
We don't need any more multiplexors from hell. mkdir() and open() have
deeply different interpretation of pathnames (and anyone who asks for
e.g. traversals of dangling symlinks on mkdir() is insane). Don't try to
mix those; even O_TMPFILE had been a mistake.
Folks, we'd paid very dearly for the atomic_open() merge. We are _still_
paying for it - and keep finding bugs induced by the convoluted horrors
in that thing (see yesterday pull from vfs.git#fixes for the latest crop).
I hope to get into more or less sane shape (part - this cycle, with
followups in the next one), but the last thing we need is more complexity
in the area.
Keep the semantics simple and regular; corner cases _suck_. "Infinitely
extensible (without review)" is no virtue. And having nowhere to hide
very special flags for very special kludges is a bloody good thing.
Every fucking time we had a multiplexed syscall, it had been a massive
source of trouble. IF it has a uniform semantics - fine; we don't need
arseloads of read_this(2)/read_that(2). But when you need pages upon
pages to describe the subtle differences in the interpretation of
its arguments, you have already lost. It will be full of corner
cases, they will get zero testing and they will rot. Inevitably. All
the faster for the lack of people who would be able to keep all of that
in head.
We do have a mechanism for multiplexing; on amd64 it lives in do_syscall_64().
We really don't need openat2() turning into another one. Syscall table
slots are not in a short supply, and the level of review one gets from
"new syscall added" is higher than from "make fubar(2) recognize a new
member in options->union_full_of_crap if it has RESOLVE_TO_WANK_WITH_RIGHT_HAND
set in options->flags, affecting its behaviour in some odd ways".
Which is a good thing, damnit.
^ permalink raw reply
* Re: [PATCH v3 3/3] KEYS: Use kvmalloc() to better handle large buffer allocation
From: Waiman Long @ 2020-03-13 17:49 UTC (permalink / raw)
To: Eric Biggers
Cc: David Howells, Jarkko Sakkinen, James Morris, Serge E. Hallyn,
Mimi Zohar, keyrings, linux-kernel, linux-security-module,
linux-integrity, Sumit Garg, Jerry Snitselaar, Roberto Sassu,
Chris von Recklinghausen
In-Reply-To: <20200313164306.GA907@sol.localdomain>
On 3/13/20 12:43 PM, Eric Biggers wrote:
> On Fri, Mar 13, 2020 at 11:21:02AM -0400, Waiman Long wrote:
>> For large multi-page temporary buffer allocation, the security/keys
>> subsystem don't need contiguous physical pages. It will work perfectly
>> fine with virtually mapped pages.
>>
>> Replace the kmalloc() call by kvmalloc() and provide a __kvzfree()
>> helper function to clear and free the kvmalloc'ed buffer. This will
>> reduce the chance of memory allocation failure just because of highly
>> fragmented pages.
>>
>> Suggested-by: David Howells <dhowells@redhat.com>
>> Signed-off-by: Waiman Long <longman@redhat.com>
>> ---
>> security/keys/internal.h | 14 ++++++++++++++
>> security/keys/keyctl.c | 10 +++++-----
>> 2 files changed, 19 insertions(+), 5 deletions(-)
>>
>> diff --git a/security/keys/internal.h b/security/keys/internal.h
>> index ba3e2da14cef..855b11eb73ee 100644
>> --- a/security/keys/internal.h
>> +++ b/security/keys/internal.h
>> @@ -16,6 +16,8 @@
>> #include <linux/keyctl.h>
>> #include <linux/refcount.h>
>> #include <linux/compat.h>
>> +#include <linux/mm.h>
>> +#include <linux/vmalloc.h>
>>
>> struct iovec;
>>
>> @@ -349,4 +351,16 @@ static inline void key_check(const struct key *key)
>>
>> #endif
>>
>> +/*
>> + * Helper function to clear and free a kvmalloc'ed memory object.
>> + */
>> +static inline void __kvzfree(const void *addr, size_t len)
>> +{
>> + if (is_vmalloc_addr(addr)) {
>> + memset((void *)addr, 0, len);
>> + vfree(addr);
>> + } else {
>> + kzfree(addr);
>> + }
>> +}
> Since this takes the length as a parameter, it can be simplified to:
>
> static inline void __kvzfree(const void *addr, size_t len)
> {
> if (addr) {
> memset((void *)addr, 0, len);
> kvfree(addr);
> }
> }
Yes, that will work too.
>> if (!tmpbuf || unlikely(ret > tmpbuflen)) {
>> if (unlikely(tmpbuf))
>> - kzfree(tmpbuf);
>> + __kvzfree(tmpbuf, tmpbuflen);
> Both kzfree() and __kvzfree() handle a NULL pointer, so there's no need for the
> NULL check first.
>
I would like to keep this one because of the unlikely annotation.
>> @@ -920,7 +920,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
>> ret = -EFAULT;
>> }
>> if (tmpbuf)
>> - kzfree(tmpbuf);
>> + __kvzfree(tmpbuf, tmpbuflen);
> Likewise here. No need for the NULL check.
Yes, that tmpbuf check is not really necessary, but it doesn't harm either.
My plan is to send out a mm patch to officially add the kvzfree()
function to mm/util.c. I will remove the tmpbuf check at that time if
you don't mind.
Cheers,
Longman
^ permalink raw reply
* [PATCH v1] perf tool: make Perf tool aware of SELinux access control
From: Alexey Budankov @ 2020-03-13 17:27 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: Jiri Olsa, Namhyung Kim, Alexander Shishkin, Peter Zijlstra,
Ingo Molnar, Andi Kleen, linux-kernel, selinux@vger.kernel.org,
linux-security-module@vger.kernel.org
Extend Perf tool with the check of /sys/fs/selinux/enforce value and notify
in case access to perf_event_open() syscall is restricted by the enforced
SELinux policy settings.
Testing and evaluation (Fedora 31 x86_64 with enforced Targeted policy extended
by perf_event class (see refpolicy [1] master branch)):
[root@host ~]# ps -Z
LABEL PID TTY TIME CMD
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 3960 pts/1 00:00:00 bash
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 4167 pts/1 00:00:00 ps
[root@host ~]# ls -alhZ /usr/local/bin/
total 56M
drwxr-xr-x. 2 root root system_u:object_r:bin_t:s0 4.0K Mar 4 12:27 .
drwxr-xr-x. 12 root root system_u:object_r:usr_t:s0 4.0K Jul 25 2019 ..
-rwxr-xr-x. 1 root root system_u:object_r:bin_t:s0 4.1M Jan 23 2017 bash
-rwxr-xr-x. 1 root root system_u:object_r:bin_t:s0 4.1M Jan 23 2017 bash.before_shellshock_patch
...
-rwxr-xr-x. 1 root root system_u:object_r:bin_t:s0 372 May 14 2019 flask
-rwxr-xr-x. 1 root root unconfined_u:object_r:bin_t:s0 24M Mar 4 12:15 perf <== unprivileged users (perf_event_paranoid)
-rwxr-x---. 1 root perf_users unconfined_u:object_r:bin_t:s0 24M Mar 4 12:19 perf.cap <== perf_users (CAP_SYS_ADMIN)
-rwxr-xr-x. 1 root root system_u:object_r:bin_t:s0 44K Dec 8 2016 spiff
...
lrwxrwxrwx. 1 root root system_u:object_r:bin_t:s0 4 Aug 21 2018 zstdmt -> zstd
[root@host ~]# getenforce
Enforcing
=== Access by unprivileged user ===
[user@host ~]$ ps -Z
LABEL PID TTY TIME CMD
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 4043 pts/2 00:00:00 bash
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 4168 pts/2 00:00:00 ps
[user@host ~]$ /usr/local/bin/perf stat -- ls
Error:
Access to performance monitoring and observability operations is limited.
SELinux Enforcing mode is enabled and can limit access to performance
monitoring and observability operations. Inspect system audit records
for more perf_event access control information and adjusting the policy.
Consider adjusting /proc/sys/kernel/perf_event_paranoid setting to open
access to performance monitoring and observability operations for users
without CAP_SYS_ADMIN capability. perf_event_paranoid setting is -1:
-1: Allow use of (almost) all events by all users
Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK
>= 0: Disallow raw and ftrace function tracepoint access
>= 1: Disallow CPU event access
>= 2: Disallow kernel profiling
To make the adjusted perf_event_paranoid setting permanent preserve it
in /etc/sysctl.conf (e.g. kernel.perf_event_paranoid = <setting>)
[root@host ~]# journalctl --follow
... audit[4186]: AVC avc: denied { open } for pid=4186 comm="perf" scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=perf_event permissive=0
... audit[4186]: AVC avc: denied { open } for pid=4186 comm="perf" scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=perf_event permissive=0
... setroubleshoot[4194]: SELinux is preventing perf from open access on the perf_event labeled unconfined_t. For complete SELinux messages run: sealert -l 9a6f3db2-3d8f-461e-afad-0b5c3a9c3b9d
... python3[4194]: SELinux is preventing perf from open access on the perf_event labeled unconfined_t.
***** Plugin catchall (100. confidence) suggests **************************
If you believe that perf should be allowed open access on perf_event labeled unconfined_t by default.
Then you should report this as a bug.
You can generate a local policy module to allow this access.
Do
allow this access for now by executing:
# ausearch -c 'perf' --raw | audit2allow -M my-perf
# semodule -X 300 -i my-perf.pp
=== Access by perf privileged user ===
[user@host ~]$ ps -Z
LABEL PID TTY TIME CMD
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 4043 pts/2 00:00:00 bash
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 4168 pts/2 00:00:00 ps
[user@host ~]$ libcap/progs/getcap /usr/local/bin/perf.cap
/usr/local/bin/perf.cap = cap_sys_ptrace,cap_syslog,cap_sys_admin+ep
[user@host ~]$ /usr/local/bin/perf.cap stat -- ls
Error:
Access to performance monitoring and observability operations is limited.
SELinux Enforcing mode is enabled and can limit access to performance
monitoring and observability operations. Inspect system audit records
for more perf_event access control information and adjusting the policy.
Consider adjusting /proc/sys/kernel/perf_event_paranoid setting to open
access to performance monitoring and observability operations for users
without CAP_SYS_ADMIN capability. perf_event_paranoid setting is -1:
-1: Allow use of (almost) all events by all users
Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK
>= 0: Disallow raw and ftrace function tracepoint access
>= 1: Disallow CPU event access
>= 2: Disallow kernel profiling
To make the adjusted perf_event_paranoid setting permanent preserve it
in /etc/sysctl.conf (e.g. kernel.perf_event_paranoid = <setting>)
[root@host ~]# journalctl --follow
... audit[3926]: AVC avc: denied { open } for pid=3926 comm="perf.cap" scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=perf_event permissive=0
... audit[3926]: AVC avc: denied { open } for pid=3926 comm="perf.cap" scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=perf_event permissive=0
... setroubleshoot[3934]: SELinux is preventing perf from open access on the perf_event labeled unconfined_t. For complete SELinux messages run: sealert -l 9a6f3db2-3d8f-461e-afad-0b5c3a9c3b9d
... python3[3934]: SELinux is preventing perf from open access on the perf_event labeled unconfined_t.
***** Plugin catchall (100. confidence) suggests **************************
If you believe that perf should be allowed open access on perf_event labeled unconfined_t by default.
Then you should report this as a bug.
You can generate a local policy module to allow this access.
Do
allow this access for now by executing:
# ausearch -c 'perf' --raw | audit2allow -M my-perf
# semodule -X 300 -i my-perf.pp
=== Open access to performance monitoring and observability operations in unconfined_t domain ===
[root@host ~]# ausearch -c 'perf' --raw | audit2allow -M my-perf && cat my-perf.te
module my-perf 1.0;
require {
type unconfined_t;
class perf_event { cpu kernel open read tracepoint write };
}
#============= unconfined_t ==============
allow unconfined_t self:perf_event { cpu kernel open read tracepoint write };
[root@host ~]# semodule -X 300 -i my-perf.pp
[user@host ~]$ ps -Z
LABEL PID TTY TIME CMD
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 4043 pts/2 00:00:00 bash
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 4168 pts/2 00:00:00 ps
[user@host ~]$ /usr/local/bin/perf stat -- ls
Desktop Documents Downloads intel Music perf.data perf.data.old Pictures Public Templates Videos
Performance counter stats for 'ls':
0.72 msec task-clock:u # 0.655 CPUs utilized
0 context-switches:u # 0.000 K/sec
0 cpu-migrations:u # 0.000 K/sec
98 page-faults:u # 0.137 M/sec
908,356 cycles:u # 1.266 GHz
729,984 instructions:u # 0.80 insn per cycle
142,774 branches:u # 198.968 M/sec
8,238 branch-misses:u # 5.77% of all branches
0.001095239 seconds time elapsed
0.001147000 seconds user
0.000000000 seconds sys
[user@host ~]$ /usr/local/bin/perf stat -a
Error:
Access to performance monitoring and observability operations is limited.
SELinux Enforcing mode is enabled and can limit access to performance
monitoring and observability operations. Inspect system audit records
for more perf_event access control information and adjusting the policy.
Consider adjusting /proc/sys/kernel/perf_event_paranoid setting to open
access to performance monitoring and observability operations for users
without CAP_SYS_ADMIN capability. perf_event_paranoid setting is -1:
-1: Allow use of (almost) all events by all users
Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK
>= 0: Disallow raw and ftrace function tracepoint access
>= 1: Disallow CPU event access
>= 2: Disallow kernel profiling
To make the adjusted perf_event_paranoid setting permanent preserve it
in /etc/sysctl.conf (e.g. kernel.perf_event_paranoid = <setting>)
[user@host ~]$ /usr/local/bin/perf.cap stat -a
^C
Performance counter stats for 'system wide':
13,427.05 msec cpu-clock # 7.997 CPUs utilized
783 context-switches # 0.058 K/sec
29 cpu-migrations # 0.002 K/sec
6 page-faults # 0.000 K/sec
161,084,874 cycles # 0.012 GHz
146,823,131 instructions # 0.91 insn per cycle
12,164,802 branches # 0.906 M/sec
380,350 branch-misses # 3.13% of all branches
1.678938906 seconds time elapsed
[1] https://github.com/SELinuxProject/refpolicy
Signed-off-by: Alexey Budankov <alexey.budankov@linux.intel.com>
---
tools/perf/util/cloexec.c | 4 ++--
tools/perf/util/evsel.c | 40 +++++++++++++++++++++++----------------
2 files changed, 26 insertions(+), 18 deletions(-)
diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c
index a12872f2856a..9c8ec816261b 100644
--- a/tools/perf/util/cloexec.c
+++ b/tools/perf/util/cloexec.c
@@ -65,7 +65,7 @@ static int perf_flag_probe(void)
return 1;
}
- WARN_ONCE(err != EINVAL && err != EBUSY,
+ WARN_ONCE(err != EINVAL && err != EBUSY && err != EACCES,
"perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n",
err, str_error_r(err, sbuf, sizeof(sbuf)));
@@ -83,7 +83,7 @@ static int perf_flag_probe(void)
if (fd >= 0)
close(fd);
- if (WARN_ONCE(fd < 0 && err != EBUSY,
+ if (WARN_ONCE(fd < 0 && err != EBUSY && err != EACCES,
"perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",
err, str_error_r(err, sbuf, sizeof(sbuf))))
return -1;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 816d930d774e..f03ce1d362d3 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -2493,32 +2493,40 @@ int perf_evsel__open_strerror(struct evsel *evsel, struct target *target,
int err, char *msg, size_t size)
{
char sbuf[STRERR_BUFSIZE];
- int printed = 0;
+ int printed = 0, enforced = 0;
switch (err) {
case EPERM:
case EACCES:
+ printed += scnprintf(msg + printed, size - printed,
+ "Access to performance monitoring and observability operations is limited.\n");
+
+ if (!sysfs__read_int("fs/selinux/enforce", &enforced)) {
+ if (enforced) {
+ printed += scnprintf(msg + printed, size - printed,
+ "SELinux Enforcing mode is enabled and can limit access to performance\n"
+ "monitoring and observability operations. Inspect system audit records\n"
+ "for more perf_event access control information and adjusting the policy.\n");
+ }
+ }
+
if (err == EPERM)
- printed = scnprintf(msg, size,
- "No permission to enable %s event.\n\n",
+ printed += scnprintf(msg, size,
+ "No permission to enable %s event.\n",
perf_evsel__name(evsel));
return scnprintf(msg + printed, size - printed,
- "You may not have permission to collect %sstats.\n\n"
- "Consider tweaking /proc/sys/kernel/perf_event_paranoid,\n"
- "which controls use of the performance events system by\n"
- "unprivileged users (without CAP_SYS_ADMIN).\n\n"
- "The current value is %d:\n\n"
+ "Consider adjusting /proc/sys/kernel/perf_event_paranoid setting to open\n"
+ "access to performance monitoring and observability operations for users\n"
+ "without CAP_SYS_ADMIN capability. perf_event_paranoid setting is %d:\n"
" -1: Allow use of (almost) all events by all users\n"
" Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK\n"
- ">= 0: Disallow ftrace function tracepoint by users without CAP_SYS_ADMIN\n"
- " Disallow raw tracepoint access by users without CAP_SYS_ADMIN\n"
- ">= 1: Disallow CPU event access by users without CAP_SYS_ADMIN\n"
- ">= 2: Disallow kernel profiling by users without CAP_SYS_ADMIN\n\n"
- "To make this setting permanent, edit /etc/sysctl.conf too, e.g.:\n\n"
- " kernel.perf_event_paranoid = -1\n" ,
- target->system_wide ? "system-wide " : "",
- perf_event_paranoid());
+ ">= 0: Disallow raw and ftrace function tracepoint access\n"
+ ">= 1: Disallow CPU event access\n"
+ ">= 2: Disallow kernel profiling\n"
+ "To make the adjusted perf_event_paranoid setting permanent preserve it\n"
+ "in /etc/sysctl.conf (e.g. kernel.perf_event_paranoid = <setting>)",
+ perf_event_paranoid());
case ENOENT:
return scnprintf(msg, size, "The %s event is not supported.",
perf_evsel__name(evsel));
--
2.24.1
^ permalink raw reply related
* Re: [PATCH v2 1/2] KEYS: Don't write out to userspace while holding key semaphore
From: Waiman Long @ 2020-03-13 16:57 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: David Howells, James Morris, Serge E. Hallyn, Mimi Zohar,
keyrings, linux-kernel, linux-security-module, linux-integrity,
Sumit Garg, Jerry Snitselaar, Roberto Sassu, Eric Biggers,
Chris von Recklinghausen
In-Reply-To: <20200313152837.GB142269@linux.intel.com>
On 3/13/20 11:28 AM, Jarkko Sakkinen wrote:
> On Fri, Mar 13, 2020 at 09:29:47AM -0400, Waiman Long wrote:
>> One way to do that is to extract the down_read/up_read block into a
>> helper function and then have 2 separate paths - one for length
>> retrieval and another one for reading the key. I think that will make
>> the code a bit easier easier to read.
>>
>> Thanks,
>> Longman
> If it is not too much trouble for you, I think this would be a legit
> cleanup to do.
Done. Please review the v3 patch.
Thanks,
Longman
^ permalink raw reply
* Re: [PATCH 01/14] VFS: Add additional RESOLVE_* flags [ver #18]
From: Jeremy Allison @ 2020-03-13 16:48 UTC (permalink / raw)
To: Aleksa Sarai
Cc: Stefan Metzmacher, Linus Torvalds, David Howells, Al Viro,
Ian Kent, Miklos Szeredi, Christian Brauner, Jann Horn,
Darrick J. Wong, Karel Zak, jlayton, Linux API, linux-fsdevel,
LSM List, Linux Kernel Mailing List, Ralph Böhme,
Volker Lendecke
In-Reply-To: <20200313095901.tdv4vl7envypgqfz@yavin>
On Fri, Mar 13, 2020 at 08:59:01PM +1100, Aleksa Sarai wrote:
>
> I have heard some folks asking for a way to create a directory and get a
> handle to it atomically -- so arguably this is something that could be
> inside openat2()'s feature set (O_MKDIR?). But I'm not sure how popular
> of an idea this is.
This would be very useful to prevent race conditions between making
a directory and EA's on it, as are needed by Samba for
DOS attributes and Windows/NFSv4 ACLS.
^ permalink raw reply
* Re: [PATCH v3 3/3] KEYS: Use kvmalloc() to better handle large buffer allocation
From: Eric Biggers @ 2020-03-13 16:43 UTC (permalink / raw)
To: Waiman Long
Cc: David Howells, Jarkko Sakkinen, James Morris, Serge E. Hallyn,
Mimi Zohar, keyrings, linux-kernel, linux-security-module,
linux-integrity, Sumit Garg, Jerry Snitselaar, Roberto Sassu,
Chris von Recklinghausen
In-Reply-To: <20200313152102.1707-4-longman@redhat.com>
On Fri, Mar 13, 2020 at 11:21:02AM -0400, Waiman Long wrote:
> For large multi-page temporary buffer allocation, the security/keys
> subsystem don't need contiguous physical pages. It will work perfectly
> fine with virtually mapped pages.
>
> Replace the kmalloc() call by kvmalloc() and provide a __kvzfree()
> helper function to clear and free the kvmalloc'ed buffer. This will
> reduce the chance of memory allocation failure just because of highly
> fragmented pages.
>
> Suggested-by: David Howells <dhowells@redhat.com>
> Signed-off-by: Waiman Long <longman@redhat.com>
> ---
> security/keys/internal.h | 14 ++++++++++++++
> security/keys/keyctl.c | 10 +++++-----
> 2 files changed, 19 insertions(+), 5 deletions(-)
>
> diff --git a/security/keys/internal.h b/security/keys/internal.h
> index ba3e2da14cef..855b11eb73ee 100644
> --- a/security/keys/internal.h
> +++ b/security/keys/internal.h
> @@ -16,6 +16,8 @@
> #include <linux/keyctl.h>
> #include <linux/refcount.h>
> #include <linux/compat.h>
> +#include <linux/mm.h>
> +#include <linux/vmalloc.h>
>
> struct iovec;
>
> @@ -349,4 +351,16 @@ static inline void key_check(const struct key *key)
>
> #endif
>
> +/*
> + * Helper function to clear and free a kvmalloc'ed memory object.
> + */
> +static inline void __kvzfree(const void *addr, size_t len)
> +{
> + if (is_vmalloc_addr(addr)) {
> + memset((void *)addr, 0, len);
> + vfree(addr);
> + } else {
> + kzfree(addr);
> + }
> +}
Since this takes the length as a parameter, it can be simplified to:
static inline void __kvzfree(const void *addr, size_t len)
{
if (addr) {
memset((void *)addr, 0, len);
kvfree(addr);
}
}
> if (!tmpbuf || unlikely(ret > tmpbuflen)) {
> if (unlikely(tmpbuf))
> - kzfree(tmpbuf);
> + __kvzfree(tmpbuf, tmpbuflen);
Both kzfree() and __kvzfree() handle a NULL pointer, so there's no need for the
NULL check first.
> @@ -920,7 +920,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
> ret = -EFAULT;
> }
> if (tmpbuf)
> - kzfree(tmpbuf);
> + __kvzfree(tmpbuf, tmpbuflen);
Likewise here. No need for the NULL check.
- Eric
^ permalink raw reply
* Re: [PATCH v2 1/2] KEYS: Don't write out to userspace while holding key semaphore
From: Jarkko Sakkinen @ 2020-03-13 15:28 UTC (permalink / raw)
To: Waiman Long
Cc: David Howells, James Morris, Serge E. Hallyn, Mimi Zohar,
keyrings, linux-kernel, linux-security-module, linux-integrity,
Sumit Garg, Jerry Snitselaar, Roberto Sassu, Eric Biggers,
Chris von Recklinghausen
In-Reply-To: <e2dc038b-0283-0bf6-45f6-ad2dd0775e81@redhat.com>
On Fri, Mar 13, 2020 at 09:29:47AM -0400, Waiman Long wrote:
> One way to do that is to extract the down_read/up_read block into a
> helper function and then have 2 separate paths - one for length
> retrieval and another one for reading the key. I think that will make
> the code a bit easier easier to read.
>
> Thanks,
> Longman
If it is not too much trouble for you, I think this would be a legit
cleanup to do.
/Jarkko
^ permalink raw reply
* [PATCH v3 1/3] KEYS: Don't write out to userspace while holding key semaphore
From: Waiman Long @ 2020-03-13 15:21 UTC (permalink / raw)
To: David Howells, Jarkko Sakkinen, James Morris, Serge E. Hallyn,
Mimi Zohar
Cc: keyrings, linux-kernel, linux-security-module, linux-integrity,
Sumit Garg, Jerry Snitselaar, Roberto Sassu, Eric Biggers,
Chris von Recklinghausen, Waiman Long
In-Reply-To: <20200313152102.1707-1-longman@redhat.com>
A lockdep circular locking dependency report was seen when running a
keyutils test:
[12537.027242] ======================================================
[12537.059309] WARNING: possible circular locking dependency detected
[12537.088148] 4.18.0-147.7.1.el8_1.x86_64+debug #1 Tainted: G OE --------- - -
[12537.125253] ------------------------------------------------------
[12537.153189] keyctl/25598 is trying to acquire lock:
[12537.175087] 000000007c39f96c (&mm->mmap_sem){++++}, at: __might_fault+0xc4/0x1b0
[12537.208365]
[12537.208365] but task is already holding lock:
[12537.234507] 000000003de5b58d (&type->lock_class){++++}, at: keyctl_read_key+0x15a/0x220
[12537.270476]
[12537.270476] which lock already depends on the new lock.
[12537.270476]
[12537.307209]
[12537.307209] the existing dependency chain (in reverse order) is:
[12537.340754]
[12537.340754] -> #3 (&type->lock_class){++++}:
[12537.367434] down_write+0x4d/0x110
[12537.385202] __key_link_begin+0x87/0x280
[12537.405232] request_key_and_link+0x483/0xf70
[12537.427221] request_key+0x3c/0x80
[12537.444839] dns_query+0x1db/0x5a5 [dns_resolver]
[12537.468445] dns_resolve_server_name_to_ip+0x1e1/0x4d0 [cifs]
[12537.496731] cifs_reconnect+0xe04/0x2500 [cifs]
[12537.519418] cifs_readv_from_socket+0x461/0x690 [cifs]
[12537.546263] cifs_read_from_socket+0xa0/0xe0 [cifs]
[12537.573551] cifs_demultiplex_thread+0x311/0x2db0 [cifs]
[12537.601045] kthread+0x30c/0x3d0
[12537.617906] ret_from_fork+0x3a/0x50
[12537.636225]
[12537.636225] -> #2 (root_key_user.cons_lock){+.+.}:
[12537.664525] __mutex_lock+0x105/0x11f0
[12537.683734] request_key_and_link+0x35a/0xf70
[12537.705640] request_key+0x3c/0x80
[12537.723304] dns_query+0x1db/0x5a5 [dns_resolver]
[12537.746773] dns_resolve_server_name_to_ip+0x1e1/0x4d0 [cifs]
[12537.775607] cifs_reconnect+0xe04/0x2500 [cifs]
[12537.798322] cifs_readv_from_socket+0x461/0x690 [cifs]
[12537.823369] cifs_read_from_socket+0xa0/0xe0 [cifs]
[12537.847262] cifs_demultiplex_thread+0x311/0x2db0 [cifs]
[12537.873477] kthread+0x30c/0x3d0
[12537.890281] ret_from_fork+0x3a/0x50
[12537.908649]
[12537.908649] -> #1 (&tcp_ses->srv_mutex){+.+.}:
[12537.935225] __mutex_lock+0x105/0x11f0
[12537.954450] cifs_call_async+0x102/0x7f0 [cifs]
[12537.977250] smb2_async_readv+0x6c3/0xc90 [cifs]
[12538.000659] cifs_readpages+0x120a/0x1e50 [cifs]
[12538.023920] read_pages+0xf5/0x560
[12538.041583] __do_page_cache_readahead+0x41d/0x4b0
[12538.067047] ondemand_readahead+0x44c/0xc10
[12538.092069] filemap_fault+0xec1/0x1830
[12538.111637] __do_fault+0x82/0x260
[12538.129216] do_fault+0x419/0xfb0
[12538.146390] __handle_mm_fault+0x862/0xdf0
[12538.167408] handle_mm_fault+0x154/0x550
[12538.187401] __do_page_fault+0x42f/0xa60
[12538.207395] do_page_fault+0x38/0x5e0
[12538.225777] page_fault+0x1e/0x30
[12538.243010]
[12538.243010] -> #0 (&mm->mmap_sem){++++}:
[12538.267875] lock_acquire+0x14c/0x420
[12538.286848] __might_fault+0x119/0x1b0
[12538.306006] keyring_read_iterator+0x7e/0x170
[12538.327936] assoc_array_subtree_iterate+0x97/0x280
[12538.352154] keyring_read+0xe9/0x110
[12538.370558] keyctl_read_key+0x1b9/0x220
[12538.391470] do_syscall_64+0xa5/0x4b0
[12538.410511] entry_SYSCALL_64_after_hwframe+0x6a/0xdf
[12538.435535]
[12538.435535] other info that might help us debug this:
[12538.435535]
[12538.472829] Chain exists of:
[12538.472829] &mm->mmap_sem --> root_key_user.cons_lock --> &type->lock_class
[12538.472829]
[12538.524820] Possible unsafe locking scenario:
[12538.524820]
[12538.551431] CPU0 CPU1
[12538.572654] ---- ----
[12538.595865] lock(&type->lock_class);
[12538.613737] lock(root_key_user.cons_lock);
[12538.644234] lock(&type->lock_class);
[12538.672410] lock(&mm->mmap_sem);
[12538.687758]
[12538.687758] *** DEADLOCK ***
[12538.687758]
[12538.714455] 1 lock held by keyctl/25598:
[12538.732097] #0: 000000003de5b58d (&type->lock_class){++++}, at: keyctl_read_key+0x15a/0x220
[12538.770573]
[12538.770573] stack backtrace:
[12538.790136] CPU: 2 PID: 25598 Comm: keyctl Kdump: loaded Tainted: G
[12538.844855] Hardware name: HP ProLiant DL360 Gen9/ProLiant DL360 Gen9, BIOS P89 12/27/2015
[12538.881963] Call Trace:
[12538.892897] dump_stack+0x9a/0xf0
[12538.907908] print_circular_bug.isra.25.cold.50+0x1bc/0x279
[12538.932891] ? save_trace+0xd6/0x250
[12538.948979] check_prev_add.constprop.32+0xc36/0x14f0
[12538.971643] ? keyring_compare_object+0x104/0x190
[12538.992738] ? check_usage+0x550/0x550
[12539.009845] ? sched_clock+0x5/0x10
[12539.025484] ? sched_clock_cpu+0x18/0x1e0
[12539.043555] __lock_acquire+0x1f12/0x38d0
[12539.061551] ? trace_hardirqs_on+0x10/0x10
[12539.080554] lock_acquire+0x14c/0x420
[12539.100330] ? __might_fault+0xc4/0x1b0
[12539.119079] __might_fault+0x119/0x1b0
[12539.135869] ? __might_fault+0xc4/0x1b0
[12539.153234] keyring_read_iterator+0x7e/0x170
[12539.172787] ? keyring_read+0x110/0x110
[12539.190059] assoc_array_subtree_iterate+0x97/0x280
[12539.211526] keyring_read+0xe9/0x110
[12539.227561] ? keyring_gc_check_iterator+0xc0/0xc0
[12539.249076] keyctl_read_key+0x1b9/0x220
[12539.266660] do_syscall_64+0xa5/0x4b0
[12539.283091] entry_SYSCALL_64_after_hwframe+0x6a/0xdf
One way to prevent this deadlock scenario from happening is to not
allow writing to userspace while holding the key semaphore. Instead,
an internal buffer is allocated for getting the keys out from the
read method first before copying them out to userspace without holding
the lock.
That requires taking out the __user modifier from the read methods as
well as additional changes to not use any userspace write helpers.
Signed-off-by: Waiman Long <longman@redhat.com>
---
include/linux/key-type.h | 2 +-
security/keys/big_key.c | 11 ++---
security/keys/encrypted-keys/encrypted.c | 7 ++-
security/keys/keyctl.c | 57 +++++++++++++++++++----
security/keys/keyring.c | 6 +--
security/keys/request_key_auth.c | 7 ++-
security/keys/trusted-keys/trusted_tpm1.c | 14 +-----
security/keys/user_defined.c | 5 +-
8 files changed, 65 insertions(+), 44 deletions(-)
diff --git a/include/linux/key-type.h b/include/linux/key-type.h
index 4ded94bcf274..2ab2d6d6aeab 100644
--- a/include/linux/key-type.h
+++ b/include/linux/key-type.h
@@ -127,7 +127,7 @@ struct key_type {
* much is copied into the buffer
* - shouldn't do the copy if the buffer is NULL
*/
- long (*read)(const struct key *key, char __user *buffer, size_t buflen);
+ long (*read)(const struct key *key, char *buffer, size_t buflen);
/* handle request_key() for this type instead of invoking
* /sbin/request-key (optional)
diff --git a/security/keys/big_key.c b/security/keys/big_key.c
index 001abe530a0d..82008f900930 100644
--- a/security/keys/big_key.c
+++ b/security/keys/big_key.c
@@ -352,7 +352,7 @@ void big_key_describe(const struct key *key, struct seq_file *m)
* read the key data
* - the key's semaphore is read-locked
*/
-long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
+long big_key_read(const struct key *key, char *buffer, size_t buflen)
{
size_t datalen = (size_t)key->payload.data[big_key_len];
long ret;
@@ -391,9 +391,8 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
ret = datalen;
- /* copy decrypted data to user */
- if (copy_to_user(buffer, buf->virt, datalen) != 0)
- ret = -EFAULT;
+ /* copy out decrypted data */
+ memcpy(buffer, buf->virt, datalen);
err_fput:
fput(file);
@@ -401,9 +400,7 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
big_key_free_buffer(buf);
} else {
ret = datalen;
- if (copy_to_user(buffer, key->payload.data[big_key_data],
- datalen) != 0)
- ret = -EFAULT;
+ memcpy(buffer, key->payload.data[big_key_data], datalen);
}
return ret;
diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
index 60720f58cbe0..f6797ba44bf7 100644
--- a/security/keys/encrypted-keys/encrypted.c
+++ b/security/keys/encrypted-keys/encrypted.c
@@ -902,14 +902,14 @@ static int encrypted_update(struct key *key, struct key_preparsed_payload *prep)
}
/*
- * encrypted_read - format and copy the encrypted data to userspace
+ * encrypted_read - format and copy out the encrypted data
*
* The resulting datablob format is:
* <master-key name> <decrypted data length> <encrypted iv> <encrypted data>
*
* On success, return to userspace the encrypted key datablob size.
*/
-static long encrypted_read(const struct key *key, char __user *buffer,
+static long encrypted_read(const struct key *key, char *buffer,
size_t buflen)
{
struct encrypted_key_payload *epayload;
@@ -957,8 +957,7 @@ static long encrypted_read(const struct key *key, char __user *buffer,
key_put(mkey);
memzero_explicit(derived_key, sizeof(derived_key));
- if (copy_to_user(buffer, ascii_buf, asciiblob_len) != 0)
- ret = -EFAULT;
+ memcpy(buffer, ascii_buf, asciiblob_len);
kzfree(ascii_buf);
return asciiblob_len;
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 9b898c969558..81f68e434b9f 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -797,6 +797,21 @@ long keyctl_keyring_search(key_serial_t ringid,
return ret;
}
+/*
+ * Call the read method
+ */
+static long __keyctl_read_key(struct key *key, char *buffer, size_t buflen)
+{
+ long ret;
+
+ down_read(&key->sem);
+ ret = key_validate(key);
+ if (ret == 0)
+ ret = key->type->read(key, buffer, buflen);
+ up_read(&key->sem);
+ return ret;
+}
+
/*
* Read a key's payload.
*
@@ -844,16 +859,42 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
/* the key is probably readable - now try to read it */
can_read_key:
- ret = -EOPNOTSUPP;
- if (key->type->read) {
- /* Read the data with the semaphore held (since we might sleep)
+ if (!key->type->read) {
+ ret = -EOPNOTSUPP;
+ goto error2;
+ }
+
+ if (!buffer || !buflen) {
+ /* Get the key length from the read method */
+ ret = __keyctl_read_key(key, NULL, 0);
+ } else {
+
+ /*
+ * Read the data with the semaphore held (since we might sleep)
* to protect against the key being updated or revoked.
+ *
+ * Allocating a temporary buffer to hold the keys before
+ * transferring them to user buffer to avoid potential
+ * deadlock involving page fault and mmap_sem.
+ */
+ char *tmpbuf = kmalloc(buflen, GFP_KERNEL);
+
+ if (!tmpbuf) {
+ ret = -ENOMEM;
+ goto error2;
+ }
+ ret = __keyctl_read_key(key, tmpbuf, buflen);
+
+ /*
+ * Read methods will just return the required length
+ * without any copying if the provided length isn't big
+ * enough.
*/
- down_read(&key->sem);
- ret = key_validate(key);
- if (ret == 0)
- ret = key->type->read(key, buffer, buflen);
- up_read(&key->sem);
+ if ((ret > 0) && (ret <= buflen)) {
+ if (copy_to_user(buffer, tmpbuf, ret))
+ ret = -EFAULT;
+ }
+ kzfree(tmpbuf);
}
error2:
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index febf36c6ddc5..5ca620d31cd3 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -459,7 +459,6 @@ static int keyring_read_iterator(const void *object, void *data)
{
struct keyring_read_iterator_context *ctx = data;
const struct key *key = keyring_ptr_to_key(object);
- int ret;
kenter("{%s,%d},,{%zu/%zu}",
key->type->name, key->serial, ctx->count, ctx->buflen);
@@ -467,10 +466,7 @@ static int keyring_read_iterator(const void *object, void *data)
if (ctx->count >= ctx->buflen)
return 1;
- ret = put_user(key->serial, ctx->buffer);
- if (ret < 0)
- return ret;
- ctx->buffer++;
+ *ctx->buffer++ = key->serial;
ctx->count += sizeof(key->serial);
return 0;
}
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index ecba39c93fd9..41e9735006d0 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -22,7 +22,7 @@ static int request_key_auth_instantiate(struct key *,
static void request_key_auth_describe(const struct key *, struct seq_file *);
static void request_key_auth_revoke(struct key *);
static void request_key_auth_destroy(struct key *);
-static long request_key_auth_read(const struct key *, char __user *, size_t);
+static long request_key_auth_read(const struct key *, char *, size_t);
/*
* The request-key authorisation key type definition.
@@ -80,7 +80,7 @@ static void request_key_auth_describe(const struct key *key,
* - the key's semaphore is read-locked
*/
static long request_key_auth_read(const struct key *key,
- char __user *buffer, size_t buflen)
+ char *buffer, size_t buflen)
{
struct request_key_auth *rka = dereference_key_locked(key);
size_t datalen;
@@ -97,8 +97,7 @@ static long request_key_auth_read(const struct key *key,
if (buflen > datalen)
buflen = datalen;
- if (copy_to_user(buffer, rka->callout_info, buflen) != 0)
- ret = -EFAULT;
+ memcpy(buffer, rka->callout_info, buflen);
}
return ret;
diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c
index d2c5ec1e040b..8001ab07e63b 100644
--- a/security/keys/trusted-keys/trusted_tpm1.c
+++ b/security/keys/trusted-keys/trusted_tpm1.c
@@ -1130,11 +1130,10 @@ static int trusted_update(struct key *key, struct key_preparsed_payload *prep)
* trusted_read - copy the sealed blob data to userspace in hex.
* On success, return to userspace the trusted key datablob size.
*/
-static long trusted_read(const struct key *key, char __user *buffer,
+static long trusted_read(const struct key *key, char *buffer,
size_t buflen)
{
const struct trusted_key_payload *p;
- char *ascii_buf;
char *bufp;
int i;
@@ -1143,18 +1142,9 @@ static long trusted_read(const struct key *key, char __user *buffer,
return -EINVAL;
if (buffer && buflen >= 2 * p->blob_len) {
- ascii_buf = kmalloc_array(2, p->blob_len, GFP_KERNEL);
- if (!ascii_buf)
- return -ENOMEM;
-
- bufp = ascii_buf;
+ bufp = buffer;
for (i = 0; i < p->blob_len; i++)
bufp = hex_byte_pack(bufp, p->blob[i]);
- if (copy_to_user(buffer, ascii_buf, 2 * p->blob_len) != 0) {
- kzfree(ascii_buf);
- return -EFAULT;
- }
- kzfree(ascii_buf);
}
return 2 * p->blob_len;
}
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
index 6f12de4ce549..07d4287e9084 100644
--- a/security/keys/user_defined.c
+++ b/security/keys/user_defined.c
@@ -168,7 +168,7 @@ EXPORT_SYMBOL_GPL(user_describe);
* read the key data
* - the key's semaphore is read-locked
*/
-long user_read(const struct key *key, char __user *buffer, size_t buflen)
+long user_read(const struct key *key, char *buffer, size_t buflen)
{
const struct user_key_payload *upayload;
long ret;
@@ -181,8 +181,7 @@ long user_read(const struct key *key, char __user *buffer, size_t buflen)
if (buflen > upayload->datalen)
buflen = upayload->datalen;
- if (copy_to_user(buffer, upayload->data, buflen) != 0)
- ret = -EFAULT;
+ memcpy(buffer, upayload->data, buflen);
}
return ret;
--
2.18.1
^ permalink raw reply related
* [PATCH v3 2/3] KEYS: Avoid false positive ENOMEM error on key read
From: Waiman Long @ 2020-03-13 15:21 UTC (permalink / raw)
To: David Howells, Jarkko Sakkinen, James Morris, Serge E. Hallyn,
Mimi Zohar
Cc: keyrings, linux-kernel, linux-security-module, linux-integrity,
Sumit Garg, Jerry Snitselaar, Roberto Sassu, Eric Biggers,
Chris von Recklinghausen, Waiman Long
In-Reply-To: <20200313152102.1707-1-longman@redhat.com>
By allocating a kernel buffer with an user-supplied buffer length, it
is possible that a false positive ENOMEM error may be returned because
the user-supplied length is just too large even if the system do have
enough memory to hold the actual key data.
To reduce this possibility, we set a threshold (1024) over which we
do check the actual key length first before allocating a buffer of the
right size to hold it.
Signed-off-by: Waiman Long <longman@redhat.com>
---
security/keys/keyctl.c | 48 ++++++++++++++++++++++++++++++++----------
1 file changed, 37 insertions(+), 11 deletions(-)
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 81f68e434b9f..a05a4dd2f9ce 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -877,24 +877,50 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
* transferring them to user buffer to avoid potential
* deadlock involving page fault and mmap_sem.
*/
- char *tmpbuf = kmalloc(buflen, GFP_KERNEL);
-
- if (!tmpbuf) {
- ret = -ENOMEM;
- goto error2;
- }
- ret = __keyctl_read_key(key, tmpbuf, buflen);
+ char *tmpbuf = NULL;
+ size_t tmpbuflen = buflen;
/*
- * Read methods will just return the required length
- * without any copying if the provided length isn't big
- * enough.
+ * We don't want an erronous -ENOMEM error due to an
+ * arbitrary large user-supplied buflen. So if buflen
+ * exceeds a threshold (1024 bytes in this case), we call
+ * the read method twice. The first time to get the buffer
+ * length and the second time to read out the key data.
+ *
+ * N.B. All the read methods will return the required
+ * buffer length with a NULL input buffer or when
+ * the input buffer length isn't large enough.
*/
+ if (buflen <= 0x400) {
+allocbuf:
+ tmpbuf = kmalloc(tmpbuflen, GFP_KERNEL);
+ if (!tmpbuf) {
+ ret = -ENOMEM;
+ goto error2;
+ }
+ }
+
+ ret = __keyctl_read_key(key, tmpbuf, tmpbuflen);
if ((ret > 0) && (ret <= buflen)) {
+ /*
+ * It is possible, though unlikely, that the key
+ * changes in between the up_read->down_read period.
+ * If the key becomes longer, we will have to
+ * allocate a larger buffer and redo the key read
+ * again.
+ */
+ if (!tmpbuf || unlikely(ret > tmpbuflen)) {
+ if (unlikely(tmpbuf))
+ kzfree(tmpbuf);
+ tmpbuflen = ret;
+ goto allocbuf;
+ }
+
if (copy_to_user(buffer, tmpbuf, ret))
ret = -EFAULT;
}
- kzfree(tmpbuf);
+ if (tmpbuf)
+ kzfree(tmpbuf);
}
error2:
--
2.18.1
^ permalink raw reply related
* [PATCH v3 3/3] KEYS: Use kvmalloc() to better handle large buffer allocation
From: Waiman Long @ 2020-03-13 15:21 UTC (permalink / raw)
To: David Howells, Jarkko Sakkinen, James Morris, Serge E. Hallyn,
Mimi Zohar
Cc: keyrings, linux-kernel, linux-security-module, linux-integrity,
Sumit Garg, Jerry Snitselaar, Roberto Sassu, Eric Biggers,
Chris von Recklinghausen, Waiman Long
In-Reply-To: <20200313152102.1707-1-longman@redhat.com>
For large multi-page temporary buffer allocation, the security/keys
subsystem don't need contiguous physical pages. It will work perfectly
fine with virtually mapped pages.
Replace the kmalloc() call by kvmalloc() and provide a __kvzfree()
helper function to clear and free the kvmalloc'ed buffer. This will
reduce the chance of memory allocation failure just because of highly
fragmented pages.
Suggested-by: David Howells <dhowells@redhat.com>
Signed-off-by: Waiman Long <longman@redhat.com>
---
security/keys/internal.h | 14 ++++++++++++++
security/keys/keyctl.c | 10 +++++-----
2 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/security/keys/internal.h b/security/keys/internal.h
index ba3e2da14cef..855b11eb73ee 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -16,6 +16,8 @@
#include <linux/keyctl.h>
#include <linux/refcount.h>
#include <linux/compat.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
struct iovec;
@@ -349,4 +351,16 @@ static inline void key_check(const struct key *key)
#endif
+/*
+ * Helper function to clear and free a kvmalloc'ed memory object.
+ */
+static inline void __kvzfree(const void *addr, size_t len)
+{
+ if (is_vmalloc_addr(addr)) {
+ memset((void *)addr, 0, len);
+ vfree(addr);
+ } else {
+ kzfree(addr);
+ }
+}
#endif /* _INTERNAL_H */
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index a05a4dd2f9ce..878259cf35d5 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -339,7 +339,7 @@ long keyctl_update_key(key_serial_t id,
payload = NULL;
if (plen) {
ret = -ENOMEM;
- payload = kmalloc(plen, GFP_KERNEL);
+ payload = kvmalloc(plen, GFP_KERNEL);
if (!payload)
goto error;
@@ -360,7 +360,7 @@ long keyctl_update_key(key_serial_t id,
key_ref_put(key_ref);
error2:
- kzfree(payload);
+ __kvzfree(payload, plen);
error:
return ret;
}
@@ -893,7 +893,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
*/
if (buflen <= 0x400) {
allocbuf:
- tmpbuf = kmalloc(tmpbuflen, GFP_KERNEL);
+ tmpbuf = kvmalloc(tmpbuflen, GFP_KERNEL);
if (!tmpbuf) {
ret = -ENOMEM;
goto error2;
@@ -911,7 +911,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
*/
if (!tmpbuf || unlikely(ret > tmpbuflen)) {
if (unlikely(tmpbuf))
- kzfree(tmpbuf);
+ __kvzfree(tmpbuf, tmpbuflen);
tmpbuflen = ret;
goto allocbuf;
}
@@ -920,7 +920,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
ret = -EFAULT;
}
if (tmpbuf)
- kzfree(tmpbuf);
+ __kvzfree(tmpbuf, tmpbuflen);
}
error2:
--
2.18.1
^ permalink raw reply related
* [PATCH v3 0/3] KEYS: Read keys to internal buffer & then copy to userspace
From: Waiman Long @ 2020-03-13 15:20 UTC (permalink / raw)
To: David Howells, Jarkko Sakkinen, James Morris, Serge E. Hallyn,
Mimi Zohar
Cc: keyrings, linux-kernel, linux-security-module, linux-integrity,
Sumit Garg, Jerry Snitselaar, Roberto Sassu, Eric Biggers,
Chris von Recklinghausen, Waiman Long
v3:
- Reorganize the keyctl_read_key() code to make it more readable as
suggested by Jarkko Sakkinen.
- Add patch 3 to use kvmalloc() for safer large buffer allocation as
suggested by David Howells.
v2:
- Handle NULL buffer and buflen properly in patch 1.
- Fix a bug in big_key.c.
- Add patch 2 to handle arbitrary large user-supplied buflen.
The current security key read methods are called with the key semaphore
held. The methods then copy out the key data to userspace which is
subjected to page fault and may acquire the mmap semaphore. That can
result in circular lock dependency and hence a chance to get into
deadlock.
To avoid such a deadlock, an internal buffer is now allocated for getting
out the necessary data first. After releasing the key semaphore, the
key data are then copied out to userspace sidestepping the circular
lock dependency.
The keyutils test suite was run and the test passed with these patchset
applied without any falure.
Waiman Long (3):
KEYS: Don't write out to userspace while holding key semaphore
KEYS: Avoid false positive ENOMEM error on key read
KEYS: Use kvmalloc() to better handle large buffer allocation
include/linux/key-type.h | 2 +-
security/keys/big_key.c | 11 ++-
security/keys/encrypted-keys/encrypted.c | 7 +-
security/keys/internal.h | 14 ++++
security/keys/keyctl.c | 87 ++++++++++++++++++++---
security/keys/keyring.c | 6 +-
security/keys/request_key_auth.c | 7 +-
security/keys/trusted-keys/trusted_tpm1.c | 14 +---
security/keys/user_defined.c | 5 +-
9 files changed, 107 insertions(+), 46 deletions(-)
--
2.18.1
^ permalink raw reply
* Re: [PATCH v2 1/2] KEYS: Don't write out to userspace while holding key semaphore
From: Waiman Long @ 2020-03-13 13:29 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: David Howells, James Morris, Serge E. Hallyn, Mimi Zohar,
keyrings, linux-kernel, linux-security-module, linux-integrity,
Sumit Garg, Jerry Snitselaar, Roberto Sassu, Eric Biggers,
Chris von Recklinghausen
In-Reply-To: <20200313010425.GA11360@linux.intel.com>
On 3/12/20 9:04 PM, Jarkko Sakkinen wrote:
> On Sun, Mar 08, 2020 at 01:04:09PM -0400, Waiman Long wrote:
>> + /*
>> + * Read methods will just return the required length
>> + * without any copying if the provided length isn't big
>> + * enough.
>> + */
>> + if ((ret > 0) && (ret <= buflen) && buffer &&
>> + copy_to_user(buffer, tmpbuf, ret))
>> + ret = -EFAULT;
> Please, reorg and remove redundant parentheses:
>
> /*
> * Read methods will just return the required length
> * without any copying if the provided length isn't big
> * enough.
> */
> if (ret > 0 && ret <= buflen) {
> if (buffer && copy_to_user(buffer, tmpbuf, ret))
> ret = -EFAULT;
> }
>
> Now the comment is attached to the exact right thing. The previous
> organization is a pain to look at when backtracking commits for
> whatever reason in the future.
Yes, I can reorganize the code.
> I'm also wondering, would it be possible to rework the code in a way
> that you don't have check whether buffer is valid on a constant basis?
One way to do that is to extract the down_read/up_read block into a
helper function and then have 2 separate paths - one for length
retrieval and another one for reading the key. I think that will make
the code a bit easier easier to read.
Thanks,
Longman
^ permalink raw reply
* Re: [PATCH v2 1/2] KEYS: Don't write out to userspace while holding key semaphore
From: Jarkko Sakkinen @ 2020-03-13 1:04 UTC (permalink / raw)
To: Waiman Long
Cc: David Howells, James Morris, Serge E. Hallyn, Mimi Zohar,
keyrings, linux-kernel, linux-security-module, linux-integrity,
Sumit Garg, Jerry Snitselaar, Roberto Sassu, Eric Biggers,
Chris von Recklinghausen
In-Reply-To: <20200308170410.14166-2-longman@redhat.com>
On Sun, Mar 08, 2020 at 01:04:09PM -0400, Waiman Long wrote:
> + /*
> + * Read methods will just return the required length
> + * without any copying if the provided length isn't big
> + * enough.
> + */
> + if ((ret > 0) && (ret <= buflen) && buffer &&
> + copy_to_user(buffer, tmpbuf, ret))
> + ret = -EFAULT;
Please, reorg and remove redundant parentheses:
/*
* Read methods will just return the required length
* without any copying if the provided length isn't big
* enough.
*/
if (ret > 0 && ret <= buflen) {
if (buffer && copy_to_user(buffer, tmpbuf, ret))
ret = -EFAULT;
}
Now the comment is attached to the exact right thing. The previous
organization is a pain to look at when backtracking commits for
whatever reason in the future.
I'm also wondering, would it be possible to rework the code in a way
that you don't have check whether buffer is valid on a constant basis?
/Jarkko
^ permalink raw reply
* Re: [PATCH 01/14] VFS: Add additional RESOLVE_* flags [ver #18]
From: Jeremy Allison @ 2020-03-12 21:48 UTC (permalink / raw)
To: Stefan Metzmacher
Cc: Linus Torvalds, David Howells, Aleksa Sarai, Al Viro, Ian Kent,
Miklos Szeredi, Christian Brauner, Jann Horn, Darrick J. Wong,
Karel Zak, jlayton, Linux API, linux-fsdevel, LSM List,
Linux Kernel Mailing List, Ralph Böhme, Volker Lendecke
In-Reply-To: <8d24e9f6-8e90-96bb-6e98-035127af0327@samba.org>
On Thu, Mar 12, 2020 at 06:11:09PM +0100, Stefan Metzmacher wrote:
> Am 12.03.20 um 17:24 schrieb Linus Torvalds:
> > On Thu, Mar 12, 2020 at 2:08 AM Stefan Metzmacher <metze@samba.org> wrote:
> >>
> >> The whole discussion was triggered by the introduction of a completely
> >> new fsinfo() call:
> >>
> >> Would you propose to have 'at_flags' and 'resolve_flags' passed in here?
> >
> > Yes, I think that would be the way to go.
>
> Ok, that's also fine for me:-)
>
> >>> If we need linkat2() and friends, so be it. Do we?
> >>
> >> Yes, I'm going to propose something like this, as it would make the life
> >> much easier for Samba to have the new features available on all path
> >> based syscalls.
> >
> > Will samba actually use them? I think we've had extensions before that
> > weren't worth the non-portability pain?
>
> Yes, we're currently moving to the portable *at() calls as a start.
> And we already make use of Linux only feature for performance reasons
> in other places. Having the new resolve flags will make it possible to
> move some of the performance intensive work into non-linux specific
> modules as fallback.
>
> I hope that we'll use most of this through io_uring in the end,
> that's the reason Jens added the IORING_REGISTER_PERSONALITY feature
> used for IORING_OP_OPENAT2.
>
> > But yes, if we have a major package like samba use it, then by all
> > means let's add linkat2(). How many things are we talking about? We
> > have a number of system calls that do *not* take flags, but do do
> > pathname walking. I'm thinking things like "mkdirat()"?)
>
> I haven't looked them up in detail yet.
> Jeremy can you provide a list?
Fixing the flags argument on fchmodat() to actually *implement*
AT_SYMLINK_NOFOLLOW would be a good start :-).
As for the syscalls that don't have
flags I'm thinking of the things like:
getxattr/setxattr/removexattr just off the top of my head.
Jeremy.
^ permalink raw reply
* Re: [PATCH 01/14] VFS: Add additional RESOLVE_* flags [ver #18]
From: Al Viro @ 2020-03-12 19:37 UTC (permalink / raw)
To: Stefan Metzmacher
Cc: Linus Torvalds, David Howells, Aleksa Sarai, Ian Kent,
Miklos Szeredi, Christian Brauner, Jann Horn, Darrick J. Wong,
Karel Zak, jlayton, Linux API, linux-fsdevel, LSM List,
Linux Kernel Mailing List, Jeremy Allison, Ralph Böhme,
Volker Lendecke
In-Reply-To: <8d24e9f6-8e90-96bb-6e98-035127af0327@samba.org>
On Thu, Mar 12, 2020 at 06:11:09PM +0100, Stefan Metzmacher wrote:
> If that works safely for hardlinks and having another process doing a
> rename between openat2() and unlinkat(), we could try that.
>
> My initial naive idea was to have one syscall instead of
> linkat2/renameat3/unlinkat2.
>
> int xlinkat(int src_dfd, const char *src_path,
> int dst_dfd, const char *dst_path,
> const struct xlinkat_how *how, size_t how_size);
>
> struct xlinkat_how {
> __u64 src_at_flags;
> __u64 src_resolve_flags;
> __u64 dst_at_flags;
> __u64 dst_resolve_flags;
> __u64 rename_flags;
> __s32 src_fd;
> };
>
> With src_dfd=-1, src_path=NULL, how.src_fd = -1, this would be like
> linkat().
> With dst_dfd=-1, dst_path=NULL, it would be like unlinkat().
> Otherwise a renameat2().
>
> If how.src_fd is not -1, it would be checked to be the same path as
> specified by src_dfd and src_path.
"Checked" as in...? And is that the same path or another link to the
same object, or...?
The idea of dumping all 3 into the same syscall looks wrong - compare
the effects of link() and rename() on the opened files, for starters,
and try to come up with documentation for all of that. Multiplexors
tend to be very bad, in large part because they have so bloody
convoluted semantics...
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox