broker_client.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "sandbox/linux/syscall_broker/broker_client.h"
  5. #include <errno.h>
  6. #include <fcntl.h>
  7. #include <stddef.h>
  8. #include <stdint.h>
  9. #include <string.h>
  10. #include <sys/socket.h>
  11. #include <sys/stat.h>
  12. #include <utility>
  13. #include "base/check.h"
  14. #include "base/posix/unix_domain_socket.h"
  15. #include "build/build_config.h"
  16. #include "sandbox/linux/syscall_broker/broker_channel.h"
  17. #include "sandbox/linux/syscall_broker/broker_command.h"
  18. #include "sandbox/linux/syscall_broker/broker_permission_list.h"
  19. #include "sandbox/linux/syscall_broker/broker_simple_message.h"
  20. #if BUILDFLAG(IS_ANDROID) && !defined(MSG_CMSG_CLOEXEC)
  21. #define MSG_CMSG_CLOEXEC 0x40000000
  22. #endif
  23. namespace sandbox {
  24. namespace syscall_broker {
  25. BrokerClient::BrokerClient(const BrokerSandboxConfig& policy,
  26. BrokerChannel::EndPoint ipc_channel,
  27. bool fast_check_in_client)
  28. : policy_(policy),
  29. ipc_channel_(std::move(ipc_channel)),
  30. fast_check_in_client_(fast_check_in_client) {}
  31. BrokerClient::~BrokerClient() {}
  32. int BrokerClient::Access(const char* pathname, int mode) const {
  33. if (!pathname)
  34. return -EFAULT;
  35. if (fast_check_in_client_ && !CommandAccessIsSafe(policy_.allowed_command_set,
  36. *policy_.file_permissions,
  37. pathname, mode, nullptr)) {
  38. return -policy_.file_permissions->denied_errno();
  39. }
  40. return PathAndFlagsSyscall(COMMAND_ACCESS, pathname, mode);
  41. }
  42. int BrokerClient::Mkdir(const char* pathname, int mode) const {
  43. if (!pathname)
  44. return -EFAULT;
  45. if (fast_check_in_client_ &&
  46. !CommandMkdirIsSafe(policy_.allowed_command_set,
  47. *policy_.file_permissions, pathname, nullptr)) {
  48. return -policy_.file_permissions->denied_errno();
  49. }
  50. return PathAndFlagsSyscall(COMMAND_MKDIR, pathname, mode);
  51. }
  52. int BrokerClient::Open(const char* pathname, int flags) const {
  53. if (!pathname)
  54. return -EFAULT;
  55. if (fast_check_in_client_ &&
  56. !CommandOpenIsSafe(policy_.allowed_command_set, *policy_.file_permissions,
  57. pathname, flags, nullptr, nullptr)) {
  58. return -policy_.file_permissions->denied_errno();
  59. }
  60. return PathAndFlagsSyscallReturningFD(COMMAND_OPEN, pathname, flags);
  61. }
  62. int BrokerClient::Readlink(const char* path, char* buf, size_t bufsize) const {
  63. if (!path || !buf)
  64. return -EFAULT;
  65. if (fast_check_in_client_ &&
  66. !CommandReadlinkIsSafe(policy_.allowed_command_set,
  67. *policy_.file_permissions, path, nullptr)) {
  68. return -policy_.file_permissions->denied_errno();
  69. }
  70. // Message structure:
  71. // int: syscall_type
  72. // char[]: pathname, including '\0' terminator
  73. BrokerSimpleMessage message;
  74. RAW_CHECK(message.AddIntToMessage(COMMAND_READLINK));
  75. RAW_CHECK(message.AddStringToMessage(path));
  76. base::ScopedFD returned_fd;
  77. BrokerSimpleMessage reply;
  78. ssize_t msg_len =
  79. message.SendRecvMsgWithFlags(ipc_channel_.get(), 0, &returned_fd, &reply);
  80. if (msg_len < 0)
  81. return msg_len;
  82. int return_value = -1;
  83. size_t return_length = 0;
  84. const char* return_data = nullptr;
  85. if (!reply.ReadInt(&return_value))
  86. return -ENOMEM;
  87. if (return_value < 0)
  88. return return_value;
  89. if (!reply.ReadData(&return_data, &return_length))
  90. return -ENOMEM;
  91. if (return_length < 0)
  92. return -ENOMEM;
  93. // Sanity check that our broker is behaving correctly.
  94. RAW_CHECK(return_length == static_cast<size_t>(return_value));
  95. if (return_length > bufsize) {
  96. return_length = bufsize;
  97. }
  98. memcpy(buf, return_data, return_length);
  99. return return_length;
  100. }
  101. int BrokerClient::Rename(const char* oldpath, const char* newpath) const {
  102. if (!oldpath || !newpath)
  103. return -EFAULT;
  104. if (fast_check_in_client_ &&
  105. !CommandRenameIsSafe(policy_.allowed_command_set,
  106. *policy_.file_permissions, oldpath, newpath, nullptr,
  107. nullptr)) {
  108. return -policy_.file_permissions->denied_errno();
  109. }
  110. BrokerSimpleMessage message;
  111. RAW_CHECK(message.AddIntToMessage(COMMAND_RENAME));
  112. RAW_CHECK(message.AddStringToMessage(oldpath));
  113. RAW_CHECK(message.AddStringToMessage(newpath));
  114. base::ScopedFD returned_fd;
  115. BrokerSimpleMessage reply;
  116. ssize_t msg_len =
  117. message.SendRecvMsgWithFlags(ipc_channel_.get(), 0, &returned_fd, &reply);
  118. if (msg_len < 0)
  119. return msg_len;
  120. int return_value = -1;
  121. if (!reply.ReadInt(&return_value))
  122. return -ENOMEM;
  123. return return_value;
  124. }
  125. int BrokerClient::Rmdir(const char* path) const {
  126. if (!path)
  127. return -EFAULT;
  128. if (fast_check_in_client_ &&
  129. !CommandRmdirIsSafe(policy_.allowed_command_set,
  130. *policy_.file_permissions, path, nullptr)) {
  131. return -policy_.file_permissions->denied_errno();
  132. }
  133. return PathOnlySyscall(COMMAND_RMDIR, path);
  134. }
  135. int BrokerClient::Stat(const char* pathname,
  136. bool follow_links,
  137. struct kernel_stat* sb) const {
  138. if (!pathname || !sb)
  139. return -EFAULT;
  140. if (fast_check_in_client_ &&
  141. !CommandStatIsSafe(policy_.allowed_command_set, *policy_.file_permissions,
  142. pathname, nullptr)) {
  143. return -policy_.file_permissions->denied_errno();
  144. }
  145. return StatFamilySyscall(COMMAND_STAT, pathname, follow_links, sb,
  146. sizeof(*sb));
  147. }
  148. int BrokerClient::Stat64(const char* pathname,
  149. bool follow_links,
  150. struct kernel_stat64* sb) const {
  151. if (!pathname || !sb)
  152. return -EFAULT;
  153. if (fast_check_in_client_ &&
  154. !CommandStatIsSafe(policy_.allowed_command_set, *policy_.file_permissions,
  155. pathname, nullptr)) {
  156. return -policy_.file_permissions->denied_errno();
  157. }
  158. return StatFamilySyscall(COMMAND_STAT64, pathname, follow_links, sb,
  159. sizeof(*sb));
  160. }
  161. int BrokerClient::Unlink(const char* path) const {
  162. if (!path)
  163. return -EFAULT;
  164. if (fast_check_in_client_ &&
  165. !CommandUnlinkIsSafe(policy_.allowed_command_set,
  166. *policy_.file_permissions, path, nullptr)) {
  167. return -policy_.file_permissions->denied_errno();
  168. }
  169. return PathOnlySyscall(COMMAND_UNLINK, path);
  170. }
  171. int BrokerClient::PathOnlySyscall(BrokerCommand syscall_type,
  172. const char* pathname) const {
  173. BrokerSimpleMessage message;
  174. RAW_CHECK(message.AddIntToMessage(syscall_type));
  175. RAW_CHECK(message.AddStringToMessage(pathname));
  176. base::ScopedFD returned_fd;
  177. BrokerSimpleMessage reply;
  178. ssize_t msg_len =
  179. message.SendRecvMsgWithFlags(ipc_channel_.get(), 0, &returned_fd, &reply);
  180. if (msg_len < 0)
  181. return msg_len;
  182. int return_value = -1;
  183. if (!reply.ReadInt(&return_value))
  184. return -ENOMEM;
  185. return return_value;
  186. }
  187. // Make a remote system call over IPC for syscalls that take a path and
  188. // flags (currently access() and mkdir()) but do not return a FD.
  189. // Will return -errno like a real system call.
  190. // This function needs to be async signal safe.
  191. int BrokerClient::PathAndFlagsSyscall(BrokerCommand syscall_type,
  192. const char* pathname,
  193. int flags) const {
  194. BrokerSimpleMessage message;
  195. RAW_CHECK(message.AddIntToMessage(syscall_type));
  196. RAW_CHECK(message.AddStringToMessage(pathname));
  197. RAW_CHECK(message.AddIntToMessage(flags));
  198. base::ScopedFD returned_fd;
  199. BrokerSimpleMessage reply;
  200. ssize_t msg_len =
  201. message.SendRecvMsgWithFlags(ipc_channel_.get(), 0, &returned_fd, &reply);
  202. if (msg_len < 0)
  203. return -ENOMEM;
  204. int return_value = -1;
  205. if (!reply.ReadInt(&return_value))
  206. return -ENOMEM;
  207. return return_value;
  208. }
  209. // Make a remote system call over IPC for syscalls that take a path and flags
  210. // as arguments and return FDs (currently open()).
  211. // Will return -errno like a real system call.
  212. // This function needs to be async signal safe.
  213. int BrokerClient::PathAndFlagsSyscallReturningFD(BrokerCommand syscall_type,
  214. const char* pathname,
  215. int flags) const {
  216. // For this "remote system call" to work, we need to handle any flag that
  217. // cannot be sent over a Unix socket in a special way.
  218. // See the comments around kCurrentProcessOpenFlagsMask.
  219. int recvmsg_flags = 0;
  220. if (syscall_type == COMMAND_OPEN && (flags & kCurrentProcessOpenFlagsMask)) {
  221. // This implementation only knows about O_CLOEXEC, someone needs to look at
  222. // this code if other flags are added.
  223. static_assert(kCurrentProcessOpenFlagsMask == O_CLOEXEC,
  224. "Must update broker client to handle other flags");
  225. recvmsg_flags |= MSG_CMSG_CLOEXEC;
  226. flags &= ~kCurrentProcessOpenFlagsMask;
  227. }
  228. BrokerSimpleMessage message;
  229. RAW_CHECK(message.AddIntToMessage(syscall_type));
  230. RAW_CHECK(message.AddStringToMessage(pathname));
  231. RAW_CHECK(message.AddIntToMessage(flags));
  232. base::ScopedFD returned_fd;
  233. BrokerSimpleMessage reply;
  234. ssize_t msg_len = message.SendRecvMsgWithFlags(
  235. ipc_channel_.get(), recvmsg_flags, &returned_fd, &reply);
  236. if (msg_len < 0)
  237. return -ENOMEM;
  238. int return_value = -1;
  239. if (!reply.ReadInt(&return_value))
  240. return -ENOMEM;
  241. if (return_value < 0)
  242. return return_value;
  243. // We have a real file descriptor to return.
  244. RAW_CHECK(returned_fd.is_valid());
  245. return returned_fd.release();
  246. }
  247. // Make a remote system call over IPC for syscalls that take a path
  248. // and return stat buffers (currently stat() and stat64()).
  249. // Will return -errno like a real system call.
  250. // This function needs to be async signal safe.
  251. int BrokerClient::StatFamilySyscall(BrokerCommand syscall_type,
  252. const char* pathname,
  253. bool follow_links,
  254. void* result_ptr,
  255. size_t expected_result_size) const {
  256. BrokerSimpleMessage message;
  257. RAW_CHECK(message.AddIntToMessage(syscall_type));
  258. RAW_CHECK(message.AddStringToMessage(pathname));
  259. RAW_CHECK(message.AddIntToMessage(static_cast<int>(follow_links)));
  260. base::ScopedFD returned_fd;
  261. BrokerSimpleMessage reply;
  262. ssize_t msg_len =
  263. message.SendRecvMsgWithFlags(ipc_channel_.get(), 0, &returned_fd, &reply);
  264. if (msg_len < 0)
  265. return msg_len;
  266. int return_value = -1;
  267. size_t return_length = 0;
  268. const char* return_data = nullptr;
  269. if (!reply.ReadInt(&return_value))
  270. return -ENOMEM;
  271. if (return_value < 0)
  272. return return_value;
  273. if (!reply.ReadData(&return_data, &return_length))
  274. return -ENOMEM;
  275. if (static_cast<size_t>(return_length) != expected_result_size)
  276. return -ENOMEM;
  277. memcpy(result_ptr, return_data, expected_result_size);
  278. return return_value;
  279. }
  280. // static
  281. intptr_t BrokerClient::SIGSYS_Handler(const arch_seccomp_data& args,
  282. void* aux_broker_client) {
  283. RAW_CHECK(aux_broker_client);
  284. auto* broker_client = static_cast<BrokerClient*>(aux_broker_client);
  285. return broker_client->DispatchSyscall(args);
  286. }
  287. } // namespace syscall_broker
  288. } // namespace sandbox