diff options
Diffstat (limited to 'hw/9pfs/9p-util.h')
| -rw-r--r-- | hw/9pfs/9p-util.h | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h index c314cf381d..df1b583a5e 100644 --- a/hw/9pfs/9p-util.h +++ b/hw/9pfs/9p-util.h @@ -13,6 +13,8 @@ #ifndef QEMU_9P_UTIL_H #define QEMU_9P_UTIL_H +#include "qemu/error-report.h" + #ifdef O_PATH #define O_PATH_9P_UTIL O_PATH #else @@ -95,6 +97,7 @@ static inline int errno_to_dotl(int err) { #endif #define qemu_openat openat +#define qemu_fstat fstat #define qemu_fstatat fstatat #define qemu_mkdirat mkdirat #define qemu_renameat renameat @@ -108,6 +111,38 @@ static inline void close_preserve_errno(int fd) errno = serrno; } +/** + * close_if_special_file() - Close @fd if neither regular file nor directory. + * + * @fd: file descriptor of open file + * Return: 0 on regular file or directory, -1 otherwise + * + * CVE-2023-2861: Prohibit opening any special file directly on host + * (especially device files), as a compromised client could potentially gain + * access outside exported tree under certain, unsafe setups. We expect + * client to handle I/O on special files exclusively on guest side. + */ +static inline int close_if_special_file(int fd) +{ + struct stat stbuf; + + if (qemu_fstat(fd, &stbuf) < 0) { + close_preserve_errno(fd); + return -1; + } + if (!S_ISREG(stbuf.st_mode) && !S_ISDIR(stbuf.st_mode)) { + error_report_once( + "9p: broken or compromised client detected; attempt to open " + "special file (i.e. neither regular file, nor directory)" + ); + close(fd); + errno = ENXIO; + return -1; + } + + return 0; +} + static inline int openat_dir(int dirfd, const char *name) { return qemu_openat(dirfd, name, @@ -142,6 +177,10 @@ again: return -1; } + if (close_if_special_file(fd) < 0) { + return -1; + } + serrno = errno; /* O_NONBLOCK was only needed to open the file. Let's drop it. We don't * do that with O_PATH since fcntl(F_SETFL) isn't supported, and openat() |