File: broker_simple_message.h

package info (click to toggle)
chromium 139.0.7258.127-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,122,156 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (131 lines) | stat: -rw-r--r-- 5,678 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef SANDBOX_LINUX_SYSCALL_BROKER_BROKER_SIMPLE_MESSAGE_H_
#define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_SIMPLE_MESSAGE_H_

#include <stdint.h>
#include <sys/types.h>

#include "base/containers/span.h"
#include "base/files/scoped_file.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "sandbox/sandbox_export.h"

namespace sandbox {
namespace syscall_broker {

// This class is meant to provide a very simple messaging mechanism that is
// signal-safe for the broker to utilize. This addresses many of the issues
// outlined in https://crbug.com/255063. In short, the use of the standard
// base::UnixDomainSockets is not possible because it uses base::Pickle and
// std::vector, which are not signal-safe.
//
// In implementation, much of the code for sending and receiving is taken from
// base::UnixDomainSockets and re-used below. Thus, ultimately, it might be
// worthwhile making a first-class base-supported signal-safe set of mechanisms
// that reduces the code duplication.
class SANDBOX_EXPORT BrokerSimpleMessage {
 public:
  BrokerSimpleMessage() = default;

  // Signal-safe
  // A synchronous version of SendMsg/RecvMsgWithFlags that creates and sends a
  // temporary IPC socket over |fd|, then listens for a response on the IPC
  // socket using reply->RecvMsgWithFlags(temporary_ipc_socket, recvmsg_flags,
  // result_fd);
  ssize_t SendRecvMsgWithFlags(int fd,
                               int recvmsg_flags,
                               base::ScopedFD* result_fd,
                               BrokerSimpleMessage* reply);

  // Same as SendRecvMsgWithFlags(), but allows sending and receiving a variable
  // number of fds. The temporary IPC return socket is always sent as the first
  // fd in the cmsg.
  ssize_t SendRecvMsgWithFlagsMultipleFds(int fd,
                                          int recvmsg_flags,
                                          base::span<const int> send_fds,
                                          base::span<base::ScopedFD> result_fds,
                                          BrokerSimpleMessage* reply);

  // Use sendmsg to write the given msg and the file descriptor |send_fd|.
  // Returns true if successful. Signal-safe.
  bool SendMsg(int fd, int send_fd);

  // Same as SendMsg() but allows sending more than one fd.
  bool SendMsgMultipleFds(int fd, base::span<const int> send_fds);

  // Similar to RecvMsg, but allows to specify |flags| for recvmsg(2).
  // Guaranteed to return either 1 or 0 fds. Signal-safe.
  ssize_t RecvMsgWithFlags(int fd, int flags, base::ScopedFD* return_fd);

  // Same as RecvMsgWithFlags() but allows receiving more than one fd.
  ssize_t RecvMsgWithFlagsMultipleFds(int fd,
                                      int flags,
                                      base::span<base::ScopedFD> return_fds);

  // Adds a NUL-terminated C-style string to the message as a raw buffer.
  // Returns true if the internal message buffer has room for the data, and
  // the data is successfully appended.
  bool AddStringToMessage(const char* string);

  // Adds a raw data buffer to the message. If the raw data is actually a
  // string, be sure to have length explicitly include the '\0' terminating
  // character. Returns true if the internal message buffer has room for the
  // data, and the data is successfully appended.
  bool AddDataToMessage(const char* buffer, size_t length);

  // Adds an int to the message. Returns true if the internal message buffer
  // has room for the int and the int is successfully added.
  bool AddIntToMessage(int int_to_add);

  // This returns a pointer to the next available data buffer in |data|. The
  // pointer is owned by |this| class. The resulting buffer is a string and
  // terminated with a '\0' character.
  [[nodiscard]] bool ReadString(const char** string);

  // This returns a pointer to the next available data buffer in the message
  // in |data|, and the length of the buffer in |length|. The buffer is owned
  // by |this| class.
  [[nodiscard]] bool ReadData(const char** data, size_t* length);

  // This reads the next available int from the message and stores it in
  // |result|.
  [[nodiscard]] bool ReadInt(int* result);

  // The maximum length of a message in the fixed size buffer.
  static constexpr size_t kMaxMessageLength = 4096;

 private:
  friend class BrokerSimpleMessageTestHelper;

  enum class EntryType : uint32_t { DATA = 0xBDBDBD80, INT = 0xBDBDBD81 };

  // Returns whether or not the next available entry matches the expected
  // entry type.
  bool ValidateType(EntryType expected_type);

  // Set to true once a message is read from, it may never be written to.
  bool read_only_ = false;
  // Set to true once a message is written to, it may never be read from.
  bool write_only_ = false;
  // Set when an operation fails, so that all subsequed operations fail,
  // including any attempt to send the broken message.
  bool broken_ = false;
  // The current length of the contents in the |message_| buffer.
  size_t length_ = 0;
  // The statically allocated buffer of size |kMaxMessageLength|.
  uint8_t message_[kMaxMessageLength];

  // Next location in the `message_` buffer to read from/write to.
  // RAW_PTR_EXCLUSION: Point into the `message_` buffer above, so they are
  // valid whenever `this` is valid.
  RAW_PTR_EXCLUSION uint8_t* read_next_ = message_;
  RAW_PTR_EXCLUSION uint8_t* write_next_ = message_;
};

}  // namespace syscall_broker
}  // namespace sandbox

#endif  // SANDBOX_LINUX_SYSCALL_BROKER_BROKER_SIMPLE_MESSAGE_H_