source: trunk/xcache/xc_sandbox.c @ 1178

Last change on this file since 1178 was 1178, checked in by moo, 23 months 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
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
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;
[1178]232    XG(initial_compile_file_called) = 0;
[986]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
[1178]294    /* CG(compiler_options) applies only if initial_compile_file_called */
295    if (XG(initial_compile_file_called)) {
[986]296#ifdef ZEND_COMPILE_DELAYED_BINDING
[1178]297        zend_do_delayed_early_binding(CG(active_op_array) TSRMLS_CC);
[986]298#else
[1178]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);
[986]302#endif
[1178]303    }
[986]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}
[989]408/* }}} */
[986]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}
[989]415/* }}} */
[986]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}
[989]422/* }}} */
[986]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
[992]440/* MINIT/MSHUTDOWN */
441int xc_sandbox_module_init(int module_number TSRMLS_DC) /* {{{ */
[986]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/* }}} */
[992]451void xc_sandbox_module_shutdown() /* {{{ */
[986]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.