2 * Copyright (c) 2003-2004 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
28 // transwalkers - server side transition data walking support
30 // These are data walker operators for securely marshaling and unmarshaling
31 // data structures across IPC. They are also in charge of fixing byte order
32 // inconsistencies between server and clients.
34 #ifndef _H_TRANSWALKERS
35 #define _H_TRANSWALKERS
37 #include <security_cdsa_utilities/AuthorizationWalkers.h>
40 #include <security_cdsa_utilities/context.h>
42 using LowLevelMemoryUtilities::increment
;
43 using LowLevelMemoryUtilities::difference
;
47 // Should we flip data?
48 // This looks at the current client's process information (a thread-global state)
49 // to determine flip status. Valid (only) within BEGIN_IPC/END_IPC brackets.
55 // A CheckingReconstituteWalker is a variant of an ordinary ReconstituteWalker
56 // that checks object pointers and sizes against the incoming block limits.
57 // It throws an exception if incoming data has pointers outside the incoming block.
58 // This avoids trouble inside of the SecurityServer caused (by bug or malice)
59 // from someone spoofing the client access side.
61 class CheckingReconstituteWalker
{
63 void check(void *addr
, size_t size
)
65 if (addr
< mBase
|| increment(addr
, size
) > mLimit
)
66 CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER
);
70 CheckingReconstituteWalker(void *ptr
, void *base
, size_t size
, bool flip
);
73 void operator () (T
&obj
, size_t size
= sizeof(T
))
75 check(increment(&obj
, -mOffset
), size
);
81 void operator () (T
* &addr
, size_t size
= sizeof(T
))
83 DEBUGWALK("checkreconst:ptr");
85 // process the pointer
88 addr
= reinterpret_cast<T
*>(p
);
90 // now flip the contents
92 Flippers::flip(*addr
);
97 void blob(T
* &addr
, size_t size
)
99 DEBUGWALK("checkreconst:blob");
101 // flip the address (the pointer itself)
103 secdebug("flippers", "flipping %s@%p", Debug::typeName(addr
).c_str(), addr
);
104 Flippers::flip(addr
);
107 // check the address against the transmitted bounds
111 addr
= increment
<T
>(addr
, mOffset
);
115 static const bool needsRelinking
= true;
116 static const bool needsSize
= false;
119 void *mBase
; // old base address
120 void *mLimit
; // old last byte address + 1
121 off_t mOffset
; // relocation offset
122 bool mFlip
; // apply byte order flipping
127 // Process an incoming (IPC) data blob of type T.
128 // This relocates pointers to fit in the local address space,
129 // and fixes byte order issues as needed.
132 void relocate(T
*obj
, T
*base
, size_t size
)
135 if (base
== NULL
) // invalid, could confuse walkers
136 CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER
);
137 CheckingReconstituteWalker
relocator(obj
, base
, size
,
138 Server::process().byteFlipped());
139 walk(relocator
, base
);
145 // Special handling for incoming CSSM contexts.
147 void relocate(Context
&context
, void *base
, Context::Attr
*attrs
, uint32 attrSize
);
151 // A FlipWalker is a walker operator that collects its direct invocations
152 // into a set of memory objects. These objects can then collectively be
153 // byte-flipped (exactly once :-) at the flick of a function.
158 virtual ~FlipBase() { }
159 virtual void flip() const = 0;
163 struct FlipRef
: public FlipBase
{
165 FlipRef(T
&s
) : obj(s
) { }
167 { secdebug("outflip", "%p flip/ref %s@%p", this, Debug::typeName(obj
).c_str(), &obj
);
168 { Flippers::flip(obj
); }
173 struct FlipPtr
: public FlipBase
{
175 FlipPtr(T
* &s
) : obj(s
) { }
177 { secdebug("outflip", "%p flip/ptr %s@%p(%p)", this, Debug::typeName(obj
).c_str(), &obj
, obj
);
178 { Flippers::flip(*obj
); Flippers::flip(obj
); }
183 struct FlipBlob
: public FlipBase
{
185 FlipBlob(T
* &s
) : obj(s
) { }
187 { secdebug("outflip", "%p flip/blob %s@%p(%p)", this, Debug::typeName(obj
).c_str(), &obj
, obj
);
188 { Flippers::flip(obj
); }
194 Flipper(FlipBase
*p
) : impl(p
) { }
195 bool operator < (const Flipper
&other
) const
196 { return impl
< other
.impl
; }
201 void doFlips(bool active
= true);
204 void operator () (T
&obj
, size_t = sizeof(T
))
205 { mFlips
.insert(new FlipRef
<T
>(obj
)); }
208 T
*operator () (T
* &addr
, size_t size
= sizeof(T
))
209 { mFlips
.insert(new FlipPtr
<T
>(addr
)); return addr
; }
212 void blob(T
* &addr
, size_t size
)
213 { mFlips
.insert(new FlipBlob
<T
>(addr
)); }
215 static const bool needsRelinking
= true;
216 static const bool needsSize
= true;
224 // A raw flip, conditioned on the client's flip state
230 secdebug("flippers", "raw flipping %s", Debug::typeName(addr
).c_str());
231 Flippers::flip(addr
);
236 void flips(T
*value
, T
** &addr
, T
** &base
)
238 *addr
= *base
= value
;
240 FlipWalker w
; // collector
241 walk(w
, value
); // collect all flippings needed
242 w
.doFlips(); // execute flips (flips value but leaves addr alone)
243 Flippers::flip(*base
); // flip base (so it arrives right side up)
248 #endif //_H_TRANSWALKERS