l-sandbox.lua /size: 9604 b    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
l-sandbox
'
]
=
{
2
version
=
1
.
001
,
3
comment
=
"
companion to luat-lib.mkiv
"
,
4
author
=
"
Hans Hagen, PRAGMA-ADE, Hasselt NL
"
,
5
copyright
=
"
PRAGMA ADE / ConTeXt Development Team
"
,
6
license
=
"
see context related readme files
"
7
}
8 9
-- We use string instead of function variables, so 'io.open' instead of io.open. That
10
-- way we can still intercept repetetive overloads. One complication is that when we use
11
-- sandboxed functions in helpers in the sanbox checkers, we can get a recursion loop
12
-- so for that reason we need to keep originals around till we enable the sandbox.
13 14
-- if sandbox then return end
15 16
local
global
=
_G
17
local
next
=
next
18
local
unpack
=
unpack
or
table
.
unpack
19
local
type
=
type
20
local
tprint
=
texio
and
texio
.
write_nl
or
print
21
local
tostring
=
tostring
22
local
format
=
string
.
format
-- no formatters yet
23
local
concat
=
table
.
concat
24
local
sort
=
table
.
sort
25
local
gmatch
=
string
.
gmatch
26
local
gsub
=
string
.
gsub
27
local
requiem
=
require
28 29
sandbox
=
{
}
30
local
sandboxed
=
false
31
local
overloads
=
{
}
32
local
skiploads
=
{
}
33
local
initializers
=
{
}
34
local
finalizers
=
{
}
35
local
originals
=
{
}
36
local
comments
=
{
}
37
local
trace
=
false
38
local
logger
=
false
39
local
blocked
=
{
}
40 41
-- this comes real early, so that we can still alias
42 43
local
function
report
(
...
)
44
tprint
(
"
sandbox !
"
.
.
format
(
...
)
)
-- poor mans tracer
45
end
46 47
sandbox
.
report
=
report
48 49
function
sandbox
.
setreporter
(
r
)
50
report
=
r
51
sandbox
.
report
=
r
52
end
53 54
function
sandbox
.
settrace
(
v
)
55
trace
=
v
56
end
57 58
function
sandbox
.
setlogger
(
l
)
59
logger
=
type
(
l
)
=
=
"
function
"
and
l
or
false
60
end
61 62
local
function
register
(
func
,
overload
,
comment
)
63
if
type
(
func
)
=
=
"
function
"
then
64
if
type
(
overload
)
=
=
"
string
"
then
65
comment
=
overload
66
overload
=
nil
67
end
68
local
function
f
(
...
)
69
if
sandboxed
then
70
local
overload
=
overloads
[
f
]
71
if
overload
then
72
if
logger
then
73
local
result
=
{
overload
(
func
,
...
)
}
74
logger
{
75
comment
=
comments
[
f
]
or
tostring
(
f
)
,
76
arguments
=
{
...
}
,
77
result
=
result
[
1
]
and
true
or
false
,
78
}
79
return
unpack
(
result
)
80
else
81
return
overload
(
func
,
...
)
82
end
83
else
84
-- ignored, maybe message
85
end
86
else
87
return
func
(
...
)
88
end
89
end
90
if
comment
then
91
comments
[
f
]
=
comment
92
if
trace
then
93
report
(
"
registering function: %s
"
,
comment
)
94
end
95
end
96
overloads
[
f
]
=
overload
or
false
97
originals
[
f
]
=
func
98
return
f
99
end
100
end
101 102
local
function
redefine
(
func
,
comment
)
103
if
type
(
func
)
=
=
"
function
"
then
104
skiploads
[
func
]
=
comment
or
comments
[
func
]
or
"
unknown
"
105
if
overloads
[
func
]
=
=
false
then
106
overloads
[
func
]
=
nil
-- not initialized anyway
107
end
108
end
109
end
110 111
sandbox
.
register
=
register
112
sandbox
.
redefine
=
redefine
113 114
function
sandbox
.
original
(
func
)
115
return
originals
and
originals
[
func
]
or
func
116
end
117 118
function
sandbox
.
overload
(
func
,
overload
,
comment
)
119
comment
=
comment
or
comments
[
func
]
or
"
?
"
120
if
type
(
func
)
~
=
"
function
"
then
121
if
trace
then
122
report
(
"
overloading unknown function: %s
"
,
comment
)
123
end
124
elseif
type
(
overload
)
~
=
"
function
"
then
125
if
trace
then
126
report
(
"
overloading function with bad overload: %s
"
,
comment
)
127
end
128
elseif
overloads
[
func
]
=
=
nil
then
129
if
trace
then
130
report
(
"
function is not registered: %s
"
,
comment
)
131
end
132
elseif
skiploads
[
func
]
then
133
if
trace
then
134
report
(
"
function is not skipped: %s
"
,
comment
)
135
end
136
else
137
if
trace
then
138
report
(
"
overloading function: %s
"
,
comment
)
139
end
140
overloads
[
func
]
=
overload
141
end
142
return
func
143
end
144 145
local
function
whatever
(
specification
,
what
,
target
)
146
if
type
(
specification
)
~
=
"
table
"
then
147
report
(
"
%s needs a specification
"
,
what
)
148
elseif
type
(
specification
.
category
)
~
=
"
string
"
or
type
(
specification
.
action
)
~
=
"
function
"
then
149
report
(
"
%s needs a category and action
"
,
what
)
150
elseif
not
sandboxed
then
151
target
[
#
target
+
1
]
=
specification
152
elseif
trace
then
153
report
(
"
already enabled, discarding %s
"
,
what
)
154
end
155
end
156 157
function
sandbox
.
initializer
(
specification
)
158
whatever
(
specification
,
"
initializer
"
,
initializers
)
159
end
160 161
function
sandbox
.
finalizer
(
specification
)
162
whatever
(
specification
,
"
finalizer
"
,
finalizers
)
163
end
164 165
function
require
(
name
)
166
local
n
=
gsub
(
name
,
"
^.*[\\/]
"
,
"
"
)
167
local
n
=
gsub
(
n
,
"
[%.].*$
"
,
"
"
)
168
local
b
=
blocked
[
n
]
169
if
b
=
=
false
then
170
return
nil
-- e.g. ffi
171
elseif
b
then
172
if
trace
then
173
report
(
"
using blocked: %s
"
,
n
)
174
end
175
return
b
176
else
177
if
trace
then
178
report
(
"
requiring: %s
"
,
name
)
179
end
180
return
requiem
(
name
)
181
end
182
end
183 184
function
blockrequire
(
name
,
lib
)
185
if
trace
then
186
report
(
"
preventing reload of: %s
"
,
name
)
187
end
188
blocked
[
name
]
=
lib
or
_G
[
name
]
or
false
189
end
190 191
function
sandbox
.
enable
(
)
192
if
not
sandboxed
then
193
debug
=
{
194
traceback
=
debug
.
traceback
,
195
}
196
for
i
=
1
,
#
initializers
do
197
initializers
[
i
]
.
action
(
)
198
end
199
for
i
=
1
,
#
finalizers
do
200
finalizers
[
i
]
.
action
(
)
201
end
202
local
nnot
=
0
203
local
nyes
=
0
204
local
cnot
=
{
}
205
local
cyes
=
{
}
206
local
skip
=
{
}
207
for
k
,
v
in
next
,
overloads
do
208
local
c
=
comments
[
k
]
209
if
v
then
210
if
c
then
211
cyes
[
#
cyes
+
1
]
=
c
212
else
-- if not skiploads[k] then
213
nyes
=
nyes
+
1
214
end
215
else
216
if
c
then
217
cnot
[
#
cnot
+
1
]
=
c
218
else
-- if not skiploads[k] then
219
nnot
=
nnot
+
1
220
end
221
end
222
end
223
for
k
,
v
in
next
,
skiploads
do
224
skip
[
#
skip
+
1
]
=
v
225
end
226
if
#
cyes
>
0
then
227
sort
(
cyes
)
228
report
(
"
overloaded known: %s
"
,
concat
(
cyes
,
"
|
"
)
)
229
end
230
if
nyes
>
0
then
231
report
(
"
overloaded unknown: %s
"
,
nyes
)
232
end
233
if
#
cnot
>
0
then
234
sort
(
cnot
)
235
report
(
"
not overloaded known: %s
"
,
concat
(
cnot
,
"
|
"
)
)
236
end
237
if
nnot
>
0
then
238
report
(
"
not overloaded unknown: %s
"
,
nnot
)
239
end
240
if
#
skip
>
0
then
241
sort
(
skip
)
242
report
(
"
not overloaded redefined: %s
"
,
concat
(
skip
,
"
|
"
)
)
243
end
244
--
245
initializers
=
nil
246
finalizers
=
nil
247
originals
=
nil
248
sandboxed
=
true
249
end
250
end
251 252
blockrequire
(
"
lfs
"
,
lfs
)
253
blockrequire
(
"
io
"
,
io
)
254
blockrequire
(
"
os
"
,
os
)
255
blockrequire
(
"
ffi
"
,
ffi
)
256 257
-- require = register(require,"require")
258 259
-- we sandbox some of the built-in functions now:
260 261
-- todo: require
262
-- todo: load
263 264
local
function
supported
(
library
)
265
local
l
=
_G
[
library
]
266
-- if l then
267
-- for k, v in next, l do
268
-- report("%s.%s",library,k)
269
-- end
270
-- end
271
return
l
272
end
273 274
-- io.tmpfile : we don't know where that one ends up but probably is user temp space
275
-- os.tmpname : no need to deal with this: outputs rubish anyway (\s9v0. \s9v0.1 \s9v0.2 etc)
276
-- os.tmpdir : not needed either (luatex.vob000 luatex.vob000 etc)
277 278
-- os.setenv : maybe
279
-- require : maybe (normally taken from tree)
280
-- http etc : maybe (all schemes that go outside)
281 282
loadfile
=
register
(
loadfile
,
"
loadfile
"
)
283 284
if
supported
(
"
lua
"
)
then
285
lua
.
openfile
=
register
(
lua
.
openfile
,
"
lua.openfile
"
)
286
end
287 288
if
supported
(
"
io
"
)
then
289
io
.
open
=
register
(
io
.
open
,
"
io.open
"
)
290
io
.
popen
=
register
(
io
.
popen
,
"
io.popen
"
)
-- needs checking
291
io
.
lines
=
register
(
io
.
lines
,
"
io.lines
"
)
292
io
.
output
=
register
(
io
.
output
,
"
io.output
"
)
293
io
.
input
=
register
(
io
.
input
,
"
io.input
"
)
294
end
295 296
if
supported
(
"
os
"
)
then
297
os
.
execute
=
register
(
os
.
execute
,
"
os.execute
"
)
298
os
.
spawn
=
register
(
os
.
spawn
,
"
os.spawn
"
)
299
os
.
exec
=
register
(
os
.
exec
,
"
os.exec
"
)
300
os
.
rename
=
register
(
os
.
rename
,
"
os.rename
"
)
301
os
.
remove
=
register
(
os
.
remove
,
"
os.remove
"
)
302
end
303 304
if
supported
(
"
lfs
"
)
then
305
lfs
.
chdir
=
register
(
lfs
.
chdir
,
"
lfs.chdir
"
)
306
lfs
.
mkdir
=
register
(
lfs
.
mkdir
,
"
lfs.mkdir
"
)
307
lfs
.
rmdir
=
register
(
lfs
.
rmdir
,
"
lfs.rmdir
"
)
308
lfs
.
isfile
=
register
(
lfs
.
isfile
,
"
lfs.isfile
"
)
309
lfs
.
isdir
=
register
(
lfs
.
isdir
,
"
lfs.isdir
"
)
310
lfs
.
attributes
=
register
(
lfs
.
attributes
,
"
lfs.attributes
"
)
311
lfs
.
dir
=
register
(
lfs
.
dir
,
"
lfs.dir
"
)
312
lfs
.
lock_dir
=
register
(
lfs
.
lock_dir
,
"
lfs.lock_dir
"
)
313
lfs
.
touch
=
register
(
lfs
.
touch
,
"
lfs.touch
"
)
314
lfs
.
link
=
register
(
lfs
.
link
,
"
lfs.link
"
)
315
lfs
.
setmode
=
register
(
lfs
.
setmode
,
"
lfs.setmode
"
)
316
lfs
.
readlink
=
register
(
lfs
.
readlink
,
"
lfs.readlink
"
)
317
lfs
.
shortname
=
register
(
lfs
.
shortname
,
"
lfs.shortname
"
)
318
lfs
.
symlinkattributes
=
register
(
lfs
.
symlinkattributes
,
"
lfs.symlinkattributes
"
)
319
end
320 321