From nobody Sun May 19 03:02:39 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1554209005247611.576252625774; Tue, 2 Apr 2019 05:43:25 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id AEE98307EAB1; Tue, 2 Apr 2019 12:43:23 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 1852317D6B; Tue, 2 Apr 2019 12:43:23 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 3030741F3C; Tue, 2 Apr 2019 12:43:22 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id x32CekJD008779 for ; Tue, 2 Apr 2019 08:40:46 -0400 Received: by smtp.corp.redhat.com (Postfix) id 9B9A16A4B7; Tue, 2 Apr 2019 12:40:46 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-112-56.ams2.redhat.com [10.36.112.56]) by smtp.corp.redhat.com (Postfix) with ESMTP id F052268403; Tue, 2 Apr 2019 12:40:44 +0000 (UTC) From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: libvir-list@redhat.com Date: Tue, 2 Apr 2019 13:40:33 +0100 Message-Id: <20190402124036.2415-2-berrange@redhat.com> In-Reply-To: <20190402124036.2415-1-berrange@redhat.com> References: <20190402124036.2415-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH 1/4] tests: fix mocking of stat() / lstat() functions X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.44]); Tue, 02 Apr 2019 12:43:24 +0000 (UTC) Quite a few of the tests have a need to mock the stat() / lstat() functions and they are taking somewhat different & inconsistent approaches none of which are actually fully correct. This is shown by fact that 'make check' fails on 32-bit hosts. Investigation revealed that the code was calling into the native C library impl, not getting intercepted by our mocks. The POSIX stat() function might resolve to any number of different symbols in the C library. The may be an additional stat64() function exposed by the headers too. On 64-bit hosts the stat & stat64 functions are identical, always refering to the 64-bit ABI. On 32-bit hosts they refer to the 32-bit & 64-bit ABIs respectively. Libvirt uses _FILE_OFFSET_BITS=3D64 on 32-bit hosts, which causes the C library to transparently rewrite stat() calls to be stat64() calls. Libvirt will never see the 32-bit ABI from the traditional stat() call. We cannot assume this rewriting is done using a macro. It might be, but on GLibC it is done with a magic __asm__ statement to apply the rewrite at link time instead of at preprocessing. In GLibC there may be two additional functions exposed by the headers, __xstat() and __xstat64(). When these exist, stat() and stat64() are transparently rewritten to call __xstat() and __xstat64() respectively. The former symbols will not actally exist in the library at all, only the header. The leading "__" indicates the symbols are a private impl detail of the C library that applications should not care about. Unfortunately, because we are trying to mock replace the C library, we need to know about this internal impl detail. With all this in mind the list of functions we have to mock will depend on several factors - If _FILE_OFFSET_BITS is set, then we are on a 32-bit host, and we only need to mock stat64 and __xstat64. The other stat / __xstat functions exist, but we'll never call them so they can be ignored for mocking. - If _FILE_OFFSET_BITS is not set, then we are on a 64-bit host and we should mock stat, stat64, __xstat & __xstat64. Either may be called by app code. - If __xstat & __xstat64 exist, then stat & stat64 will not exist as symbols in the library, so the latter should not be mocked. The same all applies to lstat() These rules are complex enough that we don't want to duplicate them across every mock file, so this centralizes all the logic in a helper file virmockstathelper.c that should be #included when needed. The code merely need to provide a filename rewriting callback called virMockStatRedirect(). Optionally VIR_MOCK_STAT_HOOK can be defined as a macro if further processing is needed inline. Signed-off-by: Daniel P. Berrang=C3=A9 --- build-aux/mock-noinline.pl | 3 + cfg.mk | 4 +- tests/Makefile.am | 1 + tests/qemusecuritymock.c | 131 ++++----------- tests/vircgroupmock.c | 146 +++-------------- tests/virfilewrapper.c | 85 ++-------- tests/virmock.h | 11 -- tests/virmockstathelpers.c | 326 +++++++++++++++++++++++++++++++++++++ tests/virpcimock.c | 93 +---------- tests/virtestmock.c | 140 +--------------- 10 files changed, 413 insertions(+), 527 deletions(-) create mode 100644 tests/virmockstathelpers.c diff --git a/build-aux/mock-noinline.pl b/build-aux/mock-noinline.pl index c6b40001c5..958e133885 100644 --- a/build-aux/mock-noinline.pl +++ b/build-aux/mock-noinline.pl @@ -6,6 +6,9 @@ my %mocked; # Functions in public header don't get the noinline annotation # so whitelist them here $noninlined{"virEventAddTimeout"} =3D 1; +# This one confuses the script as its defined in the mock file +# but is actually just a local helper +$noninlined{"virMockStatRedirect"} =3D 1; =20 foreach my $arg (@ARGV) { if ($arg =3D~ /\.h$/) { diff --git a/cfg.mk b/cfg.mk index a62d4db13b..2c473121a4 100644 --- a/cfg.mk +++ b/cfg.mk @@ -1272,10 +1272,10 @@ exclude_file_name_regexp--sc_prohibit_xmlURI =3D ^s= rc/util/viruri\.c$$ exclude_file_name_regexp--sc_prohibit_return_as_function =3D \.py$$ =20 exclude_file_name_regexp--sc_require_config_h =3D \ - ^(examples/|tools/virsh-edit\.c$$) + ^(examples/|tools/virsh-edit\.c$$|tests/virmockstathelpers.c) =20 exclude_file_name_regexp--sc_require_config_h_first =3D \ - ^(examples/|tools/virsh-edit\.c$$) + ^(examples/|tools/virsh-edit\.c$$|tests/virmockstathelpers.c) =20 exclude_file_name_regexp--sc_trailing_blank =3D \ /sysinfodata/.*\.data|/virhostcpudata/.*\.cpuinfo|^gnulib/local/.*/.*dif= f$$ diff --git a/tests/Makefile.am b/tests/Makefile.am index d3cdbff8bb..436aac285f 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -146,6 +146,7 @@ EXTRA_DIST =3D \ virjsondata \ virmacmaptestdata \ virmock.h \ + virmockstathelpers.h \ virnetdaemondata \ virnetdevtestdata \ virnwfilterbindingxml2xmldata \ diff --git a/tests/qemusecuritymock.c b/tests/qemusecuritymock.c index d1b17d8aa4..3fdc165fb1 100644 --- a/tests/qemusecuritymock.c +++ b/tests/qemusecuritymock.c @@ -50,10 +50,6 @@ =20 =20 static int (*real_chown)(const char *path, uid_t uid, gid_t gid); -static int (*real_lstat)(const char *path, struct stat *sb); -static int (*real___lxstat)(int ver, const char *path, struct stat *sb); -static int (*real_stat)(const char *path, struct stat *sb); -static int (*real___xstat)(int ver, const char *path, struct stat *sb); static int (*real_open)(const char *path, int flags, ...); static int (*real_close)(int fd); =20 @@ -106,8 +102,6 @@ init_syms(void) return; =20 VIR_MOCK_REAL_INIT(chown); - VIR_MOCK_REAL_INIT_ALT(lstat, __lxstat); - VIR_MOCK_REAL_INIT_ALT(stat, __xstat); VIR_MOCK_REAL_INIT(open); VIR_MOCK_REAL_INIT(close); =20 @@ -211,36 +205,35 @@ int virFileRemoveXAttr(const char *path, } =20 =20 -static int -mock_stat(const char *path, - struct stat *sb) -{ - uint32_t *val; - - virMutexLock(&m); - init_hash(); - - memset(sb, 0, sizeof(*sb)); - - sb->st_mode =3D S_IFREG | 0666; - sb->st_size =3D 123456; - sb->st_ino =3D 1; - - if (!(val =3D virHashLookup(chown_paths, path))) { - /* New path. Set the defaults */ - sb->st_uid =3D DEFAULT_UID; - sb->st_gid =3D DEFAULT_GID; - } else { - /* Known path. Set values passed to chown() earlier */ - sb->st_uid =3D *val % 16; - sb->st_gid =3D *val >> 16; - } - - virMutexUnlock(&m); - - return 0; -} - +#define VIR_MOCK_STAT_HOOK \ + do { \ + if (getenv(ENVVAR)) { \ + uint32_t *val; \ +\ + virMutexLock(&m); \ + init_hash(); \ +\ + memset(sb, 0, sizeof(*sb)); \ +\ + sb->st_mode =3D S_IFREG | 0666; \ + sb->st_size =3D 123456; \ + sb->st_ino =3D 1; \ +\ + if (!(val =3D virHashLookup(chown_paths, path))) { \ + /* New path. Set the defaults */ \ + sb->st_uid =3D DEFAULT_UID; \ + sb->st_gid =3D DEFAULT_GID; \ + } else { \ + /* Known path. Set values passed to chown() earlier */ \ + sb->st_uid =3D *val % 16; \ + sb->st_gid =3D *val >> 16; \ + } \ +\ + virMutexUnlock(&m); \ +\ + return 0; \ + } \ + } while (0) =20 static int mock_chown(const char *path, @@ -276,68 +269,12 @@ mock_chown(const char *path, } =20 =20 -#ifdef HAVE___LXSTAT -int -__lxstat(int ver, const char *path, struct stat *sb) -{ - int ret; - - init_syms(); - - if (getenv(ENVVAR)) - ret =3D mock_stat(path, sb); - else - ret =3D real___lxstat(ver, path, sb); - - return ret; -} -#endif /* HAVE___LXSTAT */ - -int -lstat(const char *path, struct stat *sb) -{ - int ret; - - init_syms(); - - if (getenv(ENVVAR)) - ret =3D mock_stat(path, sb); - else - ret =3D real_lstat(path, sb); - - return ret; -} - -#ifdef HAVE___XSTAT -int -__xstat(int ver, const char *path, struct stat *sb) -{ - int ret; - - init_syms(); - - if (getenv(ENVVAR)) - ret =3D mock_stat(path, sb); - else - ret =3D real___xstat(ver, path, sb); - - return ret; -} -#endif /* HAVE___XSTAT */ +#include "virmockstathelpers.c" =20 -int -stat(const char *path, struct stat *sb) +static int +virMockStatRedirect(const char *path ATTRIBUTE_UNUSED, char **newpath ATTR= IBUTE_UNUSED) { - int ret; - - init_syms(); - - if (getenv(ENVVAR)) - ret =3D mock_stat(path, sb); - else - ret =3D real_stat(path, sb); - - return ret; + return 0; } =20 =20 @@ -386,6 +323,8 @@ close(int fd) { int ret; =20 + init_syms(); + if (fd =3D=3D 42 && getenv(ENVVAR)) ret =3D 0; else diff --git a/tests/vircgroupmock.c b/tests/vircgroupmock.c index 9c67a44b0d..11a24035aa 100644 --- a/tests/vircgroupmock.c +++ b/tests/vircgroupmock.c @@ -38,10 +38,6 @@ static int (*real_open)(const char *path, int flags, ...); static FILE *(*real_fopen)(const char *path, const char *mode); static int (*real_access)(const char *path, int mode); -static int (*real_stat)(const char *path, struct stat *sb); -static int (*real___xstat)(int ver, const char *path, struct stat *sb); -static int (*real_lstat)(const char *path, struct stat *sb); -static int (*real___lxstat)(int ver, const char *path, struct stat *sb); static int (*real_mkdir)(const char *path, mode_t mode); =20 /* Don't make static, since it causes problems with clang @@ -317,8 +313,6 @@ static void init_syms(void) =20 VIR_MOCK_REAL_INIT(fopen); VIR_MOCK_REAL_INIT(access); - VIR_MOCK_REAL_INIT_ALT(lstat, __lxstat); - VIR_MOCK_REAL_INIT_ALT(stat, __xstat); VIR_MOCK_REAL_INIT(mkdir); VIR_MOCK_REAL_INIT(open); } @@ -508,139 +502,41 @@ int access(const char *path, int mode) return ret; } =20 -int __lxstat(int ver, const char *path, struct stat *sb) -{ - int ret; - - init_syms(); - - if (STRPREFIX(path, SYSFS_CGROUP_PREFIX)) { - init_sysfs(); - char *newpath; - if (asprintf(&newpath, "%s%s", - fakesysfscgroupdir, - path + strlen(SYSFS_CGROUP_PREFIX)) < 0) { - errno =3D ENOMEM; - return -1; - } - ret =3D real___lxstat(ver, newpath, sb); - free(newpath); - } else if (STRPREFIX(path, fakedevicedir0)) { - sb->st_mode =3D S_IFBLK; - sb->st_rdev =3D makedev(8, 0); - return 0; - } else if (STRPREFIX(path, fakedevicedir1)) { - sb->st_mode =3D S_IFBLK; - sb->st_rdev =3D makedev(9, 0); - return 0; - } else { - ret =3D real___lxstat(ver, path, sb); - } - return ret; -} - -int lstat(const char *path, struct stat *sb) -{ - int ret; - - init_syms(); - - if (STRPREFIX(path, SYSFS_CGROUP_PREFIX)) { - init_sysfs(); - char *newpath; - if (asprintf(&newpath, "%s%s", - fakesysfscgroupdir, - path + strlen(SYSFS_CGROUP_PREFIX)) < 0) { - errno =3D ENOMEM; - return -1; - } - ret =3D real_lstat(newpath, sb); - free(newpath); - } else if (STRPREFIX(path, fakedevicedir0)) { - sb->st_mode =3D S_IFBLK; - sb->st_rdev =3D makedev(8, 0); - return 0; - } else if (STRPREFIX(path, fakedevicedir1)) { - sb->st_mode =3D S_IFBLK; - sb->st_rdev =3D makedev(9, 0); - return 0; - } else { - ret =3D real_lstat(path, sb); - } - return ret; -} - -int __xstat(int ver, const char *path, struct stat *sb) -{ - int ret; - - init_syms(); +# define VIR_MOCK_STAT_HOOK \ + do { \ + if (STRPREFIX(path, fakedevicedir0)) { \ + sb->st_mode =3D S_IFBLK; \ + sb->st_rdev =3D makedev(8, 0); \ + return 0; \ + } else if (STRPREFIX(path, fakedevicedir1)) { \ + sb->st_mode =3D S_IFBLK; \ + sb->st_rdev =3D makedev(9, 0); \ + return 0; \ + } \ + } while (0) =20 - if (STRPREFIX(path, SYSFS_CGROUP_PREFIX)) { - init_sysfs(); - char *newpath; - if (asprintf(&newpath, "%s%s", - fakesysfscgroupdir, - path + strlen(SYSFS_CGROUP_PREFIX)) < 0) { - errno =3D ENOMEM; - return -1; - } - ret =3D real___xstat(ver, newpath, sb); - free(newpath); - } else if (STRPREFIX(path, fakedevicedir0)) { - sb->st_mode =3D S_IFBLK; - sb->st_rdev =3D makedev(8, 0); - return 0; - } else if (STRPREFIX(path, fakedevicedir1)) { - sb->st_mode =3D S_IFBLK; - sb->st_rdev =3D makedev(9, 0); - return 0; - } else { - ret =3D real___xstat(ver, path, sb); - } - return ret; -} +# include "virmockstathelpers.c" =20 -int stat(const char *path, struct stat *sb) +static int +virMockStatRedirect(const char *path, char **newpath) { - char *newpath =3D NULL; - int ret; - - init_syms(); - if (STREQ(path, SYSFS_CPU_PRESENT)) { init_sysfs(); - if (asprintf(&newpath, "%s/%s", + if (asprintf(newpath, "%s/%s", fakesysfscgroupdir, - SYSFS_CPU_PRESENT_MOCKED) < 0) { - errno =3D ENOMEM; + SYSFS_CPU_PRESENT_MOCKED) < 0) return -1; - } } else if (STRPREFIX(path, SYSFS_CGROUP_PREFIX)) { init_sysfs(); - if (asprintf(&newpath, "%s%s", + if (asprintf(newpath, "%s%s", fakesysfscgroupdir, - path + strlen(SYSFS_CGROUP_PREFIX)) < 0) { - errno =3D ENOMEM; - return -1; - } - } else if (STRPREFIX(path, fakedevicedir0)) { - sb->st_mode =3D S_IFBLK; - sb->st_rdev =3D makedev(8, 0); - return 0; - } else if (STRPREFIX(path, fakedevicedir1)) { - sb->st_mode =3D S_IFBLK; - sb->st_rdev =3D makedev(9, 0); - return 0; - } else { - if (!(newpath =3D strdup(path))) + path + strlen(SYSFS_CGROUP_PREFIX)) < 0) return -1; } - ret =3D real_stat(newpath, sb); - free(newpath); - return ret; + return 0; } =20 + int mkdir(const char *path, mode_t mode) { int ret; diff --git a/tests/virfilewrapper.c b/tests/virfilewrapper.c index 88441331ce..067cb30657 100644 --- a/tests/virfilewrapper.c +++ b/tests/virfilewrapper.c @@ -39,15 +39,9 @@ static size_t nprefixes; static const char **prefixes; =20 /* TODO: callbacks */ - - static int (*real_open)(const char *path, int flags, ...); static FILE *(*real_fopen)(const char *path, const char *mode); static int (*real_access)(const char *path, int mode); -static int (*real_stat)(const char *path, struct stat *sb); -static int (*real___xstat)(int ver, const char *path, struct stat *sb); -static int (*real_lstat)(const char *path, struct stat *sb); -static int (*real___lxstat)(int ver, const char *path, struct stat *sb); static int (*real_mkdir)(const char *path, mode_t mode); static DIR *(*real_opendir)(const char *path); =20 @@ -58,8 +52,6 @@ static void init_syms(void) =20 VIR_MOCK_REAL_INIT(fopen); VIR_MOCK_REAL_INIT(access); - VIR_MOCK_REAL_INIT_ALT(lstat, __lxstat); - VIR_MOCK_REAL_INIT_ALT(stat, __xstat); VIR_MOCK_REAL_INIT(mkdir); VIR_MOCK_REAL_INIT(open); VIR_MOCK_REAL_INIT(opendir); @@ -115,10 +107,11 @@ virFileWrapperClearPrefixes(void) VIR_FREE(overrides); } =20 -static char * -virFileWrapperOverridePrefix(const char *path) +# include "virmockstathelpers.c" + +int +virMockStatRedirect(const char *path, char **newpath) { - char *ret =3D NULL; size_t i =3D 0; =20 for (i =3D 0; i < noverrides; i++) { @@ -127,16 +120,13 @@ virFileWrapperOverridePrefix(const char *path) if (!tmp) continue; =20 - if (virAsprintfQuiet(&ret, "%s%s", overrides[i], tmp) < 0) - return NULL; + if (virAsprintfQuiet(newpath, "%s%s", overrides[i], tmp) < 0) + return -1; =20 break; } =20 - if (!ret) - ignore_value(VIR_STRDUP_QUIET(ret, path)); - - return ret; + return 0; } =20 =20 @@ -144,8 +134,7 @@ virFileWrapperOverridePrefix(const char *path) do { \ init_syms(); \ \ - newpath =3D virFileWrapperOverridePrefix(path); \ - if (!newpath) \ + if (virMockStatRedirect(path, &newpath) < 0) \ abort(); \ } while (0) =20 @@ -156,7 +145,7 @@ FILE *fopen(const char *path, const char *mode) =20 PATH_OVERRIDE(newpath, path); =20 - return real_fopen(newpath, mode); + return real_fopen(newpath ? newpath : path, mode); } =20 int access(const char *path, int mode) @@ -165,56 +154,7 @@ int access(const char *path, int mode) =20 PATH_OVERRIDE(newpath, path); =20 - return real_access(newpath, mode); -} - -# ifdef HAVE___LXSTAT -int __lxstat(int ver, const char *path, struct stat *sb) -{ - VIR_AUTOFREE(char *) newpath =3D NULL; - - PATH_OVERRIDE(newpath, path); - - return real___lxstat(ver, newpath, sb); -} -# endif /* HAVE___LXSTAT */ - -int lstat(const char *path, struct stat *sb) -{ - VIR_AUTOFREE(char *) newpath =3D NULL; - - PATH_OVERRIDE(newpath, path); - - return real_lstat(newpath, sb); -} - -# ifdef HAVE___XSTAT -int __xstat(int ver, const char *path, struct stat *sb) -{ - VIR_AUTOFREE(char *) newpath =3D NULL; - - PATH_OVERRIDE(newpath, path); - - return real___xstat(ver, newpath, sb); -} -# endif /* HAVE___XSTAT */ - -int stat(const char *path, struct stat *sb) -{ - VIR_AUTOFREE(char *) newpath =3D NULL; - - PATH_OVERRIDE(newpath, path); - - return real_stat(newpath, sb); -} - -int mkdir(const char *path, mode_t mode) -{ - VIR_AUTOFREE(char *) newpath =3D NULL; - - PATH_OVERRIDE(newpath, path); - - return real_mkdir(newpath, mode); + return real_access(newpath ? newpath : path, mode); } =20 int open(const char *path, int flags, ...) @@ -234,7 +174,7 @@ int open(const char *path, int flags, ...) va_end(ap); } =20 - return real_open(newpath, flags, mode); + return real_open(newpath ? newpath : path, flags, mode); } =20 DIR *opendir(const char *path) @@ -243,6 +183,7 @@ DIR *opendir(const char *path) =20 PATH_OVERRIDE(newpath, path); =20 - return real_opendir(newpath); + return real_opendir(newpath ? newpath : path); } + #endif diff --git a/tests/virmock.h b/tests/virmock.h index 9c7ecf60ce..46631433c7 100644 --- a/tests/virmock.h +++ b/tests/virmock.h @@ -290,15 +290,4 @@ } \ } while (0) =20 -# define VIR_MOCK_REAL_INIT_ALT(name1, name2) \ - do { \ - real_ ## name1 =3D dlsym(RTLD_NEXT, #name1); \ - real_ ## name2 =3D dlsym(RTLD_NEXT, #name2); \ - if (!real_##name1 && !real_##name2) { \ - fprintf(stderr, "Cannot find real '%s' or '%s' symbol\n", \ - #name1, #name2); \ - abort(); \ - } \ - } while (0) - #endif /* LIBVIRT_VIRMOCK_H */ diff --git a/tests/virmockstathelpers.c b/tests/virmockstathelpers.c new file mode 100644 index 0000000000..0bbea4b437 --- /dev/null +++ b/tests/virmockstathelpers.c @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2019 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * Helpers for dealing with the many variants of stat(). This + * C file should be included from any file that wants to mock + * stat() correctly. + */ + +#include "virmock.h" +#include "viralloc.h" + +#include +#include + +/* + * The POSIX stat() function might resolve to any number of different + * symbols in the C library. + * + * The may be an additional stat64() function exposed by the headers + * too. + * + * On 64-bit hosts the stat & stat64 functions are identical, always + * refering to the 64-bit ABI. + * + * On 32-bit hosts they refer to the 32-bit & 64-bit ABIs respectively. + * + * Libvirt uses _FILE_OFFSET_BITS=3D64 on 32-bit hosts, which causes the + * C library to transparently rewrite stat() calls to be stat64() calls. + * Libvirt will never see the 32-bit ABI from the traditional stat() + * call. We cannot assume this rewriting is done using a macro. It might + * be, but on GLibC it is done with a magic __asm__ statement to apply + * the rewrite at link time instead of at preprocessing. + * + * In GLibC there may be two additional functions exposed by the headers, + * __xstat() and __xstat64(). When these exist, stat() and stat64() are + * transparently rewritten to call __xstat() and __xstat64() respectively. + * The former symbols will not actally exist in the library at all, only + * the header. The leading "__" indicates the symbols are a private impl + * detail of the C library that applications should not care about. + * Unfortunately, because we are trying to mock replace the C library, + * we need to know about this internal impl detail. + * + * With all this in mind the list of functions we have to mock will depend + * on several factors + * + * - If _FILE_OFFSET_BITS is set, then we are on a 32-bit host, and we + * only need to mock stat64 and __xstat64. The other stat / __xstat + * functions exist, but we'll never call them so they can be ignored + * for mocking. + * + * - If _FILE_OFFSET_BITS is not set, then we are on a 64-bit host and + * we should mock stat, stat64, __xstat & __xstat64. Either may be + * called by app code. + * + * - If __xstat & __xstat64 exist, then stat & stat64 will not exist + * as symbols in the library, so the latter should not be mocked. + * + * The same all applies to lstat() + */ + + + +#if defined(HAVE_STAT) && !defined(HAVE___XSTAT) && !defined(_FILE_OFFSET_= BITS) +# define MOCK_STAT +#endif +#if defined(HAVE_STAT64) && !defined(HAVE___XSTAT64) +# define MOCK_STAT64 +#endif +#if defined(HAVE___XSTAT) && !defined(_FILE_OFFSET_BITS) +# define MOCK___XSTAT +#endif +#if defined(HAVE___XSTAT64) +# define MOCK___XSTAT64 +#endif +#if defined(HAVE_LSTAT) && !defined(HAVE___LXSTAT) && !defined(_FILE_OFFSE= T_BITS) +# define MOCK_LSTAT +#endif +#if defined(HAVE_LSTAT64) && !defined(HAVE___LXSTAT64) +# define MOCK_LSTAT64 +#endif +#if defined(HAVE___LXSTAT) && !defined(_FILE_OFFSET_BITS) +# define MOCK___LXSTAT +#endif +#if defined(HAVE___LXSTAT64) +# define MOCK___LXSTAT64 +#endif + +#ifdef MOCK_STAT +static int (*real_stat)(const char *path, struct stat *sb); +#endif +#ifdef MOCK_STAT64 +static int (*real_stat64)(const char *path, struct stat64 *sb); +#endif +#ifdef MOCK___XSTAT +static int (*real___xstat)(int ver, const char *path, struct stat *sb); +#endif +#ifdef MOCK___XSTAT64 +static int (*real___xstat64)(int ver, const char *path, struct stat64 *sb); +#endif +#ifdef MOCK_LSTAT +static int (*real_lstat)(const char *path, struct stat *sb); +#endif +#ifdef MOCK_LSTAT64 +static int (*real_lstat64)(const char *path, struct stat64 *sb); +#endif +#ifdef MOCK___LXSTAT +static int (*real___lxstat)(int ver, const char *path, struct stat *sb); +#endif +#ifdef MOCK___LXSTAT64 +static int (*real___lxstat64)(int ver, const char *path, struct stat64 *sb= ); +#endif + +static bool init; +static bool debug; + +#define fdebug(msg, ...) do { if (debug) fprintf(stderr, msg, __VA_ARGS__)= ; } while (0) + +static void virMockStatInit(void) +{ + if (init) + return; + + init =3D true; + debug =3D getenv("VIR_MOCK_STAT_DEBUG"); + +#ifdef MOCK_STAT + VIR_MOCK_REAL_INIT(stat); + fdebug("real stat %p\n", real_stat); +#endif +#ifdef MOCK_STAT64 + VIR_MOCK_REAL_INIT(stat64); + fdebug("real stat64 %p\n", real_stat64); +#endif +#ifdef MOCK___XSTAT + VIR_MOCK_REAL_INIT(__xstat); + fdebug("real __xstat %p\n", real___xstat); +#endif +#ifdef MOCK___XSTAT64 + VIR_MOCK_REAL_INIT(__xstat64); + fdebug("real __xstat64 %p\n", real___xstat64); +#endif +#ifdef MOCK_LSTAT + VIR_MOCK_REAL_INIT(lstat); + fdebug("real lstat %p\n", real_lstat); +#endif +#ifdef MOCK_LSTAT64 + VIR_MOCK_REAL_INIT(lstat64); + fdebug("real lstat64 %p\n", real_lstat64); +#endif +#ifdef MOCK___LXSTAT + VIR_MOCK_REAL_INIT(__lxstat); + fdebug("real __lxstat %p\n", real___lxstat); +#endif +#ifdef MOCK___LXSTAT64 + VIR_MOCK_REAL_INIT(__lxstat64); + fdebug("real __lxstat64 %p\n", real___lxstat64); +#endif +} + +/* + * @stat: the path being queried + * @newpath: fill with redirected path, or leave NULL to use orig path + * + * Return 0 on success, -1 on allocation error + */ +static int virMockStatRedirect(const char *path, char **newpath); + +#ifndef VIR_MOCK_STAT_HOOK +# define VIR_MOCK_STAT_HOOK do { } while (0) +#endif + +#ifdef MOCK_STAT +int stat(const char *path, struct stat *sb) +{ + VIR_AUTOFREE(char *) newpath =3D NULL; + + virMockStatInit(); + + if (virMockStatRedirect(path, &newpath) < 0) + abort(); + fdebug("stat redirect %s to %s sb=3D%p\n", path, newpath ? newpath : p= ath, sb); + + VIR_MOCK_STAT_HOOK; + + return real_stat(newpath ? newpath : path, sb); +} +#endif + +#ifdef MOCK_STAT64 +int stat64(const char *path, struct stat64 *sb) +{ + VIR_AUTOFREE(char *) newpath =3D NULL; + + virMockStatInit(); + + if (virMockStatRedirect(path, &newpath) < 0) + abort(); + fdebug("stat64 redirect %s to %s sb=3D%p\n", path, newpath ? newpath := path, sb); + + VIR_MOCK_STAT_HOOK; + + return real_stat64(newpath ? newpath : path, sb); +} +#endif + +#ifdef MOCK___XSTAT +int +__xstat(int ver, const char *path, struct stat *sb) +{ + VIR_AUTOFREE(char *) newpath =3D NULL; + + virMockStatInit(); + + if (virMockStatRedirect(path, &newpath) < 0) + abort(); + fdebug("__xstat redirect %s to %s sb=3D%p\n", path, newpath ? newpath = : path, sb); + + VIR_MOCK_STAT_HOOK; + + return real___xstat(ver, newpath ? newpath : path, sb); +} +#endif + +#ifdef MOCK___XSTAT64 +int +__xstat64(int ver, const char *path, struct stat64 *sb) +{ + VIR_AUTOFREE(char *) newpath =3D NULL; + + virMockStatInit(); + + if (virMockStatRedirect(path, &newpath) < 0) + abort(); + fdebug("__xstat64 redirect %s to %s sb=3D%p\n", path, newpath ? newpat= h : path, sb); + + VIR_MOCK_STAT_HOOK; + + return real___xstat64(ver, newpath ? newpath : path, sb); +} +#endif + +#ifdef MOCK_LSTAT +int +lstat(const char *path, struct stat *sb) +{ + VIR_AUTOFREE(char *) newpath =3D NULL; + + virMockStatInit(); + + if (virMockStatRedirect(path, &newpath) < 0) + abort(); + fdebug("lstat redirect %s to %s sb=3D%p\n", path, newpath ? newpath : = path, sb); + + VIR_MOCK_STAT_HOOK; + + return real_lstat(newpath ? newpath : path, sb); +} +#endif + +#ifdef MOCK_LSTAT64 +int +lstat64(const char *path, struct stat64 *sb) +{ + VIR_AUTOFREE(char *) newpath =3D NULL; + + virMockStatInit(); + + if (virMockStatRedirect(path, &newpath) < 0) + abort(); + fdebug("lstat64 redirect %s to %s sb=3D%p\n", path, newpath ? newpath = : path, sb); + + VIR_MOCK_STAT_HOOK; + + return real_lstat64(newpath ? newpath : path, sb); +} +#endif + +#ifdef MOCK___LXSTAT +int +__lxstat(int ver, const char *path, struct stat *sb) +{ + VIR_AUTOFREE(char *) newpath =3D NULL; + + virMockStatInit(); + + if (virMockStatRedirect(path, &newpath) < 0) + abort(); + fdebug("__lxstat redirect %s to %s sb=3D%p\n", path, newpath ? newpath= : path, sb); + + VIR_MOCK_STAT_HOOK; + + return real___lxstat(ver, newpath ? newpath : path, sb); +} +#endif + +#ifdef MOCK___LXSTAT64 +int +__lxstat64(int ver, const char *path, struct stat64 *sb) +{ + VIR_AUTOFREE(char *) newpath =3D NULL; + + virMockStatInit(); + + if (virMockStatRedirect(path, &newpath) < 0) + abort(); + fdebug("__lxstat64 redirect %s to %s sb=3D%p\n", path, newpath ? newpa= th : path, sb); + + VIR_MOCK_STAT_HOOK; + + return real___lxstat64(ver, newpath ? newpath : path, sb); +} +#endif diff --git a/tests/virpcimock.c b/tests/virpcimock.c index ce8176cbec..7f9cdaa9b8 100644 --- a/tests/virpcimock.c +++ b/tests/virpcimock.c @@ -31,10 +31,6 @@ # include "dirname.h" =20 static int (*real_access)(const char *path, int mode); -static int (*real_lstat)(const char *path, struct stat *sb); -static int (*real___lxstat)(int ver, const char *path, struct stat *sb); -static int (*real_stat)(const char *path, struct stat *sb); -static int (*real___xstat)(int ver, const char *path, struct stat *sb); static int (*real_open)(const char *path, int flags, ...); static int (*real_close)(int fd); static DIR * (*real_opendir)(const char *name); @@ -365,15 +361,9 @@ pci_device_new_from_stub(const struct pciDevice *data) if (virFileMakePath(devpath) < 0) ABORT("Unable to create: %s", devpath); =20 - if (real_stat && real_stat(configSrc, &sb) =3D=3D 0) + if (stat(configSrc, &sb) =3D=3D 0) configSrcExists =3D true; =20 -# ifdef HAVE___XSTAT - if (!configSrcExists && - real___xstat && real___xstat(_STAT_VER, configSrc, &sb) =3D=3D 0) - configSrcExists =3D true; -# endif - /* If there is a config file for the device within virpcitestdata dir, * symlink it. Otherwise create a dummy config file. */ if (configSrcExists) { @@ -813,8 +803,6 @@ init_syms(void) return; =20 VIR_MOCK_REAL_INIT(access); - VIR_MOCK_REAL_INIT_ALT(lstat, __lxstat); - VIR_MOCK_REAL_INIT_ALT(stat, __xstat); VIR_MOCK_REAL_INIT(open); VIR_MOCK_REAL_INIT(close); VIR_MOCK_REAL_INIT(opendir); @@ -896,85 +884,17 @@ access(const char *path, int mode) return ret; } =20 -# ifdef HAVE___LXSTAT -int -__lxstat(int ver, const char *path, struct stat *sb) -{ - int ret; - - init_syms(); - - if (STRPREFIX(path, SYSFS_PCI_PREFIX)) { - char *newpath; - if (getrealpath(&newpath, path) < 0) - return -1; - ret =3D real___lxstat(ver, newpath, sb); - VIR_FREE(newpath); - } else { - ret =3D real___lxstat(ver, path, sb); - } - return ret; -} -# endif /* HAVE___LXSTAT */ - -int -lstat(const char *path, struct stat *sb) -{ - int ret; - - init_syms(); - - if (STRPREFIX(path, SYSFS_PCI_PREFIX)) { - char *newpath; - if (getrealpath(&newpath, path) < 0) - return -1; - ret =3D real_lstat(newpath, sb); - VIR_FREE(newpath); - } else { - ret =3D real_lstat(path, sb); - } - return ret; -} =20 -# ifdef HAVE___XSTAT -int -__xstat(int ver, const char *path, struct stat *sb) +static int +virMockStatRedirect(const char *path, char **newpath) { - int ret; - - init_syms(); - if (STRPREFIX(path, SYSFS_PCI_PREFIX)) { - char *newpath; - if (getrealpath(&newpath, path) < 0) + if (getrealpath(newpath, path) < 0) return -1; - ret =3D real___xstat(ver, newpath, sb); - VIR_FREE(newpath); - } else { - ret =3D real___xstat(ver, path, sb); } - return ret; + return 0; } -# endif /* HAVE___XSTAT */ =20 -int -stat(const char *path, struct stat *sb) -{ - int ret; - - init_syms(); - - if (STRPREFIX(path, SYSFS_PCI_PREFIX)) { - char *newpath; - if (getrealpath(&newpath, path) < 0) - return -1; - ret =3D real_stat(newpath, sb); - VIR_FREE(newpath); - } else { - ret =3D real_stat(path, sb); - } - return ret; -} =20 int open(const char *path, int flags, ...) @@ -1058,6 +978,9 @@ virFileCanonicalizePath(const char *path) =20 return ret; } + +# include "virmockstathelpers.c" + #else /* Nothing to override on this platform */ #endif diff --git a/tests/virtestmock.c b/tests/virtestmock.c index 3049c90789..bc62312444 100644 --- a/tests/virtestmock.c +++ b/tests/virtestmock.c @@ -36,33 +36,9 @@ #include "viralloc.h" #include "virfile.h" =20 -/* stat can be a macro as follows: - * - * #define stat stat64 - * - * This wouldn't fly with our mock. Make sure that the macro (and - * all its friends) are undefined. We don't want anybody mangling - * our code. */ -#undef stat -#undef stat64 -#undef __xstat -#undef __xstat64 -#undef lstat -#undef lstat64 -#undef __lxstat -#undef __lxstat64 - static int (*real_open)(const char *path, int flags, ...); static FILE *(*real_fopen)(const char *path, const char *mode); static int (*real_access)(const char *path, int mode); -static int (*real_stat)(const char *path, struct stat *sb); -static int (*real_stat64)(const char *path, void *sb); -static int (*real___xstat)(int ver, const char *path, struct stat *sb); -static int (*real___xstat64)(int ver, const char *path, void *sb); -static int (*real_lstat)(const char *path, struct stat *sb); -static int (*real_lstat64)(const char *path, void *sb); -static int (*real___lxstat)(int ver, const char *path, struct stat *sb); -static int (*real___lxstat64)(int ver, const char *path, void *sb); static int (*real_connect)(int fd, const struct sockaddr *addr, socklen_t = addrlen); =20 static const char *progname; @@ -78,10 +54,6 @@ static void init_syms(void) VIR_MOCK_REAL_INIT(open); VIR_MOCK_REAL_INIT(fopen); VIR_MOCK_REAL_INIT(access); - VIR_MOCK_REAL_INIT_ALT(stat, __xstat); - VIR_MOCK_REAL_INIT_ALT(stat64, __xstat64); - VIR_MOCK_REAL_INIT_ALT(lstat, __lxstat); - VIR_MOCK_REAL_INIT_ALT(lstat64, __lxstat64); VIR_MOCK_REAL_INIT(connect); } =20 @@ -217,119 +189,15 @@ int access(const char *path, int mode) return real_access(path, mode); } =20 -/* Okay, the following ifdef rain forest may look messy at a - * first glance. But here's the thing: during run time linking of - * a binary, stat() may not be actually needing symbol stat. It - * might as well not had been stat() in the first place (see the - * reasoning at the beginning of this file). However, if we would - * expose stat symbol here, we will poison the well and trick - * dynamic linker into thinking we are some old binary that still - * uses the symbol. So whenever code from upper layers calls - * stat(), the control would get here, but real_stat can actually - * be a NULL pointer because newer glibc have __xstat instead. - * Worse, it can have __xstat64 instead __xstat. - * - * Anyway, these ifdefs are there to implement the following - * preference function: - * - * stat < stat64 < __xstat < __xstat64 - * - * It's the same story with lstat. - * Also, I feel sorry for you that you had to read this. - */ -#if defined(HAVE_STAT) && !defined(HAVE___XSTAT) -int stat(const char *path, struct stat *sb) -{ - init_syms(); =20 - checkPath(path, "stat"); +#define VIR_MOCK_STAT_HOOK CHECK_PATH(path) =20 - return real_stat(path, sb); -} -#endif +#include "virmockstathelpers.c" =20 -#if defined(HAVE_STAT64) && !defined(HAVE___XSTAT64) -int stat64(const char *path, struct stat64 *sb) +static int virMockStatRedirect(const char *path ATTRIBUTE_UNUSED, char **n= ewpath ATTRIBUTE_UNUSED) { - init_syms(); - - checkPath(path, "stat"); - - return real_stat64(path, sb); + return 0; } -#endif - -#if defined(HAVE___XSTAT) && !defined(HAVE___XSTAT64) -int -__xstat(int ver, const char *path, struct stat *sb) -{ - init_syms(); - - checkPath(path, "stat"); - - return real___xstat(ver, path, sb); -} -#endif - -#if defined(HAVE___XSTAT64) -int -__xstat64(int ver, const char *path, struct stat64 *sb) -{ - init_syms(); - - checkPath(path, "stat"); - - return real___xstat64(ver, path, sb); -} -#endif - -#if defined(HAVE_LSTAT) && !defined(HAVE___LXSTAT) -int -lstat(const char *path, struct stat *sb) -{ - init_syms(); - - checkPath(path, "lstat"); - - return real_lstat(path, sb); -} -#endif - -#if defined(HAVE_LSTAT64) && !defined(HAVE___LXSTAT64) -int -lstat64(const char *path, struct stat64 *sb) -{ - init_syms(); - - checkPath(path, "lstat"); - - return real_lstat64(path, sb); -} -#endif - -#if defined(HAVE___LXSTAT) && !defined(HAVE___LXSTAT64) -int -__lxstat(int ver, const char *path, struct stat *sb) -{ - init_syms(); - - checkPath(path, "lstat"); - - return real___lxstat(ver, path, sb); -} -#endif - -#if defined(HAVE___LXSTAT64) -int -__lxstat64(int ver, const char *path, struct stat64 *sb) -{ - init_syms(); - - checkPath(path, "lstat"); - - return real___lxstat64(ver, path, sb); -} -#endif =20 =20 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) --=20 2.20.1 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list From nobody Sun May 19 03:02:39 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1554209030889140.6439512099479; Tue, 2 Apr 2019 05:43:50 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C7A2A30992DD; Tue, 2 Apr 2019 12:43:49 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 9BB361001DF1; Tue, 2 Apr 2019 12:43:49 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 5BCFB180338C; Tue, 2 Apr 2019 12:43:49 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id x32CeohZ008789 for ; Tue, 2 Apr 2019 08:40:50 -0400 Received: by smtp.corp.redhat.com (Postfix) id 458A068403; Tue, 2 Apr 2019 12:40:50 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-112-56.ams2.redhat.com [10.36.112.56]) by smtp.corp.redhat.com (Postfix) with ESMTP id EB3EB6A4B6; Tue, 2 Apr 2019 12:40:46 +0000 (UTC) From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: libvir-list@redhat.com Date: Tue, 2 Apr 2019 13:40:34 +0100 Message-Id: <20190402124036.2415-3-berrange@redhat.com> In-Reply-To: <20190402124036.2415-1-berrange@redhat.com> References: <20190402124036.2415-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH 2/4] qemu: don't rely on the non-portable d_type field in dirent X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.43]); Tue, 02 Apr 2019 12:43:50 +0000 (UTC) d_type is a non-portable extension to the struct dirent and even if it exists, its value may be DT_UNKNOWN if the filesystem doesn't support it. This is common with older versions of XFS which have ftype=3D0 feature. Signed-off-by: Daniel P. Berrang=C3=A9 --- src/qemu/qemu_firmware.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_firmware.c b/src/qemu/qemu_firmware.c index 4ce010caaa..787b76b531 100644 --- a/src/qemu/qemu_firmware.c +++ b/src/qemu/qemu_firmware.c @@ -924,9 +924,7 @@ qemuFirmwareBuildFileList(virHashTablePtr files, const = char *dir) while ((rc =3D virDirRead(dirp, &ent, dir)) > 0) { VIR_AUTOFREE(char *) filename =3D NULL; VIR_AUTOFREE(char *) path =3D NULL; - - if (ent->d_type !=3D DT_REG && ent->d_type !=3D DT_LNK) - continue; + struct stat sb; =20 if (STRPREFIX(ent->d_name, ".")) continue; @@ -937,6 +935,14 @@ qemuFirmwareBuildFileList(virHashTablePtr files, const= char *dir) if (virAsprintf(&path, "%s/%s", dir, filename) < 0) goto cleanup; =20 + if (stat(path, &sb) < 0) { + virReportSystemError(errno, _("Unable to access %s"), path); + goto cleanup; + } + + if (!S_ISREG(sb.st_mode) && !S_ISLNK(sb.st_mode)) + continue; + if (virHashUpdateEntry(files, filename, path) < 0) goto cleanup; =20 --=20 2.20.1 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list From nobody Sun May 19 03:02:39 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1554208918485498.188483495018; Tue, 2 Apr 2019 05:41:58 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6743B74F0B; Tue, 2 Apr 2019 12:41:55 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 44E621853F; Tue, 2 Apr 2019 12:41:55 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 0A8ED41F3C; Tue, 2 Apr 2019 12:41:55 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id x32Cepf1008805 for ; Tue, 2 Apr 2019 08:40:51 -0400 Received: by smtp.corp.redhat.com (Postfix) id D927068403; Tue, 2 Apr 2019 12:40:51 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-112-56.ams2.redhat.com [10.36.112.56]) by smtp.corp.redhat.com (Postfix) with ESMTP id BCE626A49C; Tue, 2 Apr 2019 12:40:50 +0000 (UTC) From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: libvir-list@redhat.com Date: Tue, 2 Apr 2019 13:40:35 +0100 Message-Id: <20190402124036.2415-4-berrange@redhat.com> In-Reply-To: <20190402124036.2415-1-berrange@redhat.com> References: <20190402124036.2415-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH 3/4] security: avoid use of dirent d_type field X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Tue, 02 Apr 2019 12:41:56 +0000 (UTC) The d_type field cannot be assumed to be filled. Some filesystems, such as older XFS, will simply report DT_UNKNOWN. Even if the d_type is filled in, the use of it in the SELinux functions is dubious. If labelling all files in a directory there's no reason to skip things which are not regular files. We merely need to skip "." and "..", which is done by virDirRead() already. Signed-off-by: Daniel P. Berrang=C3=A9 --- src/security/security_selinux.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/security/security_selinux.c b/src/security/security_selinu= x.c index 2fceb547b4..3611bb8ebe 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -3282,9 +3282,6 @@ virSecuritySELinuxSetFileLabels(virSecurityManagerPtr= mgr, return -1; =20 while ((ret =3D virDirRead(dir, &ent, path)) > 0) { - if (ent->d_type !=3D DT_REG) - continue; - if (virAsprintf(&filename, "%s/%s", path, ent->d_name) < 0) { ret =3D -1; break; @@ -3334,7 +3331,8 @@ virSecuritySELinuxRestoreFileLabels(virSecurityManage= rPtr mgr, return -1; =20 while ((ret =3D virDirRead(dir, &ent, path)) > 0) { - if (ent->d_type !=3D DT_REG) + if (STREQ(ent->d_name, ".") || + STREQ(ent->d_name, "..")) continue; =20 if (virAsprintf(&filename, "%s/%s", path, ent->d_name) < 0) { --=20 2.20.1 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list From nobody Sun May 19 03:02:39 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1554209035040467.614000379946; Tue, 2 Apr 2019 05:43:55 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C6EE6307D98E; Tue, 2 Apr 2019 12:43:53 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 98EE76839E; Tue, 2 Apr 2019 12:43:53 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 474913FB11; Tue, 2 Apr 2019 12:43:53 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id x32Cevc5008821 for ; Tue, 2 Apr 2019 08:40:57 -0400 Received: by smtp.corp.redhat.com (Postfix) id 9E3016A49F; Tue, 2 Apr 2019 12:40:57 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-112-56.ams2.redhat.com [10.36.112.56]) by smtp.corp.redhat.com (Postfix) with ESMTP id 133636A4B2; Tue, 2 Apr 2019 12:40:52 +0000 (UTC) From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: libvir-list@redhat.com Date: Tue, 2 Apr 2019 13:40:36 +0100 Message-Id: <20190402124036.2415-5-berrange@redhat.com> In-Reply-To: <20190402124036.2415-1-berrange@redhat.com> References: <20190402124036.2415-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH 4/4] cfg.mk: block use of d_type from dirent by default X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.48]); Tue, 02 Apr 2019 12:43:54 +0000 (UTC) The use of d_type is non-portable and leads to surprises when the OS does not fill in any value except DT_UNKNOWN. Blacklist its usage except in files which inherantly don't require portability (cgroup and selinux) Signed-off-by: Daniel P. Berrang=C3=A9 --- cfg.mk | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/cfg.mk b/cfg.mk index 2c473121a4..84d40d946a 100644 --- a/cfg.mk +++ b/cfg.mk @@ -1083,6 +1083,19 @@ sc_prohibit_class: halt=3D'use klass instead of class or _class' \ $(_sc_search_regexp) =20 +# The dirent "d_type" field is non-portable and even when it +# exists some filesystems will only ever return DT_UNKNOWN. +# This field should only be used by code which is exclusively +# run platforms supporting "d_type" and must expect DT_UNKNOWN. +# We blacklist it to discourage accidental usage which has +# happened many times. Add an exclude rule if it is genuinely +# needed and the above restrictions are acceptable. +sc_prohibit_dirent_d_type: + @prohibit=3D'(->|\.)d_type' \ + in_vc_files=3D'\.[chx]$$' \ + halt=3D'do not use the d_type field in "struct dirent"' \ + $(_sc_search_regexp) + =20 # We don't use this feature of maint.mk. prev_version_file =3D /dev/null @@ -1337,3 +1350,6 @@ exclude_file_name_regexp--sc_prohibit_readdir =3D \ =20 exclude_file_name_regexp--sc_prohibit_cross_inclusion =3D \ ^(src/util/virclosecallbacks\.h|src/util/virhostdev\.h)$$ + +exclude_file_name_regexp--sc_prohibit_dirent_d_type =3D \ + ^(src/util/vircgroup.c)$ --=20 2.20.1 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list