#include "utils.h"
#include <atomic>
+#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cxxabi.h>
#include <stdlib.h>
#include <unistd.h>
+namespace {
+
+class ErrnoAbort {
+ template<int Errno>
+ [[noreturn]] static void errnoHandler() noexcept
+ {
+ abort();
+ }
+
+ using AbortMap = std::unordered_map<int, void(*)()>;
+
+ template<int... Errno>
+ void addHandler()
+ {
+ ([&] {
+ [[maybe_unused]] bool inserted = map.try_emplace(Errno, &errnoHandler<Errno>).second;
+ assert(inserted);
+ }(), ...);
+ }
+
+ AbortMap map;
+
+public:
+ ErrnoAbort()
+ {
+ addHandler<EACCES,
+ EAGAIN,
+ EBADF,
+ EDQUOT,
+ EFAULT,
+ EFBIG,
+ EINTR,
+ EINVAL,
+ EISDIR,
+ EIO,
+ ELOOP,
+ EMFILE,
+ ENAMETOOLONG,
+ ENFILE,
+ ENOENT,
+ ENOMEM,
+ ENOSPC,
+ ENOTDIR,
+ EOVERFLOW,
+ EPERM,
+ ERANGE,
+ ESRCH>();
+ }
+
+ [[noreturn]] void call() const noexcept
+ {
+ int err = errno;
+ auto it = map.find(err);
+ if (it == map.end())
+ abort();
+
+ it->second();
+ abort();
+ }
+};
+
+const ErrnoAbort errnoAbort;
+
+} // namespace
+
static const char *EMPTY = "";
static const std::string SMACK_SYSTEM = "System";
static std::string SMACK_SYSTEM_PRIVILEGED = "System::Privileged";
} // namespace Syscall
-inline static int label_for_self_internal(int tid)
+inline static int label_for_self_internal(int tid, void(*error_handler)() = nullptr)
{
char threadSelf[sizeof "/proc//attr/current" + 1 + std::numeric_limits<unsigned>::digits10];
sprintf(threadSelf, "/proc/%u/attr/current", unsigned(tid));
int fd = open(threadSelf, O_WRONLY);
- if (fd < 0)
+ if (fd < 0) {
+ if (error_handler)
+ error_handler();
return -1;
+ }
int ret = write(fd, g_p_app_label->c_str(), g_p_app_label->length());
close(fd);
+ if (ret < 0) {
+ if (error_handler)
+ error_handler();
+ return -1;
+ }
- return ret < 0 ? -1 : 0;
+ return 0;
}
// Checks if caller has required capabilities configured properly.
{
auto handle_error = [&]{
if (abort_on_error)
- abort();
+ errnoAbort.call();
return errno;
};
char buf[1024];
struct dirent64 *d;
int bpos = 0;
- for(;;) {
+ int ret = 0;
+ for(;ret == 0;) {
ssize_t nread = getdents64(dir_fd, buf, sizeof(buf));
if (nread == -1) {
- close(dir_fd);
- return handle_error();
+ ret = handle_error();
+ break;
}
if (nread == 0)
errno = 0;
long tid = strtol(d->d_name, &endptr, 10);
if (errno != 0) {
- close(dir_fd);
- return handle_error();
+ ret = handle_error();
+ break;
}
if (tid == own_tid)
}
close(dir_fd);
- return 0;
+ return ret;
}
static void check_threads(int own_tid) noexcept
g_thread_alive[i] = false;
continue;
} else {
- abort();
+ errnoAbort.call();
}
}
} else if (ESRCH == err) { // thread already gone - noop
g_thread_alive[i] = false;
continue;
} else {
- abort();
+ errnoAbort.call();
}
}
}
/*
* Change attributes of one last thread, the main thread.
*/
- if (smack_simple_check()) {
- if (g_p_app_label && label_for_self_internal(own_tid) != 0)
- abort();
- }
+ if (smack_simple_check() && g_p_app_label)
+ label_for_self_internal(own_tid, []{ errnoAbort.call(); });
if (cap_set_proc(g_cap))
- abort();
-
- // No allocations allowed before this point
-
- if (enabled)
- SecurityManager::Log::LogSystemSingleton::Instance().Enable(true);
+ errnoAbort.call();
if (smack_simple_check()) {
// This starts signal handlers to proceed once they wake up - logic in app starts in env
g_th_barrier++;
}
+ // No allocations allowed before this point
+
+ if (enabled)
+ SecurityManager::Log::LogSystemSingleton::Instance().Enable(true);
+
if (Syscall::sigaction(SIGSETXID, &old, nullptr) < 0) {
LogError("Error in sigaction()");
abort();