Add errno abort helper tizen_9.0_dev
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Mon, 14 Apr 2025 17:12:37 +0000 (19:12 +0200)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Thu, 24 Apr 2025 17:29:31 +0000 (19:29 +0200)
When allocations and logging are disallowed there's no way to get the
errno value. Add a helper that puts the errno value in the stack using
template functions.

Also move the end of no-allocation area after the last barrier bump.

Change-Id: I864c2104e2fa617feb8764e64e8e73673dd1e2d5

src/client/client-security-manager.cpp

index bb07b5949753a4c13fa2682e9b8aa3a70b97a7f4..bc966a569e15515594e29a6bae99ec1486c51ef0 100644 (file)
 #include "filesystem.h"
 #include "mount-namespace.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";
@@ -596,17 +661,25 @@ inline static int sigaction(int signum, const struct sigaction *act, struct siga
 
 } // 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 CAP_MAC_ADMIN configured properly.
@@ -655,12 +728,12 @@ static bool alive_threads_have_state(int status) noexcept
 
 static int get_alive_threads(int own_tid, bool abort_on_error) noexcept
 {
-       auto handle_error = [&]{
-               if (abort_on_error)
-                       abort();
+    auto handle_error = [&]{
+        if (abort_on_error)
+            errnoAbort.call();
 
-               return errno;
-       };
+        return errno;
+    };
 
     // reset alive status
     memset(&g_thread_alive, 0, sizeof(g_thread_alive));
@@ -672,11 +745,12 @@ static int get_alive_threads(int own_tid, bool abort_on_error) noexcept
     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)
@@ -698,8 +772,8 @@ static int get_alive_threads(int own_tid, bool abort_on_error) noexcept
             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)
@@ -721,7 +795,7 @@ static int get_alive_threads(int own_tid, bool abort_on_error) noexcept
     }
 
     close(dir_fd);
-    return 0;
+    return ret;
 }
 
 static void check_threads(int own_tid) noexcept
@@ -778,14 +852,14 @@ static void signal_and_wait_for_handlers(pid_t own_pid, 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();
                     }
                 }
             }
@@ -921,20 +995,19 @@ static inline int security_manager_sync_threads_internal(const std::string &app_
     /*
      * Change attributes of one last thread, the main thread.
      */
-    if (g_p_app_label && label_for_self_internal(own_tid) != 0)
-        abort();
+    if (g_p_app_label)
+        label_for_self_internal(own_tid, []{ errnoAbort.call(); });
 
     if (cap_set_proc(g_cap))
-        abort();
+        errnoAbort.call();
+
+    g_th_barrier++; // this starts signal handlers to proceed once they wake up - logic in app starts in env where all have changed labels
 
     // No allocations allowed before this point
 
     if (enabled)
         SecurityManager::Log::LogSystemSingleton::Instance().Enable(true);
 
-    g_th_barrier++; // this starts signal handlers to proceed once they wake up - logic in app starts in env where all have changed labels
-
-
     if (Syscall::sigaction(SIGSETXID, &old, nullptr) < 0) {
         LogError("Error in sigaction()");
         abort();