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