ueventd_test.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. * Copyright (C) 2017 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <linux/futex.h>
  17. #include <pthread.h>
  18. #include <sys/stat.h>
  19. #include <unistd.h>
  20. #include <atomic>
  21. #include <chrono>
  22. #include <string>
  23. #include <thread>
  24. #include <vector>
  25. #include <android-base/file.h>
  26. #include <android-base/scopeguard.h>
  27. #include <gtest/gtest.h>
  28. #include <selinux/android.h>
  29. #include <selinux/label.h>
  30. #include <selinux/selinux.h>
  31. using namespace std::chrono_literals;
  32. using namespace std::string_literals;
  33. template <typename T, typename F>
  34. void WriteFromMultipleThreads(std::vector<std::pair<std::string, T>>& files_and_parameters,
  35. F function) {
  36. auto num_threads = files_and_parameters.size();
  37. pthread_barrier_t barrier;
  38. pthread_barrier_init(&barrier, nullptr, num_threads);
  39. auto barrier_destroy =
  40. android::base::make_scope_guard([&barrier]() { pthread_barrier_destroy(&barrier); });
  41. auto make_thread_function = [&function, &barrier](const auto& file, const auto& parameter) {
  42. return [&]() {
  43. function(parameter);
  44. pthread_barrier_wait(&barrier);
  45. android::base::WriteStringToFile("<empty>", file);
  46. };
  47. };
  48. std::vector<std::thread> threads;
  49. // TODO(b/63712782): Structured bindings + templated containers are broken in clang :(
  50. // for (const auto& [file, parameter] : files_and_parameters) {
  51. for (const auto& pair : files_and_parameters) {
  52. const auto& file = pair.first;
  53. const auto& parameter = pair.second;
  54. threads.emplace_back(std::thread(make_thread_function(file, parameter)));
  55. }
  56. for (auto& thread : threads) {
  57. thread.join();
  58. }
  59. }
  60. TEST(ueventd, setegid_IsPerThread) {
  61. if (getuid() != 0) {
  62. GTEST_LOG_(INFO) << "Skipping test, must be run as root.";
  63. return;
  64. }
  65. TemporaryDir dir;
  66. gid_t gid = 0;
  67. std::vector<std::pair<std::string, gid_t>> files_and_gids;
  68. std::generate_n(std::back_inserter(files_and_gids), 100, [&gid, &dir]() {
  69. gid++;
  70. return std::pair(dir.path + "/gid_"s + std::to_string(gid), gid);
  71. });
  72. WriteFromMultipleThreads(files_and_gids, [](gid_t gid) { EXPECT_EQ(0, setegid(gid)); });
  73. for (const auto& [file, expected_gid] : files_and_gids) {
  74. struct stat info;
  75. ASSERT_EQ(0, stat(file.c_str(), &info));
  76. EXPECT_EQ(expected_gid, info.st_gid);
  77. }
  78. }
  79. TEST(ueventd, setfscreatecon_IsPerThread) {
  80. if (getuid() != 0) {
  81. GTEST_LOG_(INFO) << "Skipping test, must be run as root.";
  82. return;
  83. }
  84. if (!is_selinux_enabled() || security_getenforce() == 1) {
  85. GTEST_LOG_(INFO) << "Skipping test, SELinux must be enabled and in permissive mode.";
  86. return;
  87. }
  88. const char* const contexts[] = {
  89. "u:object_r:audio_device:s0",
  90. "u:object_r:sensors_device:s0",
  91. "u:object_r:video_device:s0"
  92. "u:object_r:zero_device:s0",
  93. };
  94. TemporaryDir dir;
  95. std::vector<std::pair<std::string, std::string>> files_and_contexts;
  96. for (const char* context : contexts) {
  97. files_and_contexts.emplace_back(dir.path + "/context_"s + context, context);
  98. }
  99. WriteFromMultipleThreads(files_and_contexts, [](const std::string& context) {
  100. EXPECT_EQ(0, setfscreatecon(context.c_str()));
  101. });
  102. for (const auto& [file, expected_context] : files_and_contexts) {
  103. char* file_context;
  104. ASSERT_GT(getfilecon(file.c_str(), &file_context), 0);
  105. EXPECT_EQ(expected_context, file_context);
  106. freecon(file_context);
  107. }
  108. }
  109. TEST(ueventd, selabel_lookup_MultiThreaded) {
  110. if (getuid() != 0) {
  111. GTEST_LOG_(INFO) << "Skipping test, must be run as root.";
  112. return;
  113. }
  114. // Test parameters
  115. constexpr auto num_threads = 10;
  116. constexpr auto run_time = 200ms;
  117. std::unique_ptr<selabel_handle, decltype(&selabel_close)> sehandle(
  118. selinux_android_file_context_handle(), &selabel_close);
  119. ASSERT_TRUE(sehandle);
  120. struct {
  121. const char* file;
  122. int mode;
  123. std::string expected_context;
  124. } files_and_modes[] = {
  125. {"/dev/zero", 020666, ""},
  126. {"/dev/null", 020666, ""},
  127. {"/dev/random", 020666, ""},
  128. {"/dev/urandom", 020666, ""},
  129. };
  130. // Precondition, ensure that we can lookup all of these from a single thread, and store the
  131. // expected context for each.
  132. for (size_t i = 0; i < arraysize(files_and_modes); ++i) {
  133. char* secontext;
  134. ASSERT_EQ(0, selabel_lookup(sehandle.get(), &secontext, files_and_modes[i].file,
  135. files_and_modes[i].mode));
  136. files_and_modes[i].expected_context = secontext;
  137. freecon(secontext);
  138. }
  139. // Now that we know we can access them, and what their context should be, run in parallel.
  140. std::atomic_bool stopped = false;
  141. std::atomic_uint num_api_failures = 0;
  142. std::atomic_uint num_context_check_failures = 0;
  143. std::atomic_uint num_successes = 0;
  144. auto thread_function = [&]() {
  145. while (!stopped) {
  146. for (size_t i = 0; i < arraysize(files_and_modes); ++i) {
  147. char* secontext;
  148. int result = selabel_lookup(sehandle.get(), &secontext, files_and_modes[i].file,
  149. files_and_modes[i].mode);
  150. if (result != 0) {
  151. num_api_failures++;
  152. } else {
  153. if (files_and_modes[i].expected_context != secontext) {
  154. num_context_check_failures++;
  155. } else {
  156. num_successes++;
  157. }
  158. freecon(secontext);
  159. }
  160. }
  161. }
  162. };
  163. std::vector<std::thread> threads;
  164. std::generate_n(back_inserter(threads), num_threads,
  165. [&]() { return std::thread(thread_function); });
  166. std::this_thread::sleep_for(run_time);
  167. stopped = true;
  168. for (auto& thread : threads) {
  169. thread.join();
  170. }
  171. EXPECT_EQ(0U, num_api_failures);
  172. EXPECT_EQ(0U, num_context_check_failures);
  173. EXPECT_GT(num_successes, 0U);
  174. }