2 * Copyright (c) 2003-2004 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 // transwalkers - server side transition data walking support
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.
32 #ifndef _H_TRANSWALKERS
33 #define _H_TRANSWALKERS
35 #include <security_cdsa_utilities/AuthorizationWalkers.h>
38 #include <security_cdsa_utilities/context.h>
40 using LowLevelMemoryUtilities::increment
;
41 using LowLevelMemoryUtilities::difference
;
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.
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.
59 class CheckingReconstituteWalker
{
61 void check(void *addr
, size_t size
)
63 if (addr
< mBase
|| increment(addr
, size
) > mLimit
)
64 CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER
);
68 CheckingReconstituteWalker(void *ptr
, void *base
, size_t size
, bool flip
);
71 void operator () (T
&obj
, size_t size
= sizeof(T
))
73 check(increment(&obj
, -mOffset
), size
);
79 void operator () (T
* &addr
, size_t size
= sizeof(T
))
81 DEBUGWALK("checkreconst:ptr");
83 // process the pointer
86 addr
= reinterpret_cast<T
*>(p
);
88 // now flip the contents
90 Flippers::flip(*addr
);
95 void blob(T
* &addr
, size_t size
)
97 DEBUGWALK("checkreconst:blob");
99 // flip the address (the pointer itself)
101 secdebug("flippers", "flipping %s@%p", Debug::typeName(addr
).c_str(), addr
);
102 Flippers::flip(addr
);
105 // check the address against the transmitted bounds
109 addr
= increment
<T
>(addr
, mOffset
);
113 static const bool needsRelinking
= true;
114 static const bool needsSize
= false;
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
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.
130 void relocate(T
*obj
, T
*base
, size_t size
)
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
);
143 // Special handling for incoming CSSM contexts.
145 void relocate(Context
&context
, void *base
, Context::Attr
*attrs
, uint32 attrSize
);
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.
157 virtual void flip() const = 0;
161 struct FlipRef
: public Base
{
163 FlipRef(T
&s
) : obj(s
) { }
164 void flip() const { Flippers::flip(obj
); }
168 struct FlipPtr
: public Base
{
170 FlipPtr(T
* &s
) : obj(s
) { }
171 void flip() const { Flippers::flip(*obj
); Flippers::flip(obj
); }
175 struct FlipBlob
: public Base
{
177 FlipBlob(T
* &s
) : obj(s
) { }
178 void flip() const { Flippers::flip(obj
); }
183 Flipper(Base
*p
) : impl(p
) { }
184 bool operator < (const Flipper
&other
) const
185 { return impl
< other
.impl
; }
190 void doFlips(bool active
= true);
193 void operator () (T
&obj
, size_t = sizeof(T
))
194 { mFlips
.insert(new FlipRef
<T
>(obj
)); }
197 T
*operator () (T
* &addr
, size_t size
= sizeof(T
))
198 { mFlips
.insert(new FlipPtr
<T
>(addr
)); return addr
; }
201 void blob(T
* &addr
, size_t size
)
202 { mFlips
.insert(new FlipBlob
<T
>(addr
)); }
204 static const bool needsRelinking
= true;
205 static const bool needsSize
= true;
213 // A raw flip, conditioned on the client's flip state
219 secdebug("flippers", "raw flipping %s", Debug::typeName(addr
).c_str());
220 Flippers::flip(addr
);
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.
231 void flips(T
*value
, T
** &addr
, T
** &base
)
233 *addr
= *base
= value
;
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)
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.
247 template <class BlobType
>
248 const BlobType
*makeBlob(const CssmData
&blobData
, CSSM_RETURN error
= CSSM_ERRCODE_INVALID_DATA
)
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
);
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
265 class OutputData
: public CssmData
{
267 OutputData(void **outP
, mach_msg_type_number_t
*outLength
)
268 : mData(*outP
), mLength(*outLength
) { }
270 { mData
= data(); mLength
= length(); Server::releaseWhenDone(mData
); }
272 void operator = (const CssmData
&source
)
273 { CssmData::operator = (source
); }
277 mach_msg_type_number_t
&mLength
;
282 // Choose a Database from a choice of two sources, giving preference
283 // to persistent stores and to earlier sources.
285 Database
*pickDb(Database
*db1
, Database
*db2
);
287 static inline Database
*dbOf(Key
*key
) { return key
? &key
->database() : NULL
; }
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
); }
294 #endif //_H_TRANSWALKERS