From patchwork Thu Mar 30 15:22:57 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Djalal Harouni X-Patchwork-Id: 9654447 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 439DF602BD for ; Thu, 30 Mar 2017 15:23:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 35BEA2852B for ; Thu, 30 Mar 2017 15:23:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2A60028556; Thu, 30 Mar 2017 15:23:50 +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=-4.1 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_MED, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.wl.linuxfoundation.org (Postfix) with SMTP id B722A2852B for ; Thu, 30 Mar 2017 15:23:48 +0000 (UTC) Received: (qmail 17816 invoked by uid 550); 30 Mar 2017 15:23:40 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Received: (qmail 17735 invoked from network); 30 Mar 2017 15:23:39 -0000 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=4ZryO4GGQT7MvIWcHZPGkSwEQh90612t4MeEcx2Cu2g=; b=hm0gURmkc8wilJokX1T2Wjus6EUpTGkwZ017VQFUE5ScNNQ/ssy6vCDOuTNyMgteTy /BmrNSwJlV5/+yk4qPQFCAuMkY8M9oYg5JaYHnf5QmQGfTruBAU80eXfFPvouW0Yx0z0 fcWO0aK2fuPW0HhC0AVVlmIS5TZUwOHnYwfA+ydbBMhXS+8vZwYFC8P18v/sWLQl1rPq A6+msz5fhUjZVgZotyMb3TUUe3f1kFMkb7x10QQgYYBt9kNJC+5p331/vh+gwZ6SlFsO 9RPLD13yWYYqeLRAuJ3eocHBv6ak1mgtp79cd8+sXso7jyDSAFdcGyMJHl1yTg5cdtVd pSKQ== 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=4ZryO4GGQT7MvIWcHZPGkSwEQh90612t4MeEcx2Cu2g=; b=cLzM7Mwud6GlfPHz+jb28CcGfqGAHmy5iA8TqK8dCg1/XKsRBJ5pCzVgsPNGaCmi5f RyWHXVul5hAR/4jH3dV5auY2zh+T39U0FsawwsZe0cm6+bOUEbsfBKu4Wf/UtRpEpUL5 Qz+/LIjqjtm1H4KI1I6hxE+++ROpavlgKN8ApKDKTbyPmtWVYJOF6/elc/4KTH7MDM2Q NGxpcw7qQhpKqc2mC16Rv7C28JlLQeBMenBhxv5LFZ6V3eDYhPmbGxTgNCc6NorKj3CT V0W2/lRVGjV+tCMnDh2ed4bHvuEA/duKCnDRhtpXpFtytH9XcvcXqK7Hr40i5sXxrzM6 m5Tg== X-Gm-Message-State: AFeK/H2AIY3uwXigiqJTTx3I2lS3FnL3o8TaNJIgXUu85PgnfTg+sJ50jRuxBw3BIciqzQ== X-Received: by 10.28.141.201 with SMTP id p192mr4108456wmd.66.1490887407912; Thu, 30 Mar 2017 08:23:27 -0700 (PDT) From: Djalal Harouni To: Linux Kernel Mailing List , Andy Lutomirski , Alexey Gladkov , Al Viro , , Andrew Morton Cc: Linux API , , Oleg Nesterov , Pavel Emelyanov , James Bottomley , Kees Cook , Dongsu Park , Ingo Molnar , Michal Hocko , Alexey Dobriyan , kernel-hardening@lists.openwall.com, linux-security-module@vger.kernel.org, Djalal Harouni Date: Thu, 30 Mar 2017 17:22:57 +0200 Message-Id: <1490887379-25880-3-git-send-email-tixxdz@gmail.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1490887379-25880-1-git-send-email-tixxdz@gmail.com> References: <1490887379-25880-1-git-send-email-tixxdz@gmail.com> Subject: [kernel-hardening] [PATCH RFC 2/4] proc: add helpers to set/get hidepid and gid mount options X-Virus-Scanned: ClamAV using ClamSMTP This is a preparation patch to allow to set and get hidepid and gid mount options correctly Signed-off-by: Djalal Harouni --- fs/proc/base.c | 15 +++++++++------ fs/proc/generic.c | 37 +++++++++++++++++++++++++++++++++++++ fs/proc/inode.c | 5 +++-- fs/proc/internal.h | 2 +- fs/proc/root.c | 13 ++++++++----- include/linux/proc_fs.h | 35 ++++++++++++++++++++++++++++++++--- 6 files changed, 90 insertions(+), 17 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index cd16979..fd16566 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -681,13 +681,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_get_hide_pid(fs_info); + kgid_t gid = proc_fs_get_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); } @@ -703,7 +706,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) { @@ -1745,7 +1748,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, @@ -3179,7 +3182,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/generic.c b/fs/proc/generic.c index 49c8cb9..7e5e419 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,42 @@ struct proc_fs_info *proc_sb(struct super_block *sb) return sb->s_fs_info; } +void proc_fs_set_hide_pid(struct proc_fs_info *fs_info, int hide_pid) +{ + /* For backward compatibility */ + if (fs_info->version == PROC_FS_V1) + fs_info->pid_ns->hide_pid = hide_pid; + else if (fs_info->version == PROC_FS_V2) + fs_info->hide_pid = hide_pid; +} + +void proc_fs_set_pid_gid(struct proc_fs_info *fs_info, kgid_t gid) +{ + /* For backward compatibility */ + if (fs_info->version == PROC_FS_V1) + fs_info->pid_ns->pid_gid = gid; + else if (fs_info->version == PROC_FS_V2) + fs_info->pid_gid = gid; +} + +int proc_fs_get_hide_pid(struct proc_fs_info *fs_info) +{ + /* For backward compatibility */ + if (fs_info->version == PROC_FS_V1) + return fs_info->pid_ns->hide_pid; + + return fs_info->hide_pid; +} + +kgid_t proc_fs_get_pid_gid(struct proc_fs_info *fs_info) +{ + /* For backward compatibility */ + if (fs_info->version == PROC_FS_V1) + return fs_info->pid_ns->pid_gid; + + return fs_info->pid_gid; +} + static int proc_match(unsigned int len, const char *name, struct proc_dir_entry *de) { if (len < de->namelen) diff --git a/fs/proc/inode.c b/fs/proc/inode.c index e708288..ca47a0a 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -475,11 +475,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 c5ae09b..126fa31 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -261,7 +261,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 a683e93..6a96c02 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -36,11 +36,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; @@ -56,7 +57,8 @@ 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); + proc_fs_set_pid_gid(fs_info, gid); break; case Opt_hidepid: if (match_int(&args[0], &option)) @@ -66,7 +68,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\" " @@ -81,10 +83,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) @@ -130,6 +131,8 @@ static struct dentry *proc_mount(struct file_system_type *fs_type, fs_info->pid_ns = ns; fs_info->version = PROC_FS_V1; + fs_info->hide_pid = HIDEPID_OFF; + fs_info->pid_gid = GLOBAL_ROOT_GID; refcount_set(&fs_info->users, 1); sb = sget_userns(fs_type, proc_test_super, proc_set_super, flags, diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index e1cb9c3..c23299d 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -9,8 +9,8 @@ #include enum { - PROC_FS_V1 = 1, - PROC_FS_V2 = 2, + PROC_FS_V1 = 1, /* Inside same pidns procfs mounts are shared */ + PROC_FS_V2 = 2, /* New procfs mounts are separated by default */ }; struct proc_fs_info { @@ -27,6 +27,13 @@ struct proc_dir_entry; extern struct proc_fs_info *proc_sb(struct super_block *sb); +extern void proc_fs_set_hide_pid(struct proc_fs_info *fs_info, int hide_pid); + +extern void proc_fs_set_pid_gid(struct proc_fs_info *fs_info, kgid_t gid); + +extern int proc_fs_get_hide_pid(struct proc_fs_info *fs_info); +extern kgid_t proc_fs_get_pid_gid(struct proc_fs_info *fs_info); + extern void proc_root_init(void); extern void proc_flush_task(struct task_struct *); @@ -38,7 +45,7 @@ extern struct proc_dir_entry *proc_mkdir_data(const char *, umode_t, extern struct proc_dir_entry *proc_mkdir_mode(const char *, umode_t, struct proc_dir_entry *); struct proc_dir_entry *proc_create_mount_point(const char *name); - + extern struct proc_dir_entry *proc_create_data(const char *, umode_t, struct proc_dir_entry *, const struct file_operations *, @@ -69,6 +76,28 @@ 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_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_get_hide_pid(struct proc_fs_info *fs_info) +{ + return 0; +} + +extern kgid_t proc_fs_get_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;}