From patchwork Thu Nov 9 16:14:02 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Djalal Harouni X-Patchwork-Id: 10051237 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id E630860381 for ; Thu, 9 Nov 2017 16:17:03 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D5DF92AFAB for ; Thu, 9 Nov 2017 16:17:03 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CA1532AFC0; Thu, 9 Nov 2017 16:17:03 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 16A182AFAB for ; Thu, 9 Nov 2017 16:17:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753436AbdKIQRA (ORCPT ); Thu, 9 Nov 2017 11:17:00 -0500 Received: from mail-wm0-f66.google.com ([74.125.82.66]:52066 "EHLO mail-wm0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753364AbdKIQO3 (ORCPT ); Thu, 9 Nov 2017 11:14:29 -0500 Received: by mail-wm0-f66.google.com with SMTP id b9so18867706wmh.0; Thu, 09 Nov 2017 08:14:28 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=CXPk4nAwpsApuGWflheGU19XJiL+cf8dVjjL2ghiGsg=; b=n7ejZLMYXnjEK5mP+0HxfJ1palonYOEMxFemw9AW3+KpwVHStr+snwNy7iygns1Fzi k2Bswp03IBmxkeh7tLuO9V9ZLU/V+pS/KUrgJJaCLHDpUPIxnQj26EqjtvsQHshhd7J5 hRldbbc1bSOXGQmVhObDj8bJQOwaFZboI5v5YXhag5rXSGYrcO4CmoAQgCQEcgBiP+v0 sR9Rykb97vaFhKCZaSaXgbYPkHaab6D3SB6OdDRoHKNnoJiTownjH6VtI20bBrb/YDyT S4Xdch+R0ez0lCwKmV05E1hd9WjkFyIkA5S1I1343OYYO4tAAeSu0xgDVOm2wDiWy2Fi +aQA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=CXPk4nAwpsApuGWflheGU19XJiL+cf8dVjjL2ghiGsg=; b=sC7pYle0g+BCHkPyFJO3HvBNNSQjevIqi0LR2TJkpT+A/bi3lW+D950F8Bz043lp78 CHSqUTKqBJTR00tByE5Q8iJX7SQuExVFtP2+czYfcQ6d65j9xj+k1XnkFpmgcfQYCcxH B5drcMXoskxLrKmf/sdI3VssE8vFNAhQ36+xAZsRqsw5sxOEN25utgHdLhW3kVs0Hi3B lmr1butVi7yOpkjWROZLTcxCQQJvImFCmT0iwm9LDRtLA+u6b1ffDuyGN+C8/zjhqEIr ziUb5GQUsRvuHl1dx8BFJzC4WZLbPF1Q003/NqnhZGjPE+ewS6ZtwV77BMHXgHxduC96 gyTQ== X-Gm-Message-State: AJaThX6D4cVrYpAd5jlZjN4stL96+8HDRBouo316aiXjN4Thud8yZsNu gJTOrd7HGZY10C1ZssdRFzI= X-Google-Smtp-Source: ABhQp+Q6mNBbVoWO10AFqUPuZ4/c8ri2OtzumHAajm9wfa7BWaQyXWGbGyduXMgKetiPr7VlIJE5Ng== X-Received: by 10.80.211.18 with SMTP id g18mr1320734edh.85.1510244067402; Thu, 09 Nov 2017 08:14:27 -0800 (PST) Received: from localhost.localdomain (ip-109-45-0-227.web.vodafone.de. [109.45.0.227]) by smtp.gmail.com with ESMTPSA id d3sm5826085edd.41.2017.11.09.08.14.25 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 09 Nov 2017 08:14:26 -0800 (PST) From: Djalal Harouni To: Kees Cook , Alexey Gladkov , Andy Lutomirski , Andrew Morton , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, kernel-hardening@lists.openwall.com, linux-security-module@vger.kernel.org, linux-api@vger.kernel.org Cc: Greg Kroah-Hartman , Alexander Viro , Akinobu Mita , me@tobin.cc, Oleg Nesterov , Jeff Layton , Ingo Molnar , Alexey Dobriyan , ebiederm@xmission.com, Linus Torvalds , Daniel Micay , Jonathan Corbet , bfields@fieldses.org, Stephen Rothwell , solar@openwall.com, Djalal Harouni Subject: [PATCH RFC v3 3/7] proc: add helpers to set and get proc hidepid and gid mount options Date: Thu, 9 Nov 2017 17:14:02 +0100 Message-Id: <1510244046-3256-4-git-send-email-tixxdz@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1510244046-3256-1-git-send-email-tixxdz@gmail.com> References: <1510244046-3256-1-git-send-email-tixxdz@gmail.com> Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP This is a cleaning patch to add helpers to set and get proc mount options instead of a direct access. This allows later to easily track what's happening, how these fields are accessed, and in case we need to update them in the future. Later we will move these mount options to proc_fs_info struct. First lets fix the access. 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 | 16 +++++++++------- fs/proc/inode.c | 5 +++-- fs/proc/internal.h | 2 +- fs/proc/root.c | 15 ++++++++++----- include/linux/proc_fs.h | 44 ++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 65 insertions(+), 17 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 0d9b4214..f324c49 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -682,13 +682,16 @@ 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) + 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 (in_group_p(pid->pid_gid)) + if (in_group_p(gid)) return true; return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); } @@ -704,7 +707,7 @@ static int proc_pid_permission(struct inode *inode, int mask) 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) { @@ -1778,7 +1781,6 @@ int pid_getattr(const struct path *path, struct kstat *stat, struct task_struct *task; struct inode *inode = d_inode(path->dentry); struct proc_fs_info *fs_info = proc_sb(inode->i_sb); - struct pid_namespace *pid = fs_info->pid_ns; generic_fillattr(inode, stat); @@ -1787,7 +1789,7 @@ int pid_getattr(const struct path *path, struct kstat *stat, stat->gid = GLOBAL_ROOT_GID; 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, @@ -3234,7 +3236,7 @@ int proc_pid_readdir(struct file *file, struct dir_context *ctx) 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), "%d", iter.tgid); diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 9abc370..bdd808d 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -476,11 +476,12 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de) int proc_fill_super(struct super_block *s, void *data, int silent) { struct proc_fs_info *fs_info = proc_sb(s); - struct pid_namespace *ns = get_pid_ns(fs_info->pid_ns); struct inode *root_inode; int ret; - if (!proc_parse_options(data, ns)) + get_pid_ns(fs_info->pid_ns); + + if (!proc_parse_options(data, fs_info)) return -EINVAL; /* User space would break if executables or devices appear on proc */ diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 4a67188..10bc7be 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -240,7 +240,7 @@ static inline void proc_tty_init(void) {} * root.c */ extern struct proc_dir_entry proc_root; -extern int proc_parse_options(char *options, struct pid_namespace *pid); +extern int proc_parse_options(char *options, struct proc_fs_info *fs_info); extern void proc_self_init(void); extern int proc_remount(struct super_block *, int *, char *); diff --git a/fs/proc/root.c b/fs/proc/root.c index b225ae5..48cc481 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -37,11 +37,12 @@ static const match_table_t tokens = { {Opt_err, NULL}, }; -int proc_parse_options(char *options, struct pid_namespace *pid) +int proc_parse_options(char *options, struct proc_fs_info *fs_info) { char *p; substring_t args[MAX_OPT_ARGS]; int option; + kgid_t gid; if (!options) return 1; @@ -57,7 +58,12 @@ int proc_parse_options(char *options, struct pid_namespace *pid) case Opt_gid: if (match_int(&args[0], &option)) return 0; - pid->pid_gid = make_kgid(current_user_ns(), option); + gid = make_kgid(current_user_ns(), option); + if (!gid_valid(gid)) { + pr_err("proc: invalid gid mount option.\n"); + return 0; + } + proc_fs_set_pid_gid(fs_info, gid); break; case Opt_hidepid: if (match_int(&args[0], &option)) @@ -67,7 +73,7 @@ int proc_parse_options(char *options, struct pid_namespace *pid) pr_err("proc: hidepid value must be between 0 and 2.\n"); return 0; } - pid->hide_pid = option; + proc_fs_set_hide_pid(fs_info, option); break; default: pr_err("proc: unrecognized mount option \"%s\" " @@ -82,10 +88,9 @@ int proc_parse_options(char *options, struct pid_namespace *pid) int proc_remount(struct super_block *sb, int *flags, char *data) { struct proc_fs_info *fs_info = proc_sb(sb); - struct pid_namespace *pid = fs_info->pid_ns; sync_filesystem(sb); - return !proc_parse_options(data, pid); + return !proc_parse_options(data, fs_info); } static int proc_test_super(struct super_block *s, void *data) diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 8f89069..047d0d0 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -7,6 +7,10 @@ #include #include +#include + +struct proc_dir_entry; +struct pid_namespace; struct proc_fs_info { struct pid_namespace *pid_ns; @@ -14,8 +18,6 @@ struct proc_fs_info { struct dentry *proc_thread_self; /* For /proc/thread-self/ */ }; -struct proc_dir_entry; - #ifdef CONFIG_PROC_FS static inline struct proc_fs_info *proc_sb(struct super_block *sb) @@ -23,6 +25,26 @@ static inline struct proc_fs_info *proc_sb(struct super_block *sb) return sb->s_fs_info; } +static inline void proc_fs_set_hide_pid(struct proc_fs_info *fs_info, int hide_pid) +{ + fs_info->pid_ns->hide_pid = hide_pid; +} + +static inline void proc_fs_set_pid_gid(struct proc_fs_info *fs_info, kgid_t gid) +{ + fs_info->pid_ns->pid_gid = gid; +} + +static inline int proc_fs_hide_pid(struct proc_fs_info *fs_info) +{ + return fs_info->pid_ns->hide_pid; +} + +static inline kgid_t proc_fs_pid_gid(struct proc_fs_info *fs_info) +{ + return fs_info->pid_ns->pid_gid; +} + extern void proc_root_init(void); extern void proc_flush_task(struct task_struct *); @@ -59,6 +81,24 @@ static inline void proc_flush_task(struct task_struct *task) { } +static inline void proc_fs_set_hide_pid(struct proc_fs_info *fs_info, int hide_pid) +{ +} + +static inline void proc_fs_set_pid_gid(struct proc_info_fs *fs_info, kgid_t gid) +{ +} + +static inline int proc_fs_hide_pid(struct proc_fs_info *fs_info) +{ + return 0; +} + +extern kgid_t proc_fs_pid_gid(struct proc_fs_info *fs_info) +{ + return GLOBAL_ROOT_GID; +} + extern inline struct proc_fs_info *proc_sb(struct super_block *sb) { return NULL;} static inline struct proc_dir_entry *proc_symlink(const char *name, struct proc_dir_entry *parent,const char *dest) { return NULL;}