broker_simple_message.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // Copyright 2018 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. #ifndef SANDBOX_LINUX_SYSCALL_BROKER_BROKER_SIMPLE_MESSAGE_H_
  5. #define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_SIMPLE_MESSAGE_H_
  6. #include <stdint.h>
  7. #include <sys/types.h>
  8. #include "base/containers/span.h"
  9. #include "base/files/scoped_file.h"
  10. #include "base/memory/raw_ptr.h"
  11. #include "sandbox/sandbox_export.h"
  12. namespace sandbox {
  13. namespace syscall_broker {
  14. // This class is meant to provide a very simple messaging mechanism that is
  15. // signal-safe for the broker to utilize. This addresses many of the issues
  16. // outlined in https://crbug.com/255063. In short, the use of the standard
  17. // base::UnixDomainSockets is not possible because it uses base::Pickle and
  18. // std::vector, which are not signal-safe.
  19. //
  20. // In implementation, much of the code for sending and receiving is taken from
  21. // base::UnixDomainSockets and re-used below. Thus, ultimately, it might be
  22. // worthwhile making a first-class base-supported signal-safe set of mechanisms
  23. // that reduces the code duplication.
  24. class SANDBOX_EXPORT BrokerSimpleMessage {
  25. public:
  26. BrokerSimpleMessage() = default;
  27. // Signal-safe
  28. // A synchronous version of SendMsg/RecvMsgWithFlags that creates and sends a
  29. // temporary IPC socket over |fd|, then listens for a response on the IPC
  30. // socket using reply->RecvMsgWithFlags(temporary_ipc_socket, recvmsg_flags,
  31. // result_fd);
  32. ssize_t SendRecvMsgWithFlags(int fd,
  33. int recvmsg_flags,
  34. base::ScopedFD* result_fd,
  35. BrokerSimpleMessage* reply);
  36. // Same as SendRecvMsgWithFlags(), but allows sending and receiving a variable
  37. // number of fds. The temporary IPC return socket is always sent as the first
  38. // fd in the cmsg.
  39. ssize_t SendRecvMsgWithFlagsMultipleFds(int fd,
  40. int recvmsg_flags,
  41. base::span<const int> send_fds,
  42. base::span<base::ScopedFD> result_fds,
  43. BrokerSimpleMessage* reply);
  44. // Use sendmsg to write the given msg and the file descriptor |send_fd|.
  45. // Returns true if successful. Signal-safe.
  46. bool SendMsg(int fd, int send_fd);
  47. // Same as SendMsg() but allows sending more than one fd.
  48. bool SendMsgMultipleFds(int fd, base::span<const int> send_fds);
  49. // Similar to RecvMsg, but allows to specify |flags| for recvmsg(2).
  50. // Guaranteed to return either 1 or 0 fds. Signal-safe.
  51. ssize_t RecvMsgWithFlags(int fd, int flags, base::ScopedFD* return_fd);
  52. // Same as RecvMsgWithFlags() but allows receiving more than one fd.
  53. ssize_t RecvMsgWithFlagsMultipleFds(int fd,
  54. int flags,
  55. base::span<base::ScopedFD> return_fds);
  56. // Adds a NUL-terminated C-style string to the message as a raw buffer.
  57. // Returns true if the internal message buffer has room for the data, and
  58. // the data is successfully appended.
  59. bool AddStringToMessage(const char* string);
  60. // Adds a raw data buffer to the message. If the raw data is actually a
  61. // string, be sure to have length explicitly include the '\0' terminating
  62. // character. Returns true if the internal message buffer has room for the
  63. // data, and the data is successfully appended.
  64. bool AddDataToMessage(const char* buffer, size_t length);
  65. // Adds an int to the message. Returns true if the internal message buffer
  66. // has room for the int and the int is successfully added.
  67. bool AddIntToMessage(int int_to_add);
  68. // This returns a pointer to the next available data buffer in |data|. The
  69. // pointer is owned by |this| class. The resulting buffer is a string and
  70. // terminated with a '\0' character.
  71. bool ReadString(const char** string);
  72. // This returns a pointer to the next available data buffer in the message
  73. // in |data|, and the length of the buffer in |length|. The buffer is owned
  74. // by |this| class.
  75. bool ReadData(const char** data, size_t* length);
  76. // This reads the next available int from the message and stores it in
  77. // |result|.
  78. bool ReadInt(int* result);
  79. // The maximum length of a message in the fixed size buffer.
  80. static constexpr size_t kMaxMessageLength = 4096;
  81. private:
  82. friend class BrokerSimpleMessageTestHelper;
  83. enum class EntryType : uint32_t { DATA = 0xBDBDBD80, INT = 0xBDBDBD81 };
  84. // Returns whether or not the next available entry matches the expected
  85. // entry type.
  86. bool ValidateType(EntryType expected_type);
  87. // Set to true once a message is read from, it may never be written to.
  88. bool read_only_ = false;
  89. // Set to true once a message is written to, it may never be read from.
  90. bool write_only_ = false;
  91. // Set when an operation fails, so that all subsequed operations fail,
  92. // including any attempt to send the broken message.
  93. bool broken_ = false;
  94. // The current length of the contents in the |message_| buffer.
  95. size_t length_ = 0;
  96. // The statically allocated buffer of size |kMaxMessageLength|.
  97. uint8_t message_[kMaxMessageLength];
  98. // The pointer to the next location in the |message_| buffer to read from.
  99. raw_ptr<uint8_t> read_next_ = message_;
  100. // The pointer to the next location in the |message_| buffer to write from.
  101. raw_ptr<uint8_t> write_next_ = message_;
  102. };
  103. } // namespace syscall_broker
  104. } // namespace sandbox
  105. #endif // SANDBOX_LINUX_SYSCALL_BROKER_BROKER_SIMPLE_MESSAGE_H_