2 * Copyright (c) 2003 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
20 // transwalkers - server side transition data walking support
22 // These are data walker operators for securely marshaling and unmarshaling
23 // data structures across IPC. They are also in charge of fixing byte order
24 // inconsistencies between server and clients.
26 #ifndef _H_TRANSWALKERS
27 #define _H_TRANSWALKERS
29 #include <Security/AuthorizationWalkers.h>
32 #include <Security/context.h>
34 using LowLevelMemoryUtilities::increment
;
35 using LowLevelMemoryUtilities::difference
;
39 // Should we flip data?
40 // This looks at the current client's process information (a thread-global state)
41 // to determine flip status. Valid (only) within BEGIN_IPC/END_IPC brackets.
47 // A CheckingReconstituteWalker is a variant of an ordinary ReconstituteWalker
48 // that checks object pointers and sizes against the incoming block limits.
49 // It throws an exception if incoming data has pointers outside the incoming block.
50 // This avoids trouble inside of the SecurityServer caused (by bug or malice)
51 // from someone spoofing the client access side.
53 class CheckingReconstituteWalker
{
55 void check(void *addr
, size_t size
)
57 if (addr
< mBase
|| increment(addr
, size
) > mLimit
)
58 CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER
);
62 CheckingReconstituteWalker(void *ptr
, void *base
, size_t size
, bool flip
);
65 void operator () (T
&obj
, size_t size
= sizeof(T
))
67 check(increment(&obj
, -mOffset
), size
);
73 void operator () (T
* &addr
, size_t size
= sizeof(T
))
75 DEBUGWALK("checkreconst:ptr");
77 // process the pointer
80 addr
= reinterpret_cast<T
*>(p
);
82 // now flip the contents
84 Flippers::flip(*addr
);
89 void blob(T
* &addr
, size_t size
)
91 DEBUGWALK("checkreconst:blob");
93 // flip the address (the pointer itself)
95 secdebug("flippers", "flipping %s@%p", Debug::typeName(addr
).c_str(), addr
);
99 // check the address against the transmitted bounds
103 addr
= increment
<T
>(addr
, mOffset
);
107 static const bool needsRelinking
= true;
108 static const bool needsSize
= false;
111 void *mBase
; // old base address
112 void *mLimit
; // old last byte address + 1
113 off_t mOffset
; // relocation offset
114 bool mFlip
; // apply byte order flipping
119 // Process an incoming (IPC) data blob of type T.
120 // This relocates pointers to fit in the local address space,
121 // and fixes byte order issues as needed.
124 void relocate(T
*obj
, T
*base
, size_t size
)
127 if (base
== NULL
) // invalid, could confuse walkers
128 CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER
);
129 CheckingReconstituteWalker
relocator(obj
, base
, size
,
130 Server::connection().process
.byteFlipped());
131 walk(relocator
, base
);
137 // Special handling for incoming CSSM contexts.
139 void relocate(Context
&context
, void *base
, Context::Attr
*attrs
, uint32 attrSize
);
143 // A FlipWalker is a walker operator that collects its direct invocations
144 // into a set of memory objects. These objects can then collectively be
145 // byte-flipped (exactly once :-) at the flick of a function.
150 virtual ~FlipBase() { }
151 virtual void flip() const = 0;
155 struct FlipRef
: public FlipBase
{
157 FlipRef(T
&s
) : obj(s
) { }
159 { secdebug("outflip", "%p flip/ref %s@%p", this, Debug::typeName(obj
).c_str(), &obj
);
160 { Flippers::flip(obj
); }
165 struct FlipPtr
: public FlipBase
{
167 FlipPtr(T
* &s
) : obj(s
) { }
169 { secdebug("outflip", "%p flip/ptr %s@%p(%p)", this, Debug::typeName(obj
).c_str(), &obj
, obj
);
170 { Flippers::flip(*obj
); Flippers::flip(obj
); }
175 struct FlipBlob
: public FlipBase
{
177 FlipBlob(T
* &s
) : obj(s
) { }
179 { secdebug("outflip", "%p flip/blob %s@%p(%p)", this, Debug::typeName(obj
).c_str(), &obj
, obj
);
180 { Flippers::flip(obj
); }
186 Flipper(FlipBase
*p
) : impl(p
) { }
187 bool operator < (const Flipper
&other
) const
188 { return impl
< other
.impl
; }
193 void doFlips(bool active
= true);
196 void operator () (T
&obj
, size_t = sizeof(T
))
197 { mFlips
.insert(new FlipRef
<T
>(obj
)); }
200 T
*operator () (T
* &addr
, size_t size
= sizeof(T
))
201 { mFlips
.insert(new FlipPtr
<T
>(addr
)); return addr
; }
204 void blob(T
* &addr
, size_t size
)
205 { mFlips
.insert(new FlipBlob
<T
>(addr
)); }
207 static const bool needsRelinking
= true;
208 static const bool needsSize
= true;
216 // A raw flip, conditioned on the client's flip state
222 secdebug("flippers", "raw flipping %s", Debug::typeName(addr
).c_str());
223 Flippers::flip(addr
);
228 void flips(T
*value
, T
** &addr
, T
** &base
)
230 *addr
= *base
= value
;
232 FlipWalker w
; // collector
233 walk(w
, value
); // collect all flippings needed
234 w
.doFlips(); // execute flips (flips value but leaves addr alone)
235 Flippers::flip(*base
); // flip base (so it arrives right side up)
240 #endif //_H_TRANSWALKERS