]> git.saurik.com Git - apple/securityd.git/blob - src/transwalkers.h
securityd-26674.tar.gz
[apple/securityd.git] / src / transwalkers.h
1 /*
2 * Copyright (c) 2003-2004 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 //
26 // transwalkers - server side transition data walking support
27 //
28 // These are data walker operators for securely marshaling and unmarshaling
29 // data structures across IPC. They are also in charge of fixing byte order
30 // inconsistencies between server and clients.
31 //
32 #ifndef _H_TRANSWALKERS
33 #define _H_TRANSWALKERS
34
35 #include <security_cdsa_utilities/AuthorizationWalkers.h>
36 #include "flippers.h"
37 #include "server.h"
38 #include <security_cdsa_utilities/context.h>
39
40 using LowLevelMemoryUtilities::increment;
41 using LowLevelMemoryUtilities::difference;
42
43
44 //
45 // Should we flip data?
46 // This looks at the current client's process information (a thread-global state)
47 // to determine flip status. Valid (only) within BEGIN_IPC/END_IPC brackets.
48 //
49 bool flipClient();
50
51
52 //
53 // A CheckingReconstituteWalker is a variant of an ordinary ReconstituteWalker
54 // that checks object pointers and sizes against the incoming block limits.
55 // It throws an exception if incoming data has pointers outside the incoming block.
56 // This avoids trouble inside of securityd caused (by bug or malice)
57 // from someone spoofing the client access side.
58 //
59 class CheckingReconstituteWalker {
60 private:
61 void check(void *addr, size_t size)
62 {
63 if (addr < mBase || increment(addr, size) > mLimit)
64 CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER);
65 }
66
67 public:
68 CheckingReconstituteWalker(void *ptr, void *base, size_t size, bool flip);
69
70 template <class T>
71 void operator () (T &obj, size_t size = sizeof(T))
72 {
73 check(increment(&obj, -mOffset), size);
74 if (mFlip)
75 Flippers::flip(obj);
76 }
77
78 template <class T>
79 void operator () (T * &addr, size_t size = sizeof(T))
80 {
81 DEBUGWALK("checkreconst:ptr");
82 if (addr) {
83 // process the pointer
84 void *p = addr;
85 blob(p, size);
86 addr = reinterpret_cast<T *>(p);
87
88 // now flip the contents
89 if (mFlip)
90 Flippers::flip(*addr);
91 }
92 }
93
94 template <class T>
95 void blob(T * &addr, size_t size)
96 {
97 DEBUGWALK("checkreconst:blob");
98 if (addr) {
99 // flip the address (the pointer itself)
100 if (mFlip) {
101 secdebug("flippers", "flipping %s@%p", Debug::typeName(addr).c_str(), addr);
102 Flippers::flip(addr);
103 }
104
105 // check the address against the transmitted bounds
106 check(addr, size);
107
108 // relocate it
109 addr = increment<T>(addr, mOffset);
110 }
111 }
112
113 static const bool needsRelinking = true;
114 static const bool needsSize = false;
115
116 private:
117 void *mBase; // old base address
118 void *mLimit; // old last byte address + 1
119 off_t mOffset; // relocation offset
120 bool mFlip; // apply byte order flipping
121 };
122
123
124 //
125 // Process an incoming (IPC) data blob of type T.
126 // This relocates pointers to fit in the local address space,
127 // and fixes byte order issues as needed.
128 //
129 template <class T>
130 void relocate(T *obj, T *base, size_t size)
131 {
132 if (obj) {
133 if (base == NULL) // invalid, could confuse walkers
134 CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER);
135 CheckingReconstituteWalker relocator(obj, base, size,
136 Server::process().byteFlipped());
137 walk(relocator, base);
138 }
139 }
140
141
142 //
143 // Special handling for incoming CSSM contexts.
144 //
145 void relocate(Context &context, void *base, Context::Attr *attrs, uint32 attrSize);
146
147
148 //
149 // A FlipWalker is a walker operator that collects its direct invocations
150 // into a set of memory objects. These objects can then collectively be
151 // byte-flipped (exactly once :-) at the flick of a method.
152 //
153 class FlipWalker {
154 private:
155 struct Base {
156 virtual ~Base() { }
157 virtual void flip() const = 0;
158 };
159
160 template <class T>
161 struct FlipRef : public Base {
162 T &obj;
163 FlipRef(T &s) : obj(s) { }
164 void flip() const { Flippers::flip(obj); }
165 };
166
167 template <class T>
168 struct FlipPtr : public Base {
169 T * &obj;
170 FlipPtr(T * &s) : obj(s) { }
171 void flip() const { Flippers::flip(*obj); Flippers::flip(obj); }
172 };
173
174 template <class T>
175 struct FlipBlob : public Base {
176 T * &obj;
177 FlipBlob(T * &s) : obj(s) { }
178 void flip() const { Flippers::flip(obj); }
179 };
180
181 struct Flipper {
182 Base *impl;
183 Flipper(Base *p) : impl(p) { }
184 bool operator < (const Flipper &other) const
185 { return impl < other.impl; }
186 };
187
188 public:
189 ~FlipWalker();
190 void doFlips(bool active = true);
191
192 template <class T>
193 void operator () (T &obj, size_t = sizeof(T))
194 { mFlips.insert(new FlipRef<T>(obj)); }
195
196 template <class T>
197 T *operator () (T * &addr, size_t size = sizeof(T))
198 { mFlips.insert(new FlipPtr<T>(addr)); return addr; }
199
200 template <class T>
201 void blob(T * &addr, size_t size)
202 { mFlips.insert(new FlipBlob<T>(addr)); }
203
204 static const bool needsRelinking = true;
205 static const bool needsSize = true;
206
207 private:
208 set<Flipper> mFlips;
209 };
210
211
212 //
213 // A raw flip, conditioned on the client's flip state
214 //
215 template <class T>
216 void flip(T &addr)
217 {
218 if (flipClient()) {
219 secdebug("flippers", "raw flipping %s", Debug::typeName(addr).c_str());
220 Flippers::flip(addr);
221 }
222 }
223
224
225 //
226 // Take an object at value, flip it, and return appropriately flipped
227 // addr/base pointers ready to be returned through IPC.
228 // Note that this doesn't set the outgoing length (aka 'fooLength') field.
229 //
230 template <class T>
231 void flips(T *value, T ** &addr, T ** &base)
232 {
233 *addr = *base = value;
234 if (flipClient()) {
235 FlipWalker w; // collector
236 walk(w, value); // collect all flippings needed
237 w.doFlips(); // execute flips (flips value but leaves addr alone)
238 Flippers::flip(*base); // flip base (so it arrives right side up)
239 }
240 }
241
242
243 //
244 // Take a DATA type RPC argument purportedly representing a Blob of some kind,
245 // turn it into a Blob, and fail properly if it's not kosher.
246 //
247 template <class BlobType>
248 const BlobType *makeBlob(const CssmData &blobData, CSSM_RETURN error = CSSM_ERRCODE_INVALID_DATA)
249 {
250 if (!blobData.data() || blobData.length() < sizeof(BlobType))
251 CssmError::throwMe(error);
252 const BlobType *blob = static_cast<const BlobType *>(blobData.data());
253 if (blob->totalLength != blobData.length())
254 CssmError::throwMe(error);
255 return blob;
256 }
257
258
259 //
260 // An OutputData object will take memory allocated within securityd,
261 // hand it to the MIG return-output parameters, and schedule it to be released
262 // after the MIG reply has been sent. It will also get rid of it in case of
263 // error.
264 //
265 class OutputData : public CssmData {
266 public:
267 OutputData(void **outP, mach_msg_type_number_t *outLength)
268 : mData(*outP), mLength(*outLength) { }
269 ~OutputData()
270 { mData = data(); mLength = length(); Server::releaseWhenDone(mData); }
271
272 void operator = (const CssmData &source)
273 { CssmData::operator = (source); }
274
275 private:
276 void * &mData;
277 mach_msg_type_number_t &mLength;
278 };
279
280
281 //
282 // Choose a Database from a choice of two sources, giving preference
283 // to persistent stores and to earlier sources.
284 //
285 Database *pickDb(Database *db1, Database *db2);
286
287 static inline Database *dbOf(Key *key) { return key ? &key->database() : NULL; }
288
289 inline Database *pickDb(Key *k1, Key *k2) { return pickDb(dbOf(k1), dbOf(k2)); }
290 inline Database *pickDb(Database *db1, Key *k2) { return pickDb(db1, dbOf(k2)); }
291 inline Database *pickDb(Key *k1, Database *db2) { return pickDb(dbOf(k1), db2); }
292
293
294 #endif //_H_TRANSWALKERS