lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


> In this case, I was changing the value of LUA_GLOBALSINDEX by calling
> lua_replace( L, LUA_GLOBALSINDEX ) and the thread in question was being 
used
> as a sandbox for an editing/execution environment. Could I avoid these
> problems simply by setting the sandbox as the environment for the result 
of
> compiling each chunk of code? Or should I stick with the approach of 
copying
> into the sandbox the values that cause problems?

My opinion is that you should use the sandbox as the environment for the
result of compiling each chunk of code, and leave the C global environment
untouched. This avoids any issues with the use of the C global environment
by C library functions -- although it does assume that the C library
functions are not themselves sandboxed (since it is difficult to ensure
safety of a library function written in C, that is probably not
totally unreasonable.)

As I think I have said before, putting a reference to a library
table in a sandbox is not safe, because the sandbox might alter the
table affecting other sandboxes using the same table. Consequently,
the module-management system ("require" or some substitute) ought to
be relative to the sandbox. The solution I advocate is that the
global "C" environment be used to store module instantiation functions,
but that the actual module tables be part of the sandbox state --
whether by being placed in the sandbox environment directly, or
in some table of module tables accessible only by the module management
system. (I prefer the latter, myself.) The module instantiation
function itself could choose whether to create a new table from scratch
or to just create a lazy copy of an original table (in which case
the metatable must be protected).

However, library modules sometimes have private state as well, and
the question arises as to whether the private state is sandbox-relative
or global. I don't think there is an easy answer to this question.

There are a number of places where a library module might store
private state; these include:
-- the registry (if it is a C library module)
-- the thread C global environment
-- the sandbox environment
-- upvalues/closed variables associated with library functions.
-- the module table itself
-- the metatable of the module table

No doubt there are other possibilities I haven't considered.

Some of these options are less private than others; if the
module's private state must be private to ensure integrity of
the module, several of the above options are inappropriate.

The registry is an attractive option for C library modules whose
private state is global; function closures are attractive for
library modules whose private state is sandbox-relative.
The thread C global environment might be useful for C library
modules whose private state is sandbox-relative, particularly
if the module uses lazy copy instantiation. (Although a more
sophisticated lazy copy metamethod could be used, which did
memoising lazy closure instantiation.) If the thread C
global environment is going to be used, it needs to be
protected, which is also an issue.

It may well be that the application itself needs to store
state, as well. The simplest place to keep application state
is on the main stack, underneath any script evaluation, but
this is not available to C callback functions unless those
functions are created with upvalues. More common approaches
are to use the C global environment (as the Lua standalone
interpreter does) or the registry.

I don't have any definitive answers here, but it seems to
me that if the global C environment is being used to store
globally-shared private state, it must be available from
all threads. This requires that the sandbox run in a
separate environment table, which is why I recommend that
the sandbox environment not be the C global environment.

Rici.