> From: Tim Newsham <[email protected]>
> Date: Fri, 22 Jul 2016 08:32:04 +0000
>
> Here's a new one we just found:
>
> /*
> * sysctl_tmpfs_panic.c
> * Demonstrate a panic in UFS through the getdents system call.
> *
> * gcc -g sysctl_tmpfs_panic.c -o sysctl_tmpfs_panic
> */
>
> #ifdef BUG_WRITEUP //---------------------------------------------------
> Any user can panic the kernel with the sysctl call.
>
> Impact:
> Any user can panic the kernel by using the sysctl call. If a
> user can manage to map a page at address zero, they may be able
> to gain kernel code execution and escalate privileges.
>
> Description:
> When processing sysctl calls, OpenBSD dispatches through a number
> of intermediate helper functions. For example, if the first integer
> in the path is 10, sys_sysctl() will call through vfs_sysctl() for
> further processing. vfs_sysctl() performs a table lookup based on
> the second byte, and if the byte is 19, it selects the tmpfs_vfsops
> table and dispatches further processing through the vfs_sysctl method:
>
> if (name[0] != VFS_GENERIC) {
> for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
> if (vfsp->vfc_typenum == name[0])
> break;
>
> if (vfsp == NULL)
> return (EOPNOTSUPP);
>
> return ((*vfsp->vfc_vfsops->vfs_sysctl)(&name[1], namelen - 1,
> oldp, oldlenp, newp, newlen, p));
> }
>
> Unfortunately, the definition for tmpfs_vfsops leaves this method NULL:
>
> struct vfsops tmpfs_vfsops = {
> tmpfs_mount, /* vfs_mount */
> tmpfs_start, /* vfs_start */
> tmpfs_unmount, /* vfs_unmount */
> tmpfs_root, /* vfs_root */
> (void *)eopnotsupp, /* vfs_quotactl */
> tmpfs_statfs, /* vfs_statfs */
> tmpfs_sync, /* vfs_sync */
> tmpfs_vget, /* vfs_vget */
> tmpfs_fhtovp, /* vfs_fhtovp */
> tmpfs_vptofh, /* vfs_vptofh */
> tmpfs_init, /* vfs_init */
> NULL, /* vfs_sysctl */
> (void *)eopnotsupp,
> };
>
> Trying to read or write a sysctl path starting with (10,19) results
> in a NULL pointer access and a panic of
> "attempt to execute user address 0x0 in supervisor mode".
> Since any user can perform a sysctl read, this issue can be abused
> by any logged in user to panic the system.
>
> OpenBSD intentionally prevents users from attempting to map a page
> at the NULL address. If an attacker is able to get such a mapping,
> they may be able to cause the kernel to jump to code mapped at this
> address (if other security protections such as SMEP aren't in place).
> This would allow an attacker to gain kernel code execution and
> escalate their privileges.
>
> Reproduction:
> Run the attached sysctl_tmpfs_panic.c program. It will pccess
> the (10,19,0) sysctl path and trigger a panic of
> "attempt to execute user address 0x0 in supervisor mode".
> NCC Group was able to reproduce this issue on OpenBSD 5.9 release
> running amd64.
>
> Recommendation:
> Include a NULL-pointer check in vfs_sysctl() before dispatching to
> the vfs_sysctl method. Alternately, include a vfs_sysctl method
> in the tmpfs_vfsops table.
Thanks Tim,
I'd say adding the check in vfs_sysctl() is the way to go as this will
prevent this from happening again in the future.
ok?
Index: vfs_subr.c
===================================================================
RCS file: /cvs/src/sys/kern/vfs_subr.c,v
retrieving revision 1.248
diff -u -p -r1.248 vfs_subr.c
--- vfs_subr.c 19 Jun 2016 11:54:33 -0000 1.248
+++ vfs_subr.c 22 Jul 2016 09:23:52 -0000
@@ -1290,7 +1290,7 @@ vfs_sysctl(int *name, u_int namelen, voi
if (vfsp->vfc_typenum == name[0])
break;
- if (vfsp == NULL)
+ if (vfsp == NULL || vfsp->vfc_vfsops->vfs_sysctl == NULL)
return (EOPNOTSUPP);
return ((*vfsp->vfc_vfsops->vfs_sysctl)(&name[1], namelen - 1,