mirror of
https://github.com/DoneJS-Runtime/quickjs-done-nextgen.git
synced 2025-01-09 17:43:15 +00:00
Forbid closing stdio from quickjs-libc (#576)
Intrinsically dangerous because it leaves the std{in,out,err} C globals in an undefined state.
This commit is contained in:
parent
ddabcf5e93
commit
27715a46bb
2 changed files with 31 additions and 13 deletions
|
@ -878,15 +878,19 @@ static JSClassID js_std_file_class_id;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FILE *f;
|
FILE *f;
|
||||||
BOOL close_in_finalizer;
|
|
||||||
BOOL is_popen;
|
BOOL is_popen;
|
||||||
} JSSTDFile;
|
} JSSTDFile;
|
||||||
|
|
||||||
|
static BOOL is_stdio(FILE *f)
|
||||||
|
{
|
||||||
|
return f == stdin || f == stdout || f == stderr;
|
||||||
|
}
|
||||||
|
|
||||||
static void js_std_file_finalizer(JSRuntime *rt, JSValue val)
|
static void js_std_file_finalizer(JSRuntime *rt, JSValue val)
|
||||||
{
|
{
|
||||||
JSSTDFile *s = JS_GetOpaque(val, js_std_file_class_id);
|
JSSTDFile *s = JS_GetOpaque(val, js_std_file_class_id);
|
||||||
if (s) {
|
if (s) {
|
||||||
if (s->f && s->close_in_finalizer) {
|
if (s->f && !is_stdio(s->f)) {
|
||||||
#if !defined(__wasi__)
|
#if !defined(__wasi__)
|
||||||
if (s->is_popen)
|
if (s->is_popen)
|
||||||
pclose(s->f);
|
pclose(s->f);
|
||||||
|
@ -914,9 +918,7 @@ static JSValue js_std_strerror(JSContext *ctx, JSValue this_val,
|
||||||
return JS_NewString(ctx, strerror(err));
|
return JS_NewString(ctx, strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSValue js_new_std_file(JSContext *ctx, FILE *f,
|
static JSValue js_new_std_file(JSContext *ctx, FILE *f, BOOL is_popen)
|
||||||
BOOL close_in_finalizer,
|
|
||||||
BOOL is_popen)
|
|
||||||
{
|
{
|
||||||
JSSTDFile *s;
|
JSSTDFile *s;
|
||||||
JSValue obj;
|
JSValue obj;
|
||||||
|
@ -928,7 +930,6 @@ static JSValue js_new_std_file(JSContext *ctx, FILE *f,
|
||||||
JS_FreeValue(ctx, obj);
|
JS_FreeValue(ctx, obj);
|
||||||
return JS_EXCEPTION;
|
return JS_EXCEPTION;
|
||||||
}
|
}
|
||||||
s->close_in_finalizer = close_in_finalizer;
|
|
||||||
s->is_popen = is_popen;
|
s->is_popen = is_popen;
|
||||||
s->f = f;
|
s->f = f;
|
||||||
JS_SetOpaque(obj, s);
|
JS_SetOpaque(obj, s);
|
||||||
|
@ -971,7 +972,7 @@ static JSValue js_std_open(JSContext *ctx, JSValue this_val,
|
||||||
JS_FreeCString(ctx, mode);
|
JS_FreeCString(ctx, mode);
|
||||||
if (!f)
|
if (!f)
|
||||||
return JS_NULL;
|
return JS_NULL;
|
||||||
return js_new_std_file(ctx, f, TRUE, FALSE);
|
return js_new_std_file(ctx, f, FALSE);
|
||||||
fail:
|
fail:
|
||||||
JS_FreeCString(ctx, filename);
|
JS_FreeCString(ctx, filename);
|
||||||
JS_FreeCString(ctx, mode);
|
JS_FreeCString(ctx, mode);
|
||||||
|
@ -1008,7 +1009,7 @@ static JSValue js_std_popen(JSContext *ctx, JSValue this_val,
|
||||||
JS_FreeCString(ctx, mode);
|
JS_FreeCString(ctx, mode);
|
||||||
if (!f)
|
if (!f)
|
||||||
return JS_NULL;
|
return JS_NULL;
|
||||||
return js_new_std_file(ctx, f, TRUE, TRUE);
|
return js_new_std_file(ctx, f, TRUE);
|
||||||
fail:
|
fail:
|
||||||
JS_FreeCString(ctx, filename);
|
JS_FreeCString(ctx, filename);
|
||||||
JS_FreeCString(ctx, mode);
|
JS_FreeCString(ctx, mode);
|
||||||
|
@ -1043,7 +1044,7 @@ static JSValue js_std_fdopen(JSContext *ctx, JSValue this_val,
|
||||||
JS_FreeCString(ctx, mode);
|
JS_FreeCString(ctx, mode);
|
||||||
if (!f)
|
if (!f)
|
||||||
return JS_NULL;
|
return JS_NULL;
|
||||||
return js_new_std_file(ctx, f, TRUE, FALSE);
|
return js_new_std_file(ctx, f, FALSE);
|
||||||
fail:
|
fail:
|
||||||
JS_FreeCString(ctx, mode);
|
JS_FreeCString(ctx, mode);
|
||||||
return JS_EXCEPTION;
|
return JS_EXCEPTION;
|
||||||
|
@ -1059,7 +1060,7 @@ static JSValue js_std_tmpfile(JSContext *ctx, JSValue this_val,
|
||||||
js_set_error_object(ctx, argv[0], f ? 0 : errno);
|
js_set_error_object(ctx, argv[0], f ? 0 : errno);
|
||||||
if (!f)
|
if (!f)
|
||||||
return JS_NULL;
|
return JS_NULL;
|
||||||
return js_new_std_file(ctx, f, TRUE, FALSE);
|
return js_new_std_file(ctx, f, FALSE);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1122,6 +1123,8 @@ static JSValue js_std_file_close(JSContext *ctx, JSValue this_val,
|
||||||
return JS_EXCEPTION;
|
return JS_EXCEPTION;
|
||||||
if (!s->f)
|
if (!s->f)
|
||||||
return JS_ThrowTypeError(ctx, "invalid file handle");
|
return JS_ThrowTypeError(ctx, "invalid file handle");
|
||||||
|
if (is_stdio(s->f))
|
||||||
|
return JS_ThrowTypeError(ctx, "cannot close stdio");
|
||||||
#if !defined(__wasi__)
|
#if !defined(__wasi__)
|
||||||
if (s->is_popen)
|
if (s->is_popen)
|
||||||
err = js_get_errno(pclose(s->f));
|
err = js_get_errno(pclose(s->f));
|
||||||
|
@ -1643,9 +1646,9 @@ static int js_std_init(JSContext *ctx, JSModuleDef *m)
|
||||||
|
|
||||||
JS_SetModuleExportList(ctx, m, js_std_funcs,
|
JS_SetModuleExportList(ctx, m, js_std_funcs,
|
||||||
countof(js_std_funcs));
|
countof(js_std_funcs));
|
||||||
JS_SetModuleExport(ctx, m, "in", js_new_std_file(ctx, stdin, FALSE, FALSE));
|
JS_SetModuleExport(ctx, m, "in", js_new_std_file(ctx, stdin, FALSE));
|
||||||
JS_SetModuleExport(ctx, m, "out", js_new_std_file(ctx, stdout, FALSE, FALSE));
|
JS_SetModuleExport(ctx, m, "out", js_new_std_file(ctx, stdout, FALSE));
|
||||||
JS_SetModuleExport(ctx, m, "err", js_new_std_file(ctx, stderr, FALSE, FALSE));
|
JS_SetModuleExport(ctx, m, "err", js_new_std_file(ctx, stderr, FALSE));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -289,6 +289,20 @@ function test_timeout_order()
|
||||||
function d() { assert(s === "abc"); } // not "acb"
|
function d() { assert(s === "abc"); } // not "acb"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test_stdio_close()
|
||||||
|
{
|
||||||
|
for (const f of [std.in, std.out, std.err]) {
|
||||||
|
let caught = false;
|
||||||
|
try {
|
||||||
|
f.close();
|
||||||
|
} catch (e) {
|
||||||
|
assert(/cannot close stdio/.test(e.message));
|
||||||
|
caught = true;
|
||||||
|
}
|
||||||
|
assert(caught);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test_printf();
|
test_printf();
|
||||||
test_file1();
|
test_file1();
|
||||||
test_file2();
|
test_file2();
|
||||||
|
@ -299,3 +313,4 @@ test_os();
|
||||||
test_interval();
|
test_interval();
|
||||||
test_timeout();
|
test_timeout();
|
||||||
test_timeout_order();
|
test_timeout_order();
|
||||||
|
test_stdio_close();
|
||||||
|
|
Loading…
Reference in a new issue