OLD | NEW |
| (Empty) |
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/src/internal_types.h" | |
15 #include "sandbox/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__ | |
OLD | NEW |