2012-01-27 02:01:41 +07:00
|
|
|
/*
|
2013-01-16 20:27:21 +07:00
|
|
|
* Copyright (C) 2012-2013 ProFUSION embedded systems
|
2012-01-27 02:01:41 +07:00
|
|
|
*
|
2012-07-10 19:42:24 +07:00
|
|
|
* This program 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.
|
2012-01-27 02:01:41 +07:00
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2012-07-10 19:42:24 +07:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
2012-01-27 02:01:41 +07:00
|
|
|
*
|
2012-07-10 19:42:24 +07:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2014-12-26 08:32:03 +07:00
|
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
2012-01-27 02:01:41 +07:00
|
|
|
*/
|
|
|
|
|
testsuite: fix override of `stat` on 32-bit architectures
When _FILE_OFFSET_BITS is 64, glibc headers turn `stat` calls into
`stat64`, and our `stat` override into a `stat64` function. However,
because we use dlsym to get the address of libc's `stat`, we end up
calling into the "real" `stat` function, which deals with 32-bit off_t,
and we treat its result as if it were returned from stat64. On most
architectures this seems to have been harmless, but on 32-bit mips,
st_mode's offset in struct stat and struct stat64 are different, so we
read garbage.
To fix this, explicitly unset _FILE_OFFSET_BITS in path.c, to turn off
the redirect magic in glibc headers, and override both the 32-bit and
64-bit functions so each call ends up wrapping the right libc function.
Fixes #16 (https://github.com/kmod-project/kmod/issues/16)
2022-09-05 15:32:12 +07:00
|
|
|
/* We unset _FILE_OFFSET_BITS here so we can override both stat and stat64 on
|
|
|
|
* 32-bit architectures and forward each to the right libc function */
|
|
|
|
#undef _FILE_OFFSET_BITS
|
|
|
|
|
2012-01-25 11:44:45 +07:00
|
|
|
#include <assert.h>
|
2012-01-25 21:42:13 +07:00
|
|
|
#include <dirent.h>
|
2012-01-25 11:44:45 +07:00
|
|
|
#include <dlfcn.h>
|
2014-10-03 11:41:42 +07:00
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
2012-01-25 11:44:45 +07:00
|
|
|
#include <limits.h>
|
2012-01-25 20:36:28 +07:00
|
|
|
#include <stdarg.h>
|
2012-01-25 11:44:45 +07:00
|
|
|
#include <stdio.h>
|
2014-10-03 11:41:42 +07:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2012-01-25 21:22:50 +07:00
|
|
|
#include <unistd.h>
|
2014-10-03 11:41:42 +07:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
2012-01-25 11:44:45 +07:00
|
|
|
|
2015-01-08 04:14:20 +07:00
|
|
|
#include <shared/util.h>
|
|
|
|
|
2012-01-25 11:44:45 +07:00
|
|
|
#include "testsuite.h"
|
|
|
|
|
|
|
|
static void *nextlib;
|
|
|
|
static const char *rootpath;
|
|
|
|
static size_t rootpathlen;
|
|
|
|
|
|
|
|
static inline bool need_trap(const char *path)
|
|
|
|
{
|
2015-01-08 04:14:20 +07:00
|
|
|
return path != NULL && path[0] == '/'
|
|
|
|
&& !strstartswith(path, ABS_TOP_BUILDDIR);
|
2012-01-25 11:44:45 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static const char *trap_path(const char *path, char buf[PATH_MAX * 2])
|
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
if (!need_trap(path))
|
|
|
|
return path;
|
|
|
|
|
|
|
|
len = strlen(path);
|
|
|
|
|
|
|
|
if (len + rootpathlen > PATH_MAX * 2) {
|
|
|
|
errno = ENAMETOOLONG;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(buf, rootpath, rootpathlen);
|
|
|
|
strcpy(buf + rootpathlen, path);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool get_rootpath(const char *f)
|
|
|
|
{
|
|
|
|
if (rootpath != NULL)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
rootpath = getenv(S_TC_ROOTFS);
|
|
|
|
if (rootpath == NULL) {
|
|
|
|
ERR("TRAP %s(): missing export %s?\n", f, S_TC_ROOTFS);
|
|
|
|
errno = ENOENT;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
rootpathlen = strlen(rootpath);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *get_libc_func(const char *f)
|
|
|
|
{
|
|
|
|
void *fp;
|
|
|
|
|
|
|
|
if (nextlib == NULL) {
|
|
|
|
#ifdef RTLD_NEXT
|
|
|
|
nextlib = RTLD_NEXT;
|
|
|
|
#else
|
|
|
|
nextlib = dlopen("libc.so.6", RTLD_LAZY);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
fp = dlsym(nextlib, f);
|
|
|
|
assert(fp);
|
|
|
|
|
|
|
|
return fp;
|
|
|
|
}
|
|
|
|
|
2012-08-02 04:35:34 +07:00
|
|
|
/* wrapper template for a function with one "const char* path" argument */
|
|
|
|
#define WRAP_1ARG(rettype, failret, name) \
|
|
|
|
TS_EXPORT rettype name(const char *path) \
|
|
|
|
{ \
|
|
|
|
const char *p; \
|
|
|
|
char buf[PATH_MAX * 2]; \
|
|
|
|
static rettype (*_fn)(const char*); \
|
|
|
|
\
|
|
|
|
if (!get_rootpath(__func__)) \
|
|
|
|
return failret; \
|
|
|
|
_fn = get_libc_func(#name); \
|
|
|
|
p = trap_path(path, buf); \
|
|
|
|
if (p == NULL) \
|
|
|
|
return failret; \
|
|
|
|
return (*_fn)(p); \
|
2012-01-25 11:44:45 +07:00
|
|
|
}
|
2012-01-25 20:36:28 +07:00
|
|
|
|
2012-08-02 04:35:34 +07:00
|
|
|
/* wrapper template for a function with "const char* path" and another argument */
|
|
|
|
#define WRAP_2ARGS(rettype, failret, name, arg2t) \
|
|
|
|
TS_EXPORT rettype name(const char *path, arg2t arg2) \
|
|
|
|
{ \
|
|
|
|
const char *p; \
|
|
|
|
char buf[PATH_MAX * 2]; \
|
|
|
|
static rettype (*_fn)(const char*, arg2t arg2); \
|
|
|
|
\
|
|
|
|
if (!get_rootpath(__func__)) \
|
|
|
|
return failret; \
|
|
|
|
_fn = get_libc_func(#name); \
|
|
|
|
p = trap_path(path, buf); \
|
|
|
|
if (p == NULL) \
|
|
|
|
return failret; \
|
|
|
|
return (*_fn)(p, arg2); \
|
2012-01-25 20:36:28 +07:00
|
|
|
}
|
2012-01-25 21:22:50 +07:00
|
|
|
|
2012-08-02 04:35:34 +07:00
|
|
|
/* wrapper template for open family */
|
|
|
|
#define WRAP_OPEN(suffix) \
|
|
|
|
TS_EXPORT int open ## suffix (const char *path, int flags, ...) \
|
|
|
|
{ \
|
|
|
|
const char *p; \
|
|
|
|
char buf[PATH_MAX * 2]; \
|
|
|
|
static int (*_fn)(const char *path, int flags, ...); \
|
|
|
|
\
|
|
|
|
if (!get_rootpath(__func__)) \
|
|
|
|
return -1; \
|
|
|
|
_fn = get_libc_func("open" #suffix); \
|
|
|
|
p = trap_path(path, buf); \
|
|
|
|
if (p == NULL) \
|
|
|
|
return -1; \
|
|
|
|
\
|
|
|
|
if (flags & O_CREAT) { \
|
|
|
|
mode_t mode; \
|
|
|
|
va_list ap; \
|
|
|
|
\
|
|
|
|
va_start(ap, flags); \
|
|
|
|
mode = va_arg(ap, mode_t); \
|
|
|
|
va_end(ap); \
|
|
|
|
return _fn(p, flags, mode); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
return _fn(p, flags); \
|
2012-05-24 11:58:54 +07:00
|
|
|
}
|
|
|
|
|
2012-08-02 04:35:34 +07:00
|
|
|
/* wrapper template for __xstat family */
|
|
|
|
#define WRAP_VERSTAT(prefix, suffix) \
|
|
|
|
TS_EXPORT int prefix ## stat ## suffix (int ver, \
|
|
|
|
const char *path, \
|
|
|
|
struct stat ## suffix *st) \
|
|
|
|
{ \
|
|
|
|
const char *p; \
|
|
|
|
char buf[PATH_MAX * 2]; \
|
|
|
|
static int (*_fn)(int ver, const char *path, \
|
|
|
|
struct stat ## suffix *); \
|
|
|
|
_fn = get_libc_func(#prefix "stat" #suffix); \
|
|
|
|
\
|
|
|
|
if (!get_rootpath(__func__)) \
|
|
|
|
return -1; \
|
|
|
|
p = trap_path(path, buf); \
|
|
|
|
if (p == NULL) \
|
|
|
|
return -1; \
|
|
|
|
\
|
|
|
|
return _fn(ver, p, st); \
|
2012-01-25 21:22:50 +07:00
|
|
|
}
|
|
|
|
|
2012-08-02 04:35:34 +07:00
|
|
|
WRAP_1ARG(DIR*, NULL, opendir);
|
2023-01-14 04:37:43 +07:00
|
|
|
WRAP_1ARG(int, -1, chdir);
|
2012-01-25 21:22:50 +07:00
|
|
|
|
2012-08-02 04:35:34 +07:00
|
|
|
WRAP_2ARGS(FILE*, NULL, fopen, const char*);
|
testsuite: fix override of `stat` on 32-bit architectures
When _FILE_OFFSET_BITS is 64, glibc headers turn `stat` calls into
`stat64`, and our `stat` override into a `stat64` function. However,
because we use dlsym to get the address of libc's `stat`, we end up
calling into the "real" `stat` function, which deals with 32-bit off_t,
and we treat its result as if it were returned from stat64. On most
architectures this seems to have been harmless, but on 32-bit mips,
st_mode's offset in struct stat and struct stat64 are different, so we
read garbage.
To fix this, explicitly unset _FILE_OFFSET_BITS in path.c, to turn off
the redirect magic in glibc headers, and override both the 32-bit and
64-bit functions so each call ends up wrapping the right libc function.
Fixes #16 (https://github.com/kmod-project/kmod/issues/16)
2022-09-05 15:32:12 +07:00
|
|
|
WRAP_2ARGS(FILE*, NULL, fopen64, const char*);
|
2012-08-02 04:35:34 +07:00
|
|
|
WRAP_2ARGS(int, -1, mkdir, mode_t);
|
|
|
|
WRAP_2ARGS(int, -1, access, int);
|
|
|
|
WRAP_2ARGS(int, -1, stat, struct stat*);
|
|
|
|
WRAP_2ARGS(int, -1, lstat, struct stat*);
|
2012-09-08 00:59:35 +07:00
|
|
|
WRAP_2ARGS(int, -1, stat64, struct stat64*);
|
2012-08-02 04:35:34 +07:00
|
|
|
WRAP_2ARGS(int, -1, lstat64, struct stat64*);
|
2012-09-08 00:59:35 +07:00
|
|
|
WRAP_OPEN(64);
|
2012-01-25 21:22:50 +07:00
|
|
|
|
2012-08-02 04:35:34 +07:00
|
|
|
WRAP_OPEN();
|
2012-01-25 21:22:50 +07:00
|
|
|
|
2012-08-02 04:35:34 +07:00
|
|
|
#ifdef HAVE___XSTAT
|
|
|
|
WRAP_VERSTAT(__x,);
|
|
|
|
WRAP_VERSTAT(__lx,);
|
2012-09-08 00:59:35 +07:00
|
|
|
WRAP_VERSTAT(__x,64);
|
2012-08-02 04:35:34 +07:00
|
|
|
WRAP_VERSTAT(__lx,64);
|
2012-02-09 05:29:52 +07:00
|
|
|
#endif
|