js/xpconnect/wrappers/FilteringWrapper.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:283246c86ee0
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "FilteringWrapper.h"
8 #include "AccessCheck.h"
9 #include "ChromeObjectWrapper.h"
10 #include "XrayWrapper.h"
11
12 #include "jsapi.h"
13
14 using namespace JS;
15 using namespace js;
16
17 namespace xpc {
18
19 template <typename Base, typename Policy>
20 FilteringWrapper<Base, Policy>::FilteringWrapper(unsigned flags) : Base(flags)
21 {
22 }
23
24 template <typename Base, typename Policy>
25 FilteringWrapper<Base, Policy>::~FilteringWrapper()
26 {
27 }
28
29 template <typename Policy>
30 static bool
31 Filter(JSContext *cx, HandleObject wrapper, AutoIdVector &props)
32 {
33 size_t w = 0;
34 RootedId id(cx);
35 for (size_t n = 0; n < props.length(); ++n) {
36 id = props[n];
37 if (Policy::check(cx, wrapper, id, Wrapper::GET))
38 props[w++] = id;
39 else if (JS_IsExceptionPending(cx))
40 return false;
41 }
42 props.resize(w);
43 return true;
44 }
45
46 template <typename Policy>
47 static bool
48 FilterSetter(JSContext *cx, JSObject *wrapper, jsid id, JS::MutableHandle<JSPropertyDescriptor> desc)
49 {
50 bool setAllowed = Policy::check(cx, wrapper, id, Wrapper::SET);
51 if (!setAllowed) {
52 if (JS_IsExceptionPending(cx))
53 return false;
54 desc.setSetter(nullptr);
55 }
56 return true;
57 }
58
59 template <typename Base, typename Policy>
60 bool
61 FilteringWrapper<Base, Policy>::getPropertyDescriptor(JSContext *cx, HandleObject wrapper,
62 HandleId id,
63 JS::MutableHandle<JSPropertyDescriptor> desc)
64 {
65 assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::GET | BaseProxyHandler::SET);
66 if (!Base::getPropertyDescriptor(cx, wrapper, id, desc))
67 return false;
68 return FilterSetter<Policy>(cx, wrapper, id, desc);
69 }
70
71 template <typename Base, typename Policy>
72 bool
73 FilteringWrapper<Base, Policy>::getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper,
74 HandleId id,
75 JS::MutableHandle<JSPropertyDescriptor> desc)
76 {
77 assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::GET | BaseProxyHandler::SET);
78 if (!Base::getOwnPropertyDescriptor(cx, wrapper, id, desc))
79 return false;
80 return FilterSetter<Policy>(cx, wrapper, id, desc);
81 }
82
83 template <typename Base, typename Policy>
84 bool
85 FilteringWrapper<Base, Policy>::getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
86 AutoIdVector &props)
87 {
88 assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
89 return Base::getOwnPropertyNames(cx, wrapper, props) &&
90 Filter<Policy>(cx, wrapper, props);
91 }
92
93 template <typename Base, typename Policy>
94 bool
95 FilteringWrapper<Base, Policy>::enumerate(JSContext *cx, HandleObject wrapper,
96 AutoIdVector &props)
97 {
98 assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
99 return Base::enumerate(cx, wrapper, props) &&
100 Filter<Policy>(cx, wrapper, props);
101 }
102
103 template <typename Base, typename Policy>
104 bool
105 FilteringWrapper<Base, Policy>::keys(JSContext *cx, HandleObject wrapper,
106 AutoIdVector &props)
107 {
108 assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
109 return Base::keys(cx, wrapper, props) &&
110 Filter<Policy>(cx, wrapper, props);
111 }
112
113 template <typename Base, typename Policy>
114 bool
115 FilteringWrapper<Base, Policy>::iterate(JSContext *cx, HandleObject wrapper,
116 unsigned flags, MutableHandleValue vp)
117 {
118 assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
119 // We refuse to trigger the iterator hook across chrome wrappers because
120 // we don't know how to censor custom iterator objects. Instead we trigger
121 // the default proxy iterate trap, which will ask enumerate() for the list
122 // of (censored) ids.
123 return js::BaseProxyHandler::iterate(cx, wrapper, flags, vp);
124 }
125
126 template <typename Base, typename Policy>
127 bool
128 FilteringWrapper<Base, Policy>::nativeCall(JSContext *cx, JS::IsAcceptableThis test,
129 JS::NativeImpl impl, JS::CallArgs args)
130 {
131 if (Policy::allowNativeCall(cx, test, impl))
132 return Base::Permissive::nativeCall(cx, test, impl, args);
133 return Base::Restrictive::nativeCall(cx, test, impl, args);
134 }
135
136 template <typename Base, typename Policy>
137 bool
138 FilteringWrapper<Base, Policy>::defaultValue(JSContext *cx, HandleObject obj,
139 JSType hint, MutableHandleValue vp)
140 {
141 return Base::defaultValue(cx, obj, hint, vp);
142 }
143
144 // With our entirely-opaque wrapper, the DefaultValue algorithm throws,
145 // causing spurious exceptions. Manually implement something benign.
146 template<>
147 bool
148 FilteringWrapper<CrossCompartmentSecurityWrapper, GentlyOpaque>
149 ::defaultValue(JSContext *cx, HandleObject obj,
150 JSType hint, MutableHandleValue vp)
151 {
152 JSString *str = JS_NewStringCopyZ(cx, "[Opaque]");
153 if (!str)
154 return false;
155 vp.set(JS::StringValue(str));
156 return true;
157 }
158
159
160 template <typename Base, typename Policy>
161 bool
162 FilteringWrapper<Base, Policy>::enter(JSContext *cx, HandleObject wrapper,
163 HandleId id, Wrapper::Action act, bool *bp)
164 {
165 // This is a super ugly hacky to get around Xray Resolve wonkiness.
166 //
167 // Basically, XPCWN Xrays sometimes call into the Resolve hook of the
168 // scriptable helper, and pass the wrapper itself as the object upon which
169 // the resolve is happening. Then, special handling happens in
170 // XrayWrapper::defineProperty to detect the resolve and redefine the
171 // property on the holder. Really, we should just pass the holder itself to
172 // NewResolve, but there's too much code in nsDOMClassInfo that assumes this
173 // isn't the case (in particular, code expects to be able to look up
174 // properties on the object, which doesn't work for the holder). Given that
175 // these hooks are going away eventually with the new DOM bindings, let's
176 // just hack around this for now.
177 if (XrayUtils::IsXrayResolving(cx, wrapper, id)) {
178 *bp = true;
179 return true;
180 }
181 if (!Policy::check(cx, wrapper, id, act)) {
182 *bp = JS_IsExceptionPending(cx) ? false : Policy::deny(act, id);
183 return false;
184 }
185 *bp = true;
186 return true;
187 }
188
189 #define XOW FilteringWrapper<SecurityXrayXPCWN, CrossOriginAccessiblePropertiesOnly>
190 #define DXOW FilteringWrapper<SecurityXrayDOM, CrossOriginAccessiblePropertiesOnly>
191 #define NNXOW FilteringWrapper<CrossCompartmentSecurityWrapper, Opaque>
192 #define NNXOWC FilteringWrapper<CrossCompartmentSecurityWrapper, OpaqueWithCall>
193 #define GO FilteringWrapper<CrossCompartmentSecurityWrapper, GentlyOpaque>
194 template<> XOW XOW::singleton(0);
195 template<> DXOW DXOW::singleton(0);
196 template<> NNXOW NNXOW::singleton(0);
197 template<> NNXOWC NNXOWC::singleton(0);
198
199 template<> GO GO::singleton(0);
200
201 template class XOW;
202 template class DXOW;
203 template class NNXOW;
204 template class NNXOWC;
205 template class ChromeObjectWrapperBase;
206 template class GO;
207 }

mercurial