]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
process-util: use only the least significant byte from personality()
authorFrantisek Sumsal <frantisek@sumsal.cz>
Wed, 7 Feb 2024 18:07:07 +0000 (19:07 +0100)
committerFrantisek Sumsal <frantisek@sumsal.cz>
Wed, 7 Feb 2024 18:29:53 +0000 (19:29 +0100)
The personality() syscall returns a 32-bit value where the top three
bytes are reserved for flags that emulate historical or architectural
quirks, and only the least significant byte reflects the actual
personality we're interested in (in opinionated_personality()).

Use the newly defined mask in the corresponding test as well, otherwise
the test fails on some more "exotic" architectures that set some of the
"quirk" flags:

~# uname -m
armv7l
~# build/test-seccomp
...
/* test_lock_personality */
current personality=0x0
safe_personality(PERSONALITY_INVALID)=0x800000
Assertion '(unsigned long) safe_personality(current) == current' failed at src/test/test-seccomp.c:970, function test_lock_personality(). Aborting.
lockpersonalityseccomp terminated by signal ABRT.
Assertion 'wait_for_terminate_and_check("lockpersonalityseccomp", pid, WAIT_LOG) == EXIT_SUCCESS' failed at src/test/test-seccomp.c:996, function test_lock_personality(). Aborting.
Aborted (core dumped)

See: personality(2) and comments in sys/personality.h

src/basic/process-util.c
src/basic/process-util.h
src/test/test-seccomp.c

index a94ff3840915a95bb07410fb458500e858bc9054..002aea9e8aaf0f38f5a066bb94ac09ba67311239 100644 (file)
@@ -1303,7 +1303,7 @@ int opinionated_personality(unsigned long *ret) {
         if (current < 0)
                 return current;
 
-        if (((unsigned long) current & 0xffff) == PER_LINUX32)
+        if (((unsigned long) current & OPINIONATED_PERSONALITY_MASK) == PER_LINUX32)
                 *ret = PER_LINUX32;
         else
                 *ret = PER_LINUX;
index 0fc31f7086ae230d01ebf1fd96ee347e4a30a779..7b2c6cd679a15b4032a57b80e9dad5613cddcfb3 100644 (file)
@@ -107,6 +107,11 @@ bool oom_score_adjust_is_valid(int oa);
 #define PERSONALITY_INVALID 0xffffffffLU
 #endif
 
+/* The personality() syscall returns a 32-bit value where the top three bytes are reserved for flags that
+ * emulate historical or architectural quirks, and only the least significant byte reflects the actual
+ * personality we're interested in. */
+#define OPINIONATED_PERSONALITY_MASK 0xFFUL
+
 unsigned long personality_from_string(const char *p);
 const char *personality_to_string(unsigned long);
 
index 279a155cb0a98e4be33d13496ab6d3a56c8ac377..4d3021cf9bd8b73ad02d83069231747b5fd7890c 100644 (file)
@@ -937,7 +937,7 @@ TEST(native_syscalls_filtered) {
 }
 
 TEST(lock_personality) {
-        unsigned long current;
+        unsigned long current_opinionated;
         pid_t pid;
 
         if (!is_seccomp_available()) {
@@ -949,24 +949,21 @@ TEST(lock_personality) {
                 return;
         }
 
-        assert_se(opinionated_personality(&current) >= 0);
-        /* On ppc64le sanitizers disable ASLR (i.e. by setting ADDR_NO_RANDOMIZE),
-         * which opinionated_personality() doesn't return. Let's tweak the current
-         * personality ourselves in such cases.
-         * See: https://github.com/llvm/llvm-project/commit/78f7a6eaa601bfdd6ae70ffd3da2254c21ff77f9
-         */
-        if (FLAGS_SET(safe_personality(PERSONALITY_INVALID), ADDR_NO_RANDOMIZE))
-                current |= ADDR_NO_RANDOMIZE;
+        assert_se(opinionated_personality(&current_opinionated) >= 0);
 
-        log_info("current personality=0x%lX", current);
+        log_info("current personality=0x%lX", (unsigned long) safe_personality(PERSONALITY_INVALID));
+        log_info("current opinionated personality=0x%lX", current_opinionated);
 
         pid = fork();
         assert_se(pid >= 0);
 
         if (pid == 0) {
-                assert_se(seccomp_lock_personality(current) >= 0);
+                unsigned long current;
 
-                assert_se((unsigned long) safe_personality(current) == current);
+                assert_se(seccomp_lock_personality(current_opinionated) >= 0);
+
+                current = safe_personality(current_opinionated);
+                assert_se((current & OPINIONATED_PERSONALITY_MASK) == current_opinionated);
 
                 /* Note, we also test that safe_personality() works correctly, by checking whether errno is properly
                  * set, in addition to the return value */
@@ -981,14 +978,15 @@ TEST(lock_personality) {
                 assert_se(safe_personality(PER_LINUX_32BIT) == -EPERM);
                 assert_se(safe_personality(PER_SVR4) == -EPERM);
                 assert_se(safe_personality(PER_BSD) == -EPERM);
-                assert_se(safe_personality(current == PER_LINUX ? PER_LINUX32 : PER_LINUX) == -EPERM);
+                assert_se(safe_personality(current_opinionated == PER_LINUX ? PER_LINUX32 : PER_LINUX) == -EPERM);
                 assert_se(safe_personality(PER_LINUX32_3GB) == -EPERM);
                 assert_se(safe_personality(PER_UW7) == -EPERM);
                 assert_se(safe_personality(0x42) == -EPERM);
 
                 assert_se(safe_personality(PERSONALITY_INVALID) == -EPERM); /* maybe remove this later */
 
-                assert_se((unsigned long) personality(current) == current);
+                current = safe_personality(current_opinionated);
+                assert_se((current & OPINIONATED_PERSONALITY_MASK) == current_opinionated);
                 _exit(EXIT_SUCCESS);
         }