]> git.saurik.com Git - apple/securityd.git/blob - src/transwalkers.h
67b4cb6860161ce6d867ab5167a38fb1b77c3bd5
[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 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
13 * file.
14 *
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26
27 //
28 // transwalkers - server side transition data walking support
29 //
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.
33 //
34 #ifndef _H_TRANSWALKERS
35 #define _H_TRANSWALKERS
36
37 #include <security_cdsa_utilities/AuthorizationWalkers.h>
38 #include "flippers.h"
39 #include "server.h"
40 #include <security_cdsa_utilities/context.h>
41
42 using LowLevelMemoryUtilities::increment;
43 using LowLevelMemoryUtilities::difference;
44
45
46 //
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.
50 //
51 bool flipClient();
52
53
54 //
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.
60 //
61 class CheckingReconstituteWalker {
62 private:
63 void check(void *addr, size_t size)
64 {
65 if (addr < mBase || increment(addr, size) > mLimit)
66 CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER);
67 }
68
69 public:
70 CheckingReconstituteWalker(void *ptr, void *base, size_t size, bool flip);
71
72 template <class T>
73 void operator () (T &obj, size_t size = sizeof(T))
74 {
75 check(increment(&obj, -mOffset), size);
76 if (mFlip)
77 Flippers::flip(obj);
78 }
79
80 template <class T>
81 void operator () (T * &addr, size_t size = sizeof(T))
82 {
83 DEBUGWALK("checkreconst:ptr");
84 if (addr) {
85 // process the pointer
86 void *p = addr;
87 blob(p, size);
88 addr = reinterpret_cast<T *>(p);
89
90 // now flip the contents
91 if (mFlip)
92 Flippers::flip(*addr);
93 }
94 }
95
96 template <class T>
97 void blob(T * &addr, size_t size)
98 {
99 DEBUGWALK("checkreconst:blob");
100 if (addr) {
101 // flip the address (the pointer itself)
102 if (mFlip) {
103 secdebug("flippers", "flipping %s@%p", Debug::typeName(addr).c_str(), addr);
104 Flippers::flip(addr);
105 }
106
107 // check the address against the transmitted bounds
108 check(addr, size);
109
110 // relocate it
111 addr = increment<T>(addr, mOffset);
112 }
113 }
114
115 static const bool needsRelinking = true;
116 static const bool needsSize = false;
117
118 private:
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
123 };
124
125
126 //
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.
130 //
131 template <class T>
132 void relocate(T *obj, T *base, size_t size)
133 {
134 if (obj) {
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);
140 }
141 }
142
143
144 //
145 // Special handling for incoming CSSM contexts.
146 //
147 void relocate(Context &context, void *base, Context::Attr *attrs, uint32 attrSize);
148
149
150 //
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.
154 //
155 class FlipWalker {
156 private:
157 struct FlipBase {
158 virtual ~FlipBase() { }
159 virtual void flip() const = 0;
160 };
161
162 template <class T>
163 struct FlipRef : public FlipBase {
164 T &obj;
165 FlipRef(T &s) : obj(s) { }
166 void flip() const
167 { secdebug("outflip", "%p flip/ref %s@%p", this, Debug::typeName(obj).c_str(), &obj);
168 { Flippers::flip(obj); }
169 }
170 };
171
172 template <class T>
173 struct FlipPtr : public FlipBase {
174 T * &obj;
175 FlipPtr(T * &s) : obj(s) { }
176 void flip() const
177 { secdebug("outflip", "%p flip/ptr %s@%p(%p)", this, Debug::typeName(obj).c_str(), &obj, obj);
178 { Flippers::flip(*obj); Flippers::flip(obj); }
179 }
180 };
181
182 template <class T>
183 struct FlipBlob : public FlipBase {
184 T * &obj;
185 FlipBlob(T * &s) : obj(s) { }
186 void flip() const
187 { secdebug("outflip", "%p flip/blob %s@%p(%p)", this, Debug::typeName(obj).c_str(), &obj, obj);
188 { Flippers::flip(obj); }
189 }
190 };
191
192 struct Flipper {
193 FlipBase *impl;
194 Flipper(FlipBase *p) : impl(p) { }
195 bool operator < (const Flipper &other) const
196 { return impl < other.impl; }
197 };
198
199 public:
200 ~FlipWalker();
201 void doFlips(bool active = true);
202
203 template <class T>
204 void operator () (T &obj, size_t = sizeof(T))
205 { mFlips.insert(new FlipRef<T>(obj)); }
206
207 template <class T>
208 T *operator () (T * &addr, size_t size = sizeof(T))
209 { mFlips.insert(new FlipPtr<T>(addr)); return addr; }
210
211 template <class T>
212 void blob(T * &addr, size_t size)
213 { mFlips.insert(new FlipBlob<T>(addr)); }
214
215 static const bool needsRelinking = true;
216 static const bool needsSize = true;
217
218 private:
219 set<Flipper> mFlips;
220 };
221
222
223 //
224 // A raw flip, conditioned on the client's flip state
225 //
226 template <class T>
227 void flip(T &addr)
228 {
229 if (flipClient()) {
230 secdebug("flippers", "raw flipping %s", Debug::typeName(addr).c_str());
231 Flippers::flip(addr);
232 }
233 }
234
235 template <class T>
236 void flips(T *value, T ** &addr, T ** &base)
237 {
238 *addr = *base = value;
239 if (flipClient()) {
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)
244 }
245 }
246
247
248 #endif //_H_TRANSWALKERS