userfaultfd: require CAP_SYS_PTRACE for UFFD_FEATURE_EVENT_FORK
Subsystems (2)
[email protected]
maintainerPATCH 149/158 userfaultfd: require CAP_SYS_PTRACE for UFFD_FEATURE_EVENT_FORK
From: Mike Rapoport <[email protected]>
Subject: userfaultfd: require CAP_SYS_PTRACE for UFFD_FEATURE_EVENT_FORK
A while ago Andy noticed
(http://lkml.kernel.org/r/CALCETrWY+5ynDct7eU_nDUqx=okQvjm=Y5wJvA4ahBja=CQXGw@mail.gmail.com)
that UFFD_FEATURE_EVENT_FORK used by an unprivileged user may have security implications.
As the first step of the solution the following patch limits the availably of UFFD_FEATURE_EVENT_FORK only for those having CAP_SYS_PTRACE.
The usage of CAP_SYS_PTRACE ensures compatibility with CRIU.
Yet, if there are other users of non-cooperative userfaultfd that run without CAP_SYS_PTRACE, they would be broken :(
Current implementation of UFFD_FEATURE_EVENT_FORK modifies the file descriptor table from the read() implementation of uffd, which may have security implications for unprivileged use of the userfaultfd.
Limit availability of UFFD_FEATURE_EVENT_FORK only for callers that have CAP_SYS_PTRACE.
---
fs/userfaultfd.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-)
fs/userfaultfd.c renamed from fs/userfaultfd.c~userfaultfd-require-cap_sys_ptrace-for-uffd_feature_event_fork +11 -7
@@ -1835,13 +1835,12 @@ static int userfaultfd_api(struct userfaif (copy_from_user (&uffdio_api, buf,sizeof (uffdio_api))) goto out; features = uffdio_api.features; -if (uffdio_api.api !=UFFD_API || (features & ~UFFD_API_FEATURES )) { -memset (&uffdio_api,0 ,sizeof (uffdio_api)); -if (copy_to_user (buf, &uffdio_api,sizeof (uffdio_api))) - goto out; - ret = -EINVAL ; - goto out; - } + ret = -EINVAL ; +if (uffdio_api.api !=UFFD_API || (features & ~UFFD_API_FEATURES )) + goto err_out; + ret = -EPERM ; +if ((features &UFFD_FEATURE_EVENT_FORK ) && !capable (CAP_SYS_PTRACE )) + goto err_out;/* report all available features and ioctls to userland */ uffdio_api.features =UFFD_API_FEATURES ; uffdio_api.ioctls =UFFD_API_IOCTLS ;
@@ -1854,6 +1853,11 @@ static int userfaultfd_api(struct userfa ret =0 ; out:return ret; +err_out: +memset (&uffdio_api,0 ,sizeof (uffdio_api)); +if (copy_to_user (buf, &uffdio_api,sizeof (uffdio_api))) + ret = -EFAULT ; + goto out; } static long userfaultfd_ioctl(struct file *file, unsigned cmd,
_