};
// variables & definitions for thread security attributes
-static std::string g_app_label;
+static const std::string *g_p_app_label;
static std::atomic<int> g_threads_count;
-static std::map<uid_t, std::string> g_tid_attr_current_map;
-static bool g_smack_present;
static cap_t g_cap;
#define MAX_SIG_WAIT_TIME 1000
inline static int label_for_self_internal()
{
- int fd;
- int ret;
- fd = open(g_tid_attr_current_map[Syscall::gettid()].c_str(), O_WRONLY);
- if (fd < 0) {
+ const auto tid = Syscall::gettid();
+ 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)
return -1;
- }
- ret = write(fd, g_app_label.c_str(), g_app_label.length());
+ int ret = write(fd, g_p_app_label->c_str(), g_p_app_label->length());
close(fd);
- if (ret < 0) {
- return -1;
- }
- return 0;
+ return ret < 0 ? -1 : 0;
}
static inline int security_manager_sync_threads_internal(const std::string &app_label)
{
- if (ATOMIC_INT_LOCK_FREE != 2) {
- LogError("std::atomic<int> is not always lock free");
- return SECURITY_MANAGER_ERROR_UNKNOWN;
- }
+ static_assert(ATOMIC_INT_LOCK_FREE == 2, "std::atomic<int> is not always lock free");
- FS::FileNameVector files = FS::getSubDirectoriesFromDirectory("/proc/self/task");
- uid_t cur_tid = Syscall::gettid();
- pid_t cur_pid = getpid();
+ FS::FileNameVector files = FS::getSubDirectoriesFromDirectory("/proc/self/task", true);
- g_app_label = app_label;
- g_threads_count = 0;
- g_tid_attr_current_map.clear();
- g_smack_present = smack_check();
g_cap = cap_init();
if (!g_cap) {
return SECURITY_MANAGER_ERROR_MEMORY;
}
- if (cap_clear(g_cap)) {
- LogError("Unable to initialize capability object");
- cap_free(g_cap);
- return SECURITY_MANAGER_ERROR_UNKNOWN;
- }
+ if (smack_check())
+ g_p_app_label = &app_label;
- struct sigaction act;
- struct sigaction old;
- memset(&act, '\0', sizeof(act));
- memset(&old, '\0', sizeof(old));
+ if (files.size() > 1) {
+ const pid_t cur_pid = getpid();
+ const pid_t cur_tid = Syscall::gettid();
+ g_threads_count = files.size() - 1;
- sigemptyset(&act.sa_mask);
- act.sa_flags = SA_RESTART;
- act.sa_handler = [](int signo) {
- (void)signo;
+ struct sigaction act;
+ struct sigaction old;
+ memset(&act, '\0', sizeof(act));
- std::atomic_thread_fence(std::memory_order_acquire);
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_RESTART;
+ act.sa_handler = [](int signo) {
+ (void)signo;
- if (g_smack_present)
- if (label_for_self_internal() != 0)
- return;
-
- if (cap_set_proc(g_cap))
- return;
+ std::atomic_thread_fence(std::memory_order_acquire);
- g_threads_count++;
- };
+ if (g_p_app_label)
+ if (label_for_self_internal() != 0)
+ return;
- if (Syscall::sigaction(SIGSETXID, &act, &old) < 0) {
- LogError("Error in sigaction()");
- cap_free(g_cap);
- return SECURITY_MANAGER_ERROR_UNKNOWN;
- }
-
- int sent_signals_count = 0;
+ if (cap_set_proc(g_cap))
+ return;
- for (auto const &e : files) {
- if (e.compare(".") == 0 || e.compare("..") == 0)
- continue;
+ g_threads_count--;
+ };
- int tid = atoi(e.c_str());
- if (tid == static_cast<int>(cur_tid))
- continue;
+ if (Syscall::sigaction(SIGSETXID, &act, &old) < 0) {
+ LogError("Error in sigaction()");
+ goto err;
+ }
- g_tid_attr_current_map[tid] = "/proc/self/task/" + std::to_string(tid) + "/attr/current";
- }
+ std::atomic_thread_fence(std::memory_order_release);
- std::atomic_thread_fence(std::memory_order_release);
+ for (auto const &e : files) {
+ const int tid = atoi(e.c_str());
+ if (tid == static_cast<int>(cur_tid))
+ continue;
- for (auto const& t_pair : g_tid_attr_current_map) {
- if (Syscall::tgkill(cur_pid, t_pair.first, SIGSETXID) < 0) {
- LogWarning("Error in tgkill()");
- continue;
+ if (Syscall::tgkill(cur_pid, tid, SIGSETXID) < 0) {
+ LogWarning("Error in tgkill()");
+ continue;
+ }
}
- sent_signals_count++;
- }
+ LogDebug("sent_signals_count: " << files.size() - 1);
- LogDebug("sent_signals_count: " << sent_signals_count);
+ for (int i = MAX_SIG_WAIT_TIME; g_threads_count && i; i--)
+ usleep(1000); // 1 ms
- for (int i = 0; g_threads_count != sent_signals_count && i < MAX_SIG_WAIT_TIME; ++i)
- usleep(1000); // 1 ms
+ Syscall::sigaction(SIGSETXID, &old, nullptr);
- Syscall::sigaction(SIGSETXID, &old, nullptr);
-
- if (g_threads_count != sent_signals_count) {
- LogError("Not all threads synchronized: threads done: " << g_threads_count);
- cap_free(g_cap);
- return SECURITY_MANAGER_ERROR_UNKNOWN;
+ if (g_threads_count) {
+ LogError("Not all threads synchronized: threads left: " << g_threads_count);
+ goto err;
+ }
}
- if (g_smack_present && smack_set_label_for_self(g_app_label.c_str()) != 0) {
+ if (g_p_app_label && smack_set_label_for_self(app_label.c_str()) != 0) {
LogError("smack_set_label_for_self failed");
- cap_free(g_cap);
- return SECURITY_MANAGER_ERROR_UNKNOWN;
+ goto err;
}
if (cap_set_proc(g_cap)) {
LogError("Can't drop main thread capabilities");
- cap_free(g_cap);
- return SECURITY_MANAGER_ERROR_UNKNOWN;
+ goto err;
}
cap_free(g_cap);
return SECURITY_MANAGER_SUCCESS;
+
+err:
+ cap_free(g_cap);
+ return SECURITY_MANAGER_ERROR_UNKNOWN;
}
static int security_manager_set_process_groups_internal(const std::string &app_label)