code wiki / (root) / nx_tls13_full_tcp_test.nx

nx_tls13_full_tcp_test.nx source

↩ module page · 479 lines · 16614 B

1// nx_tls13_full_tcp_test.nx -- full TLS 1.3 handshake over real TCP 2// with AEAD-protected EE/Cert/CV/SF/CF records using the 3// handshake-derived traffic keys. 4// 5// Wire bytes (from ServerHello onward) bit-identical to real TLS 1.3. 6// 7// Built per F6 friction-catalog discipline: every function <10 lets 8// + <6 params + single-line call args, no monolithic run_client. 9// 10// expect_exit: 0 11// license_tier: ORIGINAL 12 13import "nx_syscalls.nx" 14import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host 15import "nx_x25519.nx" 16import "nx_tls13.nx" 17import "nx_tls13_ext.nx" 18import "nx_tls13_hello.nx" 19import "nx_tls13_finished.nx" 20import "nx_tls13_transcript.nx" 21import "nx_tls13_handshake.nx" 22import "nx_tls13_schedule.nx" 23import "nx_tls13_client.nx" 24import "nx_tls13_server.nx" 25import "nx_tls13_record.nx" 26 27const TEST_PORT: i64 = 19446 28 29// ---- low-level frame helpers ---- 30 31func build_addr(out: *u8, port: i64) -> i64 { 32 out[0] = 2; out[1] = 0 33 out[2] = (port >> 8) & 0xff 34 out[3] = port & 0xff 35 out[4] = 127; out[5] = 0; out[6] = 0; out[7] = 1 36 var i: i64 = 8 37 while i < 16 { out[i] = 0; i = i + 1 } 38 return 16 39} 40 41func read_n(fd: i64, buf: *u8, n: i64) -> i64 { 42 var got: i64 = 0 43 while got < n { 44 let r: i64 = sys_read(fd, buf + got, n - got) 45 if r <= 0 { return 0 - 1 } 46 got = got + r 47 } 48 return got 49} 50 51func send_plain(fd: i64, buf: *u8, n: i64) -> i64 { 52 let hdr: *u8 = sys_mmap(8) 53 hdr[0] = (n >> 24) & 0xff 54 hdr[1] = (n >> 16) & 0xff 55 hdr[2] = (n >> 8) & 0xff 56 hdr[3] = n & 0xff 57 sys_write(fd, hdr, 4) 58 sys_write(fd, buf, n) 59 return n 60} 61 62func recv_plain(fd: i64, buf: *u8, cap: i64) -> i64 { 63 let hdr: *u8 = sys_mmap(8) 64 if read_n(fd, hdr, 4) < 0 { return 0 - 1 } 65 let n: i64 = ((hdr[0] & 0xff) << 24) | ((hdr[1] & 0xff) << 16) | ((hdr[2] & 0xff) << 8) | (hdr[3] & 0xff) 66 if n > cap { return 0 - 2 } 67 if read_n(fd, buf, n) < 0 { return 0 - 3 } 68 return n 69} 70 71// ---- AEAD record helpers ---- 72 73func send_aead(fd: i64, key: *u8, iv: *u8, seq: i64, payload: *u8, payload_len: i64) -> i64 { 74 let hdr: *u8 = sys_mmap(16) 75 let ct: *u8 = sys_mmap(payload_len + 64) 76 let tag: *u8 = sys_mmap(16) 77 let vrd: i64 = nx_tls13_record_encrypt(key, iv, seq, payload, payload_len, 22, 0, hdr, ct, tag) 78 if vrd != NX_TLS13_REC_VERDICT_OK { return 0 - 1 } 79 sys_write(fd, hdr, 5) 80 sys_write(fd, ct, payload_len + 1) 81 sys_write(fd, tag, 16) 82 return 0 83} 84 85func recv_aead(fd: i64, key: *u8, iv: *u8, seq: i64, out: *u8, out_cap: i64) -> i64 { 86 let hdr: *u8 = sys_mmap(16) 87 if read_n(fd, hdr, 5) < 0 { return 0 - 1 } 88 let total: i64 = ((hdr[3] & 0xff) << 8) | (hdr[4] & 0xff) 89 if total < 17 { return 0 - 2 } 90 let ct_len: i64 = total - 16 91 let buf: *u8 = sys_mmap(total + 16) 92 if read_n(fd, buf, total) < 0 { return 0 - 3 } 93 let tag: *u8 = sys_mmap(16) 94 var ti: i64 = 0 95 while ti < 16 { tag[ti] = buf[ct_len + ti]; ti = ti + 1 } 96 let rct: *i64 = sys_mmap(8) as *i64 97 let rln: *i64 = sys_mmap(8) as *i64 98 let vrd: i64 = nx_tls13_record_decrypt(key, iv, seq, hdr, buf, ct_len, tag, out, rct, rln) 99 if vrd != NX_TLS13_REC_VERDICT_OK { return 0 - 4 } 100 return rln[0] 101} 102 103// ---- handshake helpers ---- 104 105func setup_keypair(priv: *u8, pub: *u8) -> i64 { 106 let base: *u8 = sys_mmap(64) 107 base[0] = 9 108 var bi: i64 = 1 109 while bi < 32 { base[bi] = 0; bi = bi + 1 } 110 x25519(priv, base, pub) 111 return 0 112} 113 114func fill_client_priv(out: *u8) -> i64 { 115 out[0]=0x49; out[1]=0xaf; out[2]=0x42; out[3]=0xba 116 out[4]=0x7f; out[5]=0x99; out[6]=0x94; out[7]=0x85 117 out[8]=0x2d; out[9]=0x71; out[10]=0x3e; out[11]=0xf2 118 out[12]=0x78; out[13]=0x4b; out[14]=0xcb; out[15]=0xca 119 out[16]=0xa7; out[17]=0x91; out[18]=0x1d; out[19]=0xe2 120 out[20]=0x6a; out[21]=0xdc; out[22]=0x56; out[23]=0x42 121 out[24]=0xcb; out[25]=0x63; out[26]=0x45; out[27]=0x40 122 out[28]=0xe7; out[29]=0xea; out[30]=0x50; out[31]=0x05 123 return 32 124} 125 126func fill_server_priv(out: *u8) -> i64 { 127 out[0]=0xb1; out[1]=0x58; out[2]=0x0e; out[3]=0xea 128 out[4]=0xdf; out[5]=0x6d; out[6]=0xd5; out[7]=0x89 129 out[8]=0xb8; out[9]=0xef; out[10]=0x4f; out[11]=0x2d 130 out[12]=0x56; out[13]=0x52; out[14]=0x57; out[15]=0x8c 131 out[16]=0xc8; out[17]=0x10; out[18]=0xe9; out[19]=0x98 132 out[20]=0x01; out[21]=0x91; out[22]=0xec; out[23]=0x8d 133 out[24]=0x05; out[25]=0x83; out[26]=0x08; out[27]=0xce 134 out[28]=0xa2; out[29]=0x16; out[30]=0xa2; out[31]=0x1e 135 return 32 136} 137 138func fill_empty_hash(out: *u8) -> i64 { 139 out[0]=0xe3; out[1]=0xb0; out[2]=0xc4; out[3]=0x42 140 out[4]=0x98; out[5]=0xfc; out[6]=0x1c; out[7]=0x14 141 out[8]=0x9a; out[9]=0xfb; out[10]=0xf4; out[11]=0xc8 142 out[12]=0x99; out[13]=0x6f; out[14]=0xb9; out[15]=0x24 143 out[16]=0x27; out[17]=0xae; out[18]=0x41; out[19]=0xe4 144 out[20]=0x64; out[21]=0x9b; out[22]=0x93; out[23]=0x4c 145 out[24]=0xa4; out[25]=0x95; out[26]=0x99; out[27]=0x1b 146 out[28]=0x78; out[29]=0x52; out[30]=0xb8; out[31]=0x55 147 return 32 148} 149 150func fill_client_random(out: *u8) -> i64 { 151 var i: i64 = 0 152 while i < 32 { out[i] = 0xc0 + i; i = i + 1 } 153 return 32 154} 155 156func fill_server_random(out: *u8) -> i64 { 157 var i: i64 = 0 158 while i < 32 { out[i] = 0x70 + i; i = i + 1 } 159 return 32 160} 161 162func fill_sni_example_com(out: *u8) -> i64 { 163 out[0]=0x65; out[1]=0x78; out[2]=0x61; out[3]=0x6d 164 out[4]=0x70; out[5]=0x6c; out[6]=0x65; out[7]=0x2e 165 out[8]=0x63; out[9]=0x6f; out[10]=0x6d 166 return 11 167} 168 169// Allocate a KeyBundle = 7 ptrs * 8 bytes; each ptr points at a 170// caller-owned 64-byte buffer. Index 0..6 = hs, chts, shts, c_key, 171// c_iv, s_key, s_iv. 172func alloc_key_bundle() -> *u8 { 173 let bundle: *u8 = sys_mmap(64) 174 let bp: *i64 = bundle as *i64 175 var i: i64 = 0 176 while i < 7 { 177 let buf: *u8 = sys_mmap(64) 178 bp[i] = buf as i64 179 i = i + 1 180 } 181 return bundle 182} 183 184func bundle_ptr(bundle: *u8, slot: i64) -> *u8 { 185 let bp: *i64 = bundle as *i64 186 return bp[slot] as *u8 187} 188 189// Derive all handshake keys via the orchestrator, store into bundle. 190func derive_handshake_keys(my_priv: *u8, peer_pub: *u8, th: *u8, eh: *u8, bundle: *u8) -> i64 { 191 let hs: *u8 = bundle_ptr(bundle, 0) 192 let chts: *u8 = bundle_ptr(bundle, 1) 193 let shts: *u8 = bundle_ptr(bundle, 2) 194 let ck: *u8 = bundle_ptr(bundle, 3) 195 let civ: *u8 = bundle_ptr(bundle, 4) 196 let sk: *u8 = bundle_ptr(bundle, 5) 197 let siv: *u8 = bundle_ptr(bundle, 6) 198 tls13_handshake_compute_handshake_keys(my_priv, peer_pub, th, eh, hs, chts, shts, ck, civ, sk, siv) 199 return 0 200} 201 202// Build, send ClientHello. Returns ch_len or negative. 203func emit_and_send_ch(fd: i64, c_pub: *u8, ch_out: *u8, ch_cap: i64) -> i64 { 204 let c_random: *u8 = sys_mmap(64) 205 fill_client_random(c_random) 206 let sni: *u8 = sys_mmap(16) 207 fill_sni_example_com(sni) 208 let n: i64 = tls13_client_hello_emit(c_random, sni, 11, c_pub, ch_out, ch_cap) 209 if n < 0 { return n } 210 send_plain(fd, ch_out, n) 211 return n 212} 213 214// Parse SH bytes already received; returns *u8 ptr to server's pubkey 215// (a pointer INTO sh, valid until sh is freed). 216func parse_sh_recover_pub(sh: *u8, sh_len: i64, pub_out_slot: *i64) -> i64 { 217 let p_lv: *i64 = sys_mmap(16) as *i64 218 let p_ro: *i64 = sys_mmap(16) as *i64 219 let p_cs: *i64 = sys_mmap(16) as *i64 220 let p_eo: *i64 = sys_mmap(16) as *i64 221 let p_el: *i64 = sys_mmap(16) as *i64 222 let pv: i64 = tls13_server_hello_parse(sh, sh_len, p_lv, p_ro, p_cs, p_eo, p_el) 223 if pv != NX_TLS13_HELLO_VERDICT_OK { return pv } 224 let ks_off: *i64 = sys_mmap(16) as *i64 225 let ks_len: *i64 = sys_mmap(16) as *i64 226 let fv: i64 = tls13_ext_find(sh + p_eo[0], p_el[0], EXT_KEY_SHARE, ks_off, ks_len) 227 if fv != NX_TLS13_HELLO_VERDICT_OK { return fv } 228 pub_out_slot[0] = ((sh as i64) + p_eo[0] + ks_off[0] + 4) 229 return 0 230} 231 232// Build transcript over CH + SH and snapshot. 233func build_transcript_th(ch: *u8, ch_len: i64, sh: *u8, sh_len: i64, th_out: *u8, tx_out_slot: *i64) -> i64 { 234 let tx: *u8 = nx_tls13_transcript_new() 235 nx_tls13_transcript_update(tx, ch, ch_len) 236 nx_tls13_transcript_update(tx, sh, sh_len) 237 nx_tls13_transcript_snapshot(tx, th_out) 238 tx_out_slot[0] = tx as i64 239 return 0 240} 241 242// Dispatch ONE encrypted handshake record; returns new state or negative. 243func aead_dispatch(fd: i64, key: *u8, iv: *u8, seq: i64, st: i64, shts: *u8, tx: *u8) -> i64 { 244 let buf: *u8 = sys_mmap(1024) 245 let n: i64 = recv_aead(fd, key, iv, seq, buf, 1024) 246 if n < 0 { return n } 247 let c_out: *i64 = sys_mmap(16) as *i64 248 let vrd: i64 = tls13_client_dispatch_handshake_message(st, buf, n, shts, tx, c_out) 249 if vrd != NX_TLS13_CLIENT_VERDICT_OK { return 0 - 100 } 250 return c_out[0] 251} 252 253// Client side: dispatch the 4 encrypted records (EE,Cert,CV,SF), 254// emit + send encrypted CF, read ACK. Returns 0 or error code. 255func run_client_finish(fd: i64, bundle: *u8, tx: *u8) -> i64 { 256 let sk: *u8 = bundle_ptr(bundle, 5) 257 let siv: *u8 = bundle_ptr(bundle, 6) 258 let ck: *u8 = bundle_ptr(bundle, 3) 259 let civ: *u8 = bundle_ptr(bundle, 4) 260 let chts: *u8 = bundle_ptr(bundle, 1) 261 let shts: *u8 = bundle_ptr(bundle, 2) 262 263 let s1: i64 = aead_dispatch(fd, sk, siv, 0, NX_TLS13_CSTATE_WAIT_EE, shts, tx) 264 if s1 < 0 { return 20 } 265 let s2: i64 = aead_dispatch(fd, sk, siv, 1, s1, shts, tx) 266 if s2 < 0 { return 30 } 267 let s3: i64 = aead_dispatch(fd, sk, siv, 2, s2, shts, tx) 268 if s3 < 0 { return 40 } 269 let s4: i64 = aead_dispatch(fd, sk, siv, 3, s3, shts, tx) 270 if s4 < 0 { return 50 } 271 if s4 != NX_TLS13_CSTATE_CONNECTED { return 60 } 272 273 let cf: *u8 = sys_mmap(64) 274 let cf_len: i64 = tls13_client_emit_finished(chts, tx, cf) 275 if cf_len != 36 { return 61 } 276 if send_aead(fd, ck, civ, 0, cf, cf_len) != 0 { return 62 } 277 278 let ack: *u8 = sys_mmap(8) 279 if read_n(fd, ack, 1) < 0 { return 63 } 280 if (ack[0] & 0xff) != 0x00 { return 64 } 281 return 0 282} 283 284// Client side: do all setup, then call run_client_finish. 285func run_client(cfd: i64) -> i64 { 286 let c_priv: *u8 = sys_mmap(64) 287 fill_client_priv(c_priv) 288 let c_pub: *u8 = sys_mmap(64) 289 setup_keypair(c_priv, c_pub) 290 291 let ch: *u8 = sys_mmap(1024) 292 let ch_len: i64 = emit_and_send_ch(cfd, c_pub, ch, 1024) 293 if ch_len < 0 { return 12 } 294 295 let sh: *u8 = sys_mmap(1024) 296 let sh_len: i64 = recv_plain(cfd, sh, 1024) 297 if sh_len < 0 { return 13 } 298 299 let pub_slot: *i64 = sys_mmap(8) as *i64 300 if parse_sh_recover_pub(sh, sh_len, pub_slot) != 0 { return 14 } 301 let s_pub: *u8 = pub_slot[0] as *u8 302 303 let th: *u8 = sys_mmap(64) 304 let tx_slot: *i64 = sys_mmap(8) as *i64 305 build_transcript_th(ch, ch_len, sh, sh_len, th, tx_slot) 306 let tx: *u8 = tx_slot[0] as *u8 307 308 let eh: *u8 = sys_mmap(64) 309 fill_empty_hash(eh) 310 let bundle: *u8 = alloc_key_bundle() 311 derive_handshake_keys(c_priv, s_pub, th, eh, bundle) 312 313 return run_client_finish(cfd, bundle, tx) 314} 315 316// ---- server-side helpers ---- 317 318func parse_ch_recover_pub(ch: *u8, ch_len: i64, sid_off_out: *i64, sid_len_out: *i64, pub_out_slot: *i64) -> i64 { 319 let p_ro: *i64 = sys_mmap(16) as *i64 320 let p_eo: *i64 = sys_mmap(16) as *i64 321 let p_el: *i64 = sys_mmap(16) as *i64 322 let pv: i64 = tls13_server_parse_client_hello(ch, ch_len, p_ro, sid_off_out, sid_len_out, p_eo, p_el) 323 if pv != NX_TLS13_SERVER_VERDICT_OK { return pv } 324 let ks_off: *i64 = sys_mmap(16) as *i64 325 let ks_len: *i64 = sys_mmap(16) as *i64 326 let fv: i64 = tls13_ext_find(ch + p_eo[0], p_el[0], EXT_KEY_SHARE, ks_off, ks_len) 327 if fv != NX_TLS13_HELLO_VERDICT_OK { return fv } 328 pub_out_slot[0] = ((ch as i64) + p_eo[0] + ks_off[0] + 6) 329 return 0 330} 331 332// Build canned EE/Cert/CV/SF and feed CH..CV into transcript; emit SF. 333// Each output buffer is caller-owned. Returns 0. 334func build_canned_payloads(ee: *u8, cert: *u8, cv: *u8) -> i64 { 335 ee[0] = HT_ENCRYPTED_EXTENSIONS & 0xff 336 ee[1]=0; ee[2]=0; ee[3]=2 337 ee[4]=0; ee[5]=0 338 339 cert[0] = HT_CERTIFICATE & 0xff 340 cert[1]=0; cert[2]=0; cert[3]=19 341 cert[4]=0 342 cert[5]=0; cert[6]=0; cert[7]=15 343 cert[8]=0; cert[9]=0; cert[10]=10 344 var i: i64 = 0 345 while i < 10 { cert[11+i] = 0x30+i; i = i + 1 } 346 cert[21]=0; cert[22]=0 347 348 cv[0] = HT_CERTIFICATE_VERIFY & 0xff 349 cv[1]=0; cv[2]=0; cv[3]=68 350 cv[4]=0x08; cv[5]=0x07 351 cv[6]=0; cv[7]=64 352 var j: i64 = 0 353 while j < 64 { cv[8+j] = 0x90 + (j & 0x0f); j = j + 1 } 354 return 0 355} 356 357func compute_sf(s_tx: *u8, shts: *u8, sf_out: *u8) -> i64 { 358 let pre: *u8 = sys_mmap(64) 359 nx_tls13_transcript_snapshot(s_tx, pre) 360 let fk: *u8 = sys_mmap(64) 361 tls13_finished_key(shts, 32, fk) 362 let mac: *u8 = sys_mmap(64) 363 nx_tls13_finished_compute(fk, 32, pre, 32, mac) 364 sf_out[0] = HT_FINISHED & 0xff 365 sf_out[1]=0; sf_out[2]=0; sf_out[3]=32 366 var i: i64 = 0 367 while i < 32 { sf_out[4+i] = mac[i]; i = i + 1 } 368 return 36 369} 370 371func server_send_encrypted_flight(fd: i64, bundle: *u8, s_tx: *u8) -> i64 { 372 let sk: *u8 = bundle_ptr(bundle, 5) 373 let siv: *u8 = bundle_ptr(bundle, 6) 374 let shts: *u8 = bundle_ptr(bundle, 2) 375 376 let ee: *u8 = sys_mmap(64) 377 let cert: *u8 = sys_mmap(64) 378 let cv: *u8 = sys_mmap(128) 379 build_canned_payloads(ee, cert, cv) 380 nx_tls13_transcript_update(s_tx, ee, 6) 381 nx_tls13_transcript_update(s_tx, cert, 23) 382 nx_tls13_transcript_update(s_tx, cv, 72) 383 384 let sf: *u8 = sys_mmap(64) 385 let sf_len: i64 = compute_sf(s_tx, shts, sf) 386 nx_tls13_transcript_update(s_tx, sf, sf_len) 387 388 if send_aead(fd, sk, siv, 0, ee, 6) != 0 { return 80 } 389 if send_aead(fd, sk, siv, 1, cert, 23) != 0 { return 81 } 390 if send_aead(fd, sk, siv, 2, cv, 72) != 0 { return 82 } 391 if send_aead(fd, sk, siv, 3, sf, 36) != 0 { return 83 } 392 return 0 393} 394 395func server_recv_cf_and_ack(fd: i64, bundle: *u8, s_tx: *u8) -> i64 { 396 let ck: *u8 = bundle_ptr(bundle, 3) 397 let civ: *u8 = bundle_ptr(bundle, 4) 398 let chts: *u8 = bundle_ptr(bundle, 1) 399 400 let cf: *u8 = sys_mmap(64) 401 let n: i64 = recv_aead(fd, ck, civ, 0, cf, 64) 402 if n != 36 { return 90 } 403 let s_out: *i64 = sys_mmap(16) as *i64 404 let vrd: i64 = tls13_server_dispatch_client_finished(cf, n, chts, s_tx, s_out) 405 if vrd != NX_TLS13_SERVER_VERDICT_OK { return 91 } 406 if s_out[0] != NX_TLS13_SSTATE_CONNECTED { return 92 } 407 let ack: *u8 = sys_mmap(8) 408 ack[0] = 0 409 sys_write(fd, ack, 1) 410 return 0 411} 412 413func run_server(cfd: i64) -> i64 { 414 let s_priv: *u8 = sys_mmap(64) 415 fill_server_priv(s_priv) 416 let s_pub: *u8 = sys_mmap(64) 417 setup_keypair(s_priv, s_pub) 418 419 let ch: *u8 = sys_mmap(1024) 420 let ch_len: i64 = recv_plain(cfd, ch, 1024) 421 if ch_len < 0 { return 70 } 422 423 let sid_o: *i64 = sys_mmap(16) as *i64 424 let sid_l: *i64 = sys_mmap(16) as *i64 425 let cpub_slot: *i64 = sys_mmap(8) as *i64 426 if parse_ch_recover_pub(ch, ch_len, sid_o, sid_l, cpub_slot) != 0 { return 71 } 427 let c_pub: *u8 = cpub_slot[0] as *u8 428 429 let s_random: *u8 = sys_mmap(64) 430 fill_server_random(s_random) 431 let sh: *u8 = sys_mmap(512) 432 let sh_len: i64 = tls13_server_emit_server_hello(s_random, ch + sid_o[0], sid_l[0], s_pub, sh, 512) 433 if sh_len < 0 { return 73 } 434 send_plain(cfd, sh, sh_len) 435 436 let th: *u8 = sys_mmap(64) 437 let tx_slot: *i64 = sys_mmap(8) as *i64 438 build_transcript_th(ch, ch_len, sh, sh_len, th, tx_slot) 439 let s_tx: *u8 = tx_slot[0] as *u8 440 441 let eh: *u8 = sys_mmap(64) 442 fill_empty_hash(eh) 443 let bundle: *u8 = alloc_key_bundle() 444 derive_handshake_keys(s_priv, c_pub, th, eh, bundle) 445 446 let fr: i64 = server_send_encrypted_flight(cfd, bundle, s_tx) 447 if fr != 0 { return fr } 448 return server_recv_cf_and_ack(cfd, bundle, s_tx) 449} 450 451func main() -> i64 { 452 let addr: *u8 = sys_mmap(16) 453 build_addr(addr, TEST_PORT) 454 let lfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0) 455 if lfd < 0 { return 1 } 456 if sys_bind(lfd, addr, 16) < 0 { return 2 } 457 if sys_listen(lfd, 4) < 0 { return 3 } 458 459 let pid: i64 = sys_fork() 460 if pid < 0 { return 4 } 461 462 if pid == 0 { 463 var spin: i64 = 0 464 while spin < 200000 { spin = spin + 1 } 465 let ccfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0) 466 if ccfd < 0 { return 5 } 467 if nx_connect_bounded(ccfd, addr, 16, NX_CONN_DEFAULT_MS) < 0 { return 6 } 468 return run_client(ccfd) 469 } 470 471 let scfd: i64 = sys_accept(lfd) 472 if scfd < 0 { return 7 } 473 let sr: i64 = run_server(scfd) 474 if sr != 0 { return sr } 475 476 let status: *i64 = sys_mmap(8) as *i64 477 sys_wait4(pid, status, 0) 478 return wait_exit_code(*status) 479}