// Copyright 2016 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // for S_IF* #define _XOPEN_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "filesystems.h" // The __wrap_* symbols are generated by the linker, but this is done after all // bitcode has been translated when doing the LTO build, and as such compiler // might optimize these out as unused. To avoid this, we need to explicitly mark // these as used. #define FN(n) __attribute__((used)) __wrap_##n #define FL(n) __real_##n int status_to_errno(zx_status_t status) { switch (status) { case ZX_OK: return 0; default: return EIO; } } #define FAIL(err) \ do { \ return err ? -1 : 0; \ } while (0) #define STATUS(status) \ FAIL(status_to_errno(status)) #define PATH_WRAP(path_in, path_out) \ do { \ if (wrap_path(path_in, path_out)) \ FAIL(EINVAL); \ } while (0) #define DO_REAL(name, args...) \ do { \ int status = __real_##name(args); \ if (status < 0) \ STATUS(status); \ return status; \ } while (0) #define PATH_PREFIX "::" #define PREFIX_SIZE 2 // Occasionally, we test with paths that push against PATH_MAX. // Our 'wrap' functions should *not* be the cause of error; rather, we should see errors emerging // from either libc or our filesystems themselves. #define WPATH_MAX (PATH_MAX * 2) static inline int wrap_path(const char* path_in, char* path_out) { path_out[0] = '\0'; int bytes_left = WPATH_MAX - 1; if (strncmp(path_in, PATH_PREFIX, PREFIX_SIZE) || (kMountPath == NULL)) { // Unfiltered path strncat(path_out, path_in, bytes_left); return 0; } // Remove the "::" prefix, and substitute the actual path strncat(path_out, kMountPath, bytes_left); bytes_left -= strlen(kMountPath); strncat(path_out, "/", bytes_left); bytes_left -= 1; strncat(path_out, path_in + PREFIX_SIZE, bytes_left); return 0; } int FL(open)(const char* path, int flags, mode_t mode); int FN(open)(const char* path, int flags, mode_t mode) { char real_path[WPATH_MAX]; PATH_WRAP(path, real_path); DO_REAL(open, real_path, flags, mode); } DIR* FL(opendir)(const char* path); DIR* FN(opendir)(const char* path) { char real_path[WPATH_MAX]; if (wrap_path(path, real_path)) { return NULL; } return __real_opendir(real_path); } int FL(chdir)(const char* path); int FN(chdir)(const char* path) { char real_path[WPATH_MAX]; PATH_WRAP(path, real_path); DO_REAL(chdir, real_path); } int FL(mkdir)(const char* path, mode_t mode); int FN(mkdir)(const char* path, mode_t mode) { char real_path[WPATH_MAX]; PATH_WRAP(path, real_path); DO_REAL(mkdir, real_path, mode); } int FL(unlink)(const char* path); int FN(unlink)(const char* path) { char real_path[WPATH_MAX]; PATH_WRAP(path, real_path); DO_REAL(unlink, real_path); } int FL(rmdir)(const char* path); int FN(rmdir)(const char* path) { char real_path[WPATH_MAX]; PATH_WRAP(path, real_path); DO_REAL(rmdir, real_path); } int FL(remove)(const char* path); int FN(remove)(const char* path) { char real_path[WPATH_MAX]; PATH_WRAP(path, real_path); DO_REAL(remove, real_path); } int FL(truncate)(const char* path, off_t len); int FN(truncate)(const char* path, off_t len) { char real_path[WPATH_MAX]; PATH_WRAP(path, real_path); DO_REAL(truncate, real_path, len); } int FL(rename)(const char* oldpath, const char* newpath); int FN(rename)(const char* oldpath, const char* newpath) { char real_oldpath[WPATH_MAX]; char real_newpath[WPATH_MAX]; PATH_WRAP(oldpath, real_oldpath); PATH_WRAP(newpath, real_newpath); DO_REAL(rename, real_oldpath, real_newpath); } char* FL(realpath)(const char* path, char* resolved_path); char* FN(realpath)(const char* path, char* resolved_path) { char real_path[WPATH_MAX]; if (wrap_path(path, real_path)) { return NULL; } return __real_realpath(real_path, resolved_path); } int FL(renameat)(int olddirfd, const char* oldpath, int newdirfd, const char* newpath); int FN(renameat)(int olddirfd, const char* oldpath, int newdirfd, const char* newpath) { char real_oldpath[WPATH_MAX]; char real_newpath[WPATH_MAX]; PATH_WRAP(oldpath, real_oldpath); PATH_WRAP(newpath, real_newpath); DO_REAL(renameat, olddirfd, real_oldpath, newdirfd, real_newpath); } int FL(link)(const char* oldpath, const char* newpath); int FN(link)(const char* oldpath, const char* newpath) { char real_oldpath[WPATH_MAX]; char real_newpath[WPATH_MAX]; PATH_WRAP(oldpath, real_oldpath); PATH_WRAP(newpath, real_newpath); DO_REAL(link, real_oldpath, real_newpath); } int FL(symlink)(const char* oldpath, const char* newpath); int FN(symlink)(const char* oldpath, const char* newpath) { char real_oldpath[WPATH_MAX]; char real_newpath[WPATH_MAX]; PATH_WRAP(oldpath, real_oldpath); PATH_WRAP(newpath, real_newpath); DO_REAL(symlink, real_oldpath, real_newpath); } int FL(stat)(const char* fn, struct stat* s); int FN(stat)(const char* fn, struct stat* s) { char real_fn[WPATH_MAX]; PATH_WRAP(fn, real_fn); DO_REAL(stat, real_fn, s); } int FL(utimes)(const char* fn, struct timeval t[2]); int FN(utimes)(const char* fn, struct timeval t[2]) { char real_fn[WPATH_MAX]; PATH_WRAP(fn, real_fn); DO_REAL(utimes, real_fn, t); }