source: trunk/xcache/xc_sandbox.c @ 1275

Last change on this file since 1275 was 1275, checked in by moo, 16 months ago

disassembler: fixes crash with nested sandbox (since 3.0)

  • Property svn:eol-style set to native
File size: 13.5 KB
RevLine 
[986]1
2#include "xcache.h"
3#include "xc_sandbox.h"
4#include "xc_utils.h"
5#include "xcache_globals.h"
6
7/* utilities used by sandbox */
8static void (*old_zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args) = NULL;
9static void call_old_zend_error_cb(int type, const char *error_filename, const uint error_lineno, const char *format, ...) /* {{{ */
10{
11    va_list args;
12    va_start(args, format);
13    old_zend_error_cb(type, error_filename, error_lineno, format, args);
14}
15/* }}} */
16#ifdef ZEND_ENGINE_2_1
17static zend_bool xc_auto_global_callback(ZEND_24(NOTHING, const) char *name, uint name_len TSRMLS_DC) /* {{{ */
18{
19    return 0;
20}
21/* }}} */
22static int xc_auto_global_arm(zend_auto_global *auto_global TSRMLS_DC) /* {{{ */
23{
24    if (auto_global->auto_global_callback) {
25        auto_global->armed = 1;
26        auto_global->auto_global_callback = xc_auto_global_callback;
27    }
28    else {
29        auto_global->armed = 0;
30    }
31    return ZEND_HASH_APPLY_KEEP;
32}
33/* }}} */
34#endif
35
36#ifdef HAVE_XCACHE_CONSTANT
37static void xc_free_zend_constant(zend_constant *c) /* {{{ */
38{
39    if (!(c->flags & CONST_PERSISTENT)) {
40        zval_dtor(&c->value);
41    }
42    free(ZSTR_V(c->name));
43}
44/* }}} */
45#endif
46
[1275]47typedef struct _xc_sandbox_t { /* sandbox {{{ */
[986]48    ZEND_24(NOTHING, const) char *filename;
49
50    HashTable orig_included_files;
51    HashTable *tmp_included_files;
52
53#ifdef HAVE_XCACHE_CONSTANT
54    HashTable *orig_zend_constants;
55    HashTable tmp_zend_constants;
56#endif
57    HashTable *orig_function_table;
58    HashTable *orig_class_table;
59    HashTable *orig_auto_globals;
60    HashTable tmp_function_table;
61    HashTable tmp_class_table;
62    HashTable tmp_auto_globals;
63#ifdef HAVE_XCACHE_CONSTANT
64    Bucket    *tmp_internal_constant_tail;
65#endif
66    Bucket    *tmp_internal_function_tail;
67    Bucket    *tmp_internal_class_tail;
68
69#ifdef XCACHE_ERROR_CACHING
70    int orig_user_error_handler_error_reporting;
71    zend_uint compilererror_cnt;
72    zend_uint compilererror_size;
73    xc_compilererror_t *compilererrors;
74#endif
75
76#ifdef ZEND_COMPILE_IGNORE_INTERNAL_CLASSES
77    zend_uint orig_compiler_options;
78#endif
[1275]79    struct _xc_sandbox_t *parent;
[986]80} xc_sandbox_t;
81
82#undef TG
83#undef OG
84#define TG(x) (sandbox->tmp_##x)
85#define OG(x) (sandbox->orig_##x)
86/* }}} */
87#ifdef XCACHE_ERROR_CACHING
88static void xc_sandbox_error_cb(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args) /* {{{ */
89{
90    xc_compilererror_t *compilererror;
91    xc_sandbox_t *sandbox;
92    TSRMLS_FETCH();
93
94    sandbox = (xc_sandbox_t *) XG(sandbox);
95    if (!sandbox) {
96        old_zend_error_cb(type, error_filename, error_lineno, format, args);
97        return;
98    }
99
100    switch (type) {
101#ifdef E_STRICT
102    case E_STRICT:
103#endif
104#ifdef E_DEPRECATED
105    case E_DEPRECATED:
106#endif
107        if (sandbox->compilererror_cnt <= sandbox->compilererror_size) {
108            if (sandbox->compilererror_size) {
109                sandbox->compilererror_size += 16;
110                sandbox->compilererrors = erealloc(sandbox->compilererrors, sandbox->compilererror_size * sizeof(sandbox->compilererrors));
111            }
112            else {
113                sandbox->compilererror_size = 16;
114                sandbox->compilererrors = emalloc(sandbox->compilererror_size * sizeof(sandbox->compilererrors));
115            }
116        }
117        compilererror = &sandbox->compilererrors[sandbox->compilererror_cnt++];
118        compilererror->type = type;
119        compilererror->lineno = error_lineno;
120        compilererror->error_len = vspprintf(&compilererror->error, 0, format, args);
121        break;
122
123    default: {
124        /* give up, and user handler is not supported in this case */
125        zend_uint i;
126        zend_uint old_lineno = CG(zend_lineno);
127
128        for (i = 0; i < sandbox->compilererror_cnt; i ++) {
129            compilererror = &sandbox->compilererrors[i];
130            CG(zend_lineno) = compilererror->lineno;
131            call_old_zend_error_cb(compilererror->type, error_filename, error_lineno, "%s", compilererror->error);
132            efree(compilererror->error);
133        }
134        if (sandbox->compilererrors) {
135            efree(sandbox->compilererrors);
136            sandbox->compilererrors = NULL;
137        }
138        sandbox->compilererror_cnt  = 0;
139        sandbox->compilererror_size = 0;
140
141        CG(zend_lineno) = old_lineno;
142        old_zend_error_cb(type, error_filename, error_lineno, format, args);
143        break;
144    }
145    }
146}
147/* }}} */
148#endif
149
150static xc_sandbox_t *xc_sandbox_init(xc_sandbox_t *sandbox, ZEND_24(NOTHING, const) char *filename TSRMLS_DC) /* {{{ */
151{
152    HashTable *h;
153
154    assert(sandbox);
155    memset(sandbox, 0, sizeof(sandbox[0]));
156
157    memcpy(&OG(included_files), &EG(included_files), sizeof(EG(included_files)));
158
159#ifdef HAVE_XCACHE_CONSTANT
160    OG(zend_constants) = EG(zend_constants);
161    EG(zend_constants) = &TG(zend_constants);
162#endif
163
164    OG(function_table) = CG(function_table);
165    CG(function_table) = &TG(function_table);
166
167    OG(class_table) = CG(class_table);
168    CG(class_table) = &TG(class_table);
169    EG(class_table) = CG(class_table);
170
171#ifdef ZEND_ENGINE_2_1
172    OG(auto_globals) = CG(auto_globals);
173    CG(auto_globals) = &TG(auto_globals);
174#endif
175
176    TG(included_files) = &EG(included_files);
177
178    zend_hash_init_ex(TG(included_files), 5, NULL, NULL, 0, 1);
179#ifdef HAVE_XCACHE_CONSTANT
180    h = OG(zend_constants);
181    zend_hash_init_ex(&TG(zend_constants),  20, NULL, (dtor_func_t) xc_free_zend_constant, h->persistent, h->bApplyProtection);
182    xc_copy_internal_zend_constants(&TG(zend_constants), &XG(internal_constant_table));
183    TG(internal_constant_tail) = TG(zend_constants).pListTail;
184#endif
185    h = OG(function_table);
186    zend_hash_init_ex(&TG(function_table), 128, NULL, ZEND_FUNCTION_DTOR, h->persistent, h->bApplyProtection);
187    {
188        zend_function tmp_func;
189        zend_hash_copy(&TG(function_table), &XG(internal_function_table), NULL, (void *) &tmp_func, sizeof(tmp_func));
190    }
191    TG(internal_function_tail) = TG(function_table).pListTail;
192
193    h = OG(class_table);
194    zend_hash_init_ex(&TG(class_table),     16, NULL, ZEND_CLASS_DTOR, h->persistent, h->bApplyProtection);
195#if 0 && TODO
196    {
197        xc_cest_t tmp_cest;
198        zend_hash_copy(&TG(class_table), &XG(internal_class_table), NULL, (void *) &tmp_cest, sizeof(tmp_cest));
199    }
200#endif
201    TG(internal_class_tail) = TG(class_table).pListTail;
202
203#ifdef ZEND_ENGINE_2_1
204    /* shallow copy, don't destruct */
205    h = OG(auto_globals);
206    zend_hash_init_ex(&TG(auto_globals),     8, NULL,           NULL, h->persistent, h->bApplyProtection);
207    {
208        zend_auto_global tmp_autoglobal;
209
210        zend_hash_copy(&TG(auto_globals), OG(auto_globals), NULL, (void *) &tmp_autoglobal, sizeof(tmp_autoglobal));
211        zend_hash_apply(&TG(auto_globals), (apply_func_t) xc_auto_global_arm TSRMLS_CC);
212    }
213#endif
214
215    sandbox->filename = filename;
216
217#ifdef XCACHE_ERROR_CACHING
218    sandbox->orig_user_error_handler_error_reporting = EG(user_error_handler_error_reporting);
219    EG(user_error_handler_error_reporting) = 0;
220
221    sandbox->compilererror_cnt  = 0;
222    sandbox->compilererror_size = 0;
223#endif
224
225#ifdef ZEND_COMPILE_IGNORE_INTERNAL_CLASSES
226    sandbox->orig_compiler_options = CG(compiler_options);
227    /* Using ZEND_COMPILE_IGNORE_INTERNAL_CLASSES for ZEND_FETCH_CLASS_RT_NS_CHECK
228     */
229    CG(compiler_options) |= ZEND_COMPILE_IGNORE_INTERNAL_CLASSES | ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION | ZEND_COMPILE_DELAYED_BINDING;
230#endif
231
[1275]232    sandbox->parent = XG(sandbox);
[986]233    XG(sandbox) = (void *) sandbox;
[1178]234    XG(initial_compile_file_called) = 0;
[986]235    return sandbox;
236}
237/* }}} */
238
239#ifndef ZEND_COMPILE_DELAYED_BINDING
240static void xc_early_binding_cb(zend_op *opline, int oplineno, void *data TSRMLS_DC) /* {{{ */
241{
242    xc_sandbox_t *sandbox = (xc_sandbox_t *) data;
243    xc_do_early_binding(CG(active_op_array), OG(class_table), oplineno TSRMLS_CC);
244}
245/* }}} */
246#endif
247static void xc_sandbox_install(xc_sandbox_t *sandbox TSRMLS_DC) /* {{{ */
248{
249    zend_uint i;
250    Bucket *b;
251
252#ifdef HAVE_XCACHE_CONSTANT
253    for (b = TG(zend_constants).pListHead; b != NULL && b != TG(internal_constant_tail); b = b->pListNext) {
254        zend_constant *c = (zend_constant*) b->pData;
255        xc_free_zend_constant(c);
256    }
257
258    b = TG(internal_constant_tail) ? TG(internal_constant_tail)->pListNext : TG(zend_constants).pListHead;
259    /* install constants */
260    while (b != NULL) {
261        zend_constant *c = (zend_constant*) b->pData;
262        xc_install_constant(sandbox->filename, c,
263                BUCKET_KEY_TYPE(b), ZSTR(BUCKET_KEY_S(b)), b->nKeyLength, b->h TSRMLS_CC);
264        b = b->pListNext;
265    }
266#endif
267
268    b = TG(internal_function_tail) ? TG(internal_function_tail)->pListNext : TG(function_table).pListHead;
269    /* install function */
270    while (b != NULL) {
271        zend_function *func = (zend_function*) b->pData;
272        xc_install_function(sandbox->filename, func,
273                BUCKET_KEY_TYPE(b), ZSTR(BUCKET_KEY_S(b)), b->nKeyLength, b->h TSRMLS_CC);
274        b = b->pListNext;
275    }
276
277    b = TG(internal_class_tail) ? TG(internal_class_tail)->pListNext : TG(class_table).pListHead;
278    /* install class */
279    while (b != NULL) {
280        xc_install_class(sandbox->filename, (xc_cest_t*) b->pData, -1,
281                BUCKET_KEY_TYPE(b), ZSTR(BUCKET_KEY_S(b)), b->nKeyLength, b->h TSRMLS_CC);
282        b = b->pListNext;
283    }
284
285#ifdef ZEND_ENGINE_2_1
286    /* trigger auto_globals jit */
287    for (b = TG(auto_globals).pListHead; b != NULL; b = b->pListNext) {
288        zend_auto_global *auto_global = (zend_auto_global *) b->pData;
289        /* check if actived */
290        if (auto_global->auto_global_callback && !auto_global->armed) {
291            zend_u_is_auto_global(BUCKET_KEY_TYPE(b), ZSTR(BUCKET_KEY_S(b)), auto_global->name_len TSRMLS_CC);
292        }
293    }
294#endif
295
[1178]296    /* CG(compiler_options) applies only if initial_compile_file_called */
297    if (XG(initial_compile_file_called)) {
[986]298#ifdef ZEND_COMPILE_DELAYED_BINDING
[1178]299        zend_do_delayed_early_binding(CG(active_op_array) TSRMLS_CC);
[986]300#else
[1178]301        xc_undo_pass_two(CG(active_op_array) TSRMLS_CC);
302        xc_foreach_early_binding_class(CG(active_op_array), xc_early_binding_cb, (void *) sandbox TSRMLS_CC);
303        xc_redo_pass_two(CG(active_op_array) TSRMLS_CC);
[986]304#endif
[1178]305    }
[986]306
307#ifdef XCACHE_ERROR_CACHING
308    /* restore trigger errors */
309    for (i = 0; i < sandbox->compilererror_cnt; i ++) {
310        xc_compilererror_t *error = &sandbox->compilererrors[i];
311        CG(zend_lineno) = error->lineno;
312        zend_error(error->type, "%s", error->error);
313    }
314    CG(zend_lineno) = 0;
315#endif
316
317    i = 1;
318    /* still needed because in zend_language_scanner.l, require()/include() check file_handle.handle.stream.handle */
319    zend_hash_add(&OG(included_files), sandbox->filename, strlen(sandbox->filename) + 1, (void *)&i, sizeof(int), NULL);
320}
321/* }}} */
322static void xc_sandbox_free(xc_sandbox_t *sandbox, zend_op_array *op_array TSRMLS_DC) /* {{{ */
323{
[1275]324    XG(sandbox) = sandbox->parent;
[986]325#ifdef XCACHE_ERROR_CACHING
326    EG(user_error_handler_error_reporting) = sandbox->orig_user_error_handler_error_reporting;
327#endif
328
329    /* restore first first install function/class */
330#ifdef HAVE_XCACHE_CONSTANT
331    EG(zend_constants) = OG(zend_constants);
332#endif
333    CG(function_table) = OG(function_table);
334    CG(class_table)    = OG(class_table);
335    EG(class_table)    = CG(class_table);
336#ifdef ZEND_ENGINE_2_1
337    CG(auto_globals)   = OG(auto_globals);
338#endif
339
340    if (op_array) {
341        zend_op_array *old_active_op_array = CG(active_op_array);
342        CG(in_compilation)    = 1;
343        CG(compiled_filename) = ZEND_24(NOTHING, (char *)) sandbox->filename;
344        CG(zend_lineno)       = 0;
345
346        CG(active_op_array) = op_array;
347        xc_sandbox_install(sandbox TSRMLS_CC);
348        CG(active_op_array) = old_active_op_array;
349
350        CG(in_compilation)    = 0;
351        CG(compiled_filename) = NULL;
352
353        /* no free as it's installed */
354#ifdef HAVE_XCACHE_CONSTANT
355        TG(zend_constants).pDestructor = NULL;
356#endif
357        TG(function_table).pDestructor = NULL;
358        TG(class_table).pDestructor = NULL;
359    }
360
361    /* destroy all the tmp */
362#ifdef HAVE_XCACHE_CONSTANT
363    zend_hash_destroy(&TG(zend_constants));
364#endif
365    zend_hash_destroy(&TG(function_table));
366    zend_hash_destroy(&TG(class_table));
367#ifdef ZEND_ENGINE_2_1
368    zend_hash_destroy(&TG(auto_globals));
369#endif
370    zend_hash_destroy(TG(included_files));
371
372    /* restore orig here, as EG/CG holded tmp before */
373    memcpy(&EG(included_files), &OG(included_files), sizeof(EG(included_files)));
374
375#ifdef XCACHE_ERROR_CACHING
376    if (sandbox->compilererrors) {
377        zend_uint i;
378        for (i = 0; i < sandbox->compilererror_cnt; i ++) {
379            efree(sandbox->compilererrors[i].error);
380        }
381        efree(sandbox->compilererrors);
382    }
383#endif
384
385#ifdef ZEND_COMPILE_IGNORE_INTERNAL_CLASSES
386    CG(compiler_options) = sandbox->orig_compiler_options;
387#endif
388}
389/* }}} */
390zend_op_array *xc_sandbox(xc_sandboxed_func_t sandboxed_func, void *data, ZEND_24(NOTHING, const) char *filename TSRMLS_DC) /* {{{ */
391{
392    xc_sandbox_t sandbox;
393    zend_op_array *op_array = NULL;
394    zend_bool catched = 0;
395
396    memset(&sandbox, 0, sizeof(sandbox));
397    zend_try {
398        xc_sandbox_init(&sandbox, filename TSRMLS_CC);
399        op_array = sandboxed_func(data TSRMLS_CC);
400    } zend_catch {
401        catched = 1;
402    } zend_end_try();
403
404    xc_sandbox_free(&sandbox, op_array TSRMLS_CC);
405    if (catched) {
406        zend_bailout();
407    }
408    return op_array;
409}
[989]410/* }}} */
[986]411const Bucket *xc_sandbox_user_function_begin(TSRMLS_D) /* {{{ */
412{
413    xc_sandbox_t *sandbox = (xc_sandbox_t *) XG(sandbox);
414    assert(sandbox);
415    return TG(internal_function_tail) ? TG(internal_function_tail)->pListNext : TG(function_table).pListHead;
416}
[989]417/* }}} */
[986]418const Bucket *xc_sandbox_user_class_begin(TSRMLS_D) /* {{{ */
419{
420    xc_sandbox_t *sandbox = (xc_sandbox_t *) XG(sandbox);
421    assert(sandbox);
422    return TG(internal_class_tail) ? TG(internal_class_tail)->pListNext : TG(class_table).pListHead;
423}
[989]424/* }}} */
[986]425#ifdef XCACHE_ERROR_CACHING
426xc_compilererror_t *xc_sandbox_compilererrors(TSRMLS_D) /* {{{ */
427{
428    xc_sandbox_t *sandbox = (xc_sandbox_t *) XG(sandbox);
429    assert(sandbox);
430    return sandbox->compilererrors;
431}
432/* }}} */
433zend_uint xc_sandbox_compilererror_cnt(TSRMLS_D) /* {{{ */
434{
435    xc_sandbox_t *sandbox = (xc_sandbox_t *) XG(sandbox);
436    assert(sandbox);
437    return sandbox->compilererror_cnt;
438}
439/* }}} */
440#endif
441
[992]442/* MINIT/MSHUTDOWN */
443int xc_sandbox_module_init(int module_number TSRMLS_DC) /* {{{ */
[986]444{
445#ifdef XCACHE_ERROR_CACHING
446    old_zend_error_cb = zend_error_cb;
447    zend_error_cb = xc_sandbox_error_cb;
448#endif
449
450    return SUCCESS;
451}
452/* }}} */
[992]453void xc_sandbox_module_shutdown() /* {{{ */
[986]454{
455#ifdef XCACHE_ERROR_CACHING
456    if (zend_error_cb == xc_sandbox_error_cb) {
457        zend_error_cb = old_zend_error_cb;
458    }
459#endif
460}
461/* }}} */
Note: See TracBrowser for help on using the repository browser.