source: trunk/xcache/xc_sandbox.c @ 1434

Last change on this file since 1434 was 1434, checked in by moo, 13 months ago

fixed #329: compatbile with bcompiler

  • Property svn:eol-style set to native
File size: 13.6 KB
Line 
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
47typedef struct _xc_sandbox_t { /* sandbox {{{ */
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
79    struct _xc_sandbox_t *parent;
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    EG(function_table) = CG(function_table);
167
168    OG(class_table) = CG(class_table);
169    CG(class_table) = &TG(class_table);
170    EG(class_table) = CG(class_table);
171
172#ifdef ZEND_ENGINE_2_1
173    OG(auto_globals) = CG(auto_globals);
174    CG(auto_globals) = &TG(auto_globals);
175#endif
176
177    TG(included_files) = &EG(included_files);
178
179    zend_hash_init_ex(TG(included_files), 5, NULL, NULL, 0, 1);
180#ifdef HAVE_XCACHE_CONSTANT
181    h = OG(zend_constants);
182    zend_hash_init_ex(&TG(zend_constants),  20, NULL, (dtor_func_t) xc_free_zend_constant, h->persistent, h->bApplyProtection);
183    xc_copy_internal_zend_constants(&TG(zend_constants), &XG(internal_constant_table));
184    TG(internal_constant_tail) = TG(zend_constants).pListTail;
185#endif
186    h = OG(function_table);
187    zend_hash_init_ex(&TG(function_table), 128, NULL, ZEND_FUNCTION_DTOR, h->persistent, h->bApplyProtection);
188    {
189        zend_function tmp_func;
190        zend_hash_copy(&TG(function_table), &XG(internal_function_table), NULL, (void *) &tmp_func, sizeof(tmp_func));
191    }
192    TG(internal_function_tail) = TG(function_table).pListTail;
193
194    h = OG(class_table);
195    zend_hash_init_ex(&TG(class_table),     16, NULL, ZEND_CLASS_DTOR, h->persistent, h->bApplyProtection);
196#if 0 && TODO
197    {
198        xc_cest_t tmp_cest;
199        zend_hash_copy(&TG(class_table), &XG(internal_class_table), NULL, (void *) &tmp_cest, sizeof(tmp_cest));
200    }
201#endif
202    TG(internal_class_tail) = TG(class_table).pListTail;
203
204#ifdef ZEND_ENGINE_2_1
205    /* shallow copy, don't destruct */
206    h = OG(auto_globals);
207    zend_hash_init_ex(&TG(auto_globals),     8, NULL,           NULL, h->persistent, h->bApplyProtection);
208    {
209        zend_auto_global tmp_autoglobal;
210
211        zend_hash_copy(&TG(auto_globals), OG(auto_globals), NULL, (void *) &tmp_autoglobal, sizeof(tmp_autoglobal));
212        zend_hash_apply(&TG(auto_globals), (apply_func_t) xc_auto_global_arm TSRMLS_CC);
213    }
214#endif
215
216    sandbox->filename = filename;
217
218#ifdef XCACHE_ERROR_CACHING
219    sandbox->orig_user_error_handler_error_reporting = EG(user_error_handler_error_reporting);
220    EG(user_error_handler_error_reporting) = 0;
221
222    sandbox->compilererror_cnt  = 0;
223    sandbox->compilererror_size = 0;
224#endif
225
226#ifdef ZEND_COMPILE_IGNORE_INTERNAL_CLASSES
227    sandbox->orig_compiler_options = CG(compiler_options);
228    /* Using ZEND_COMPILE_IGNORE_INTERNAL_CLASSES for ZEND_FETCH_CLASS_RT_NS_CHECK
229     */
230    CG(compiler_options) |= ZEND_COMPILE_IGNORE_INTERNAL_CLASSES | ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION | ZEND_COMPILE_DELAYED_BINDING;
231#endif
232
233    sandbox->parent = XG(sandbox);
234    XG(sandbox) = (void *) sandbox;
235    XG(initial_compile_file_called) = 0;
236    return sandbox;
237}
238/* }}} */
239
240#ifndef ZEND_COMPILE_DELAYED_BINDING
241static void xc_early_binding_cb(zend_op *opline, int oplineno, void *data TSRMLS_DC) /* {{{ */
242{
243    xc_sandbox_t *sandbox = (xc_sandbox_t *) data;
244    xc_do_early_binding(CG(active_op_array), OG(class_table), oplineno TSRMLS_CC);
245}
246/* }}} */
247#endif
248static void xc_sandbox_install(xc_sandbox_t *sandbox TSRMLS_DC) /* {{{ */
249{
250    zend_uint i;
251    Bucket *b;
252
253#ifdef HAVE_XCACHE_CONSTANT
254    for (b = TG(zend_constants).pListHead; b != NULL && b != TG(internal_constant_tail); b = b->pListNext) {
255        zend_constant *c = (zend_constant*) b->pData;
256        xc_free_zend_constant(c);
257    }
258
259    b = TG(internal_constant_tail) ? TG(internal_constant_tail)->pListNext : TG(zend_constants).pListHead;
260    /* install constants */
261    while (b != NULL) {
262        zend_constant *c = (zend_constant*) b->pData;
263        xc_install_constant(sandbox->filename, c,
264                BUCKET_KEY_TYPE(b), ZSTR(BUCKET_KEY_S(b)), b->nKeyLength, b->h TSRMLS_CC);
265        b = b->pListNext;
266    }
267#endif
268
269    b = TG(internal_function_tail) ? TG(internal_function_tail)->pListNext : TG(function_table).pListHead;
270    /* install function */
271    while (b != NULL) {
272        zend_function *func = (zend_function*) b->pData;
273        xc_install_function(sandbox->filename, func,
274                BUCKET_KEY_TYPE(b), ZSTR(BUCKET_KEY_S(b)), b->nKeyLength, b->h TSRMLS_CC);
275        b = b->pListNext;
276    }
277
278    b = TG(internal_class_tail) ? TG(internal_class_tail)->pListNext : TG(class_table).pListHead;
279    /* install class */
280    while (b != NULL) {
281        xc_install_class(sandbox->filename, (xc_cest_t*) b->pData, -1,
282                BUCKET_KEY_TYPE(b), ZSTR(BUCKET_KEY_S(b)), b->nKeyLength, b->h TSRMLS_CC);
283        b = b->pListNext;
284    }
285
286#ifdef ZEND_ENGINE_2_1
287    /* trigger auto_globals jit */
288    for (b = TG(auto_globals).pListHead; b != NULL; b = b->pListNext) {
289        zend_auto_global *auto_global = (zend_auto_global *) b->pData;
290        /* check if actived */
291        if (auto_global->auto_global_callback && !auto_global->armed) {
292            zend_u_is_auto_global(BUCKET_KEY_TYPE(b), ZSTR(BUCKET_KEY_S(b)), auto_global->name_len TSRMLS_CC);
293        }
294    }
295#endif
296
297    /* CG(compiler_options) applies only if initial_compile_file_called */
298    if (XG(initial_compile_file_called)) {
299#ifdef ZEND_COMPILE_DELAYED_BINDING
300        zend_do_delayed_early_binding(CG(active_op_array) TSRMLS_CC);
301#else
302        xc_undo_pass_two(CG(active_op_array) TSRMLS_CC);
303        xc_foreach_early_binding_class(CG(active_op_array), xc_early_binding_cb, (void *) sandbox TSRMLS_CC);
304        xc_redo_pass_two(CG(active_op_array) TSRMLS_CC);
305#endif
306    }
307
308#ifdef XCACHE_ERROR_CACHING
309    /* restore trigger errors */
310    for (i = 0; i < sandbox->compilererror_cnt; i ++) {
311        xc_compilererror_t *error = &sandbox->compilererrors[i];
312        CG(zend_lineno) = error->lineno;
313        zend_error(error->type, "%s", error->error);
314    }
315    CG(zend_lineno) = 0;
316#endif
317
318    i = 1;
319    /* still needed because in zend_language_scanner.l, require()/include() check file_handle.handle.stream.handle */
320    zend_hash_add(&OG(included_files), sandbox->filename, strlen(sandbox->filename) + 1, (void *)&i, sizeof(int), NULL);
321}
322/* }}} */
323static void xc_sandbox_free(xc_sandbox_t *sandbox, zend_op_array *op_array TSRMLS_DC) /* {{{ */
324{
325    XG(sandbox) = sandbox->parent;
326#ifdef XCACHE_ERROR_CACHING
327    EG(user_error_handler_error_reporting) = sandbox->orig_user_error_handler_error_reporting;
328#endif
329
330    /* restore first first install function/class */
331#ifdef HAVE_XCACHE_CONSTANT
332    EG(zend_constants) = OG(zend_constants);
333#endif
334    CG(function_table) = OG(function_table);
335    EG(function_table) = CG(function_table);
336    CG(class_table)    = OG(class_table);
337    EG(class_table)    = CG(class_table);
338#ifdef ZEND_ENGINE_2_1
339    CG(auto_globals)   = OG(auto_globals);
340#endif
341
342    if (op_array) {
343        zend_op_array *old_active_op_array = CG(active_op_array);
344        CG(in_compilation)    = 1;
345        CG(compiled_filename) = ZEND_24(NOTHING, (char *)) sandbox->filename;
346        CG(zend_lineno)       = 0;
347
348        CG(active_op_array) = op_array;
349        xc_sandbox_install(sandbox TSRMLS_CC);
350        CG(active_op_array) = old_active_op_array;
351
352        CG(in_compilation)    = 0;
353        CG(compiled_filename) = NULL;
354
355        /* no free as it's installed */
356#ifdef HAVE_XCACHE_CONSTANT
357        TG(zend_constants).pDestructor = NULL;
358#endif
359        TG(function_table).pDestructor = NULL;
360        TG(class_table).pDestructor = NULL;
361    }
362
363    /* destroy all the tmp */
364#ifdef HAVE_XCACHE_CONSTANT
365    zend_hash_destroy(&TG(zend_constants));
366#endif
367    zend_hash_destroy(&TG(function_table));
368    zend_hash_destroy(&TG(class_table));
369#ifdef ZEND_ENGINE_2_1
370    zend_hash_destroy(&TG(auto_globals));
371#endif
372    zend_hash_destroy(TG(included_files));
373
374    /* restore orig here, as EG/CG holded tmp before */
375    memcpy(&EG(included_files), &OG(included_files), sizeof(EG(included_files)));
376
377#ifdef XCACHE_ERROR_CACHING
378    if (sandbox->compilererrors) {
379        zend_uint i;
380        for (i = 0; i < sandbox->compilererror_cnt; i ++) {
381            efree(sandbox->compilererrors[i].error);
382        }
383        efree(sandbox->compilererrors);
384    }
385#endif
386
387#ifdef ZEND_COMPILE_IGNORE_INTERNAL_CLASSES
388    CG(compiler_options) = sandbox->orig_compiler_options;
389#endif
390}
391/* }}} */
392zend_op_array *xc_sandbox(xc_sandboxed_func_t sandboxed_func, void *data, ZEND_24(NOTHING, const) char *filename TSRMLS_DC) /* {{{ */
393{
394    xc_sandbox_t sandbox;
395    zend_op_array *op_array = NULL;
396    zend_bool catched = 0;
397
398    memset(&sandbox, 0, sizeof(sandbox));
399    zend_try {
400        xc_sandbox_init(&sandbox, filename TSRMLS_CC);
401        op_array = sandboxed_func(data TSRMLS_CC);
402    } zend_catch {
403        catched = 1;
404    } zend_end_try();
405
406    xc_sandbox_free(&sandbox, op_array TSRMLS_CC);
407    if (catched) {
408        zend_bailout();
409    }
410    return op_array;
411}
412/* }}} */
413const Bucket *xc_sandbox_user_function_begin(TSRMLS_D) /* {{{ */
414{
415    xc_sandbox_t *sandbox = (xc_sandbox_t *) XG(sandbox);
416    assert(sandbox);
417    return TG(internal_function_tail) ? TG(internal_function_tail)->pListNext : TG(function_table).pListHead;
418}
419/* }}} */
420const Bucket *xc_sandbox_user_class_begin(TSRMLS_D) /* {{{ */
421{
422    xc_sandbox_t *sandbox = (xc_sandbox_t *) XG(sandbox);
423    assert(sandbox);
424    return TG(internal_class_tail) ? TG(internal_class_tail)->pListNext : TG(class_table).pListHead;
425}
426/* }}} */
427#ifdef XCACHE_ERROR_CACHING
428xc_compilererror_t *xc_sandbox_compilererrors(TSRMLS_D) /* {{{ */
429{
430    xc_sandbox_t *sandbox = (xc_sandbox_t *) XG(sandbox);
431    assert(sandbox);
432    return sandbox->compilererrors;
433}
434/* }}} */
435zend_uint xc_sandbox_compilererror_cnt(TSRMLS_D) /* {{{ */
436{
437    xc_sandbox_t *sandbox = (xc_sandbox_t *) XG(sandbox);
438    assert(sandbox);
439    return sandbox->compilererror_cnt;
440}
441/* }}} */
442#endif
443
444/* MINIT/MSHUTDOWN */
445int xc_sandbox_module_init(int module_number TSRMLS_DC) /* {{{ */
446{
447#ifdef XCACHE_ERROR_CACHING
448    old_zend_error_cb = zend_error_cb;
449    zend_error_cb = xc_sandbox_error_cb;
450#endif
451
452    return SUCCESS;
453}
454/* }}} */
455void xc_sandbox_module_shutdown() /* {{{ */
456{
457#ifdef XCACHE_ERROR_CACHING
458    if (zend_error_cb == xc_sandbox_error_cb) {
459        zend_error_cb = old_zend_error_cb;
460    }
461#endif
462}
463/* }}} */
Note: See TracBrowser for help on using the repository browser.