|
1 // Copyright (c) 2012 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 |
|
5 #ifndef SANDBOX_SRC_CROSSCALL_PARAMS_H__ |
|
6 #define SANDBOX_SRC_CROSSCALL_PARAMS_H__ |
|
7 |
|
8 #include <windows.h> |
|
9 #include <lmaccess.h> |
|
10 |
|
11 #include <memory> |
|
12 |
|
13 #include "base/basictypes.h" |
|
14 #include "sandbox/win/src/internal_types.h" |
|
15 #include "sandbox/win/src/sandbox_types.h" |
|
16 |
|
17 namespace { |
|
18 |
|
19 // Increases |value| until there is no need for padding given an int64 |
|
20 // alignment. Returns the increased value. |
|
21 uint32 Align(uint32 value) { |
|
22 uint32 alignment = sizeof(int64); |
|
23 return ((value + alignment - 1) / alignment) * alignment; |
|
24 } |
|
25 |
|
26 } |
|
27 // This header is part of CrossCall: the sandbox inter-process communication. |
|
28 // This header defines the basic types used both in the client IPC and in the |
|
29 // server IPC code. CrossCallParams and ActualCallParams model the input |
|
30 // parameters of an IPC call and CrossCallReturn models the output params and |
|
31 // the return value. |
|
32 // |
|
33 // An IPC call is defined by its 'tag' which is a (uint32) unique identifier |
|
34 // that is used to route the IPC call to the proper server. Every tag implies |
|
35 // a complete call signature including the order and type of each parameter. |
|
36 // |
|
37 // Like most IPC systems. CrossCall is designed to take as inputs 'simple' |
|
38 // types such as integers and strings. Classes, generic arrays or pointers to |
|
39 // them are not supported. |
|
40 // |
|
41 // Another limitation of CrossCall is that the return value and output |
|
42 // parameters can only be uint32 integers. Returning complex structures or |
|
43 // strings is not supported. |
|
44 |
|
45 namespace sandbox { |
|
46 |
|
47 // max number of extended return parameters. See CrossCallReturn |
|
48 const size_t kExtendedReturnCount = 8; |
|
49 |
|
50 // Union of multiple types to be used as extended results |
|
51 // in the CrossCallReturn. |
|
52 union MultiType { |
|
53 uint32 unsigned_int; |
|
54 void* pointer; |
|
55 HANDLE handle; |
|
56 ULONG_PTR ulong_ptr; |
|
57 }; |
|
58 |
|
59 // Maximum number of IPC parameters currently supported. |
|
60 // To increase this value, we have to: |
|
61 // - Add another Callback typedef to Dispatcher. |
|
62 // - Add another case to the switch on SharedMemIPCServer::InvokeCallback. |
|
63 // - Add another case to the switch in GetActualAndMaxBufferSize |
|
64 const int kMaxIpcParams = 9; |
|
65 |
|
66 // Contains the information about a parameter in the ipc buffer. |
|
67 struct ParamInfo { |
|
68 ArgType type_; |
|
69 uint32 offset_; |
|
70 uint32 size_; |
|
71 }; |
|
72 |
|
73 // Models the return value and the return parameters of an IPC call |
|
74 // currently limited to one status code and eight generic return values |
|
75 // which cannot be pointers to other data. For x64 ports this structure |
|
76 // might have to use other integer types. |
|
77 struct CrossCallReturn { |
|
78 // the IPC tag. It should match the original IPC tag. |
|
79 uint32 tag; |
|
80 // The result of the IPC operation itself. |
|
81 ResultCode call_outcome; |
|
82 // the result of the IPC call as executed in the server. The interpretation |
|
83 // of this value depends on the specific service. |
|
84 union { |
|
85 NTSTATUS nt_status; |
|
86 DWORD win32_result; |
|
87 }; |
|
88 // Number of extended return values. |
|
89 uint32 extended_count; |
|
90 // for calls that should return a windows handle. It is found here. |
|
91 HANDLE handle; |
|
92 // The array of extended values. |
|
93 MultiType extended[kExtendedReturnCount]; |
|
94 }; |
|
95 |
|
96 // CrossCallParams base class that models the input params all packed in a |
|
97 // single compact memory blob. The representation can vary but in general a |
|
98 // given child of this class is meant to represent all input parameters |
|
99 // necessary to make a IPC call. |
|
100 // |
|
101 // This class cannot have virtual members because its assumed the IPC |
|
102 // parameters start from the 'this' pointer to the end, which is defined by |
|
103 // one of the subclasses |
|
104 // |
|
105 // Objects of this class cannot be constructed directly. Only derived |
|
106 // classes have the proper knowledge to construct it. |
|
107 class CrossCallParams { |
|
108 public: |
|
109 // Returns the tag (ipc unique id) associated with this IPC. |
|
110 uint32 GetTag() const { |
|
111 return tag_; |
|
112 } |
|
113 |
|
114 // Returns the beggining of the buffer where the IPC params can be stored. |
|
115 // prior to an IPC call |
|
116 const void* GetBuffer() const { |
|
117 return this; |
|
118 } |
|
119 |
|
120 // Returns how many parameter this IPC call should have. |
|
121 const uint32 GetParamsCount() const { |
|
122 return params_count_; |
|
123 } |
|
124 |
|
125 // Returns a pointer to the CrossCallReturn structure. |
|
126 CrossCallReturn* GetCallReturn() { |
|
127 return &call_return; |
|
128 } |
|
129 |
|
130 // Returns TRUE if this call contains InOut parameters. |
|
131 const bool IsInOut() const { |
|
132 return (1 == is_in_out_); |
|
133 } |
|
134 |
|
135 // Tells the CrossCall object if it contains InOut parameters. |
|
136 void SetIsInOut(bool value) { |
|
137 if (value) |
|
138 is_in_out_ = 1; |
|
139 else |
|
140 is_in_out_ = 0; |
|
141 } |
|
142 |
|
143 protected: |
|
144 // constructs the IPC call params. Called only from the derived classes |
|
145 CrossCallParams(uint32 tag, uint32 params_count) |
|
146 : tag_(tag), |
|
147 params_count_(params_count), |
|
148 is_in_out_(0) { |
|
149 } |
|
150 |
|
151 private: |
|
152 uint32 tag_; |
|
153 uint32 is_in_out_; |
|
154 CrossCallReturn call_return; |
|
155 const uint32 params_count_; |
|
156 DISALLOW_COPY_AND_ASSIGN(CrossCallParams); |
|
157 }; |
|
158 |
|
159 // ActualCallParams models an specific IPC call parameters with respect to the |
|
160 // storage allocation that the packed parameters should need. |
|
161 // NUMBER_PARAMS: the number of parameters, valid from 1 to N |
|
162 // BLOCK_SIZE: the total storage that the NUMBER_PARAMS parameters can take, |
|
163 // typically the block size is defined by the channel size of the underlying |
|
164 // ipc mechanism. |
|
165 // In practice this class is used to levergage C++ capacity to properly |
|
166 // calculate sizes and displacements given the possibility of the packed params |
|
167 // blob to be complex. |
|
168 // |
|
169 // As is, this class assumes that the layout of the blob is as follows. Assume |
|
170 // that NUMBER_PARAMS = 2 and a 32-bit build: |
|
171 // |
|
172 // [ tag 4 bytes] |
|
173 // [ IsOnOut 4 bytes] |
|
174 // [ call return 52 bytes] |
|
175 // [ params count 4 bytes] |
|
176 // [ parameter 0 type 4 bytes] |
|
177 // [ parameter 0 offset 4 bytes] ---delta to ---\ |
|
178 // [ parameter 0 size 4 bytes] | |
|
179 // [ parameter 1 type 4 bytes] | |
|
180 // [ parameter 1 offset 4 bytes] ---------------|--\ |
|
181 // [ parameter 1 size 4 bytes] | | |
|
182 // [ parameter 2 type 4 bytes] | | |
|
183 // [ parameter 2 offset 4 bytes] ----------------------\ |
|
184 // [ parameter 2 size 4 bytes] | | | |
|
185 // |---------------------------| | | | |
|
186 // | value 0 (x bytes) | <--------------/ | | |
|
187 // | value 1 (y bytes) | <-----------------/ | |
|
188 // | | | |
|
189 // | end of buffer | <---------------------/ |
|
190 // |---------------------------| |
|
191 // |
|
192 // Note that the actual number of params is NUMBER_PARAMS + 1 |
|
193 // so that the size of each actual param can be computed from the difference |
|
194 // between one parameter and the next down. The offset of the last param |
|
195 // points to the end of the buffer and the type and size are undefined. |
|
196 // |
|
197 template <size_t NUMBER_PARAMS, size_t BLOCK_SIZE> |
|
198 class ActualCallParams : public CrossCallParams { |
|
199 public: |
|
200 // constructor. Pass the ipc unique tag as input |
|
201 explicit ActualCallParams(uint32 tag) |
|
202 : CrossCallParams(tag, NUMBER_PARAMS) { |
|
203 param_info_[0].offset_ = parameters_ - reinterpret_cast<char*>(this); |
|
204 } |
|
205 |
|
206 // Testing-only constructor. Allows setting the |number_params| to a |
|
207 // wrong value. |
|
208 ActualCallParams(uint32 tag, uint32 number_params) |
|
209 : CrossCallParams(tag, number_params) { |
|
210 param_info_[0].offset_ = parameters_ - reinterpret_cast<char*>(this); |
|
211 } |
|
212 |
|
213 // Testing-only method. Allows setting the apparent size to a wrong value. |
|
214 // returns the previous size. |
|
215 uint32 OverrideSize(uint32 new_size) { |
|
216 uint32 previous_size = param_info_[NUMBER_PARAMS].offset_; |
|
217 param_info_[NUMBER_PARAMS].offset_ = new_size; |
|
218 return previous_size; |
|
219 } |
|
220 |
|
221 // Copies each paramter into the internal buffer. For each you must supply: |
|
222 // index: 0 for the first param, 1 for the next an so on |
|
223 bool CopyParamIn(uint32 index, const void* parameter_address, uint32 size, |
|
224 bool is_in_out, ArgType type) { |
|
225 if (index >= NUMBER_PARAMS) { |
|
226 return false; |
|
227 } |
|
228 |
|
229 if (kuint32max == size) { |
|
230 // Memory error while getting the size. |
|
231 return false; |
|
232 } |
|
233 |
|
234 if (size && !parameter_address) { |
|
235 return false; |
|
236 } |
|
237 |
|
238 if (param_info_[index].offset_ > sizeof(*this)) { |
|
239 // It does not fit, abort copy. |
|
240 return false; |
|
241 } |
|
242 |
|
243 char* dest = reinterpret_cast<char*>(this) + param_info_[index].offset_; |
|
244 |
|
245 // We might be touching user memory, this has to be done from inside a try |
|
246 // except. |
|
247 __try { |
|
248 memcpy(dest, parameter_address, size); |
|
249 } |
|
250 __except(EXCEPTION_EXECUTE_HANDLER) { |
|
251 return false; |
|
252 } |
|
253 |
|
254 // Set the flag to tell the broker to update the buffer once the call is |
|
255 // made. |
|
256 if (is_in_out) |
|
257 SetIsInOut(true); |
|
258 |
|
259 param_info_[index + 1].offset_ = Align(param_info_[index].offset_ + |
|
260 size); |
|
261 param_info_[index].size_ = size; |
|
262 param_info_[index].type_ = type; |
|
263 return true; |
|
264 } |
|
265 |
|
266 // Returns a pointer to a parameter in the memory section. |
|
267 void* GetParamPtr(size_t index) { |
|
268 return reinterpret_cast<char*>(this) + param_info_[index].offset_; |
|
269 } |
|
270 |
|
271 // Returns the total size of the buffer. Only valid once all the paramters |
|
272 // have been copied in with CopyParamIn. |
|
273 uint32 GetSize() const { |
|
274 return param_info_[NUMBER_PARAMS].offset_; |
|
275 } |
|
276 |
|
277 protected: |
|
278 ActualCallParams() : CrossCallParams(0, NUMBER_PARAMS) { } |
|
279 |
|
280 private: |
|
281 ParamInfo param_info_[NUMBER_PARAMS + 1]; |
|
282 char parameters_[BLOCK_SIZE - sizeof(CrossCallParams) |
|
283 - sizeof(ParamInfo) * (NUMBER_PARAMS + 1)]; |
|
284 DISALLOW_COPY_AND_ASSIGN(ActualCallParams); |
|
285 }; |
|
286 |
|
287 COMPILE_ASSERT(sizeof(ActualCallParams<1, 1024>) == 1024, bad_size_buffer); |
|
288 COMPILE_ASSERT(sizeof(ActualCallParams<2, 1024>) == 1024, bad_size_buffer); |
|
289 COMPILE_ASSERT(sizeof(ActualCallParams<3, 1024>) == 1024, bad_size_buffer); |
|
290 |
|
291 } // namespace sandbox |
|
292 |
|
293 #endif // SANDBOX_SRC_CROSSCALL_PARAMS_H__ |