@ai-ecoverse/slicc-kernel 1.148.1 → 1.149.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5954,6 +5954,9 @@ function link(a, b) {
5954
5954
  a.attach({ rx: ba, tx: ab });
5955
5955
  b.attach({ rx: ab, tx: ba });
5956
5956
  }
5957
+ var SERVE_CHUNK = 64 * 1024;
5958
+ var NEVER_ABORTED = new AbortController().signal;
5959
+ var EMPTY = new Uint8Array(0);
5957
5960
  var KernelSocket = class _KernelSocket {
5958
5961
  net;
5959
5962
  domain;
@@ -6151,6 +6154,54 @@ var KernelSocket = class _KernelSocket {
6151
6154
  if (this.state !== "open") throw new KernelError("EISCONN");
6152
6155
  return this.dial(addr, route2, secure2);
6153
6156
  }
6157
+ serving;
6158
+ served = false;
6159
+ get loopbackLinked() {
6160
+ return this.state === "connected" && !this.switch;
6161
+ }
6162
+ async secureLink(make, signal = NEVER_ABORTED) {
6163
+ const raw2 = this.connection();
6164
+ if (this.switch || this.served || this.writeShut || this.readShut)
6165
+ throw new KernelError("EINVAL");
6166
+ signal.throwIfAborted();
6167
+ this.served = true;
6168
+ let handshaking = true;
6169
+ const view2 = {
6170
+ localAddr: "",
6171
+ remoteAddr: "",
6172
+ read: async () => {
6173
+ const bytes = await raw2.rx.read(SERVE_CHUNK, handshaking ? signal : void 0).catch(() => EMPTY);
6174
+ return bytes.length > 0 ? bytes : null;
6175
+ },
6176
+ write: (bytes) => raw2.tx.write(bytes),
6177
+ closeWrite: () => raw2.tx.closeWrite(),
6178
+ close: () => {
6179
+ raw2.rx.closeRead();
6180
+ raw2.tx.closeWrite();
6181
+ }
6182
+ };
6183
+ let made2;
6184
+ const abandon = () => view2.close();
6185
+ signal.addEventListener("abort", abandon, { once: true });
6186
+ try {
6187
+ made2 = await make(view2);
6188
+ } catch (err) {
6189
+ view2.close();
6190
+ this.readShut = true;
6191
+ this.writeShut = true;
6192
+ this.changes.wake();
6193
+ throw signal.aborted ? signal.reason : err;
6194
+ } finally {
6195
+ handshaking = false;
6196
+ signal.removeEventListener("abort", abandon);
6197
+ }
6198
+ this.link = uplinkLink(made2.conn, (err) => {
6199
+ this.reset = err instanceof KernelError && err.code === "EPROTO" ? err : new KernelError("ECONNRESET");
6200
+ this.changes.wake();
6201
+ });
6202
+ this.changes.wake();
6203
+ return made2.info;
6204
+ }
6154
6205
  upgradeSecure(make) {
6155
6206
  if (this.state !== "connected") throw new KernelError("ENOTCONN");
6156
6207
  if (!this.switch) throw new KernelError("EOPNOTSUPP");
@@ -6282,6 +6333,8 @@ var KernelSocket = class _KernelSocket {
6282
6333
  }
6283
6334
  if (this.boundAt) this.net.release(this.boundAt, this, this.named);
6284
6335
  this.boundAt = void 0;
6336
+ this.serving?.release();
6337
+ this.serving = void 0;
6285
6338
  this.changes.wake();
6286
6339
  }
6287
6340
  static pair(net, domain, cred) {
@@ -6784,6 +6837,7 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS2 } = {})
6784
6837
  const flow = {
6785
6838
  inflight: 0,
6786
6839
  closing: false,
6840
+ dropped: false,
6787
6841
  deadline: () => AbortSignal.timeout(closeWaitMs).addEventListener("abort", late, { once: true })
6788
6842
  };
6789
6843
  credit.set(nid, flow);
@@ -6795,7 +6849,7 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS2 } = {})
6795
6849
  const next3 = await Promise.race([messages.next(), unanswered]);
6796
6850
  if (next3 === "late" || next3.done) break;
6797
6851
  const data = next3.value;
6798
- if (flow.closing) continue;
6852
+ if (flow.dropped) continue;
6799
6853
  if (payloadSize(data) > MESSAGE_LIMIT) {
6800
6854
  oversize = true;
6801
6855
  break;
@@ -6849,6 +6903,8 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS2 } = {})
6849
6903
  };
6850
6904
  const drop = (nid) => {
6851
6905
  sockets.get(nid)?.close(1e3, "cancelled");
6906
+ const flow = credit.get(nid);
6907
+ if (flow) flow.dropped = true;
6852
6908
  refill(nid, 0, true);
6853
6909
  const entry = open2.get(nid);
6854
6910
  open2.delete(nid);
@@ -7855,7 +7911,7 @@ function satisfies(version, range2) {
7855
7911
  }
7856
7912
 
7857
7913
  // src/version.ts
7858
- var KERNEL_VERSION = true ? "1.148.1" : "0.0.0-dev";
7914
+ var KERNEL_VERSION = true ? "1.149.1" : "0.0.0-dev";
7859
7915
  var OS_RELEASE = "6.0.0-slicc";
7860
7916
  function procVersion() {
7861
7917
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -10354,7 +10410,7 @@ async function followLinks(fs, path) {
10354
10410
  return current;
10355
10411
  }
10356
10412
  var NOBODY = { ruid: -1, euid: -1, suid: -1, rgid: -1, egid: -1, sgid: -1, groups: [] };
10357
- var EMPTY = new Uint8Array(0);
10413
+ var EMPTY2 = new Uint8Array(0);
10358
10414
  function quiet(promise) {
10359
10415
  return promise.catch(() => void 0);
10360
10416
  }
@@ -10437,13 +10493,13 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
10437
10493
  return target?.path;
10438
10494
  }
10439
10495
  const absent2 = (err) => {
10440
- if (missing3(err)) return EMPTY;
10496
+ if (missing3(err)) return EMPTY2;
10441
10497
  throw err;
10442
10498
  };
10443
10499
  async function content(path, err) {
10444
10500
  if (!missing3(err) || !(await linked2(path))?.isFile) throw err;
10445
10501
  const target = await redirected2(path);
10446
- return target === void 0 ? EMPTY : fs.readFileBuffer(target).catch(absent2);
10502
+ return target === void 0 ? EMPTY2 : fs.readFileBuffer(target).catch(absent2);
10447
10503
  }
10448
10504
  const ranged2 = rangedOps(fs);
10449
10505
  async function stat(path, real) {
@@ -16717,6 +16773,8 @@ function realmCa(owner, store) {
16717
16773
  var TLS_CLIENT_INSECURE_SKIP_VERIFY = 1;
16718
16774
  var TLS_CLIENT_NO_SNI = 2;
16719
16775
  var TLS_CLIENT_VERIFY_CHAIN_ONLY = 4;
16776
+ var TLS_SERVER_REQUEST_CERT = 1;
16777
+ var TLS_SERVER_REQUIRE_CERT = 2;
16720
16778
  var SCRATCH = 64 * 1024;
16721
16779
  var EOF = -1;
16722
16780
  var TlsError = class extends Error {
@@ -16765,6 +16823,35 @@ var TlsEngine = class {
16765
16823
  this.m._free(name2);
16766
16824
  }
16767
16825
  }
16826
+ get serverSessions() {
16827
+ return typeof this.m._tls_server_new === "function";
16828
+ }
16829
+ importLeaf(chain2, key, pass2) {
16830
+ const leafImport = this.m._tls_leaf_import;
16831
+ const keyLen = key[0] === 45 ? key.length + 1 : key.length;
16832
+ const ptr = this.withBytes(
16833
+ chain2,
16834
+ (c) => this.withSecret(
16835
+ key,
16836
+ (k) => this.withSecret(
16837
+ pass2,
16838
+ (p) => leafImport(c, chain2.length, k, keyLen, pass2.length > 0 ? p : 0, pass2.length)
16839
+ )
16840
+ )
16841
+ );
16842
+ if (!ptr) throw this.error(this.m._tls_last_error(), "server certificate");
16843
+ return new TlsLeaf(this, this.m, ptr);
16844
+ }
16845
+ serverSession(leaf, alpn, clientCa, flags2) {
16846
+ const open2 = this.m._tls_server_new;
16847
+ const wire = alpnWire(alpn);
16848
+ const ptr = this.withBytes(
16849
+ wire,
16850
+ (p) => open2(leaf.ptr, wire.length > 0 ? p : 0, wire.length, clientCa?.ptr ?? 0, flags2)
16851
+ );
16852
+ if (!ptr) throw this.error(this.m._tls_last_error(), "tls server");
16853
+ return new TlsSession(this, this.m, ptr);
16854
+ }
16768
16855
  withBytes(bytes, fn) {
16769
16856
  const ptr = this.put(bytes);
16770
16857
  try {
@@ -16969,6 +17056,12 @@ var TlsSession = class {
16969
17056
  get version() {
16970
17057
  return this.c._tls_version(this.ptr);
16971
17058
  }
17059
+ get sni() {
17060
+ const out = this.engine.intoScratch(
17061
+ (p, max) => this.m._tls_sni(this.ptr, p, max)
17062
+ );
17063
+ return out instanceof Uint8Array ? new TextDecoder().decode(out) : "";
17064
+ }
16972
17065
  get alpn() {
16973
17066
  const out = this.engine.intoScratch((p, max) => this.c._tls_alpn(this.ptr, p, max));
16974
17067
  return out instanceof Uint8Array ? new TextDecoder().decode(out) : void 0;
@@ -17471,7 +17564,7 @@ var Upload = class {
17471
17564
  }
17472
17565
  }
17473
17566
  };
17474
- var EMPTY2 = new Uint8Array(0);
17567
+ var EMPTY3 = new Uint8Array(0);
17475
17568
  function message2(e) {
17476
17569
  return e instanceof Error ? e.message : String(e);
17477
17570
  }
@@ -17546,8 +17639,8 @@ var HttpHandles = class {
17546
17639
  const entry = {
17547
17640
  abort,
17548
17641
  head: Promise.resolve({ ok: true, kind: "void" }),
17549
- body: once(EMPTY2),
17550
- left: EMPTY2,
17642
+ body: once(EMPTY3),
17643
+ left: EMPTY3,
17551
17644
  done: false,
17552
17645
  reading: Promise.resolve(),
17553
17646
  cancel: async () => void 0,
@@ -18785,6 +18878,46 @@ async function tlsClient(conn, o, taken = new Uint8Array(0)) {
18785
18878
  throw err;
18786
18879
  }
18787
18880
  }
18881
+ async function serverHandshake(conn, session, inbox) {
18882
+ for (; ; ) {
18883
+ let done5;
18884
+ try {
18885
+ done5 = session.handshake();
18886
+ } catch (err) {
18887
+ await send(conn, session).catch(() => void 0);
18888
+ const text = err instanceof TlsError ? err.message : String(err);
18889
+ throw new KernelError("EPROTO", `ERR_SSL_HANDSHAKE_FAILURE: ${text}${alertOf(session)}`);
18890
+ }
18891
+ await send(conn, session);
18892
+ if (done5) return;
18893
+ if (!await inbox.more()) {
18894
+ throw new KernelError(
18895
+ "ECONNRESET",
18896
+ "the client closed the connection during the TLS handshake"
18897
+ );
18898
+ }
18899
+ }
18900
+ }
18901
+ async function tlsServer(conn, session, clientCerts) {
18902
+ const inbox = new Ciphertext(conn, session);
18903
+ try {
18904
+ await serverHandshake(conn, session, inbox);
18905
+ const chain2 = session.peerChain();
18906
+ const code = clientCerts ? verifyCode(session.verifyResult) : void 0;
18907
+ const info = {
18908
+ protocol: session.version === 772 ? "TLSv1.3" : "TLSv1.2",
18909
+ alpnProtocol: session.alpn ?? false,
18910
+ servername: session.sni,
18911
+ authorized: clientCerts && chain2.length > 0 && code === void 0,
18912
+ ...clientCerts && chain2.length > 0 && code ? { authorizationError: code } : {},
18913
+ peerCertificates: chain2
18914
+ };
18915
+ return { conn: plaintext(conn, session, inbox), info };
18916
+ } catch (err) {
18917
+ session.free();
18918
+ throw err;
18919
+ }
18920
+ }
18788
18921
 
18789
18922
  // src/kernel/net/tls-chain.ts
18790
18923
  var CN_MISMATCH = 4;
@@ -19237,7 +19370,7 @@ var RANK = {
19237
19370
  };
19238
19371
  var CR2 = 13;
19239
19372
  var LF2 = 10;
19240
- var EMPTY3 = new Uint8Array(0);
19373
+ var EMPTY4 = new Uint8Array(0);
19241
19374
  function register(automaton, sources, ids, bytes, source) {
19242
19375
  const key = Array.from(bytes).join(",");
19243
19376
  let id2 = ids.get(key);
@@ -19417,12 +19550,12 @@ function compile(secrets, options = {}) {
19417
19550
  return { text: decoder4.decode(bytes), hits };
19418
19551
  },
19419
19552
  stream() {
19420
- let pending = EMPTY3;
19553
+ let pending = EMPTY4;
19421
19554
  const hits = /* @__PURE__ */ new Map();
19422
19555
  const run2 = (final) => {
19423
19556
  if (c.secrets.length === 0 || pending.length === 0) {
19424
19557
  const out = pending;
19425
- pending = EMPTY3;
19558
+ pending = EMPTY4;
19426
19559
  return out;
19427
19560
  }
19428
19561
  const result = pass(c, pending, final);
@@ -19436,7 +19569,7 @@ function compile(secrets, options = {}) {
19436
19569
  return run2(false);
19437
19570
  },
19438
19571
  idle() {
19439
- return pending.length < FRAGMENT ? run2(true) : EMPTY3;
19572
+ return pending.length < FRAGMENT ? run2(true) : EMPTY4;
19440
19573
  },
19441
19574
  end() {
19442
19575
  return run2(true);
@@ -21598,6 +21731,7 @@ function sealedConn(conn, s) {
21598
21731
  }
21599
21732
 
21600
21733
  // src/kernel/net/tls-uplink.ts
21734
+ var handshakeAbort = (proc) => proc.cancelled ?? proc.blocking();
21601
21735
  var isIP2 = (text) => ipv4Bytes(text) !== void 0 || text.includes(":") && ipv6Groups(text) !== void 0;
21602
21736
  var LABEL2 = /^(?!-)[A-Za-z0-9-]{1,63}(?<!-)$/;
21603
21737
  function serverName(name2) {
@@ -21718,6 +21852,9 @@ function takeCert(req) {
21718
21852
  const cert = req.clientCert;
21719
21853
  if (!cert) return void 0;
21720
21854
  delete req.clientCert;
21855
+ return certBytes(cert);
21856
+ }
21857
+ function certBytes(cert) {
21721
21858
  if (!Array.isArray(cert.chain) || cert.chain.length === 0 || typeof cert.key !== "string")
21722
21859
  throw new KernelError("EINVAL", "ERR_INVALID_ARG_VALUE: cert and key go together");
21723
21860
  let ders;
@@ -21893,8 +22030,32 @@ async function connectSecure(proc, socket, host, port, req) {
21893
22030
  }
21894
22031
  return sessionOf(info, servername);
21895
22032
  }
22033
+ async function loopbackSecure(proc, socket, servername, req) {
22034
+ const prepared = await prepare2(supportOf(proc.net), req, servername);
22035
+ let ran = false;
22036
+ try {
22037
+ const info = await socket.secureLink(async (raw2) => {
22038
+ ran = true;
22039
+ try {
22040
+ return await tlsClient(raw2, prepared.options);
22041
+ } finally {
22042
+ prepared.own?.release();
22043
+ }
22044
+ }, handshakeAbort(proc));
22045
+ return sessionOf({ ...info, substitutes: false }, servername);
22046
+ } finally {
22047
+ if (!ran) {
22048
+ prepared.options.session.free();
22049
+ prepared.own?.release();
22050
+ }
22051
+ }
22052
+ }
21896
22053
  async function upgradeSecure(proc, socket, req) {
21897
22054
  const peer = socket.peer;
22055
+ if (socket.loopbackLinked) {
22056
+ const host2 = req.servername || (peer?.family === "inet" ? peer.host : "localhost");
22057
+ return loopbackSecure(proc, socket, serverName(host2), req);
22058
+ }
21898
22059
  const host = req.servername || (peer?.family === "inet" ? peer.host : "");
21899
22060
  const servername = serverName(host);
21900
22061
  const port = peer?.family === "inet" ? peer.port : 0;
@@ -21909,6 +22070,120 @@ async function upgradeSecure(proc, socket, req) {
21909
22070
  }
21910
22071
  }
21911
22072
 
22073
+ // src/kernel/net/tls-server.ts
22074
+ var HANDSHAKE_TIMEOUT_MS = 12e4;
22075
+ function leafOf(engine, cert) {
22076
+ try {
22077
+ return engine.importLeaf(cert.chain, cert.key, cert.pass);
22078
+ } catch (err) {
22079
+ throw keyRefused(err, cert.pass.length > 0 && encryptedKey(cert.key));
22080
+ } finally {
22081
+ wipe(cert);
22082
+ }
22083
+ }
22084
+ function storeOf(engine, ca) {
22085
+ const store = engine.store();
22086
+ try {
22087
+ for (const der2 of ca) store.add(base64Der(der2));
22088
+ return store;
22089
+ } catch (err) {
22090
+ store.release();
22091
+ throw new KernelError("EINVAL", `ERR_INVALID_ARG_VALUE: ca: ${err.message}`);
22092
+ }
22093
+ }
22094
+ function flagsOf(req, store) {
22095
+ if (!req.requestCert) return 0;
22096
+ if (!store) throw new KernelError("EINVAL", "ERR_INVALID_ARG_VALUE: requestCert needs a ca");
22097
+ return req.rejectUnauthorized === false ? TLS_SERVER_REQUEST_CERT : TLS_SERVER_REQUIRE_CERT;
22098
+ }
22099
+ function timeoutOf(req) {
22100
+ const ms = req.handshakeTimeout ?? HANDSHAKE_TIMEOUT_MS;
22101
+ if (!Number.isInteger(ms) || ms <= 0)
22102
+ throw new KernelError(
22103
+ "EINVAL",
22104
+ "ERR_OUT_OF_RANGE: handshakeTimeout must be a positive integer"
22105
+ );
22106
+ return ms;
22107
+ }
22108
+ function handshakeSignal(proc, ms) {
22109
+ const timer = new AbortController();
22110
+ const id2 = setTimeout(
22111
+ () => timer.abort(new KernelError("EPROTO", "ERR_TLS_HANDSHAKE_TIMEOUT: TLS handshake timeout")),
22112
+ ms
22113
+ );
22114
+ return {
22115
+ signal: AbortSignal.any([handshakeAbort(proc), timer.signal]),
22116
+ done: () => clearTimeout(id2)
22117
+ };
22118
+ }
22119
+ async function serverOf(proc, req) {
22120
+ const own = req.cert;
22121
+ delete req.cert;
22122
+ if (!own) throw new KernelError("EINVAL", "ERR_INVALID_ARG_VALUE: a server needs cert and key");
22123
+ const cert = certBytes(own);
22124
+ let engine;
22125
+ try {
22126
+ engine = await supportOf(proc.net).engine();
22127
+ if (!engine.serverSessions)
22128
+ throw new KernelError("ENOTSUP", "the installed tls engine has no server sessions");
22129
+ } catch (err) {
22130
+ wipe(cert);
22131
+ throw err;
22132
+ }
22133
+ const leaf = leafOf(engine, cert);
22134
+ let store;
22135
+ try {
22136
+ store = req.ca && req.ca.length > 0 ? storeOf(engine, req.ca) : void 0;
22137
+ const flags2 = flagsOf(req, store);
22138
+ return {
22139
+ engine,
22140
+ leaf,
22141
+ store,
22142
+ alpn: req.alpn ?? [],
22143
+ flags: flags2,
22144
+ timeoutMs: timeoutOf(req),
22145
+ release() {
22146
+ leaf.release();
22147
+ store?.release();
22148
+ }
22149
+ };
22150
+ } catch (err) {
22151
+ leaf.release();
22152
+ store?.release();
22153
+ throw err;
22154
+ }
22155
+ }
22156
+ async function listenSecure(proc, socket, req) {
22157
+ if (!socket.listening) throw new KernelError("EINVAL", "not a listening socket");
22158
+ const server = await serverOf(proc, req);
22159
+ socket.serving?.release();
22160
+ socket.serving = server;
22161
+ }
22162
+ async function serveSecure(proc, socket, req) {
22163
+ const shared = req.listener?.serving;
22164
+ if (req.listener && !shared) throw new KernelError("EINVAL", "the listener has no tls");
22165
+ const server = shared ?? await serverOf(proc, req);
22166
+ try {
22167
+ const { engine, leaf, alpn, store, flags: flags2 } = server;
22168
+ const limit = handshakeSignal(proc, server.timeoutMs);
22169
+ const info = await socket.secureLink(
22170
+ (raw2) => tlsServer(raw2, engine.serverSession(leaf, alpn, store, flags2), flags2 !== 0),
22171
+ limit.signal
22172
+ ).finally(limit.done);
22173
+ return {
22174
+ path: "kernel",
22175
+ protocol: info.protocol,
22176
+ alpnProtocol: info.alpnProtocol,
22177
+ servername: info.servername,
22178
+ authorized: info.authorized,
22179
+ ...info.authorizationError ? { authorizationError: info.authorizationError } : {},
22180
+ peerCertificates: info.peerCertificates.map(encode)
22181
+ };
22182
+ } finally {
22183
+ if (!shared) server.release();
22184
+ }
22185
+ }
22186
+
21912
22187
  // src/kernel/unix-dgram.ts
21913
22188
  var SOL_SOCKET3 = 1;
21914
22189
  var SO_TYPE3 = 3;
@@ -22071,7 +22346,9 @@ var SOCKET_OPS = [
22071
22346
  "sock-sendto",
22072
22347
  "sock-recvfrom",
22073
22348
  "sock-tls",
22074
- "sock-tls-upgrade"
22349
+ "sock-tls-upgrade",
22350
+ "sock-tls-serve",
22351
+ "sock-tls-listen"
22075
22352
  ];
22076
22353
  function socketAt(fds, fd) {
22077
22354
  const file = anySocketAt(fds, fd);
@@ -22147,6 +22424,14 @@ async function socketSyscall(req, proc) {
22147
22424
  return ok3(await secureConnect(req, proc));
22148
22425
  case "sock-tls-upgrade":
22149
22426
  return ok3(await upgradeSecure(proc, socketAt(fds, req.fd), req));
22427
+ case "sock-tls-serve": {
22428
+ const { from, ...rest2 } = req;
22429
+ const listener = from === void 0 ? {} : { listener: socketAt(fds, from) };
22430
+ return ok3(await serveSecure(proc, socketAt(fds, req.fd), { ...rest2, ...listener }));
22431
+ }
22432
+ case "sock-tls-listen":
22433
+ await listenSecure(proc, socketAt(fds, req.fd), req);
22434
+ return ok3({});
22150
22435
  default:
22151
22436
  return datagram(req, proc);
22152
22437
  }
@@ -24578,6 +24863,7 @@ var WasmProcess = class {
24578
24863
  fds: this.fds,
24579
24864
  net: this.net,
24580
24865
  blocking: () => this.blockingSignal(cancelled),
24866
+ cancelled,
24581
24867
  resolve: (name2, family, blocking) => resolver.resolve(name2, family, blocking),
24582
24868
  cred: () => ({ pid: this.pid, uid: this.cred.euid, gid: this.cred.egid }),
24583
24869
  stamp: () => this.connectorStamp(),