On Thu, Jan 21, 2021 at 02:44:29PM +0000, Stefan Hajnoczi wrote: > A well-behaved FUSE client does not attempt to open special files with > FUSE_OPEN because they are handled on the client side (e.g. device nodes > are handled by client-side device drivers). > > The check to prevent virtiofsd from opening special files is missing in > a few cases, most notably FUSE_OPEN. A malicious client can cause > virtiofsd to open a device node, potentially allowing the guest to > escape. This can be exploited by a modified guest device driver. It is > not exploitable from guest userspace since the guest kernel will handle > special files inside the guest instead of sending FUSE requests. > > This patch adds the missing checks to virtiofsd. This is a short-term > solution because it does not prevent a compromised virtiofsd process > from opening device nodes on the host. > > Reported-by: Alex Xu <a...@alxu.ca> > Fixes: CVE-2020-35517 > Signed-off-by: Stefan Hajnoczi <stefa...@redhat.com> > --- > This issue was diagnosed on public IRC and is therefore already known > and not embargoed. > > A stronger fix, and the long-term solution, is for users to mount the > shared directory and any sub-mounts with nodev, as well as nosuid and > noexec. Unfortunately virtiofsd cannot do this automatically because > bind mounts added by the user after virtiofsd has launched would not be > detected. I suggest the following: > > 1. Modify libvirt and Kata Containers to explicitly set these mount > options. > 2. Then modify virtiofsd to check that the shared directory has the > necessary options at startup. Refuse to start if the options are > missing so that the user is aware of the security requirements. > > As a bonus this also increases the likelihood that other host processes > besides virtiofsd will be protected by nosuid/noexec/nodev so that a > malicious guest cannot drop these files in place and then arrange for a > host process to come across them. > > Additionally, user namespaces have been discussed. They seem like a > worthwhile addition as an unprivileged or privilege-separated mode > although there are limitations with respect to security xattrs and the > actual uid/gid stored on the host file system not corresponding to the > guest uid/gid. > --- > tools/virtiofsd/passthrough_ll.c | 84 +++++++++++++++++++++----------- > 1 file changed, 56 insertions(+), 28 deletions(-) > > diff --git a/tools/virtiofsd/passthrough_ll.c > b/tools/virtiofsd/passthrough_ll.c > index 5fb36d9407..e08352d649 100644 > --- a/tools/virtiofsd/passthrough_ll.c > +++ b/tools/virtiofsd/passthrough_ll.c > @@ -555,6 +555,29 @@ static int lo_fd(fuse_req_t req, fuse_ino_t ino) > return fd; > } > > +/* > + * Open a file descriptor for an inode. Returns -EBADF if the inode is not a > + * regular file or a directory. Use this helper function instead of raw > + * openat(2) to prevent security issues when a malicious client opens special > + * files such as block device nodes. > + */ > +static int lo_inode_open(struct lo_data *lo, struct lo_inode *inode, > + int open_flags) > +{ > + g_autofree char *fd_str = g_strdup_printf("%d", inode->fd); > + int fd; > + > + if (!S_ISREG(inode->filetype) && !S_ISDIR(inode->filetype)) { > + return -EBADF; > + } > + > + fd = openat(lo->proc_self_fd, fd_str, open_flags);
Whats the intended behaviour with symlinks ? Do we need to allow S_ISLNK, or are we assuming the symlink has already been expanded to the target file by this point ? If the latter adding a comment about this would be useful. > + if (fd < 0) { > + return -errno; > + } > + return fd; > +} > + Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|