From 314aec4a6e06844937f1677f6cba21981005f389 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 14 Feb 2019 11:10:04 +0800 Subject: hostmem-file: reject invalid pmem file sizes Guests started with NVDIMMs larger than the underlying host file produce confusing errors inside the guest. This happens because the guest accesses pages beyond the end of the file. Check the pmem file size on startup and print a clear error message if the size is invalid. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1669053 Cc: Wei Yang Cc: Zhang Yi Cc: Eduardo Habkost Cc: Igor Mammedov Signed-off-by: Stefan Hajnoczi Message-Id: <20190214031004.32522-3-stefanha@redhat.com> Reviewed-by: Wei Yang Reviewed-by: Igor Mammedov Reviewed-by: Pankaj Gupta Signed-off-by: Eduardo Habkost --- util/oslib-posix.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ util/oslib-win32.c | 5 +++++ 2 files changed, 58 insertions(+) (limited to 'util') diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 37c5854..10d90d1 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -500,6 +500,59 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, } } +uint64_t qemu_get_pmem_size(const char *filename, Error **errp) +{ + struct stat st; + + if (stat(filename, &st) < 0) { + error_setg(errp, "unable to stat pmem file \"%s\"", filename); + return 0; + } + +#if defined(__linux__) + /* Special handling for devdax character devices */ + if (S_ISCHR(st.st_mode)) { + char *subsystem_path = NULL; + char *subsystem = NULL; + char *size_path = NULL; + char *size_str = NULL; + uint64_t ret = 0; + + subsystem_path = g_strdup_printf("/sys/dev/char/%d:%d/subsystem", + major(st.st_rdev), minor(st.st_rdev)); + subsystem = g_file_read_link(subsystem_path, NULL); + if (!subsystem) { + error_setg(errp, "unable to read subsystem for pmem file \"%s\"", + filename); + goto devdax_err; + } + + if (!g_str_has_suffix(subsystem, "/dax")) { + error_setg(errp, "pmem file \"%s\" is not a dax device", filename); + goto devdax_err; + } + + size_path = g_strdup_printf("/sys/dev/char/%d:%d/size", + major(st.st_rdev), minor(st.st_rdev)); + if (!g_file_get_contents(size_path, &size_str, NULL, NULL)) { + error_setg(errp, "unable to read size for pmem file \"%s\"", + size_path); + goto devdax_err; + } + + ret = g_ascii_strtoull(size_str, NULL, 0); + +devdax_err: + g_free(size_str); + g_free(size_path); + g_free(subsystem); + g_free(subsystem_path); + return ret; + } +#endif /* defined(__linux__) */ + + return st.st_size; +} char *qemu_get_pid_name(pid_t pid) { diff --git a/util/oslib-win32.c b/util/oslib-win32.c index b4c17f5..bd633af 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -560,6 +560,11 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, } } +uint64_t qemu_get_pmem_size(const char *filename, Error **errp) +{ + error_setg(errp, "pmem support not available"); + return 0; +} char *qemu_get_pid_name(pid_t pid) { -- cgit v1.1 From 92db922f66cde45bb216c36eb43b762429c96a74 Mon Sep 17 00:00:00 2001 From: Ilya Maximets Date: Mon, 11 Mar 2019 16:58:48 +0300 Subject: memfd: always check for MFD_CLOEXEC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU always sets this flag unconditionally. We need to check if it's supported. Signed-off-by: Ilya Maximets Reviewed-by: Marc-André Lureau Message-Id: <20190311135850.6537-3-i.maximets@samsung.com> Signed-off-by: Eduardo Habkost --- util/memfd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'util') diff --git a/util/memfd.c b/util/memfd.c index 8debd0d..d74ce4d 100644 --- a/util/memfd.c +++ b/util/memfd.c @@ -188,7 +188,7 @@ bool qemu_memfd_alloc_check(void) bool qemu_memfd_check(unsigned int flags) { #ifdef CONFIG_LINUX - int mfd = memfd_create("test", flags); + int mfd = memfd_create("test", flags | MFD_CLOEXEC); if (mfd >= 0) { close(mfd); -- cgit v1.1 From df20819328d6fa3cb9d4a259a58cebbee35cdd09 Mon Sep 17 00:00:00 2001 From: Ilya Maximets Date: Mon, 11 Mar 2019 16:58:49 +0300 Subject: memfd: set up correct errno if not supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qemu_memfd_create() prints the value of 'errno' which is not set in this case. Signed-off-by: Ilya Maximets Reviewed-by: Marc-André Lureau Message-Id: <20190311135850.6537-4-i.maximets@samsung.com> Signed-off-by: Eduardo Habkost --- util/memfd.c | 1 + 1 file changed, 1 insertion(+) (limited to 'util') diff --git a/util/memfd.c b/util/memfd.c index d74ce4d..393d23d 100644 --- a/util/memfd.c +++ b/util/memfd.c @@ -40,6 +40,7 @@ static int memfd_create(const char *name, unsigned int flags) #ifdef __NR_memfd_create return syscall(__NR_memfd_create, name, flags); #else + errno = ENOSYS; return -1; #endif } -- cgit v1.1 From edaed6c711f07267785a05a633d97dc9268a7385 Mon Sep 17 00:00:00 2001 From: Ilya Maximets Date: Mon, 11 Mar 2019 16:58:50 +0300 Subject: memfd: improve error messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This gives more information about the failure. Additionally 'ENOSYS' returned for a non-Linux platforms instead of 'errno', which is not initilaized in this case. Signed-off-by: Ilya Maximets Reviewed-by: Marc-André Lureau Message-Id: <20190311135850.6537-5-i.maximets@samsung.com> Signed-off-by: Eduardo Habkost --- util/memfd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'util') diff --git a/util/memfd.c b/util/memfd.c index 393d23d..00334e5 100644 --- a/util/memfd.c +++ b/util/memfd.c @@ -71,14 +71,18 @@ int qemu_memfd_create(const char *name, size_t size, bool hugetlb, } mfd = memfd_create(name, flags); if (mfd < 0) { + error_setg_errno(errp, errno, + "failed to create memfd with flags 0x%x", flags); goto err; } if (ftruncate(mfd, size) == -1) { + error_setg_errno(errp, errno, "failed to resize memfd to %zu", size); goto err; } if (seals && fcntl(mfd, F_ADD_SEALS, seals) == -1) { + error_setg_errno(errp, errno, "failed to add seals 0x%x", seals); goto err; } @@ -88,8 +92,9 @@ err: if (mfd >= 0) { close(mfd); } +#else + error_setg_errno(errp, ENOSYS, "failed to create memfd"); #endif - error_setg_errno(errp, errno, "failed to create memfd"); return -1; } -- cgit v1.1