Line data Source code
1 : /**
2 : * The Lua allocator hook
3 : */
4 :
5 : #ifdef HAVE_CONFIG_H
6 : #include "config.h"
7 : #endif
8 :
9 : #include <lua.h>
10 : #include <lauxlib.h>
11 : #include <string.h>
12 : #include <limits.h>
13 :
14 : #include "php.h"
15 : #include "php_luasandbox.h"
16 :
17 : static inline int luasandbox_update_memory_accounting(php_luasandbox_alloc * obj,
18 : size_t osize, size_t nsize);
19 : static void *luasandbox_php_alloc(void *ud, void *ptr, size_t osize, size_t nsize);
20 :
21 126 : lua_State * luasandbox_alloc_new_state(php_luasandbox_alloc * alloc, php_luasandbox_obj * sandbox)
22 : {
23 : lua_State * L;
24 126 : L = lua_newstate(luasandbox_php_alloc, sandbox);
25 126 : return L;
26 : }
27 :
28 125 : void luasandbox_alloc_delete_state(php_luasandbox_alloc * alloc, lua_State * L)
29 : {
30 125 : lua_close(L);
31 125 : }
32 :
33 :
34 : /** {{{ luasandbox_update_memory_accounting
35 : *
36 : * Update memory usage statistics for the given memory allocation request.
37 : * Returns 1 if the allocation should be allowed, 0 if it should fail.
38 : */
39 298305 : static inline int luasandbox_update_memory_accounting(php_luasandbox_alloc * alloc,
40 : size_t osize, size_t nsize)
41 : {
42 298305 : if (nsize > osize && (nsize > alloc->memory_limit
43 115414 : || alloc->memory_usage + nsize > alloc->memory_limit))
44 : {
45 : // Memory limit exceeded
46 9 : return 0;
47 : }
48 :
49 298296 : if (osize > nsize && alloc->memory_usage + nsize < osize) {
50 : // Negative memory usage -- do not update
51 0 : return 1;
52 : }
53 :
54 298296 : alloc->memory_usage += nsize - osize;
55 298296 : if (alloc->memory_usage > alloc->peak_memory_usage) {
56 39041 : alloc->peak_memory_usage = alloc->memory_usage;
57 : }
58 298296 : return 1;
59 : }
60 : /* }}} */
61 :
62 : /** {{{ luasandbox_update_gc_pause
63 : * Scale the GC pause size so that collection will start before an OOM occurs (T349462)
64 : */
65 298296 : static inline void luasandbox_update_gc_pause(lua_State * L, php_luasandbox_alloc * alloc)
66 : {
67 298296 : size_t limit = alloc->memory_limit;
68 298296 : size_t usage = alloc->memory_usage;
69 :
70 : // Guard against overflow and division by zero
71 298296 : if (limit >= SIZE_MAX / 90 || usage == 0) {
72 264299 : return;
73 : }
74 33997 : size_t pause = limit * 90 / usage;
75 33997 : if (pause > 200) {
76 32899 : pause = 200;
77 : }
78 33997 : lua_gc(L, LUA_GCSETPAUSE, (int)pause);
79 : }
80 : /* }}} */
81 :
82 : /** {{{ luasandbox_php_alloc
83 : *
84 : * The Lua allocator function. Use PHP's request-local allocator as a backend.
85 : * Account for memory usage and deny the allocation request if the amount
86 : * allocated is above the user-specified limit.
87 : */
88 298305 : static void *luasandbox_php_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
89 : {
90 298305 : php_luasandbox_obj * obj = (php_luasandbox_obj*)ud;
91 : void * nptr;
92 298305 : obj->in_php ++;
93 298305 : if (!luasandbox_update_memory_accounting(&obj->alloc, osize, nsize)) {
94 9 : obj->in_php --;
95 9 : return NULL;
96 : }
97 :
98 298296 : luasandbox_update_gc_pause(obj->state, &obj->alloc);
99 :
100 298296 : if (nsize == 0) {
101 181483 : if (ptr) {
102 112524 : efree(ptr);
103 : }
104 181483 : nptr = NULL;
105 116813 : } else if (osize == 0) {
106 112760 : nptr = ecalloc(1, nsize);
107 : } else {
108 4053 : nptr = erealloc(ptr, nsize);
109 4053 : if (nsize > osize) {
110 2645 : memset(nptr + osize, 0, nsize - osize);
111 : }
112 : }
113 298295 : obj->in_php --;
114 298295 : return nptr;
115 : }
116 : /* }}} */
|