148 lines
4 KiB
C++
148 lines
4 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "SandboxLogging.h"
|
|
|
|
#ifdef ANDROID
|
|
# include <android/log.h>
|
|
#endif
|
|
#include <algorithm>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/uio.h>
|
|
#include <unistd.h>
|
|
|
|
#include "base/posix/eintr_wrapper.h"
|
|
|
|
#ifdef __GLIBC_PREREQ
|
|
# if __GLIBC_PREREQ(2, 32)
|
|
# define HAVE_STRERRORNAME_NP 1
|
|
# endif
|
|
#endif
|
|
|
|
namespace mozilla {
|
|
|
|
// Alters an iovec array to remove the first `toDrop` bytes. This
|
|
// complexity is necessary because writev can return a short write
|
|
// (e.g., if stderr is a pipe and the buffer is almost full).
|
|
static void IOVecDrop(struct iovec* iov, int iovcnt, size_t toDrop) {
|
|
while (toDrop > 0 && iovcnt > 0) {
|
|
size_t toDropHere = std::min(toDrop, iov->iov_len);
|
|
iov->iov_base = static_cast<char*>(iov->iov_base) + toDropHere;
|
|
iov->iov_len -= toDropHere;
|
|
toDrop -= toDropHere;
|
|
++iov;
|
|
--iovcnt;
|
|
}
|
|
}
|
|
|
|
void SandboxLogError(const char* message) {
|
|
#ifdef ANDROID
|
|
// This uses writev internally and appears to be async signal safe.
|
|
__android_log_write(ANDROID_LOG_ERROR, "Sandbox", message);
|
|
#endif
|
|
static char logPrefixProcess[16];
|
|
static const ssize_t printfSize =
|
|
::base::strings::SafeSPrintf(logPrefixProcess, "[%d] ", getpid());
|
|
static const size_t pidSize =
|
|
std::clamp(static_cast<size_t>(printfSize), static_cast<size_t>(0),
|
|
static_cast<size_t>(sizeof(logPrefixProcess) - 1));
|
|
static const char logPrefix[] = "Sandbox: ", logSuffix[] = "\n";
|
|
struct iovec iovs[4] = {
|
|
{const_cast<char*>(logPrefixProcess), pidSize},
|
|
{const_cast<char*>(logPrefix), sizeof(logPrefix) - 1},
|
|
{const_cast<char*>(message), strlen(message)},
|
|
{const_cast<char*>(logSuffix), sizeof(logSuffix) - 1},
|
|
};
|
|
while (iovs[2].iov_len > 0) {
|
|
ssize_t written = HANDLE_EINTR(writev(STDERR_FILENO, iovs, 4));
|
|
if (written <= 0) {
|
|
break;
|
|
}
|
|
IOVecDrop(iovs, 4, static_cast<size_t>(written));
|
|
}
|
|
}
|
|
|
|
ssize_t GetLibcErrorName(char* aBuf, size_t aSize, int aErr) {
|
|
const char* errStr;
|
|
|
|
#ifdef HAVE_STRERRORNAME_NP
|
|
// This is the function we'd like to have, but it's a glibc
|
|
// extension and present only in newer versions.
|
|
errStr = strerrorname_np(aErr);
|
|
#else
|
|
// Otherwise, handle most of the basic / common errors with a big
|
|
// switch statement.
|
|
switch (aErr) {
|
|
|
|
# define HANDLE_ERR(x) \
|
|
case x: \
|
|
errStr = #x; \
|
|
break
|
|
|
|
// errno-base.h
|
|
HANDLE_ERR(EPERM);
|
|
HANDLE_ERR(ENOENT);
|
|
HANDLE_ERR(ESRCH);
|
|
HANDLE_ERR(EINTR);
|
|
HANDLE_ERR(EIO);
|
|
HANDLE_ERR(ENXIO);
|
|
HANDLE_ERR(E2BIG);
|
|
HANDLE_ERR(ENOEXEC);
|
|
HANDLE_ERR(EBADF);
|
|
HANDLE_ERR(ECHILD);
|
|
HANDLE_ERR(EAGAIN);
|
|
HANDLE_ERR(ENOMEM);
|
|
HANDLE_ERR(EACCES);
|
|
HANDLE_ERR(EFAULT);
|
|
HANDLE_ERR(ENOTBLK);
|
|
HANDLE_ERR(EBUSY);
|
|
HANDLE_ERR(EEXIST);
|
|
HANDLE_ERR(EXDEV);
|
|
HANDLE_ERR(ENODEV);
|
|
HANDLE_ERR(ENOTDIR);
|
|
HANDLE_ERR(EISDIR);
|
|
HANDLE_ERR(EINVAL);
|
|
HANDLE_ERR(ENFILE);
|
|
HANDLE_ERR(EMFILE);
|
|
HANDLE_ERR(ENOTTY);
|
|
HANDLE_ERR(ETXTBSY);
|
|
HANDLE_ERR(EFBIG);
|
|
HANDLE_ERR(ENOSPC);
|
|
HANDLE_ERR(ESPIPE);
|
|
HANDLE_ERR(EROFS);
|
|
HANDLE_ERR(EMLINK);
|
|
HANDLE_ERR(EPIPE);
|
|
HANDLE_ERR(EDOM);
|
|
HANDLE_ERR(ERANGE);
|
|
|
|
// selected other errors
|
|
HANDLE_ERR(ENAMETOOLONG);
|
|
HANDLE_ERR(ENOSYS);
|
|
HANDLE_ERR(ENOTEMPTY);
|
|
HANDLE_ERR(ELOOP);
|
|
HANDLE_ERR(ENOTSOCK);
|
|
HANDLE_ERR(EMSGSIZE);
|
|
HANDLE_ERR(ECONNRESET);
|
|
HANDLE_ERR(ECONNREFUSED);
|
|
HANDLE_ERR(EHOSTUNREACH);
|
|
HANDLE_ERR(ESTALE);
|
|
|
|
# undef HANDLE_ERR
|
|
|
|
default:
|
|
errStr = nullptr;
|
|
}
|
|
#endif // no strerrorname_np
|
|
|
|
if (errStr) {
|
|
return base::strings::SafeSNPrintf(aBuf, aSize, "%s", errStr);
|
|
}
|
|
|
|
return base::strings::SafeSNPrintf(aBuf, aSize, "error %d", aErr);
|
|
}
|
|
|
|
} // namespace mozilla
|