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 // Fix DBAttributes, which have to be processed specially
127 void fixDbAttributes (CssmDbAttributeData
&data
);
128 void fixDbAttributes (CssmQuery
&query
);
129 void fixDbAttributes (CssmDbRecordAttributeData
&data
);
132 void fixDbAttributes(T
&n
) {} // handle the default case
136 // Process an incoming (IPC) data blob of type T.
137 // This relocates pointers to fit in the local address space,
138 // and fixes byte order issues as needed.
141 void relocate(T
*obj
, T
*base
, size_t size
)
144 if (base
== NULL
) // invalid, could confuse walkers
145 CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER
);
146 CheckingReconstituteWalker
relocator(obj
, base
, size
,
147 Server::process().byteFlipped());
148 walk(relocator
, base
);
150 // resolve weird type interdependency in DB_ATTRIBUTE_DATA
151 if (Server::process().byteFlipped())
152 fixDbAttributes(*obj
);
158 // Special handling for incoming CSSM contexts.
160 void relocate(Context
&context
, void *base
, Context::Attr
*attrs
, uint32 attrSize
);
164 // A FlipWalker is a walker operator that collects its direct invocations
165 // into a set of memory objects. These objects can then collectively be
166 // byte-flipped (exactly once :-) at the flick of a method.
172 virtual void flip() const = 0;
176 struct FlipRef
: public Base
{
178 FlipRef(T
&s
) : obj(s
) { }
179 void flip() const { Flippers::flip(obj
); }
183 struct FlipPtr
: public Base
{
185 FlipPtr(T
* &s
) : obj(s
) { }
186 void flip() const { Flippers::flip(*obj
); Flippers::flip(obj
); }
190 struct FlipBlob
: public Base
{
192 FlipBlob(T
* &s
) : obj(s
) { }
193 void flip() const { Flippers::flip(obj
); }
198 Flipper(Base
*p
) : impl(p
) { }
199 bool operator < (const Flipper
&other
) const
200 { return impl
< other
.impl
; }
205 void doFlips(bool active
= true);
208 void operator () (T
&obj
, size_t = sizeof(T
))
209 { mFlips
.insert(new FlipRef
<T
>(obj
)); }
212 T
*operator () (T
* &addr
, size_t size
= sizeof(T
))
213 { mFlips
.insert(new FlipPtr
<T
>(addr
)); return addr
; }
216 void blob(T
* &addr
, size_t size
)
217 { mFlips
.insert(new FlipBlob
<T
>(addr
)); }
219 static const bool needsRelinking
= true;
220 static const bool needsSize
= true;
228 // A raw flip, conditioned on the client's flip state
234 secdebug("flippers", "raw flipping %s", Debug::typeName(addr
).c_str());
235 Flippers::flip(addr
);
240 void flipCssmDbAttributeData (CssmDbRecordAttributeData
*value
, CssmDbRecordAttributeData
**&addr
, CssmDbRecordAttributeData
**&base
);
243 // Take an object at value, flip it, and return appropriately flipped
244 // addr/base pointers ready to be returned through IPC.
245 // Note that this doesn't set the outgoing length (aka 'fooLength') field.
248 void flips(T
*value
, T
** &addr
, T
** &base
)
250 *addr
= *base
= value
;
252 // resolve weird type inter-dependency in DB_ATTRIBUTE_DATA
254 fixDbAttributes(*value
);
255 FlipWalker w
; // collector
256 walk(w
, value
); // collect all flippings needed
257 w
.doFlips(); // execute flips (flips value but leaves addr alone)
258 Flippers::flip(*base
); // flip base (so it arrives right side up)
263 // Take a DATA type RPC argument purportedly representing a Blob of some kind,
264 // turn it into a Blob, and fail properly if it's not kosher.
266 template <class BlobType
>
267 const BlobType
*makeBlob(const CssmData
&blobData
, CSSM_RETURN error
= CSSM_ERRCODE_INVALID_DATA
)
269 if (!blobData
.data() || blobData
.length() < sizeof(BlobType
))
270 CssmError::throwMe(error
);
271 const BlobType
*blob
= static_cast<const BlobType
*>(blobData
.data());
272 if (blob
->totalLength
!= blobData
.length())
273 CssmError::throwMe(error
);
279 // An OutputData object will take memory allocated within securityd,
280 // hand it to the MIG return-output parameters, and schedule it to be released
281 // after the MIG reply has been sent. It will also get rid of it in case of
284 class OutputData
: public CssmData
{
286 OutputData(void **outP
, mach_msg_type_number_t
*outLength
)
287 : mData(*outP
), mLength(*outLength
) { }
289 { mData
= data(); mLength
= length(); Server::releaseWhenDone(mData
); }
291 void operator = (const CssmData
&source
)
292 { CssmData::operator = (source
); }
296 mach_msg_type_number_t
&mLength
;
301 // Choose a Database from a choice of two sources, giving preference
302 // to persistent stores and to earlier sources.
304 Database
*pickDb(Database
*db1
, Database
*db2
);
306 static inline Database
*dbOf(Key
*key
) { return key
? &key
->database() : NULL
; }
308 inline Database
*pickDb(Key
*k1
, Key
*k2
) { return pickDb(dbOf(k1
), dbOf(k2
)); }
309 inline Database
*pickDb(Database
*db1
, Key
*k2
) { return pickDb(db1
, dbOf(k2
)); }
310 inline Database
*pickDb(Key
*k1
, Database
*db2
) { return pickDb(dbOf(k1
), db2
); }
313 #endif //_H_TRANSWALKERS