zet.tlv: switch file writes to new API
The interface for apps looks much nicer now, see 'main' in zet.tlv. However there are some open issues: - It can still be confusing to the computer owner that an app tries to write to some temporary file that isn't mentioned anywhere. - File renames can fail if /tmp is on a different volume. - What happens if an app overrides start_writing()? The computer owner may think they've audited the caller of start_writing and give it blanket file permissions. Teliva tunnels through start_writing when computing the caller. If the app can control what start_writing does, the app could be performing arbitrary malicious file operations. Right now things actually seem perfectly secure. Overriding start_writing has no effect. Our approach for loading .tlv files (in reverse chronological order, preventing older versions from overriding newer ones) has the accidentally _great_ property that Teliva apps can never override system definitions. So we have a new reason to put standard libraries in a .lua file: if we need to prevent apps from overriding it. This feels like something that needs an automated test, both to make sure I'm running the right experiment and to ensure I don't accidentally cause a regression in the future. I can totally imagine a future rewrite that tried a different approach than reverse-chronological.
This commit is contained in:
parent
7a315e3d9f
commit
38063812b6
14
src/liolib.c
14
src/liolib.c
|
@ -122,6 +122,11 @@ static int io_tostring (lua_State *L) {
|
|||
}
|
||||
|
||||
|
||||
static int is_equal(const char *a, const char *b) {
|
||||
return strcmp(a, b) == 0;
|
||||
}
|
||||
|
||||
|
||||
static char iolib_errbuf[1024] = {0};
|
||||
static int io_open (lua_State *L) {
|
||||
const char *filename = luaL_checkstring(L, 1);
|
||||
|
@ -134,6 +139,15 @@ static int io_open (lua_State *L) {
|
|||
const char *caller = get_caller(L);
|
||||
if (file_operation_permitted(caller, filename, mode))
|
||||
*pf = fopen(filename, mode);
|
||||
else if (is_equal(caller, "start_writing") || is_equal(caller, "start_reading")) {
|
||||
caller = get_caller_of_caller(L);
|
||||
if (file_operation_permitted(caller, filename, mode))
|
||||
*pf = fopen(filename, mode);
|
||||
else {
|
||||
snprintf(iolib_errbuf, 1024, "app tried to open file '%s' from caller '%s'; adjust its permissions (ctrl-p) if that is expected", filename, caller);
|
||||
Previous_message = iolib_errbuf;
|
||||
}
|
||||
}
|
||||
else {
|
||||
snprintf(iolib_errbuf, 1024, "app tried to open file '%s' from caller '%s'; adjust its permissions (ctrl-p) if that is expected", filename, caller);
|
||||
Previous_message = iolib_errbuf;
|
||||
|
|
11
src/teliva.c
11
src/teliva.c
|
@ -337,6 +337,17 @@ char* get_caller(lua_State* L) {
|
|||
return result;
|
||||
}
|
||||
|
||||
char* get_caller_of_caller(lua_State* L) {
|
||||
static char result[1024] = {0};
|
||||
lua_Debug ar;
|
||||
lua_getstack(L, 2, &ar);
|
||||
lua_getinfo(L, "n", &ar);
|
||||
memset(result, '\0', 1024);
|
||||
if (ar.name)
|
||||
strncpy(result, ar.name, 1020);
|
||||
return result;
|
||||
}
|
||||
|
||||
void save_caller_as(lua_State* L, const char* name, const char* caller_name) {
|
||||
// push table of caller tables
|
||||
luaL_newmetatable(L, "__teliva_caller");
|
||||
|
|
|
@ -168,6 +168,8 @@ extern void assign_call_graph_depth_to_name(lua_State* L, int depth, const char*
|
|||
extern char* get_caller(lua_State* L);
|
||||
extern void save_caller(lua_State* L, const char* name, int call_graph_depth);
|
||||
extern void draw_callers_of_current_definition(lua_State* L);
|
||||
extern char* get_caller_of_caller(lua_State* L);
|
||||
|
||||
extern void append_to_audit_log(lua_State* L, const char* buffer);
|
||||
|
||||
/* Standard UI elements */
|
||||
|
|
37
zet.tlv
37
zet.tlv
|
@ -3593,3 +3593,40 @@
|
|||
>function read_zettels(infile)
|
||||
> zettels = jsonf.decode(infile)
|
||||
>end
|
||||
- __teliva_timestamp:
|
||||
>Mon Mar 7 10:31:27 2022
|
||||
main:
|
||||
>function main()
|
||||
> init_colors()
|
||||
> curses.curs_set(0) -- hide cursor except when editing
|
||||
>
|
||||
> -- load any saved zettels
|
||||
> local infile = start_reading(nil, 'zet')
|
||||
> if infile then
|
||||
> read_zettels(infile)
|
||||
> end
|
||||
> current_zettel_id = zettels.root -- cursor
|
||||
> view_settings.first_zettel = zettels.root -- start rendering here
|
||||
>
|
||||
> while true do
|
||||
> render(Window)
|
||||
> update(Window)
|
||||
>
|
||||
> -- save zettels
|
||||
> local outfile = start_writing(nil, 'zet')
|
||||
> if outfile then
|
||||
> write_zettels(outfile)
|
||||
> end
|
||||
> -- TODO: what if io.open failed for a non-sandboxing related reason?!
|
||||
> -- We could silently fail to save.
|
||||
> end
|
||||
>end
|
||||
- __teliva_timestamp:
|
||||
>Mon Mar 7 10:32:08 2022
|
||||
__teliva_note:
|
||||
>switch to new file API for writing
|
||||
write_zettels:
|
||||
>function write_zettels(outfile)
|
||||
> outfile:send(json.encode(zettels))
|
||||
> outfile:close()
|
||||
>end
|
||||
|
|
Loading…
Reference in New Issue