oss-sec mailing list archives
Re: Linux kernel: no permission check during open() time of /proc/[pid]/maps in kernels < 3.18
From: Solar Designer <solar () openwall com>
Date: Thu, 25 Apr 2019 15:02:19 +0200
On Thu, Apr 25, 2019 at 02:12:36PM +0200, Matthias Gerstner wrote:
I stumbled over a leak of memory mappings for arbitrary processes in kernels older than version 3.18. As it turns out the permissions check for the pseudo file in /proc/[pid]/maps in affected kernels is performed not during open() time but during read() time. This allows an unprivileged user to open a valid file descriptor for these maps files and pass it to privileged programs like setuid root binaries or D-Bus services running as root that support file descriptor passing in their interface. The privileged program needs behave in a way that the passed file descriptor is read() with root premissions and the content is passed back to the unprivileged user in some way.
Looks like mostly a rediscovery of what was brought up in here by Jason A. Donenfeld and further discussed with Djalal Harouni in 2012: https://www.openwall.com/lists/oss-security/2012/02/08/2 and had already been fixed in grsecurity, given that I fixed it with: * Sat Feb 25 2012 Solar Designer <solar-at-owl.openwall.com> 2.6.18-274.18.1.el5.028stab098.1.owl1 [...] - Introduced protection against unintended self-read by a SUID/SGID program of /proc/<pid>/mem and /proc/<pid>/*maps files, based on approaches taken in recent grsecurity patches. +++ linux-2.6.18-431.el5.028stab123.1-owl/fs/proc/task_mmu.c 2018-05-20 16:37:29 +0000 @@ -166,7 +166,7 @@ static int show_map_internal(struct seq_ struct proc_maps_private *priv = m->private; struct task_struct *task = priv->task; #ifdef __i386__ - struct mm_struct *tmm = get_task_mm(task); + struct mm_struct *tmm; #endif struct vm_area_struct *vma = v; struct mm_struct *mm = vma->vm_mm; @@ -177,6 +177,13 @@ static int show_map_internal(struct seq_ dev_t dev = 0; int len; + if (current->exec_id != m->exec_id) + return 0; + +#ifdef __i386__ + tmm = get_task_mm(task); +#endif + if (file) { struct inode *inode = vma->vm_file->f_dentry->d_inode; dev = inode->i_sb->s_dev; Was this not fixed upstream until the permissions check on open() was added in 2014? I guess it also wasn't fixed in RHEL, since I carried the above patch hunk into 2018+ as you can see (or maybe it became redundant with RHEL's different fix for the issue - I don't recall). The idea of passing the fd to D-Bus services, etc. might be a new one, but the fix above should be sufficient against that as well due to the exec_id's being globally unique (except between fork-without-exec sibling processes): /* execve success */ + current->exec_id = atomic64_inc_return(&global_exec_counter); Alexander
Current thread:
- Linux kernel: no permission check during open() time of /proc/[pid]/maps in kernels < 3.18 Matthias Gerstner (Apr 25)
- Re: Linux kernel: no permission check during open() time of /proc/[pid]/maps in kernels < 3.18 Solar Designer (Apr 25)