Re: [PATCH RFC v3 6/7] proc: support new 'pids=all|ptraceable' mount option
On Fri, Nov 10, 2017 at 3:38 AM, Andy Lutomirskiwrote: > On Thu, Nov 9, 2017 at 8:14 AM, Djalal Harouni wrote: >> This patch introduces the new 'pids' mount option, as it was discussed >> and suggested by Andy Lutomirski [1]. >> >> * If 'pids=' is passed without 'newinstance' then it has no effect. > > Would it be safer this were an error instead? Hm, I tend to say that you are right, but I also keep your comment when you said that "newinstance" should be the default later and users won't have to explicitly pass it. What you think ? -- tixxdz
Re: [PATCH RFC v3 6/7] proc: support new 'pids=all|ptraceable' mount option
On Fri, Nov 10, 2017 at 3:38 AM, Andy Lutomirski wrote: > On Thu, Nov 9, 2017 at 8:14 AM, Djalal Harouni wrote: >> This patch introduces the new 'pids' mount option, as it was discussed >> and suggested by Andy Lutomirski [1]. >> >> * If 'pids=' is passed without 'newinstance' then it has no effect. > > Would it be safer this were an error instead? Hm, I tend to say that you are right, but I also keep your comment when you said that "newinstance" should be the default later and users won't have to explicitly pass it. What you think ? -- tixxdz
Re: [PATCH RFC v3 6/7] proc: support new 'pids=all|ptraceable' mount option
On Thu, 9 Nov 2017, Djalal Harouni wrote: > This patch introduces the new 'pids' mount option, as it was discussed > and suggested by Andy Lutomirski [1]. > > * If 'pids=' is passed without 'newinstance' then it has no effect. > > * If 'newinstance,pids=all' then all processes will be shown in proc. > > * If 'newinstance,pids=ptraceable' then only ptraceable processes will be > shown. > > * 'pids=' takes precendence over 'hidepid=' since 'hidepid=' can be > ignored if "gid=" was set and caller has the "gid=" set in its groups. > We want to guarantee that LSM have a security path there that can not > be disabled with "gid=". > > This allows to support lightweight sandboxes in Embedded Linux. > > Later Yama LSM can be updated to check that processes are able only > able to see their children inside /proc/, allowing to support more tight > cases. > > [1] https://lkml.org/lkml/2017/4/26/646 > > Cc: Kees Cook> Cc: Greg Kroah-Hartman > Suggested-by: Andy Lutomirski > Signed-off-by: Alexey Gladkov > Signed-off-by: Djalal Harouni Reviewed-by: James Morris -- James Morris
Re: [PATCH RFC v3 6/7] proc: support new 'pids=all|ptraceable' mount option
On Thu, 9 Nov 2017, Djalal Harouni wrote: > This patch introduces the new 'pids' mount option, as it was discussed > and suggested by Andy Lutomirski [1]. > > * If 'pids=' is passed without 'newinstance' then it has no effect. > > * If 'newinstance,pids=all' then all processes will be shown in proc. > > * If 'newinstance,pids=ptraceable' then only ptraceable processes will be > shown. > > * 'pids=' takes precendence over 'hidepid=' since 'hidepid=' can be > ignored if "gid=" was set and caller has the "gid=" set in its groups. > We want to guarantee that LSM have a security path there that can not > be disabled with "gid=". > > This allows to support lightweight sandboxes in Embedded Linux. > > Later Yama LSM can be updated to check that processes are able only > able to see their children inside /proc/, allowing to support more tight > cases. > > [1] https://lkml.org/lkml/2017/4/26/646 > > Cc: Kees Cook > Cc: Greg Kroah-Hartman > Suggested-by: Andy Lutomirski > Signed-off-by: Alexey Gladkov > Signed-off-by: Djalal Harouni Reviewed-by: James Morris -- James Morris
Re: [PATCH RFC v3 6/7] proc: support new 'pids=all|ptraceable' mount option
On Thu, Nov 9, 2017 at 8:14 AM, Djalal Harouniwrote: > This patch introduces the new 'pids' mount option, as it was discussed > and suggested by Andy Lutomirski [1]. > > * If 'pids=' is passed without 'newinstance' then it has no effect. Would it be safer this were an error instead?
Re: [PATCH RFC v3 6/7] proc: support new 'pids=all|ptraceable' mount option
On Thu, Nov 9, 2017 at 8:14 AM, Djalal Harouni wrote: > This patch introduces the new 'pids' mount option, as it was discussed > and suggested by Andy Lutomirski [1]. > > * If 'pids=' is passed without 'newinstance' then it has no effect. Would it be safer this were an error instead?
[PATCH RFC v3 6/7] proc: support new 'pids=all|ptraceable' mount option
This patch introduces the new 'pids' mount option, as it was discussed and suggested by Andy Lutomirski [1]. * If 'pids=' is passed without 'newinstance' then it has no effect. * If 'newinstance,pids=all' then all processes will be shown in proc. * If 'newinstance,pids=ptraceable' then only ptraceable processes will be shown. * 'pids=' takes precendence over 'hidepid=' since 'hidepid=' can be ignored if "gid=" was set and caller has the "gid=" set in its groups. We want to guarantee that LSM have a security path there that can not be disabled with "gid=". This allows to support lightweight sandboxes in Embedded Linux. Later Yama LSM can be updated to check that processes are able only able to see their children inside /proc/, allowing to support more tight cases. [1] https://lkml.org/lkml/2017/4/26/646 Cc: Kees CookCc: Greg Kroah-Hartman Suggested-by: Andy Lutomirski Signed-off-by: Alexey Gladkov Signed-off-by: Djalal Harouni --- fs/proc/base.c | 36 +--- fs/proc/inode.c | 6 +- fs/proc/root.c | 20 ++-- include/linux/proc_fs.h | 30 ++ 4 files changed, 82 insertions(+), 10 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 54b527c..88b92bc 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -686,13 +686,24 @@ static bool has_pid_permissions(struct proc_fs_info *fs_info, struct task_struct *task, int hide_pid_min) { - int hide_pid = proc_fs_hide_pid(fs_info); - kgid_t gid = proc_fs_pid_gid(fs_info); + int pids = proc_fs_pids(fs_info); + + /* +* If 'pids=all' or if it was not set then lets fallback +* to 'hidepid' and 'gid', if those are not enforced too, then +* ptrace checks are skipped. Otherwise ptrace permission is +* required for all other cases. +*/ + if (pids == PIDS_ALL) { + int hide_pid = proc_fs_hide_pid(fs_info); + kgid_t gid = proc_fs_pid_gid(fs_info); + + if (hide_pid < hide_pid_min) + return true; - if (hide_pid < hide_pid_min) - return true; - if (in_group_p(gid)) - return true; + if (in_group_p(gid)) + return true; + } return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); } @@ -701,6 +712,7 @@ static int proc_pid_permission(struct inode *inode, int mask) { struct proc_fs_info *fs_info = proc_sb(inode->i_sb); int hide_pid = proc_fs_hide_pid(fs_info); + int pids = proc_fs_pids(fs_info); struct task_struct *task; bool has_perms; @@ -711,7 +723,8 @@ static int proc_pid_permission(struct inode *inode, int mask) put_task_struct(task); if (!has_perms) { - if (hide_pid == HIDEPID_INVISIBLE) { + if (pids == PIDS_PTRACEABLE || + hide_pid == HIDEPID_INVISIBLE) { /* * Let's make getdents(), stat(), and open() * consistent with each other. If a process @@ -3140,6 +3153,7 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsign unsigned tgid; struct proc_fs_info *fs_info = proc_sb(dir->i_sb); struct pid_namespace *ns = fs_info->pid_ns; + int pids = proc_fs_pids(fs_info); tgid = name_to_int(>d_name); if (tgid == ~0U) @@ -3153,7 +3167,15 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsign if (!task) goto out; + /* Limit procfs to only ptraceable tasks */ + if (pids != PIDS_ALL) { + cond_resched(); + if (!has_pid_permissions(fs_info, task, HIDEPID_NO_ACCESS)) + goto out_put_task; + } + result = proc_pid_instantiate(dir, dentry, task, NULL); +out_put_task: put_task_struct(task); out: return ERR_PTR(result); diff --git a/fs/proc/inode.c b/fs/proc/inode.c index faec32a..2707d5f 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -108,8 +108,12 @@ static int proc_show_options(struct seq_file *seq, struct dentry *root) int hide_pid = proc_fs_hide_pid(fs_info); kgid_t pid_gid = proc_fs_pid_gid(fs_info); - if (proc_fs_newinstance(fs_info)) + if (proc_fs_newinstance(fs_info)) { + int pids = proc_fs_pids(fs_info); + seq_printf(seq, ",newinstance"); + seq_printf(seq, ",pids=%s", pids == PIDS_ALL ? "all" : "ptraceable"); + } if (!gid_eq(pid_gid, GLOBAL_ROOT_GID)) seq_printf(seq, ",gid=%u", from_kgid_munged(current_user_ns(),pid_gid)); diff --git a/fs/proc/root.c
[PATCH RFC v3 6/7] proc: support new 'pids=all|ptraceable' mount option
This patch introduces the new 'pids' mount option, as it was discussed and suggested by Andy Lutomirski [1]. * If 'pids=' is passed without 'newinstance' then it has no effect. * If 'newinstance,pids=all' then all processes will be shown in proc. * If 'newinstance,pids=ptraceable' then only ptraceable processes will be shown. * 'pids=' takes precendence over 'hidepid=' since 'hidepid=' can be ignored if "gid=" was set and caller has the "gid=" set in its groups. We want to guarantee that LSM have a security path there that can not be disabled with "gid=". This allows to support lightweight sandboxes in Embedded Linux. Later Yama LSM can be updated to check that processes are able only able to see their children inside /proc/, allowing to support more tight cases. [1] https://lkml.org/lkml/2017/4/26/646 Cc: Kees Cook Cc: Greg Kroah-Hartman Suggested-by: Andy Lutomirski Signed-off-by: Alexey Gladkov Signed-off-by: Djalal Harouni --- fs/proc/base.c | 36 +--- fs/proc/inode.c | 6 +- fs/proc/root.c | 20 ++-- include/linux/proc_fs.h | 30 ++ 4 files changed, 82 insertions(+), 10 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 54b527c..88b92bc 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -686,13 +686,24 @@ static bool has_pid_permissions(struct proc_fs_info *fs_info, struct task_struct *task, int hide_pid_min) { - int hide_pid = proc_fs_hide_pid(fs_info); - kgid_t gid = proc_fs_pid_gid(fs_info); + int pids = proc_fs_pids(fs_info); + + /* +* If 'pids=all' or if it was not set then lets fallback +* to 'hidepid' and 'gid', if those are not enforced too, then +* ptrace checks are skipped. Otherwise ptrace permission is +* required for all other cases. +*/ + if (pids == PIDS_ALL) { + int hide_pid = proc_fs_hide_pid(fs_info); + kgid_t gid = proc_fs_pid_gid(fs_info); + + if (hide_pid < hide_pid_min) + return true; - if (hide_pid < hide_pid_min) - return true; - if (in_group_p(gid)) - return true; + if (in_group_p(gid)) + return true; + } return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); } @@ -701,6 +712,7 @@ static int proc_pid_permission(struct inode *inode, int mask) { struct proc_fs_info *fs_info = proc_sb(inode->i_sb); int hide_pid = proc_fs_hide_pid(fs_info); + int pids = proc_fs_pids(fs_info); struct task_struct *task; bool has_perms; @@ -711,7 +723,8 @@ static int proc_pid_permission(struct inode *inode, int mask) put_task_struct(task); if (!has_perms) { - if (hide_pid == HIDEPID_INVISIBLE) { + if (pids == PIDS_PTRACEABLE || + hide_pid == HIDEPID_INVISIBLE) { /* * Let's make getdents(), stat(), and open() * consistent with each other. If a process @@ -3140,6 +3153,7 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsign unsigned tgid; struct proc_fs_info *fs_info = proc_sb(dir->i_sb); struct pid_namespace *ns = fs_info->pid_ns; + int pids = proc_fs_pids(fs_info); tgid = name_to_int(>d_name); if (tgid == ~0U) @@ -3153,7 +3167,15 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsign if (!task) goto out; + /* Limit procfs to only ptraceable tasks */ + if (pids != PIDS_ALL) { + cond_resched(); + if (!has_pid_permissions(fs_info, task, HIDEPID_NO_ACCESS)) + goto out_put_task; + } + result = proc_pid_instantiate(dir, dentry, task, NULL); +out_put_task: put_task_struct(task); out: return ERR_PTR(result); diff --git a/fs/proc/inode.c b/fs/proc/inode.c index faec32a..2707d5f 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -108,8 +108,12 @@ static int proc_show_options(struct seq_file *seq, struct dentry *root) int hide_pid = proc_fs_hide_pid(fs_info); kgid_t pid_gid = proc_fs_pid_gid(fs_info); - if (proc_fs_newinstance(fs_info)) + if (proc_fs_newinstance(fs_info)) { + int pids = proc_fs_pids(fs_info); + seq_printf(seq, ",newinstance"); + seq_printf(seq, ",pids=%s", pids == PIDS_ALL ? "all" : "ptraceable"); + } if (!gid_eq(pid_gid, GLOBAL_ROOT_GID)) seq_printf(seq, ",gid=%u", from_kgid_munged(current_user_ns(),pid_gid)); diff --git a/fs/proc/root.c b/fs/proc/root.c index 33ab965..5cdff69 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -28,13 +28,14 @@