source: trunk/xcache/xc_sandbox.c @ 1178

Last change on this file since 1178 was 1178, checked in by moo, 2 years ago

improve compatibility with "the ionCube PHP Loader", Zend Optimizer. dont do early binding for cached opcode

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