Merged PR 546149: [linux-sandbox] Eagerly load syscall symbols of importance

- eagerly call `dlsym` to resolve all sycall symbols upfront (instead of lazily once we are already handling a syscall)
 - call the original syscall implementation before reporting accesses (helps avoid potential deadlocks when there are multiple libraries intercepting syscalls)
 - capture the value of `errno` right after calling the original implementation, and restore it right before returning

Related work items: #1706182
This commit is contained in:
Aleksandar Milicevic 2020-04-11 00:41:26 +00:00
Родитель efdcf576a2
Коммит ec26ac404a
9 изменённых файлов: 525 добавлений и 405 удалений

Просмотреть файл

@ -57,10 +57,7 @@ namespace Tests.Linux {
// Engine
createDef(importFrom("BuildXL.Core.UnitTests").Cache.dll, true),
createDef(importFrom("BuildXL.Core.UnitTests").Cache.Plugin.Core.dll, true),
createDef(importFrom("BuildXL.Core.UnitTests").Processes.test_BuildXL_Processes_dll, true,
/* deploySeparately */ false,
// TODO: re-anable process tests once the issue with AzDev Ubuntu VM is resolved
/* testClasses */ [ "Bogus.Test.Class" ]),
createDef(importFrom("BuildXL.Core.UnitTests").Processes.test_BuildXL_Processes_dll, true),
// createDef(importFrom("BuildXL.Core.UnitTests").Engine.dll, true,
// /* deploySeparately */ false,

Просмотреть файл

@ -73,17 +73,15 @@ namespace BuildXL.Processes
internal string ReportsFifoPath { get; }
internal string FamPath { get; }
private readonly LoggingContext m_loggingContext;
private readonly Sandbox.ManagedFailureCallback m_failureCallback;
private readonly Dictionary<string, PathCacheRecord> m_pathCache; // TODO: use AbsolutePath instead of string
private readonly HashSet<int> m_activeProcesses;
private readonly Lazy<SafeFileHandle> m_lazyWriteHandle;
private readonly Thread m_workerThread;
internal Info(Sandbox.ManagedFailureCallback failureCallback, LoggingContext loggingContext, SandboxedProcessUnix process, string reportsFifoPath, string famPath)
internal Info(Sandbox.ManagedFailureCallback failureCallback, SandboxedProcessUnix process, string reportsFifoPath, string famPath)
{
m_failureCallback = failureCallback;
m_loggingContext = loggingContext;
Process = process;
ReportsFifoPath = reportsFifoPath;
FamPath = famPath;
@ -96,7 +94,11 @@ namespace BuildXL.Processes
// create a write handle (used to keep the fifo open, i.e.,
// the 'read' syscall won't receive EOF until we close this writer
m_lazyWriteHandle = new Lazy<SafeFileHandle>(() => IO.Open(ReportsFifoPath, IO.OpenFlags.O_WRONLY, 0));
m_lazyWriteHandle = new Lazy<SafeFileHandle>(() =>
{
LogDebug($"Opening FIFO '{ReportsFifoPath}' for writing");
return IO.Open(ReportsFifoPath, IO.OpenFlags.O_WRONLY, 0);
});
// start a background thread for reading from the FIFO
m_workerThread = new Thread(StartReceivingAccessReports);
@ -118,6 +120,7 @@ namespace BuildXL.Processes
/// </summary>
internal void RequestStop()
{
LogDebug($"Closing the write handle for FIFO '{ReportsFifoPath}'");
// this will cause read() on the other end of the FIFO to return EOF once all native writers are done writing
m_lazyWriteHandle.Value.Dispose();
}
@ -125,7 +128,8 @@ namespace BuildXL.Processes
/// <summary>Adds <paramref name="pid" /> to the set of active processes</summary>
internal void AddPid(int pid)
{
m_activeProcesses.Add(pid);
bool added = m_activeProcesses.Add(pid);
LogDebug($"AddPid({pid}) :: added: {added}; size: {m_activeProcesses.Count()}");
}
/// <summary>
@ -134,7 +138,8 @@ namespace BuildXL.Processes
/// </summary>
internal void RemovePid(int pid)
{
m_activeProcesses.Remove(pid);
bool removed = m_activeProcesses.Remove(pid);
LogDebug($"RemovePid({pid}) :: removed: {removed}; size: {m_activeProcesses.Count()}");
if (m_activeProcesses.Count == 0)
{
RequestStop();
@ -158,19 +163,13 @@ namespace BuildXL.Processes
internal void LogError(string message)
{
if (m_loggingContext != null)
{
Logger.Log.PipProcessStartFailed(m_loggingContext, Process.PipSemiStableHash, Process.PipDescription, Marshal.GetLastWin32Error(), message);
m_failureCallback?.Invoke(1, message);
}
Process.LogDebug("[ERROR]: " + message);
m_failureCallback?.Invoke(1, message);
}
internal void LogDebug(string message)
{
if (m_loggingContext != null)
{
Tracing.Logger.Log.LogDetoursDebugMessage(m_loggingContext, Process.PipSemiStableHash, message);
}
Process.LogDebug(message);
}
/// <nodoc />
@ -189,7 +188,8 @@ namespace BuildXL.Processes
// Format:
// "%s|%d|%d|%d|%d|%d|%d|%s\n", __progname, getpid(), access, status, explicitLogging, err, opcode, reportPath
string message = Encoding.GetString(bytes).TrimEnd('\n');
LogDebug($"Processing message: {message}");
// parse message and create AccessReport
string[] parts = message.Split(new[] { '|' });
Contract.Assert(parts.Length == 8);
@ -266,6 +266,7 @@ namespace BuildXL.Processes
var fifoName = ReportsFifoPath;
// opening FIFO for reading (blocks until there is at least one writer connected)
LogDebug($"Opening FIFO '{fifoName}' for reading");
using var readHandle = IO.Open(fifoName, IO.OpenFlags.O_RDONLY, 0);
if (readHandle.IsInvalid)
{
@ -312,8 +313,7 @@ namespace BuildXL.Processes
break;
}
// Update last received timestamp
long now = DateTime.UtcNow.Ticks;
LogDebug($"Received a {numRead}-byte message");
// Add message to processing queue
actionBlock.Post(messageBytes);
@ -424,6 +424,8 @@ namespace BuildXL.Processes
File.WriteAllBytes(famPath, manifestBytes.ToArray());
}
process.LogDebug($"Saved FAM to '{famPath}'");
// create a FIFO (named pipe)
if (IO.MkFifo(fifoPath, IO.FilePermissions.S_IRWXU) != 0)
{
@ -431,8 +433,10 @@ namespace BuildXL.Processes
return false;
}
process.LogDebug($"Created FIFO at '{fifoPath}'");
// create and save info for this pip
var info = new Info(m_failureCallback, loggingContext, process, fifoPath, famPath);
var info = new Info(m_failureCallback, process, fifoPath, famPath);
if (!m_pipProcesses.TryAdd(process.PipId, info))
{
throw new BuildXLException($"Process with PidId {process.PipId} already exists");

Просмотреть файл

@ -592,6 +592,17 @@ namespace BuildXL.Processes
m_sumOfReportQueueTimesUs += (stats.DequeueTime - stats.EnqueueTime) / 1000;
}
/// <summary>
/// Logs a detailed message if <see cref="FileAccessManifest.ReportFileAccesses"/> is set.
/// </summary>
internal void LogDebug(string message)
{
if (ShouldReportFileAccesses)
{
LogProcessState(message);
}
}
private void HandleAccessReport(AccessReport report)
{
if (ShouldReportFileAccesses)

Просмотреть файл

@ -28,18 +28,19 @@ BxlObserver* BxlObserver::GetInstance()
BxlObserver::BxlObserver()
{
GEN_REAL(FILE*, fopen, const char *, const char *);
GEN_REAL(size_t, fread, void*, size_t, size_t, FILE*);
GEN_REAL(int, fclose, FILE*);
GEN_REAL(ssize_t, readlink, const char *, char *, size_t);
real_readlink("/proc/self/exe", progFullPath_, PATH_MAX);
InitFam();
InitLogFile();
}
void BxlObserver::InitFam()
{
// read FAM env var
const char *famPath = getenv(BxlEnvFamPath);
if (!(famPath && *famPath))
{
_fatal("Env var '%s' not set", BxlEnvFamPath);
fprintf(stderr, "[%s] ERROR: Env var '%s' not set\n", __func__, BxlEnvFamPath);
return;
}
// read FAM
@ -74,12 +75,22 @@ BxlObserver::BxlObserver()
sandbox_->SetAccessReportCallback(HandleAccessReport);
}
void BxlObserver::InitLogFile()
{
const char *logPath = getenv(BxlEnvLogPath);
if (logPath && *logPath)
{
strlcpy(logFile_, logPath, PATH_MAX);
logFile_[PATH_MAX-1] = '\0';
}
else
{
logFile_[0] = '\0';
}
}
bool BxlObserver::Send(const char *buf, size_t bufsiz)
{
GEN_REAL(int, open, const char *, int);
GEN_REAL(ssize_t, write, int, const void*, size_t);
GEN_REAL(int, close, int);
if (!real_open)
{
_fatal("syscall 'open' not found; errno: %d", errno);
@ -92,7 +103,7 @@ bool BxlObserver::Send(const char *buf, size_t bufsiz)
}
const char *reportsPath = GetReportsPath();
int logFd = real_open(reportsPath, O_WRONLY | O_APPEND);
int logFd = real_open(reportsPath, O_WRONLY | O_APPEND, 0);
if (logFd == -1)
{
_fatal("Could not open file '%s'; errno: %d", reportsPath, errno);
@ -110,8 +121,6 @@ bool BxlObserver::Send(const char *buf, size_t bufsiz)
bool BxlObserver::SendReport(AccessReport &report)
{
GEN_REAL(char*, realpath, const char*, char*);
// there is no central sendbox process here (i.e., there is an instance of this
// guy in every child process), so counting process tree size is not feasible
if (report.operation == FileOperation::kOpProcessTreeCompleted)
@ -119,19 +128,12 @@ bool BxlObserver::SendReport(AccessReport &report)
return true;
}
char realpathBuf[PATH_MAX];
char *realpathPtr = real_realpath(report.path, realpathBuf);
int err = realpathPtr == NULL ? 2 : 0;
const char *reportPath = realpathPtr == NULL ? report.path : realpathPtr;
RequestedAccess realAccess = realpathPtr == NULL ? RequestedAccess::Probe : (RequestedAccess)report.requestedAccess;
const int PrefixLength = sizeof(uint);
char buffer[PIPE_BUF] = {0};
int maxMessageLength = PIPE_BUF - PrefixLength;
int numWritten = snprintf(
&buffer[PrefixLength], maxMessageLength, "%s|%d|%d|%d|%d|%d|%d|%s\n",
__progname, getpid(), (int)realAccess, report.status, report.reportExplicitly, err, report.operation, reportPath);
__progname, getpid(), report.requestedAccess, report.status, report.reportExplicitly, report.error, report.operation, report.path);
if (numWritten == maxMessageLength)
{
// TODO: once 'send' is capable of sending more than PIPE_BUF at once, allocate a bigger buffer and send that
@ -141,3 +143,128 @@ bool BxlObserver::SendReport(AccessReport &report)
*(uint*)(buffer) = numWritten;
return Send(buffer, numWritten + PrefixLength);
}
bool BxlObserver::report_access(const char *syscallName, es_event_type_t eventType, std::string reportPath, std::string secondPath)
{
// TODO: don't stat all the time
struct stat s;
mode_t mode = real___lxstat(1, reportPath.c_str(), &s) == 0
? s.st_mode
: 0;
std::string execPath = eventType == ES_EVENT_TYPE_NOTIFY_EXEC
? reportPath
: std::string(progFullPath_);
IOEvent event(getpid(), 0, getppid(), eventType, reportPath, secondPath, execPath, mode, false);
return report_access(syscallName, event);
}
bool BxlObserver::report_access(const char *syscallName, IOEvent &event)
{
es_event_type_t eventType = event.GetEventType();
LogDebug("(( %10s:%2d )) %s", syscallName, event.GetEventType(), event.GetEventPath());
if (IsValid())
{
IOHandler handler(sandbox_);
handler.SetProcess(process_);
handler.HandleEvent(event); // TODO: this should return AccessCheckResult, which should be returned from here
return true;
}
else
{
return false;
}
}
bool BxlObserver::report_access(const char *syscallName, es_event_type_t eventType, const char *pathname)
{
return report_access(syscallName, eventType, normalize_path(pathname), "");
}
bool BxlObserver::report_access_fd(const char *syscallName, es_event_type_t eventType, int fd)
{
char fullpath[PATH_MAX] = {0};
fd_to_path(fd, fullpath, PATH_MAX);
return report_access(syscallName, eventType, fullpath);
}
bool BxlObserver::report_access_at(const char *syscallName, es_event_type_t eventType, int dirfd, const char *pathname)
{
char fullpath[PATH_MAX] = {0};
ssize_t len = 0;
if (dirfd == AT_FDCWD)
{
getcwd(fullpath, PATH_MAX);
len = strlen(fullpath);
}
else
{
len = fd_to_path(dirfd, fullpath, PATH_MAX);
}
if (len <= 0)
{
_fatal("Could not get path for fd %d; errno: %d", dirfd, errno);
}
snprintf(&fullpath[len], PATH_MAX - len, "/%s", pathname);
return report_access(syscallName, eventType, fullpath);
}
static enum RequestedAccess oflag_to_access(int oflag)
{
return oflag & (O_WRONLY | O_RDWR) ? RequestedAccess::Write : RequestedAccess::Read;
}
ssize_t BxlObserver::fd_to_path(int fd, char *buf, size_t bufsiz)
{
char procPath[100] = {0};
sprintf(procPath, "/proc/self/fd/%d", fd);
return real_readlink(procPath, buf, bufsiz);
}
std::string BxlObserver::normalize_path_at(int dirfd, const char *pathname)
{
char fullpath[PATH_MAX] = {0};
char finalPath[PATH_MAX] = {0};
ssize_t len = 0;
// no pathname given --> read path for dirfd
if (pathname == NULL)
{
fd_to_path(dirfd, fullpath, PATH_MAX);
return fullpath;
}
// if relative path --> resolve it against dirfd
else if (*pathname != '/' && *pathname != '~')
{
if (dirfd == AT_FDCWD)
{
getcwd(fullpath, PATH_MAX);
len = strlen(fullpath);
}
else
{
len = fd_to_path(dirfd, fullpath, PATH_MAX);
}
if (len <= 0)
{
_fatal("Could not get path for fd %d; errno: %d", dirfd, errno);
}
snprintf(&fullpath[len], PATH_MAX - len, "/%s", pathname);
char *result = real_realpath(fullpath, finalPath);
return result != NULL ? result : fullpath;
}
else
{
char *result = real_realpath(pathname, finalPath);
return result != NULL ? result : pathname;
}
}

Просмотреть файл

@ -14,14 +14,43 @@
#define ARRAYSIZE(arr) (sizeof(arr)/sizeof(arr[0]))
#define GEN_REAL(ret, name, ...) \
#define GEN_FN_DEF(ret, name, ...) \
typedef ret (*fn_real_##name)(__VA_ARGS__); \
static fn_real_##name real_##name = NULL; \
if (!real_##name) { real_##name = (fn_real_##name)dlsym(RTLD_NEXT, #name); assert(real_##name); }
const fn_real_##name real_##name = (fn_real_##name)dlsym(RTLD_NEXT, #name);
#define INTERPOSE(ret, name, ...) \
ret name(__VA_ARGS__)
#define _fatal(fmt, ...) do { fprintf(stderr, "(%s) " fmt "\n", __func__, __VA_ARGS__); _exit(1); } while (0)
#define fatal(msg) _fatal("%s", msg)
/**
* Wraps the result of a syscall together with the current 'errno'.
*
* When the destructor is called, 'errno' is reset back to the value
* that was captured in the constructor.
*/
template <typename T>
class result_t final
{
private:
int my_errno_;
T result_;
public:
result_t(T result) : result_(result), my_errno_(errno) {}
~result_t() { errno = my_errno_; }
operator T() { return result_; }
};
/**
* Singleton class responsible for reporting accesses.
*
* Accesses are observed by intercepting syscalls.
*
* Accesses are reported to a file (can be a regular file or a FIFO)
* at the location specified by the FileAccessManifest.
*/
class BxlObserver final
{
private:
@ -31,23 +60,87 @@ private:
BxlObserver& operator = (const BxlObserver&) = delete;
char progFullPath_[PATH_MAX];
char logFile_[PATH_MAX];
std::shared_ptr<SandboxedPip> pip_;
std::shared_ptr<SandboxedProcess> process_;
Sandbox *sandbox_;
static BxlObserver *sInstance;
void InitFam();
void InitLogFile();
bool Send(const char *buf, size_t bufsiz);
bool IsValid() { return sandbox_ != NULL; }
static BxlObserver *sInstance;
#define LogDebug(fmt, ...) if (logFile_ && *logFile_) do { \
FILE* _lf = real_fopen(logFile_, "a"); \
if (_lf) fprintf(_lf, "[%s:%d] " fmt "\n", __progname, getpid(), __VA_ARGS__); \
if (_lf) real_fclose(_lf); \
} while(0);
public:
static BxlObserver* GetInstance();
bool SendReport(AccessReport &report);
inline std::shared_ptr<SandboxedPip> GetPip() { return pip_; }
inline std::shared_ptr<SandboxedProcess> GetProcess() { return process_; }
inline Sandbox* GetSandbox() { return sandbox_; }
inline const char* GetProgramPath() { return progFullPath_; }
inline const char* GetReportsPath() { int len; return pip_->GetReportsPath(&len); }
const char* GetProgramPath() { return progFullPath_; }
const char* GetReportsPath() { int len; return IsValid() ? pip_->GetReportsPath(&len) : NULL; }
static BxlObserver* GetInstance();
bool report_access(const char *syscallName, IOEvent &event);
bool report_access(const char *syscallName, es_event_type_t eventType, const char *pathname);
bool report_access(const char *syscallName, es_event_type_t eventType, std::string reportPath, std::string secondPath);
bool report_access_fd(const char *syscallName, es_event_type_t eventType, int fd);
bool report_access_at(const char *syscallName, es_event_type_t eventType, int dirfd, const char *pathname);
ssize_t fd_to_path(int fd, char *buf, size_t bufsiz);
std::string normalize_path_at(int dirfd, const char *pathname);
std::string normalize_path(const char *pathname)
{
return normalize_path_at(AT_FDCWD, pathname);
}
std::string normalize_fd(int fd)
{
return normalize_path_at(fd, NULL);
}
GEN_FN_DEF(pid_t, fork, void)
GEN_FN_DEF(int, fexecve, int, char *const[], char *const[])
GEN_FN_DEF(int, execv, const char *, char *const[])
GEN_FN_DEF(int, execve, const char *, char *const[], char *const[])
GEN_FN_DEF(int, execvp, const char *, char *const[])
GEN_FN_DEF(int, execvpe, const char *, char *const[], char *const[])
GEN_FN_DEF(int, __fxstat, int, int, struct stat*);
GEN_FN_DEF(int, statfs, const char *, struct statfs *)
GEN_FN_DEF(int, __xstat, int, const char *, struct stat *)
GEN_FN_DEF(int, __lxstat, int, const char *, struct stat *)
GEN_FN_DEF(int, __xstat64, int, const char*, struct stat64*)
GEN_FN_DEF(int, __lxstat64, int, const char*, struct stat64*)
GEN_FN_DEF(int, __fxstat64, int, int, struct stat64*)
GEN_FN_DEF(FILE*, fopen, const char *, const char *)
GEN_FN_DEF(size_t, fread, void*, size_t, size_t, FILE*)
GEN_FN_DEF(int, fclose, FILE*)
GEN_FN_DEF(int, access, const char *, int)
GEN_FN_DEF(int, faccessat, int, const char *, int, int)
GEN_FN_DEF(int, creat, const char *, mode_t)
GEN_FN_DEF(int, open, const char *, int, mode_t)
GEN_FN_DEF(int, openat, int, const char *, int, mode_t)
GEN_FN_DEF(int, close, int)
GEN_FN_DEF(ssize_t, write, int, const void*, size_t)
GEN_FN_DEF(int, remove, const char *)
GEN_FN_DEF(int, rename, const char *, const char *)
GEN_FN_DEF(int, link, const char *, const char *)
GEN_FN_DEF(int, linkat, int, const char *, int, const char *, int)
GEN_FN_DEF(int, unlink, const char *)
GEN_FN_DEF(int, symlink, const char *, const char *)
GEN_FN_DEF(int, symlinkat, const char *, int, const char *)
GEN_FN_DEF(ssize_t, readlink, const char *, char *, size_t)
GEN_FN_DEF(ssize_t, readlinkat, int, const char *, char *, size_t)
GEN_FN_DEF(char*, realpath, const char*, char*)
GEN_FN_DEF(DIR*, opendir, const char*)
GEN_FN_DEF(int, utimensat, int, const char*, const struct timespec[2], int)
GEN_FN_DEF(int, futimens, int, const struct timespec[2])
};

Просмотреть файл

@ -21,378 +21,249 @@
#include <sys/xattr.h>
#include "bxl_observer.hpp"
#include "IOHandler.hpp"
#include "EventProcessor.hpp"
static ssize_t fd_to_path(int fd, char *buf, size_t bufsiz)
static BxlObserver *g_bxl = BxlObserver::GetInstance();
INTERPOSE(pid_t, fork, void)
{
GEN_REAL(ssize_t, readlink, const char *, char *, size_t);
char procPath[100] = {0};
sprintf(procPath, "/proc/self/fd/%d", fd);
return real_readlink(procPath, buf, bufsiz);
}
static std::string normalize_path_at(int dirfd, const char *pathname)
{
// TODO: remove since it's being done in Send
GEN_REAL(char*, realpath, const char*, char*);
char fullpath[PATH_MAX] = {0};
char finalPath[PATH_MAX] = {0};
ssize_t len = 0;
// no pathname given --> read path for dirfd
if (pathname == NULL)
{
fd_to_path(dirfd, fullpath, PATH_MAX);
return fullpath;
}
// if relative path --> resolve it against dirfd
else if (*pathname != '/' && *pathname != '~')
{
if (dirfd == AT_FDCWD)
{
getcwd(fullpath, PATH_MAX);
len = strlen(fullpath);
}
else
{
len = fd_to_path(dirfd, fullpath, PATH_MAX);
}
if (len <= 0)
{
_fatal("Could not get path for fd %d; errno: %d", dirfd, errno);
}
snprintf(&fullpath[len], PATH_MAX - len, "/%s", pathname);
char *result = real_realpath(fullpath, finalPath);
return result != NULL ? result : fullpath;
}
else
{
char *result = real_realpath(pathname, finalPath);
return result != NULL ? result : pathname;
}
}
static std::string normalize_path(const char *pathname)
{
return normalize_path_at(AT_FDCWD, pathname);
}
static std::string normalize_fd(int fd)
{
return normalize_path_at(fd, NULL);
}
static bool report_access(const char *syscallName, IOEvent &event);
static bool report_access(const char *syscallName, es_event_type_t eventType, std::string reportPath, std::string secondPath)
{
GEN_REAL(int, __lxstat, int, const char *, struct stat *);
GEN_REAL(ssize_t, readlink, const char *, char *, size_t);
// TODO: don't stat all the time
struct stat s;
mode_t mode = real___lxstat(1, reportPath.c_str(), &s) == 0
? s.st_mode
: 0;
std::string execPath = eventType == ES_EVENT_TYPE_NOTIFY_EXEC
? reportPath
: std::string(BxlObserver::GetInstance()->GetProgramPath());
IOEvent event(getpid(), 0, getppid(), eventType, reportPath, secondPath, execPath, mode, false);
return report_access(syscallName, event);
}
static bool report_access(const char *syscallName, IOEvent &event)
{
es_event_type_t eventType = event.GetEventType();
BxlObserver *bxl_observer = BxlObserver::GetInstance();
IOHandler handler(bxl_observer->GetSandbox());
handler.SetProcess(bxl_observer->GetProcess());
// TODO: this should return AccessCheckResult, which should be returned from here
handler.HandleEvent(event);
return true;
}
static bool report_access(const char *syscallName, es_event_type_t eventType, const char *pathname, const char *otherPath = NULL)
{
std::string reportPath = normalize_path(pathname);
std::string secondPath = otherPath != NULL
? normalize_path(otherPath)
: "";
return report_access(syscallName, eventType, reportPath, secondPath);
}
static bool report_access_fd(const char *syscallName, es_event_type_t eventType, int fd)
{
char fullpath[PATH_MAX] = {0};
fd_to_path(fd, fullpath, PATH_MAX);
return report_access(syscallName, eventType, fullpath);
}
static bool report_access_at(const char *syscallName, es_event_type_t eventType, int dirfd, const char *pathname)
{
char fullpath[PATH_MAX] = {0};
ssize_t len = 0;
if (dirfd == AT_FDCWD)
{
getcwd(fullpath, PATH_MAX);
len = strlen(fullpath);
}
else
{
len = fd_to_path(dirfd, fullpath, PATH_MAX);
}
if (len <= 0)
{
_fatal("Could not get path for fd %d; errno: %d", dirfd, errno);
}
snprintf(&fullpath[len], PATH_MAX - len, "/%s", pathname);
return report_access(syscallName, eventType, fullpath);
}
static enum RequestedAccess oflag_to_access(int oflag)
{
return oflag & (O_WRONLY | O_RDWR) ? RequestedAccess::Write : RequestedAccess::Read;
}
pid_t fork(void)
{
GEN_REAL(pid_t, fork);
GEN_REAL(ssize_t, readlink, const char *, char *, size_t);
pid_t childPid = real_fork();
result_t<pid_t> childPid = g_bxl->real_fork();
// report fork only when we are in the parent process
if (childPid > 0)
{
std::string exePath(BxlObserver::GetInstance()->GetProgramPath());
std::string exePath(g_bxl->GetProgramPath());
IOEvent event(getpid(), childPid, getppid(), ES_EVENT_TYPE_NOTIFY_FORK, exePath, std::string(""), exePath, 0, false);
report_access(__func__, event);
g_bxl->report_access(__func__, event);
}
return childPid;
}
int fexecve(int fd, char *const argv[], char *const envp[]) {
GEN_REAL(int, fexecve, int, char *const[], char *const[])
report_access_fd(__func__, ES_EVENT_TYPE_NOTIFY_EXEC, fd);
return real_fexecve(fd, argv, envp);
}
int execv(const char *file, char *const argv[]) {
GEN_REAL(int, execv, const char *, char *const[])
report_access(__func__, ES_EVENT_TYPE_NOTIFY_EXEC, file);
return real_execv(file, argv);
}
int execve(const char *file, char *const argv[], char *const envp[]) {
GEN_REAL(int, execve, const char *, char *const[], char *const[])
report_access(__func__, ES_EVENT_TYPE_NOTIFY_EXEC, file);
return real_execve(file, argv, envp);
}
int execvp(const char *file, char *const argv[]) {
GEN_REAL(int, execvp, const char *, char *const[])
report_access(__func__, ES_EVENT_TYPE_NOTIFY_EXEC, std::string(file), std::string(""));
return real_execvp(file, argv);
}
int execvpe(const char *file, char *const argv[], char *const envp[]) {
GEN_REAL(int, execvpe, const char *, char *const[], char *const[])
report_access(__func__, ES_EVENT_TYPE_NOTIFY_EXEC, std::string(file), std::string(""));
return real_execvpe(file, argv, envp);
}
int __fxstat(int __ver, int fd, struct stat *__stat_buf) {
GEN_REAL(int, __fxstat, int, int, struct stat*);
report_access_fd(__func__, ES_EVENT_TYPE_NOTIFY_STAT, fd);
return real___fxstat(__ver, fd, __stat_buf);
}
int statfs(const char *pathname, struct statfs *buf) {
GEN_REAL(int, statfs, const char *, struct statfs *);
report_access(__func__, ES_EVENT_TYPE_NOTIFY_STAT, pathname);
return real_statfs(pathname, buf);
}
int __xstat(int __ver, const char *pathname, struct stat *buf) {
GEN_REAL(int, __xstat, int, const char *, struct stat *);
report_access(__func__, ES_EVENT_TYPE_NOTIFY_STAT, pathname);
return real___xstat(__ver, pathname, buf);
}
int __xstat64(int __ver, const char *pathname, struct stat64 *buf)
INTERPOSE(int, fexecve, int fd, char *const argv[], char *const envp[])
{
GEN_REAL(int, __xstat64, int, const char*, struct stat64*);
report_access(__func__, ES_EVENT_TYPE_NOTIFY_STAT, pathname);
return real___xstat64(__ver, pathname, buf);
g_bxl->report_access_fd(__func__, ES_EVENT_TYPE_NOTIFY_EXEC, fd);
return g_bxl->real_fexecve(fd, argv, envp);
}
int __lxstat64(int __ver, const char *pathname, struct stat64 *buf)
INTERPOSE(int, execv, const char *file, char *const argv[])
{
GEN_REAL(int, __lxstat64, int, const char*, struct stat64*);
report_access(__func__, ES_EVENT_TYPE_NOTIFY_STAT, pathname);
return real___lxstat64(__ver, pathname, buf);
g_bxl->report_access(__func__, ES_EVENT_TYPE_NOTIFY_EXEC, file);
return g_bxl->real_execv(file, argv);
}
int __fxstat64(int __ver, int fd, struct stat64 *buf)
INTERPOSE(int, execve, const char *file, char *const argv[], char *const envp[])
{
GEN_REAL(int, __fxstat64, int, int, struct stat64*);
report_access_fd(__func__, ES_EVENT_TYPE_NOTIFY_STAT, fd);
return real___fxstat64(__ver, fd, buf);
g_bxl->report_access(__func__, ES_EVENT_TYPE_NOTIFY_EXEC, file);
return g_bxl->real_execve(file, argv, envp);
}
int __lxstat(int __ver, const char *pathname, struct stat *buf) {
GEN_REAL(int, __lxstat, int, const char *, struct stat *);
report_access(__func__, ES_EVENT_TYPE_NOTIFY_STAT, pathname);
return real___lxstat(__ver, pathname, buf);
INTERPOSE(int, execvp, const char *file, char *const argv[])
{
g_bxl->report_access(__func__, ES_EVENT_TYPE_NOTIFY_EXEC, std::string(file), std::string(""));
return g_bxl->real_execvp(file, argv);
}
FILE* fopen(const char *pathname, const char *mode) {
GEN_REAL(FILE*, fopen, const char *, const char *);
report_access(__func__, ES_EVENT_TYPE_NOTIFY_OPEN, pathname);
return real_fopen(pathname, mode);
INTERPOSE(int, execvpe, const char *file, char *const argv[], char *const envp[])
{
g_bxl->report_access(__func__, ES_EVENT_TYPE_NOTIFY_EXEC, std::string(file), std::string(""));
return g_bxl->real_execvpe(file, argv, envp);
}
int access(const char *pathname, int mode) {
GEN_REAL(int, access, const char *, int);
report_access(__func__, ES_EVENT_TYPE_NOTIFY_ACCESS, pathname);
return real_access(pathname, mode);
INTERPOSE(int, __fxstat, int __ver, int fd, struct stat *__stat_buf)
{
result_t<int> result = g_bxl->real___fxstat(__ver, fd, __stat_buf);
g_bxl->report_access_fd(__func__, ES_EVENT_TYPE_NOTIFY_STAT, fd);
return result;
}
int faccessat(int dirfd, const char *pathname, int mode, int flags) {
GEN_REAL(int, faccessat, int, const char *, int, int);
report_access_at(__func__, ES_EVENT_TYPE_NOTIFY_ACCESS, dirfd, pathname);
return real_faccessat(dirfd, pathname, mode, flags);
INTERPOSE(int, statfs, const char *pathname, struct statfs *buf)
{
result_t<int> result = g_bxl->real_statfs(pathname, buf);
g_bxl->report_access(__func__, ES_EVENT_TYPE_NOTIFY_STAT, pathname);
return result;
}
int open(const char *path, int oflag, ...) {
GEN_REAL(int, open, const char *, int, mode_t);
INTERPOSE(int, __xstat, int __ver, const char *pathname, struct stat *buf)
{
result_t<int> result = g_bxl->real___xstat(__ver, pathname, buf);
g_bxl->report_access(__func__, ES_EVENT_TYPE_NOTIFY_STAT, pathname);
return result;
}
INTERPOSE(int, __xstat64, int __ver, const char *pathname, struct stat64 *buf)
{
result_t<int> result(g_bxl->real___xstat64(__ver, pathname, buf));
g_bxl->report_access(__func__, ES_EVENT_TYPE_NOTIFY_STAT, pathname);
return result;
}
INTERPOSE(int, __lxstat64, int __ver, const char *pathname, struct stat64 *buf)
{
result_t<int> result(g_bxl->real___lxstat64(__ver, pathname, buf));
g_bxl->report_access(__func__, ES_EVENT_TYPE_NOTIFY_STAT, pathname);
return result;
}
INTERPOSE(int, __fxstat64, int __ver, int fd, struct stat64 *buf)
{
result_t<int> result(g_bxl->real___fxstat64(__ver, fd, buf));
g_bxl->report_access_fd(__func__, ES_EVENT_TYPE_NOTIFY_STAT, fd);
return result;
}
INTERPOSE(int, __lxstat, int __ver, const char *pathname, struct stat *buf)
{
result_t<int> result = g_bxl->real___lxstat(__ver, pathname, buf);
g_bxl->report_access(__func__, ES_EVENT_TYPE_NOTIFY_STAT, pathname);
return result;
}
INTERPOSE(FILE*, fopen, const char *pathname, const char *mode)
{
result_t<FILE*> result = g_bxl->real_fopen(pathname, mode);
g_bxl->report_access(__func__, ES_EVENT_TYPE_NOTIFY_OPEN, pathname);
return result;
}
INTERPOSE(int, access, const char *pathname, int mode)
{
result_t<int> result = g_bxl->real_access(pathname, mode);
g_bxl->report_access(__func__, ES_EVENT_TYPE_NOTIFY_ACCESS, pathname);
return result;
}
INTERPOSE(int, faccessat, int dirfd, const char *pathname, int mode, int flags)
{
result_t<int> result = g_bxl->real_faccessat(dirfd, pathname, mode, flags);
g_bxl->report_access_at(__func__, ES_EVENT_TYPE_NOTIFY_ACCESS, dirfd, pathname);
return result;
}
INTERPOSE(int, open, const char *path, int oflag, ...)
{
va_list args;
va_start(args, oflag);
mode_t mode = va_arg(args, mode_t);
va_end(args);
report_access(__func__, ES_EVENT_TYPE_NOTIFY_OPEN, path);
return real_open(path, oflag, mode);
result_t<int> result = g_bxl->real_open(path, oflag, mode);
g_bxl->report_access(__func__, ES_EVENT_TYPE_NOTIFY_OPEN, path);
return result;
}
int creat(const char *pathname, mode_t mode) {
GEN_REAL(int, creat, const char *, mode_t);
report_access(__func__, ES_EVENT_TYPE_NOTIFY_CREATE, pathname);
return real_creat(pathname, mode);
INTERPOSE(int, creat, const char *pathname, mode_t mode)
{
result_t<int> result = g_bxl->real_creat(pathname, mode);
g_bxl->report_access(__func__, ES_EVENT_TYPE_NOTIFY_CREATE, pathname);
return result;
}
int openat(int dirfd, const char *pathname, int flags, ...) {
GEN_REAL(int, openat, int, const char *, int, mode_t);
INTERPOSE(int, openat, int dirfd, const char *pathname, int flags, ...)
{
va_list args;
va_start(args, flags);
mode_t mode = va_arg(args, mode_t);
va_end(args);
report_access_at(__func__, ES_EVENT_TYPE_NOTIFY_OPEN, dirfd, pathname);
return real_openat(dirfd, pathname, flags, mode);
result_t<int> result = g_bxl->real_openat(dirfd, pathname, flags, mode);
g_bxl->report_access_at(__func__, ES_EVENT_TYPE_NOTIFY_OPEN, dirfd, pathname);
return result;
}
ssize_t write(int fd, const void *buf, size_t bufsiz)
INTERPOSE(ssize_t, write, int fd, const void *buf, size_t bufsiz)
{
GEN_REAL(ssize_t, write, int, const void*, size_t);
report_access_fd(__func__, ES_EVENT_TYPE_NOTIFY_WRITE, fd);
return real_write(fd, buf, bufsiz);
result_t<ssize_t> result = g_bxl->real_write(fd, buf, bufsiz);
g_bxl->report_access_fd(__func__, ES_EVENT_TYPE_NOTIFY_WRITE, fd);
return result;
}
int remove(const char *pathname) {
GEN_REAL(int, remove, const char *);
report_access(__func__, ES_EVENT_TYPE_NOTIFY_UNLINK, pathname);
return real_remove(pathname);
}
int rename(const char *old, const char *n) {
GEN_REAL(int, rename, const char *, const char *);
report_access(__func__, ES_EVENT_TYPE_NOTIFY_RENAME, old, n);
return real_rename(old, n);
}
int link(const char *path1, const char *path2) {
GEN_REAL(int, link, const char *, const char *);
report_access(__func__, ES_EVENT_TYPE_NOTIFY_LINK, path1, path2);
return real_link(path1, path2);
}
int linkat(int fd1, const char *name1, int fd2, const char *name2, int flag) {
GEN_REAL(int, linkat, int, const char *, int, const char *, int);
report_access(__func__, ES_EVENT_TYPE_NOTIFY_LINK, normalize_path_at(fd1, name1), normalize_path_at(fd2, name2));
return real_linkat(fd1, name1, fd2, name2, flag);
}
int unlink(const char *path) {
GEN_REAL(int, unlink, const char *);
report_access(__func__, ES_EVENT_TYPE_NOTIFY_UNLINK, path);
return real_unlink(path);
}
int symlink(const char *path1, const char *path2) {
GEN_REAL(int, symlink, const char *, const char *);
report_access(__func__, ES_EVENT_TYPE_NOTIFY_CREATE, path2);
return real_symlink(path1, path2);
}
int symlinkat(const char *name1, int fd, const char *name2) {
GEN_REAL(int, symlinkat, const char *, int, const char *);
report_access_at(__func__, ES_EVENT_TYPE_NOTIFY_CREATE, fd, name2);
return real_symlinkat(name1, fd, name2);
}
ssize_t readlink(const char *path, char *buf, size_t bufsize) {
GEN_REAL(ssize_t, readlink, const char *, char *, size_t);
report_access(__func__, ES_EVENT_TYPE_NOTIFY_READLINK, path);
return real_readlink(path, buf, bufsize);
}
ssize_t readlinkat(int fd, const char *path, char *buf, size_t bufsize) {
GEN_REAL(ssize_t, readlinkat, int, const char *, char *, size_t);
report_access_at(__func__, ES_EVENT_TYPE_NOTIFY_READLINK, fd, path);
return real_readlinkat(fd, path, buf, bufsize);
}
DIR* opendir(const char *name) {
GEN_REAL(DIR*, opendir, const char*);
report_access(__func__, ES_EVENT_TYPE_NOTIFY_READDIR, name);
return real_opendir(name);
}
int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags)
INTERPOSE(int, remove, const char *pathname)
{
GEN_REAL(int, utimensat, int, const char*, const struct timespec[2], int);
report_access_at(__func__, ES_EVENT_TYPE_NOTIFY_SETTIME, dirfd, pathname);
return real_utimensat(dirfd, pathname, times, flags);
result_t<int> result = g_bxl->real_remove(pathname);
g_bxl->report_access(__func__, ES_EVENT_TYPE_NOTIFY_UNLINK, pathname);
return result;
}
int futimens(int fd, const struct timespec times[2])
INTERPOSE(int, rename, const char *old, const char *n)
{
GEN_REAL(int, futimens, int, const struct timespec[2]);
report_access_fd(__func__, ES_EVENT_TYPE_NOTIFY_SETTIME, fd);
return real_futimens(fd, times);
result_t<int> result = g_bxl->real_rename(old, n);
g_bxl->report_access(__func__, ES_EVENT_TYPE_NOTIFY_RENAME, old, n);
return result;
}
static inline void report_exit()
INTERPOSE(int, link, const char *path1, const char *path2)
{
report_access("atexit", ES_EVENT_TYPE_NOTIFY_EXIT, std::string(""), std::string(""));
result_t<int> result = g_bxl->real_link(path1, path2);
g_bxl->report_access(__func__, ES_EVENT_TYPE_NOTIFY_LINK, path1, path2);
return result;
}
INTERPOSE(int, linkat, int fd1, const char *name1, int fd2, const char *name2, int flag)
{
result_t<int> result = g_bxl->real_linkat(fd1, name1, fd2, name2, flag);
g_bxl->report_access(__func__, ES_EVENT_TYPE_NOTIFY_LINK, g_bxl->normalize_path_at(fd1, name1), g_bxl->normalize_path_at(fd2, name2));
return result;
}
INTERPOSE(int, unlink, const char *path)
{
result_t<int> result = g_bxl->real_unlink(path);
g_bxl->report_access(__func__, ES_EVENT_TYPE_NOTIFY_UNLINK, path);
return result;
}
INTERPOSE(int, symlink, const char *path1, const char *path2)
{
result_t<int> result = g_bxl->real_symlink(path1, path2);
g_bxl->report_access(__func__, ES_EVENT_TYPE_NOTIFY_CREATE, path2);
return result;
}
INTERPOSE(int, symlinkat, const char *name1, int fd, const char *name2)
{
result_t<int> result = g_bxl->real_symlinkat(name1, fd, name2);
g_bxl->report_access_at(__func__, ES_EVENT_TYPE_NOTIFY_CREATE, fd, name2);
return result;
}
INTERPOSE(ssize_t, readlink, const char *path, char *buf, size_t bufsize)
{
result_t<int> result = g_bxl->real_readlink(path, buf, bufsize);
g_bxl->report_access(__func__, ES_EVENT_TYPE_NOTIFY_READLINK, path);
return result;
}
INTERPOSE(ssize_t, readlinkat, int fd, const char *path, char *buf, size_t bufsize)
{
result_t<ssize_t> result = g_bxl->real_readlinkat(fd, path, buf, bufsize);
g_bxl->report_access_at(__func__, ES_EVENT_TYPE_NOTIFY_READLINK, fd, path);
return result;
}
INTERPOSE(DIR*, opendir, const char *name)
{
result_t<DIR*> result = g_bxl->real_opendir(name);
g_bxl->report_access(__func__, ES_EVENT_TYPE_NOTIFY_READDIR, name);
return result;
}
INTERPOSE(int, utimensat, int dirfd, const char *pathname, const struct timespec times[2], int flags)
{
result_t<int> result = g_bxl->real_utimensat(dirfd, pathname, times, flags);
g_bxl->report_access_at(__func__, ES_EVENT_TYPE_NOTIFY_SETTIME, dirfd, pathname);
return result;
}
INTERPOSE(int, futimens, int fd, const struct timespec times[2])
{
result_t<int> result = g_bxl->real_futimens(fd, times);
g_bxl->report_access_fd(__func__, ES_EVENT_TYPE_NOTIFY_SETTIME, fd);
return result;
}
static void report_exit()
{
g_bxl->report_access("atexit", ES_EVENT_TYPE_NOTIFY_EXIT, std::string(""), std::string(""));
}
void __attribute__ ((constructor)) _bxl_linux_sandbox_init(void)
@ -407,35 +278,4 @@ int main(int argc, char **argv)
{
BxlObserver *inst = BxlObserver::GetInstance();
printf("Path: %s\n", inst->GetReportsPath());
GEN_REAL(int, fexecve, int, char *const[], char *const[])
GEN_REAL(int, execv, const char *, char *const[])
GEN_REAL(int, execve, const char *, char *const[], char *const[])
GEN_REAL(int, execvp, const char *, char *const[])
GEN_REAL(int, execvpe, const char *, char *const[], char *const[])
GEN_REAL(int, __fxstat, int, int, struct stat*);
GEN_REAL(int, statfs, const char *, struct statfs *);
GEN_REAL(int, __xstat, int, const char *, struct stat *);
GEN_REAL(int, __lxstat, int, const char *, struct stat *);
GEN_REAL(int, __xstat64, int, const char*, struct stat64*);
GEN_REAL(int, __lxstat64, int, const char*, struct stat64*);
GEN_REAL(int, __fxstat64, int, const char*, struct stat64*);
GEN_REAL(FILE*, fopen, const char *, const char *);
GEN_REAL(int, access, const char *, int);
GEN_REAL(int, faccessat, int, const char *, int, int);
GEN_REAL(int, open, const char *, int, mode_t);
GEN_REAL(int, creat, const char *, mode_t);
GEN_REAL(int, openat, int, const char *, int, mode_t);
GEN_REAL(ssize_t, write, int, const void*, size_t);
GEN_REAL(int, remove, const char *);
GEN_REAL(int, rename, const char *, const char *);
GEN_REAL(int, link, const char *, const char *);
GEN_REAL(int, linkat, int, const char *, int, const char *, int);
GEN_REAL(int, unlink, const char *);
GEN_REAL(int, symlink, const char *, const char *);
GEN_REAL(int, symlinkat, const char *, int, const char *);
GEN_REAL(ssize_t, readlink, const char *, char *, size_t);
GEN_REAL(ssize_t, readlinkat, int, const char *, char *, size_t);
GEN_REAL(DIR*, opendir, const char*);
GEN_REAL(int, utimensat, int, const char*, const struct timespec[2], int);
}

Просмотреть файл

@ -0,0 +1,48 @@
#!/bin/bash
readonly __dir=$(cd `dirname ${BASH_SOURCE[0]}` && pwd)
set -e
set -u
function onExit {
popd > /dev/null 2>&1
}
readonly version="$1"
readonly pkgName="runtime.linux-x64.BuildXL.${version}"
pushd "${__dir}" > /dev/null 2>&1
trap onExit EXIT
cd "${__dir}"
make debug release
cd bin
rm -rf "${pkgName}"
mkdir -p "${pkgName}/ref/netstandard"
touch "${pkgName}/ref/netstandard/_._"
mkdir -p "${pkgName}/runtimes/linux-x64/native"
cp -r debug release "${pkgName}/runtimes/linux-x64/native"
cat > "${pkgName}/runtime.linux-x64.buildxl.nuspec" <<EOF
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/01/nuspec.xsd">
<metadata minClientVersion="2.12">
<id>runtime.linux-x64.BuildXL</id>
<version>${version}</version>
<title>runtime.linux-x64.BuildXL</title>
<authors>Microsoft</authors>
<owners>microsoft,buildxl,bxl</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>The BuildXL runtime libraries for Linux.</description>
<copyright>© Microsoft Corporation. All rights reserved.</copyright>
<serviceable>true</serviceable>
</metadata>
</package>
EOF
cd "${pkgName}"
zip -v ../${pkgName}.nupkg *

Просмотреть файл

@ -4326,7 +4326,7 @@
"Type": "NuGet",
"NuGet": {
"Name": "runtime.linux-x64.BuildXL",
"Version": "0.0.3"
"Version": "0.0.4"
}
}
},

Просмотреть файл

@ -333,7 +333,7 @@ config({
// Runtime dependencies for Linux
{
id: "runtime.linux-x64.BuildXL",
version: "0.0.3",
version: "0.0.4",
osSkip: importFile(f`config.microsoftInternal.dsc`).isMicrosoftInternal
? []
: [ "win", "macOS", "linux" ]