[Mesa-dev] [PATCH] RFC: Workaround for pthread_setaffinity_np() seccomp filtering

marcandre.lureau at redhat.com marcandre.lureau at redhat.com
Wed Feb 27 23:13:39 UTC 2019


From: Marc-André Lureau <marcandre.lureau at redhat.com>

Since commit d877451b48a59ab0f9a4210fc736f51da5851c9a ("util/u_queue:
add UTIL_QUEUE_INIT_SET_FULL_THREAD_AFFINITY"), mesa calls
sched_setaffinity syscall. Unfortunately, qemu crashes with SIGSYS
when sandboxing is enabled (by default with libvirt), as this syscall
is filtered.

There doesn't seem to be a way to check for the seccomp rule other
than doing a call, which may result in various behaviour depending on
seccomp actions. There is a PTRACE_SECCOMP_GET_FILTER, but it is
low-level and a priviledged operation (but there might be a way to use
it?). A safe way would be to try the call in a subprocess,
unfortunately, qemu also prohibits fork(). Also this could be subject
to TOCTOU.

There seems to be few solutions, but the issue can be considered a
regression for various libvirt/Boxes users.

Introduce MESA_NO_THREAD_AFFINITY environment variable to prevent the
offending call. Wrap pthread_setaffinity_np() in a utility function
u_pthread_setaffinity_np(), returning a EACCESS error if the variable
is set.

Note: one call is left with a FIXME, as I didn't investigate how to
build and test it, help welcome!

See also:
https://bugs.freedesktop.org/show_bug.cgi?id=109695

Signed-off-by: Marc-André Lureau <marcandre.lureau at redhat.com>
---
 .../drivers/swr/rasterizer/core/threads.cpp       |  1 +
 src/util/u_queue.c                                |  2 +-
 src/util/u_thread.h                               | 15 ++++++++++++++-
 3 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/src/gallium/drivers/swr/rasterizer/core/threads.cpp b/src/gallium/drivers/swr/rasterizer/core/threads.cpp
index e30c1170568..d10c79512a1 100644
--- a/src/gallium/drivers/swr/rasterizer/core/threads.cpp
+++ b/src/gallium/drivers/swr/rasterizer/core/threads.cpp
@@ -364,6 +364,7 @@ void bindThread(SWR_CONTEXT* pContext,
     CPU_ZERO(&cpuset);
     CPU_SET(threadId, &cpuset);
 
+    /* FIXME: use u_pthread_setaffinity_np() if possible */
     int err = pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
     if (err != 0)
     {
diff --git a/src/util/u_queue.c b/src/util/u_queue.c
index 3812c824b6d..dea8d2bb4ae 100644
--- a/src/util/u_queue.c
+++ b/src/util/u_queue.c
@@ -249,7 +249,7 @@ util_queue_thread_func(void *input)
       for (unsigned i = 0; i < CPU_SETSIZE; i++)
          CPU_SET(i, &cpuset);
 
-      pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset);
+      u_pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset);
    }
 #endif
 
diff --git a/src/util/u_thread.h b/src/util/u_thread.h
index a46c18d3db2..a4e6dbae5d7 100644
--- a/src/util/u_thread.h
+++ b/src/util/u_thread.h
@@ -70,6 +70,19 @@ static inline void u_thread_setname( const char *name )
    (void)name;
 }
 
+#if defined(HAVE_PTHREAD_SETAFFINITY)
+static inline int u_pthread_setaffinity_np(pthread_t thread, size_t cpusetsize,
+                                           const cpu_set_t *cpuset)
+{
+   if (getenv("MESA_NO_THREAD_AFFINITY")) {
+      errno = EACCES;
+      return -1;
+   }
+
+   return pthread_setaffinity_np(thread, cpusetsize, cpuset);
+}
+#endif
+
 /**
  * An AMD Zen CPU consists of multiple modules where each module has its own L3
  * cache. Inter-thread communication such as locks and atomics between modules
@@ -89,7 +102,7 @@ util_pin_thread_to_L3(thrd_t thread, unsigned L3_index, unsigned cores_per_L3)
    CPU_ZERO(&cpuset);
    for (unsigned i = 0; i < cores_per_L3; i++)
       CPU_SET(L3_index * cores_per_L3 + i, &cpuset);
-   pthread_setaffinity_np(thread, sizeof(cpuset), &cpuset);
+   u_pthread_setaffinity_np(thread, sizeof(cpuset), &cpuset);
 #endif
 }
 
-- 
2.21.0



More information about the mesa-dev mailing list