• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
Align(uint32 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.
GetTag()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
GetBuffer()116   const void* GetBuffer() const {
117     return this;
118   }
119 
120   // Returns how many parameter this IPC call should have.
GetParamsCount()121   const uint32 GetParamsCount() const {
122     return params_count_;
123   }
124 
125   // Returns a pointer to the CrossCallReturn structure.
GetCallReturn()126   CrossCallReturn* GetCallReturn() {
127     return &call_return;
128   }
129 
130   // Returns TRUE if this call contains InOut parameters.
IsInOut()131   const bool IsInOut() const {
132     return (1 == is_in_out_);
133   }
134 
135   // Tells the CrossCall object if it contains InOut parameters.
SetIsInOut(bool value)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
CrossCallParams(uint32 tag,uint32 params_count)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
ActualCallParams(uint32 tag)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.
ActualCallParams(uint32 tag,uint32 number_params)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.
OverrideSize(uint32 new_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
CopyParamIn(uint32 index,const void * parameter_address,uint32 size,bool is_in_out,ArgType type)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 ((size > sizeof(*this)) ||
239         (param_info_[index].offset_ > (sizeof(*this) - size))) {
240       // It does not fit, abort copy.
241       return false;
242     }
243 
244     char* dest = reinterpret_cast<char*>(this) +  param_info_[index].offset_;
245 
246     // We might be touching user memory, this has to be done from inside a try
247     // except.
248     __try {
249       memcpy(dest, parameter_address, size);
250     }
251     __except(EXCEPTION_EXECUTE_HANDLER) {
252       return false;
253     }
254 
255     // Set the flag to tell the broker to update the buffer once the call is
256     // made.
257     if (is_in_out)
258       SetIsInOut(true);
259 
260     param_info_[index + 1].offset_ = Align(param_info_[index].offset_ +
261                                                 size);
262     param_info_[index].size_ = size;
263     param_info_[index].type_ = type;
264     return true;
265   }
266 
267   // Returns a pointer to a parameter in the memory section.
GetParamPtr(size_t index)268   void* GetParamPtr(size_t index) {
269     return reinterpret_cast<char*>(this) + param_info_[index].offset_;
270   }
271 
272   // Returns the total size of the buffer. Only valid once all the paramters
273   // have been copied in with CopyParamIn.
GetSize()274   uint32 GetSize() const {
275     return param_info_[NUMBER_PARAMS].offset_;
276   }
277 
278  protected:
ActualCallParams()279   ActualCallParams() : CrossCallParams(0, NUMBER_PARAMS) { }
280 
281  private:
282   ParamInfo param_info_[NUMBER_PARAMS + 1];
283   char parameters_[BLOCK_SIZE - sizeof(CrossCallParams)
284                    - sizeof(ParamInfo) * (NUMBER_PARAMS + 1)];
285   DISALLOW_COPY_AND_ASSIGN(ActualCallParams);
286 };
287 
288 COMPILE_ASSERT(sizeof(ActualCallParams<1, 1024>) == 1024, bad_size_buffer);
289 COMPILE_ASSERT(sizeof(ActualCallParams<2, 1024>) == 1024, bad_size_buffer);
290 COMPILE_ASSERT(sizeof(ActualCallParams<3, 1024>) == 1024, bad_size_buffer);
291 
292 }  // namespace sandbox
293 
294 #endif  // SANDBOX_SRC_CROSSCALL_PARAMS_H__
295