Skip to content

Commit ca1c44c

Browse files
authored
Start work on sandboxing fastly-world (#586)
1 parent 115055a commit ca1c44c

File tree

10 files changed

+107
-144
lines changed

10 files changed

+107
-144
lines changed

runtime/js-compute-runtime/builtins/client-info.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "builtins/client-info.h"
22
#include "core/geo_ip.h"
33
#include "host_interface/host_api.h"
4+
#include "host_interface/host_call.h"
45
#include "openssl/evp.h"
56

67
#include "js/JSON.h"

runtime/js-compute-runtime/builtins/config-store.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace builtins {
55

66
Dict ConfigStore::config_store_handle(JSObject *obj) {
77
JS::Value val = JS::GetReservedSlot(obj, ConfigStore::Slots::Handle);
8-
return Dict{static_cast<fastly_compute_at_edge_fastly_dictionary_handle_t>(val.toInt32())};
8+
return Dict(val.toInt32());
99
}
1010

1111
bool ConfigStore::get(JSContext *cx, unsigned argc, JS::Value *vp) {

runtime/js-compute-runtime/builtins/dictionary.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace builtins {
55

66
Dict Dictionary::dictionary_handle(JSObject *obj) {
77
JS::Value val = JS::GetReservedSlot(obj, Dictionary::Slots::Handle);
8-
return Dict{static_cast<fastly_compute_at_edge_fastly_dictionary_handle_t>(val.toInt32())};
8+
return Dict(val.toInt32());
99
}
1010

1111
bool Dictionary::get(JSContext *cx, unsigned argc, JS::Value *vp) {

runtime/js-compute-runtime/builtins/headers.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ bool lazy_values(JSObject *self) {
7373
.toBoolean();
7474
}
7575

76-
fastly_compute_at_edge_fastly_request_handle_t get_handle(JSObject *self) {
76+
uint32_t get_handle(JSObject *self) {
7777
MOZ_ASSERT(Headers::is_instance(self));
7878
return static_cast<uint32_t>(
7979
JS::GetReservedSlot(self, static_cast<uint32_t>(Headers::Slots::Handle)).toInt32());
@@ -197,9 +197,7 @@ JS::UniqueChars normalize_header_value(JSContext *cx, JS::MutableHandleValue val
197197
return value;
198198
}
199199

200-
namespace {
201200
JS::PersistentRooted<JSString *> comma;
202-
}
203201

204202
// Append an already normalized value for an already normalized header name
205203
// to the JS side map, but not the host.

runtime/js-compute-runtime/builtins/kv-store.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,7 @@ namespace {
116116

117117
ObjectStore kv_store_handle(JSObject *obj) {
118118
JS::Value val = JS::GetReservedSlot(obj, static_cast<uint32_t>(KVStore::Slots::KVStore));
119-
return ObjectStore(
120-
static_cast<fastly_compute_at_edge_fastly_object_store_handle_t>(val.toInt32()));
119+
return ObjectStore(val.toInt32());
121120
}
122121

123122
bool parse_and_validate_key(JSContext *cx, const char *key, size_t len) {

runtime/js-compute-runtime/builtins/request-response.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -740,9 +740,8 @@ bool RequestOrResponse::bodyAll(JSContext *cx, JS::CallArgs args, JS::HandleObje
740740

741741
JS::RootedValue body_parser(cx, JS::PrivateValue((void *)parse_body<result_type>));
742742

743-
// If the body is a ReadableStream that's not backed by a
744-
// fastly_compute_at_edge_fastly_body_handle_t, we need to manually read all chunks from the
745-
// stream.
743+
// If the body is a ReadableStream that's not backed by a body handle, we need to
744+
// manually read all chunks from the stream.
746745
// TODO(performance): ensure that we're properly shortcutting reads from TransformStream
747746
// readables.
748747
// https://github.com/fastly/js-compute-runtime/issues/218

runtime/js-compute-runtime/builtins/secret-store.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ namespace builtins {
55

66
host_api::Secret SecretStoreEntry::secret_handle(JSObject *obj) {
77
JS::Value val = JS::GetReservedSlot(obj, SecretStoreEntry::Slots::Handle);
8-
return host_api::Secret{
9-
static_cast<fastly_compute_at_edge_fastly_secret_handle_t>(val.toInt32())};
8+
return host_api::Secret(val.toInt32());
109
}
1110

1211
bool SecretStoreEntry::plaintext(JSContext *cx, unsigned argc, JS::Value *vp) {
@@ -69,8 +68,7 @@ bool SecretStoreEntry::init_class(JSContext *cx, JS::HandleObject global) {
6968

7069
host_api::SecretStore SecretStore::secret_store_handle(JSObject *obj) {
7170
JS::Value val = JS::GetReservedSlot(obj, SecretStore::Slots::Handle);
72-
return host_api::SecretStore{
73-
static_cast<fastly_compute_at_edge_fastly_secret_store_handle_t>(val.toInt32())};
71+
return host_api::SecretStore(val.toInt32());
7472
}
7573

7674
bool SecretStore::get(JSContext *cx, unsigned argc, JS::Value *vp) {

runtime/js-compute-runtime/host_interface/host_call.cpp

Lines changed: 94 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,100 @@
11

2+
#include <type_traits>
3+
4+
#include "host_interface/fastly.h"
25
#include "host_interface/host_call.h"
36

4-
bool OwnedHostCallBuffer::initialize(JSContext *cx) {
5-
// Ensure the buffer is all zeros so it doesn't add too much to the
6-
// snapshot.
7-
hostcall_buffer = (char *)js_calloc(HOSTCALL_BUFFER_LEN);
8-
return !!hostcall_buffer;
9-
}
7+
// Ensure that our type synonyms match what's generated by wit-bindgen.
8+
static_assert(std::is_same_v<FastlyError, fastly_compute_at_edge_fastly_error_t>);
109

11-
OwnedHostCallBuffer::OwnedHostCallBuffer() {
12-
MOZ_RELEASE_ASSERT(hostcall_buffer != nullptr);
13-
borrowed_buffer = hostcall_buffer;
14-
hostcall_buffer = nullptr;
15-
}
10+
/* Returns false if an exception is set on `cx` and the caller should
11+
immediately return to propagate the exception. */
12+
void handle_fastly_error(JSContext *cx, FastlyError err, int line, const char *func) {
13+
switch (err) {
14+
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_GENERIC_ERROR:
15+
JS_ReportErrorUTF8(cx,
16+
"%s: Generic error value. This means that some unexpected error "
17+
"occurred during a hostcall.\n",
18+
func);
1619

17-
char *OwnedHostCallBuffer::get() { return borrowed_buffer; }
18-
19-
OwnedHostCallBuffer::~OwnedHostCallBuffer() {
20-
// TODO: consider adding a build config that makes this zero the buffer.
21-
hostcall_buffer = borrowed_buffer;
20+
break;
21+
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_INVALID_ARGUMENT:
22+
JS_ReportErrorUTF8(cx, "%s: Invalid argument.\n", func);
23+
break;
24+
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_BAD_HANDLE:
25+
JS_ReportErrorUTF8(cx,
26+
"%s: Invalid handle. Thrown when a request, response, dictionary, or "
27+
"body handle is not valid.\n",
28+
func);
29+
break;
30+
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_BUFFER_LEN:
31+
JS_ReportErrorUTF8(cx, "%s: Buffer length error. Buffer is too long.\n", func);
32+
break;
33+
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_UNSUPPORTED:
34+
JS_ReportErrorUTF8(cx,
35+
"%s: Unsupported operation error. This error is thrown "
36+
"when some operation cannot be performed, because it is "
37+
"not supported.\n",
38+
func);
39+
break;
40+
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_BAD_ALIGN:
41+
JS_ReportErrorUTF8(cx,
42+
"%s: Alignment error. This is thrown when a pointer does not point to "
43+
"a properly aligned slice of memory.\n",
44+
func);
45+
break;
46+
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_HTTP_INVALID:
47+
JS_ReportErrorUTF8(cx,
48+
"%s: HTTP parse error. This can be thrown when a method, URI, header, "
49+
"or status is not valid. This can also be thrown if a message head is "
50+
"too large.\n",
51+
func);
52+
break;
53+
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_HTTP_USER:
54+
JS_ReportErrorUTF8(cx,
55+
"%s: HTTP user error. This is thrown in cases where user code caused "
56+
"an HTTP error. For example, attempt to send a 1xx response code, or a "
57+
"request with a non-absolute URI. This can also be caused by an "
58+
"unexpected header: both `content-length` and `transfer-encoding`, for "
59+
"example.\n",
60+
func);
61+
break;
62+
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_HTTP_INCOMPLETE:
63+
JS_ReportErrorUTF8(cx,
64+
"%s: HTTP incomplete message error. A stream ended "
65+
"unexpectedly.\n",
66+
func);
67+
break;
68+
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_OPTIONAL_NONE:
69+
JS_ReportErrorUTF8(cx,
70+
"%s: A `None` error. This status code is used to "
71+
"indicate when an optional value did not exist, as "
72+
"opposed to an empty value.\n",
73+
func);
74+
break;
75+
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_HTTP_HEAD_TOO_LARGE:
76+
JS_ReportErrorUTF8(cx,
77+
"%s: HTTP head too large error. This error will be thrown when the "
78+
"message head is too large.\n",
79+
func);
80+
break;
81+
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_HTTP_INVALID_STATUS:
82+
JS_ReportErrorUTF8(cx,
83+
"%s: HTTP invalid status error. This error will be "
84+
"thrown when the HTTP message contains an invalid "
85+
"status code.\n",
86+
func);
87+
break;
88+
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_LIMIT_EXCEEDED:
89+
JS_ReportErrorUTF8(cx,
90+
"%s: Limit exceeded error. This error will be thrown when an attempt"
91+
"to allocate a resource has exceeded the maximum number of resources"
92+
"permitted. For example, creating too many response handles."
93+
"\n",
94+
func);
95+
break;
96+
default:
97+
fprintf(stdout, __FILE__ ":%d (%s)\n", line, func);
98+
JS_ReportErrorUTF8(cx, "Fastly error code %d", err);
99+
}
22100
}
23-
24-
char *OwnedHostCallBuffer::hostcall_buffer;
Lines changed: 4 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,123 +1,21 @@
11
#ifndef JS_COMPUTE_RUNTIME_HOST_CALL_H
22
#define JS_COMPUTE_RUNTIME_HOST_CALL_H
33

4+
#include <cstdint>
5+
46
// TODO: remove these once the warnings are fixed
57
#pragma clang diagnostic push
68
#pragma clang diagnostic ignored "-Winvalid-offsetof"
79
#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"
810
#include "jsapi.h"
911
#pragma clang diagnostic pop
1012

11-
#include "host_interface/fastly.h"
12-
13-
/* Returns false if an exception is set on `cx` and the caller should
14-
immediately return to propagate the exception. */
15-
static inline void handle_fastly_error(JSContext *cx, fastly_compute_at_edge_fastly_error_t err,
16-
int line, const char *func) {
17-
switch (err) {
18-
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_GENERIC_ERROR:
19-
JS_ReportErrorUTF8(cx,
20-
"%s: Generic error value. This means that some unexpected error "
21-
"occurred during a hostcall.\n",
22-
func);
13+
using FastlyError = uint8_t;
2314

24-
break;
25-
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_INVALID_ARGUMENT:
26-
JS_ReportErrorUTF8(cx, "%s: Invalid argument.\n", func);
27-
break;
28-
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_BAD_HANDLE:
29-
JS_ReportErrorUTF8(cx,
30-
"%s: Invalid handle. Thrown when a request, response, dictionary, or "
31-
"body handle is not valid.\n",
32-
func);
33-
break;
34-
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_BUFFER_LEN:
35-
JS_ReportErrorUTF8(cx, "%s: Buffer length error. Buffer is too long.\n", func);
36-
break;
37-
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_UNSUPPORTED:
38-
JS_ReportErrorUTF8(cx,
39-
"%s: Unsupported operation error. This error is thrown "
40-
"when some operation cannot be performed, because it is "
41-
"not supported.\n",
42-
func);
43-
break;
44-
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_BAD_ALIGN:
45-
JS_ReportErrorUTF8(cx,
46-
"%s: Alignment error. This is thrown when a pointer does not point to "
47-
"a properly aligned slice of memory.\n",
48-
func);
49-
break;
50-
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_HTTP_INVALID:
51-
JS_ReportErrorUTF8(cx,
52-
"%s: HTTP parse error. This can be thrown when a method, URI, header, "
53-
"or status is not valid. This can also be thrown if a message head is "
54-
"too large.\n",
55-
func);
56-
break;
57-
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_HTTP_USER:
58-
JS_ReportErrorUTF8(cx,
59-
"%s: HTTP user error. This is thrown in cases where user code caused "
60-
"an HTTP error. For example, attempt to send a 1xx response code, or a "
61-
"request with a non-absolute URI. This can also be caused by an "
62-
"unexpected header: both `content-length` and `transfer-encoding`, for "
63-
"example.\n",
64-
func);
65-
break;
66-
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_HTTP_INCOMPLETE:
67-
JS_ReportErrorUTF8(cx,
68-
"%s: HTTP incomplete message error. A stream ended "
69-
"unexpectedly.\n",
70-
func);
71-
break;
72-
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_OPTIONAL_NONE:
73-
JS_ReportErrorUTF8(cx,
74-
"%s: A `None` error. This status code is used to "
75-
"indicate when an optional value did not exist, as "
76-
"opposed to an empty value.\n",
77-
func);
78-
break;
79-
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_HTTP_HEAD_TOO_LARGE:
80-
JS_ReportErrorUTF8(cx,
81-
"%s: HTTP head too large error. This error will be thrown when the "
82-
"message head is too large.\n",
83-
func);
84-
break;
85-
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_HTTP_INVALID_STATUS:
86-
JS_ReportErrorUTF8(cx,
87-
"%s: HTTP invalid status error. This error will be "
88-
"thrown when the HTTP message contains an invalid "
89-
"status code.\n",
90-
func);
91-
break;
92-
case FASTLY_COMPUTE_AT_EDGE_FASTLY_ERROR_LIMIT_EXCEEDED:
93-
JS_ReportErrorUTF8(cx,
94-
"%s: Limit exceeded error. This error will be thrown when an attempt"
95-
"to allocate a resource has exceeded the maximum number of resources"
96-
"permitted. For example, creating too many response handles."
97-
"\n",
98-
func);
99-
break;
100-
default:
101-
fprintf(stdout, __FILE__ ":%d (%s)\n", line, func);
102-
JS_ReportErrorUTF8(cx, "Fastly error code %d", err);
103-
}
104-
}
15+
void handle_fastly_error(JSContext *cx, FastlyError err, int line, const char *func);
10516

10617
#define HANDLE_ERROR(cx, err) handle_fastly_error(cx, err, __LINE__, __func__)
10718

10819
#define HOSTCALL_BUFFER_LEN HEADER_MAX_LEN
10920

110-
class OwnedHostCallBuffer {
111-
static char *hostcall_buffer;
112-
char *borrowed_buffer;
113-
114-
public:
115-
static bool initialize(JSContext *cx);
116-
117-
OwnedHostCallBuffer();
118-
~OwnedHostCallBuffer();
119-
120-
char *get();
121-
};
122-
12321
#endif

runtime/js-compute-runtime/js-compute-builtins.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,12 +1275,6 @@ bool math_random(JSContext *cx, unsigned argc, Value *vp) {
12751275
}
12761276

12771277
bool define_fastly_sys(JSContext *cx, HandleObject global, FastlyOptions options) {
1278-
// Allocating the reusable hostcall buffer here means it's baked into the
1279-
// snapshot, and since it's all zeros, it won't increase the size of the
1280-
// snapshot.
1281-
if (!OwnedHostCallBuffer::initialize(cx))
1282-
return false;
1283-
12841278
if (!GlobalProperties::init(cx, global))
12851279
return false;
12861280

0 commit comments

Comments
 (0)