aboutsummaryrefslogtreecommitdiff
path: root/hw/9pfs/9p-util.h
AgeCommit message (Collapse)AuthorFilesLines
2020-05-149pfs: local: ignore O_NOATIME if we don't have permissionsOmar Sandoval1-0/+13
QEMU's local 9pfs server passes through O_NOATIME from the client. If the QEMU process doesn't have permissions to use O_NOATIME (namely, it does not own the file nor have the CAP_FOWNER capability), the open will fail. This causes issues when from the client's point of view, it believes it has permissions to use O_NOATIME (e.g., a process running as root in the virtual machine). Additionally, overlayfs on Linux opens files on the lower layer using O_NOATIME, so in this case a 9pfs mount can't be used as a lower layer for overlayfs (cf. https://github.com/osandov/drgn/blob/dabfe1971951701da13863dbe6d8a1d172ad9650/vmtest/onoatimehack.c and https://github.com/NixOS/nixpkgs/issues/54509). Luckily, O_NOATIME is effectively a hint, and is often ignored by, e.g., network filesystems. open(2) notes that O_NOATIME "may not be effective on all filesystems. One example is NFS, where the server maintains the access time." This means that we can honor it when possible but fall back to ignoring it. Acked-by: Christian Schoenebeck <qemu_oss@crudebyte.com> Signed-off-by: Omar Sandoval <osandov@fb.com> Message-Id: <e9bee604e8df528584693a4ec474ded6295ce8ad.1587149256.git.osandov@fb.com> Signed-off-by: Greg Kurz <groug@kaod.org>
2018-06-079p: Move a couple xattr functions to 9p-utilKeno Fischer1-0/+4
These functions will need custom implementations on Darwin. Since the implementation is very similar among all of them, and 9p-util already has the _nofollow version of fgetxattrat, let's move them all there. Signed-off-by: Keno Fischer <keno@juliacomputing.com> Signed-off-by: Greg Kurz <groug@kaod.org>
2017-08-109pfs: local: fix fchmodat_nofollow() limitationsGreg Kurz1-9/+15
This function has to ensure it doesn't follow a symlink that could be used to escape the virtfs directory. This could be easily achieved if fchmodat() on linux honored the AT_SYMLINK_NOFOLLOW flag as described in POSIX, but it doesn't. There was a tentative to implement a new fchmodat2() syscall with the correct semantics: https://patchwork.kernel.org/patch/9596301/ but it didn't gain much momentum. Also it was suggested to look at an O_PATH based solution in the first place. The current implementation covers most use-cases, but it notably fails if: - the target path has access rights equal to 0000 (openat() returns EPERM), => once you've done chmod(0000) on a file, you can never chmod() again - the target path is UNIX domain socket (openat() returns ENXIO) => bind() of UNIX domain sockets fails if the file is on 9pfs The solution is to use O_PATH: openat() now succeeds in both cases, and we can ensure the path isn't a symlink with fstat(). The associated entry in "/proc/self/fd" can hence be safely passed to the regular chmod() syscall. The previous behavior is kept for older systems that don't have O_PATH. Signed-off-by: Greg Kurz <groug@kaod.org> Reviewed-by: Eric Blake <eblake@redhat.com> Tested-by: Zhi Yong Wu <zhiyong.wu@ucloud.cn> Acked-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
2017-05-259pfs: local: simplify file openingGreg Kurz1-2/+0
The logic to open a path currently sits between local_open_nofollow() and the relative_openat_nofollow() helper, which has no other user. For the sake of clarity, this patch moves all the code of the helper into its unique caller. While here we also: - drop the code to skip leading "/" because the backend isn't supposed to pass anything but relative paths without consecutive slashes. The assert() is kept because we really don't want a buggy backend to pass an absolute path to openat(). - use strchrnul() to get a simpler code. This is ok since virtfs is for linux+glibc hosts only. - don't dup() the initial directory and add an assert() to ensure we don't return the global mountfd to the caller. BTW, this would mean that the caller passed an empty path, which isn't supposed to happen either. Signed-off-by: Greg Kurz <groug@kaod.org> Reviewed-by: Eric Blake <eblake@redhat.com> [groug: fixed typos in changelog]
2017-03-069pfs: fix vulnerability in openat_dir() and local_unlinkat_common()Greg Kurz1-1/+2
We should pass O_NOFOLLOW otherwise openat() will follow symlinks and make QEMU vulnerable. While here, we also fix local_unlinkat_common() to use openat_dir() for the same reasons (it was a leftover in the original patchset actually). This fixes CVE-2016-9602. Signed-off-by: Greg Kurz <groug@kaod.org> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com>
2017-03-069pfs: fix O_PATH build break with older glibc versionsGreg Kurz1-1/+6
When O_PATH is used with O_DIRECTORY, it only acts as an optimization: the openat() syscall simply finds the name in the VFS, and doesn't trigger the underlying filesystem. On systems that don't define O_PATH, because they have glibc version 2.13 or older for example, we can safely omit it. We don't want to deactivate O_PATH globally though, in case it is used without O_DIRECTORY. The is done with a dedicated macro. Systems without O_PATH may thus fail to resolve names that involve unreadable directories, compared to newer systems succeeding, but such corner case failure is our only option on those older systems to avoid the security hole of chasing symlinks inappropriately. Signed-off-by: Greg Kurz <groug@kaod.org> Reviewed-by: Eric Blake <eblake@redhat.com> (added last paragraph to changelog as suggested by Eric Blake) Signed-off-by: Greg Kurz <groug@kaod.org>
2017-02-289pfs: local: lsetxattr: don't follow symlinksGreg Kurz1-0/+2
The local_lsetxattr() callback is vulnerable to symlink attacks because it calls lsetxattr() which follows symbolic links in all path elements but the rightmost one. This patch introduces a helper to emulate the non-existing fsetxattrat() function: it is implemented with /proc/self/fd which provides a trusted path that can be safely passed to lsetxattr(). local_lsetxattr() is converted to use this helper and opendir_nofollow(). This partly fixes CVE-2016-9602. Signed-off-by: Greg Kurz <groug@kaod.org> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
2017-02-289pfs: local: lgetxattr: don't follow symlinksGreg Kurz1-0/+2
The local_lgetxattr() callback is vulnerable to symlink attacks because it calls lgetxattr() which follows symbolic links in all path elements but the rightmost one. This patch introduces a helper to emulate the non-existing fgetxattrat() function: it is implemented with /proc/self/fd which provides a trusted path that can be safely passed to lgetxattr(). local_lgetxattr() is converted to use this helper and opendir_nofollow(). This partly fixes CVE-2016-9602. Signed-off-by: Greg Kurz <groug@kaod.org> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
2017-02-289pfs: introduce relative_openat_nofollow() helperGreg Kurz1-0/+50
When using the passthrough security mode, symbolic links created by the guest are actual symbolic links on the host file system. Since the resolution of symbolic links during path walk is supposed to occur on the client side. The server should hence never receive any path pointing to an actual symbolic link. This isn't guaranteed by the protocol though, and malicious code in the guest can trick the server to issue various syscalls on paths whose one or more elements are symbolic links. In the case of the "local" backend using the "passthrough" or "none" security modes, the guest can directly create symbolic links to arbitrary locations on the host (as per spec). The "mapped-xattr" and "mapped-file" security modes are also affected to a lesser extent as they require some help from an external entity to create actual symbolic links on the host, i.e. another guest using "passthrough" mode for example. The current code hence relies on O_NOFOLLOW and "l*()" variants of system calls. Unfortunately, this only applies to the rightmost path component. A guest could maliciously replace any component in a trusted path with a symbolic link. This could allow any guest to escape a virtfs shared folder. This patch introduces a variant of the openat() syscall that successively opens each path element with O_NOFOLLOW. When passing a file descriptor pointing to a trusted directory, one is guaranteed to be returned a file descriptor pointing to a path which is beneath the trusted directory. This will be used by subsequent patches to implement symlink-safe path walk for any access to the backend. Symbolic links aren't the only threats actually: a malicious guest could change a path element to point to other types of file with undesirable effects: - a named pipe or any other thing that would cause openat() to block - a terminal device which would become QEMU's controlling terminal These issues can be addressed with O_NONBLOCK and O_NOCTTY. Two helpers are introduced: one to open intermediate path elements and one to open the rightmost path element. Suggested-by: Jann Horn <jannh@google.com> Signed-off-by: Greg Kurz <groug@kaod.org> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> (renamed openat_nofollow() to relative_openat_nofollow(), assert path is relative and doesn't contain '//', fixed side-effect in assert, Greg Kurz) Signed-off-by: Greg Kurz <groug@kaod.org>