Nothing to see here, move along
at main 914 lines 32 kB view raw
1#![no_std] 2#![no_main] 3 4mod rng; 5mod ssh; 6 7use lancer_core::ipc::{MAX_IPC_BYTES, unpack_bytes}; 8use lancer_core::packet_ring::{PacketRingReader, PacketRingWriter}; 9use lancer_user::path; 10use lancer_user::syscall; 11use ssh::{SshProgress, SshSession}; 12 13const SHELL_RING_BASE_SLOT: u64 = 64; 14const SHELL_RING_FRAME_COUNT: u64 = 4; 15const OWN_NOTIF_SLOT: u64 = 3; 16const NETSTACK_NOTIF_SLOT: u64 = 4; 17 18const MAX_SESSIONS: usize = 4; 19 20const TAG_ENDPOINT: u64 = 1; 21const TAG_NOTIFICATION: u64 = 2; 22const TAG_SCHED_CONTEXT: u64 = 5; 23const TAG_FRAME: u64 = 11; 24const RIGHTS_ALL: u64 = 0b1111; 25 26const SLOT_UNTYPED: u64 = 28; 27 28const VFS_RING_BASE: u64 = 128; 29const VFS_RING_FRAMES: u64 = 16; 30const VFS_CLIENT_NOTIF_SLOT: u64 = 12; 31const VFS_NOTIF_SLOT: u64 = 13; 32const VFS_PROC_SLOT: u64 = 15; 33 34const BOOT_MODULE_COUNT: u64 = 7; 35 36const RING_BASE: u64 = 0x4000_0000; 37const RING_HALF: usize = 8192; 38 39const MSG_DATA: u8 = 0; 40const MSG_CONNECT: u8 = 1; 41const MSG_DISCONNECT: u8 = 2; 42const MSG_DNS_RESULT: u8 = 4; 43const MSG_PING_RESULT: u8 = 6; 44const MSG_PING_DONE: u8 = 7; 45const MSG_UDP_RECV: u8 = 10; 46const MSG_UDP_CLOSE: u8 = 11; 47const MSG_UDP_BOUND: u8 = 12; 48const MSG_DNS_RESULT6: u8 = 14; 49const MSG_IFCONFIG_RESULT: u8 = 17; 50const MSG_ARP_ENTRY: u8 = 19; 51const MSG_ARP_DONE: u8 = 20; 52const MSG_NETSTAT_ENTRY: u8 = 22; 53const MSG_NETSTAT_ENTRY_UDP: u8 = 23; 54const MSG_NETSTAT_DONE: u8 = 24; 55 56const IDLE_TIMEOUT_MS: i64 = 300_000; 57const NOTIFY_BIT_SHELL_DEATH_BASE: u64 = 0x10; 58const NOTIFY_BIT_SHELL_NETSOCK: u64 = 0x04; 59 60const INPUT_RING_PAGES: u64 = 1; 61const INPUT_RING_SIZE: usize = 4096; 62const INPUT_RING_SLOT_SIZE: u32 = 64; 63 64const NETSOCK_RING_PAGES: u64 = 2; 65const NETSOCK_RING_HALF: usize = 4096; 66const NETSOCK_RING_SLOT_SIZE: u32 = 128; 67 68static mut SSH_INBUFS: [[u8; 35000]; MAX_SESSIONS] = [[0u8; 35000]; MAX_SESSIONS]; 69static mut SSH_OUTBUFS: [[u8; 35000]; MAX_SESSIONS] = [[0u8; 35000]; MAX_SESSIONS]; 70 71fn slot_proc(i: usize) -> u64 { 72 30 + i as u64 * 7 73} 74fn slot_sched(i: usize) -> u64 { 75 31 + i as u64 * 7 76} 77fn slot_output_ep(i: usize) -> u64 { 78 32 + i as u64 * 7 79} 80fn slot_input_ring_mem(i: usize) -> u64 { 81 33 + i as u64 * 7 82} 83fn slot_netsock_mem(i: usize) -> u64 { 84 34 + i as u64 * 7 85} 86fn slot_shell_notif(i: usize) -> u64 { 87 36 + i as u64 * 7 88} 89 90fn input_ring_vaddr(i: usize) -> u64 { 91 0x7000_0000 + i as u64 * 0x1000 92} 93fn netsock_ring_vaddr(i: usize) -> u64 { 94 0x8000_0000 + i as u64 * 0x2000 95} 96 97struct Session<'a> { 98 ssh: Option<SshSession<'a>>, 99 shell_running: bool, 100 input_tx: Option<PacketRingWriter>, 101 netsock_tx: Option<PacketRingWriter>, 102 netsock_rx: Option<PacketRingReader>, 103 last_activity_ms: i64, 104} 105 106impl<'a> Session<'a> { 107 const fn new() -> Self { 108 Self { 109 ssh: None, 110 shell_running: false, 111 input_tx: None, 112 netsock_tx: None, 113 netsock_rx: None, 114 last_activity_ms: 0, 115 } 116 } 117} 118 119fn find_module_by_name(name: &[u8]) -> Option<u64> { 120 let mut dummy = [0u8; 0]; 121 let total = syscall::module_info(u64::MAX, &mut dummy); 122 if total < 0 { 123 return None; 124 } 125 126 let mut path_buf = [0u8; 128]; 127 (BOOT_MODULE_COUNT..total as u64).find(|&i| { 128 path_buf = [0u8; 128]; 129 let path_len = syscall::module_info(i, &mut path_buf); 130 match path_len < 0 { 131 true => false, 132 false => { 133 let used = (path_len as usize).min(path_buf.len()); 134 path::bytes_eq(path::extract_filename(&path_buf[..used]), name) 135 } 136 } 137 }) 138} 139 140fn send_ssh_bytes(ssh: &mut SshSession, tx: &PacketRingWriter, conn_id: u8, data: &[u8]) { 141 let mut offset = 0usize; 142 core::iter::from_fn(|| match offset < data.len() { 143 true => { 144 let written = ssh.write_plaintext(&data[offset..]); 145 offset += written; 146 flush_ssh_output(ssh, tx, conn_id); 147 Some(()) 148 } 149 false => None, 150 }) 151 .take(64) 152 .count(); 153} 154 155fn flush_ssh_output(ssh: &mut SshSession, tx: &PacketRingWriter, conn_id: u8) -> bool { 156 let mut flushed = false; 157 let mut tmp = [0u8; 126]; 158 core::iter::from_fn(|| { 159 let n = ssh.peek_output(&mut tmp[2..]); 160 match n > 0 { 161 true => { 162 tmp[0] = conn_id; 163 tmp[1] = MSG_DATA; 164 match tx.try_push(&tmp[..2 + n]) { 165 true => { 166 ssh.consume_output(n); 167 flushed = true; 168 Some(()) 169 } 170 false => None, 171 } 172 } 173 false => None, 174 } 175 }) 176 .take(32) 177 .count(); 178 if flushed { 179 syscall::notify_signal(NETSTACK_NOTIF_SLOT, 4); 180 } 181 flushed 182} 183 184fn drive_ssh(ssh: &mut SshSession, tx: &PacketRingWriter, conn_id: u8) -> bool { 185 let mut any_flushed = false; 186 let mut keep_going = true; 187 core::iter::from_fn(|| match keep_going { 188 true => { 189 any_flushed |= flush_ssh_output(ssh, tx, conn_id); 190 let r = ssh.progress(); 191 any_flushed |= flush_ssh_output(ssh, tx, conn_id); 192 match r { 193 SshProgress::Continue => Some(()), 194 SshProgress::ShellReady => { 195 any_flushed = true; 196 None 197 } 198 SshProgress::Idle => { 199 keep_going = false; 200 None 201 } 202 SshProgress::Disconnected => { 203 keep_going = false; 204 None 205 } 206 } 207 } 208 false => None, 209 }) 210 .take(128) 211 .count(); 212 any_flushed 213} 214 215fn spawn_shell(conn_id: usize, module_idx: u64, session: &mut Session) -> bool { 216 let proc_slot = slot_proc(conn_id); 217 let sched_slot = slot_sched(conn_id); 218 let output_ep = slot_output_ep(conn_id); 219 let input_mem = slot_input_ring_mem(conn_id); 220 let netsock_mem = slot_netsock_mem(conn_id); 221 let shell_notif = slot_shell_notif(conn_id); 222 223 let r = syscall::untyped_retype(SLOT_UNTYPED, TAG_ENDPOINT, 0, output_ep, 1); 224 if r < 0 { 225 return false; 226 } 227 228 let child_pid = syscall::proc_create(proc_slot); 229 if child_pid < 0 { 230 syscall::cap_revoke(output_ep); 231 return false; 232 } 233 234 let r = syscall::proc_load_module(proc_slot, module_idx); 235 if r < 0 { 236 syscall::proc_destroy(proc_slot); 237 syscall::cap_revoke(output_ep); 238 return false; 239 } 240 241 let r = syscall::cap_grant(output_ep, proc_slot, 2, RIGHTS_ALL); 242 if r < 0 { 243 syscall::proc_destroy(proc_slot); 244 syscall::cap_revoke(output_ep); 245 return false; 246 } 247 248 let r = syscall::untyped_retype(SLOT_UNTYPED, TAG_FRAME, 0, input_mem, INPUT_RING_PAGES); 249 if r < 0 { 250 syscall::proc_destroy(proc_slot); 251 syscall::cap_revoke(output_ep); 252 return false; 253 } 254 let ir_vaddr = input_ring_vaddr(conn_id); 255 let map_ok = (0..INPUT_RING_PAGES).all(|i| { 256 syscall::frame_map(input_mem + i, ir_vaddr + i * 4096, 1) >= 0 257 }); 258 if !map_ok { 259 (0..INPUT_RING_PAGES).for_each(|i| { 260 syscall::frame_unmap(input_mem + i, ir_vaddr + i * 4096); 261 }); 262 (0..INPUT_RING_PAGES).for_each(|i| { 263 syscall::cap_revoke(input_mem + i); 264 }); 265 syscall::proc_destroy(proc_slot); 266 syscall::cap_revoke(output_ep); 267 return false; 268 } 269 let input_tx = unsafe { 270 PacketRingWriter::init(ir_vaddr as *mut u8, INPUT_RING_SIZE, INPUT_RING_SLOT_SIZE) 271 }; 272 let r = syscall::cap_grant(input_mem, proc_slot, 1, RIGHTS_ALL); 273 if r < 0 { 274 (0..INPUT_RING_PAGES).for_each(|i| { 275 syscall::frame_unmap(input_mem + i, ir_vaddr + i * 4096); 276 }); 277 (0..INPUT_RING_PAGES).for_each(|i| { 278 syscall::cap_revoke(input_mem + i); 279 }); 280 syscall::proc_destroy(proc_slot); 281 syscall::cap_revoke(output_ep); 282 return false; 283 } 284 285 let r = syscall::untyped_retype(SLOT_UNTYPED, TAG_FRAME, 0, netsock_mem, NETSOCK_RING_PAGES); 286 if r < 0 { 287 (0..INPUT_RING_PAGES).for_each(|i| { 288 syscall::frame_unmap(input_mem + i, ir_vaddr + i * 4096); 289 }); 290 (0..INPUT_RING_PAGES).for_each(|i| { 291 syscall::cap_revoke(input_mem + i); 292 }); 293 syscall::proc_destroy(proc_slot); 294 syscall::cap_revoke(output_ep); 295 return false; 296 } 297 let ns_vaddr = netsock_ring_vaddr(conn_id); 298 let ns_map_ok = (0..NETSOCK_RING_PAGES).all(|i| { 299 syscall::frame_map(netsock_mem + i, ns_vaddr + i * 4096, 1) >= 0 300 }); 301 if !ns_map_ok { 302 (0..NETSOCK_RING_PAGES).for_each(|i| { 303 syscall::frame_unmap(netsock_mem + i, ns_vaddr + i * 4096); 304 }); 305 (0..NETSOCK_RING_PAGES).for_each(|i| { 306 syscall::cap_revoke(netsock_mem + i); 307 }); 308 (0..INPUT_RING_PAGES).for_each(|i| { 309 syscall::frame_unmap(input_mem + i, ir_vaddr + i * 4096); 310 }); 311 (0..INPUT_RING_PAGES).for_each(|i| { 312 syscall::cap_revoke(input_mem + i); 313 }); 314 syscall::proc_destroy(proc_slot); 315 syscall::cap_revoke(output_ep); 316 return false; 317 } 318 let netsock_tx = unsafe { 319 PacketRingWriter::init( 320 ns_vaddr as *mut u8, 321 NETSOCK_RING_HALF, 322 NETSOCK_RING_SLOT_SIZE, 323 ) 324 }; 325 let _ = unsafe { 326 PacketRingWriter::init( 327 (ns_vaddr + NETSOCK_RING_HALF as u64) as *mut u8, 328 NETSOCK_RING_HALF, 329 NETSOCK_RING_SLOT_SIZE, 330 ) 331 }; 332 let netsock_rx = unsafe { 333 PacketRingReader::attach( 334 (ns_vaddr + NETSOCK_RING_HALF as u64) as *mut u8, 335 NETSOCK_RING_HALF, 336 ) 337 }; 338 let netsock_grant_ok = (0..NETSOCK_RING_PAGES).all(|i| { 339 syscall::cap_grant(netsock_mem + i, proc_slot, 3 + i, RIGHTS_ALL) >= 0 340 }); 341 if !netsock_grant_ok { 342 (0..NETSOCK_RING_PAGES).for_each(|i| { 343 syscall::frame_unmap(netsock_mem + i, ns_vaddr + i * 4096); 344 }); 345 (0..NETSOCK_RING_PAGES).for_each(|i| { 346 syscall::cap_revoke(netsock_mem + i); 347 }); 348 (0..INPUT_RING_PAGES).for_each(|i| { 349 syscall::frame_unmap(input_mem + i, ir_vaddr + i * 4096); 350 }); 351 (0..INPUT_RING_PAGES).for_each(|i| { 352 syscall::cap_revoke(input_mem + i); 353 }); 354 syscall::proc_destroy(proc_slot); 355 syscall::cap_revoke(output_ep); 356 return false; 357 } 358 359 let r = syscall::untyped_retype(SLOT_UNTYPED, TAG_NOTIFICATION, 0, shell_notif, 1); 360 if r < 0 { 361 (0..NETSOCK_RING_PAGES).for_each(|i| { 362 syscall::frame_unmap(netsock_mem + i, ns_vaddr + i * 4096); 363 }); 364 (0..NETSOCK_RING_PAGES).for_each(|i| { 365 syscall::cap_revoke(netsock_mem + i); 366 }); 367 (0..INPUT_RING_PAGES).for_each(|i| { 368 syscall::frame_unmap(input_mem + i, ir_vaddr + i * 4096); 369 }); 370 (0..INPUT_RING_PAGES).for_each(|i| { 371 syscall::cap_revoke(input_mem + i); 372 }); 373 syscall::proc_destroy(proc_slot); 374 syscall::cap_revoke(output_ep); 375 return false; 376 } 377 let r = syscall::cap_grant(shell_notif, proc_slot, 9, RIGHTS_ALL); 378 if r < 0 { 379 syscall::cap_revoke(shell_notif); 380 (0..NETSOCK_RING_PAGES).for_each(|i| { 381 syscall::frame_unmap(netsock_mem + i, ns_vaddr + i * 4096); 382 }); 383 (0..NETSOCK_RING_PAGES).for_each(|i| { 384 syscall::cap_revoke(netsock_mem + i); 385 }); 386 (0..INPUT_RING_PAGES).for_each(|i| { 387 syscall::frame_unmap(input_mem + i, ir_vaddr + i * 4096); 388 }); 389 (0..INPUT_RING_PAGES).for_each(|i| { 390 syscall::cap_revoke(input_mem + i); 391 }); 392 syscall::proc_destroy(proc_slot); 393 syscall::cap_revoke(output_ep); 394 return false; 395 } 396 397 let _ = syscall::cap_grant(OWN_NOTIF_SLOT, proc_slot, 10, 0b0010); 398 399 (0..VFS_RING_FRAMES).for_each(|i| { 400 let _ = syscall::cap_grant(VFS_RING_BASE + i, proc_slot, 11 + i, RIGHTS_ALL); 401 }); 402 [ 403 (VFS_CLIENT_NOTIF_SLOT, 28u64), 404 (VFS_NOTIF_SLOT, 29), 405 (VFS_PROC_SLOT, 15), 406 ] 407 .iter() 408 .for_each(|&(src, dst)| { 409 let _ = syscall::cap_grant(src, proc_slot, dst, RIGHTS_ALL); 410 }); 411 412 let death_badge = NOTIFY_BIT_SHELL_DEATH_BASE << conn_id as u64; 413 syscall::proc_bind_death_notif(proc_slot, OWN_NOTIF_SLOT, death_badge); 414 415 let r = syscall::untyped_retype(SLOT_UNTYPED, TAG_SCHED_CONTEXT, 0, sched_slot, 1); 416 if r < 0 { 417 cleanup_shell_caps(conn_id); 418 return false; 419 } 420 421 let r = syscall::sched_configure(sched_slot, 10_000_000, 10_000_000, 100); 422 if r < 0 { 423 cleanup_shell_caps(conn_id); 424 return false; 425 } 426 427 let r = syscall::sched_attach(sched_slot, child_pid as u64); 428 if r < 0 { 429 cleanup_shell_caps(conn_id); 430 return false; 431 } 432 433 let r = syscall::proc_start(proc_slot, 2); 434 if r < 0 { 435 cleanup_shell_caps(conn_id); 436 return false; 437 } 438 439 syscall::notify_signal(VFS_CLIENT_NOTIF_SLOT, 1); 440 441 session.shell_running = true; 442 session.input_tx = Some(input_tx); 443 session.netsock_tx = Some(netsock_tx); 444 session.netsock_rx = Some(netsock_rx); 445 446 true 447} 448 449fn cleanup_shell_caps(conn_id: usize) { 450 let ir_vaddr = input_ring_vaddr(conn_id); 451 let ns_vaddr = netsock_ring_vaddr(conn_id); 452 let input_mem = slot_input_ring_mem(conn_id); 453 let netsock_mem = slot_netsock_mem(conn_id); 454 455 (0..INPUT_RING_PAGES).for_each(|i| { 456 syscall::frame_unmap(input_mem + i, ir_vaddr + i * 4096); 457 }); 458 (0..INPUT_RING_PAGES).for_each(|i| { 459 syscall::cap_revoke(input_mem + i); 460 }); 461 462 (0..NETSOCK_RING_PAGES).for_each(|i| { 463 syscall::frame_unmap(netsock_mem + i, ns_vaddr + i * 4096); 464 }); 465 (0..NETSOCK_RING_PAGES).for_each(|i| { 466 syscall::cap_revoke(netsock_mem + i); 467 }); 468 469 syscall::cap_revoke(slot_shell_notif(conn_id)); 470 syscall::cap_revoke(slot_sched(conn_id)); 471 syscall::cap_revoke(slot_output_ep(conn_id)); 472} 473 474fn drain_shell_output(conn_id: usize, ssh: &mut SshSession, tx: &PacketRingWriter) -> bool { 475 let ep_slot = slot_output_ep(conn_id); 476 let cid = conn_id as u8; 477 let mut ipc_raw = [0u8; MAX_IPC_BYTES]; 478 let mut had_data = false; 479 480 core::iter::from_fn(|| { 481 let (status, msg) = syscall::nb_recv(ep_slot); 482 match status >= 0 { 483 true => { 484 let count = unpack_bytes(&msg, &mut ipc_raw); 485 const _: () = assert!(MAX_IPC_BYTES * 2 <= 80); 486 if count > 0 { 487 had_data = true; 488 let mut translated = [0u8; MAX_IPC_BYTES * 2]; 489 let tlen = (0..count).fold(0usize, |pos, i| match ipc_raw[i] { 490 b'\n' => { 491 translated[pos] = b'\r'; 492 translated[pos + 1] = b'\n'; 493 pos + 2 494 } 495 b => { 496 translated[pos] = b; 497 pos + 1 498 } 499 }); 500 send_ssh_bytes(ssh, tx, cid, &translated[..tlen]); 501 } 502 Some(()) 503 } 504 false => None, 505 } 506 }) 507 .take(64) 508 .count(); 509 had_data 510} 511 512fn drain_shell_netsock( 513 conn_id: usize, 514 netsock_rx: &PacketRingReader, 515 netstack_tx: &PacketRingWriter, 516) -> bool { 517 let cid = conn_id as u8; 518 let mut buf = [0u8; 128]; 519 let mut relayed = false; 520 521 core::iter::from_fn(|| match netsock_rx.try_pop(&mut buf) { 522 Some(n) if n > 0 => { 523 buf[0] = cid; 524 match netstack_tx.try_push(&buf[..n]) { 525 true => { 526 relayed = true; 527 Some(()) 528 } 529 false => None, 530 } 531 } 532 _ => None, 533 }) 534 .take(16) 535 .count(); 536 537 relayed 538} 539 540fn relay_netstack_to_shell(netsock_tx: &PacketRingWriter, data: &[u8], shell_notif: u64) { 541 let mut buf = [0u8; 128]; 542 let copy_len = data.len().min(buf.len() - 1); 543 buf[0] = 0; 544 buf[1..1 + copy_len].copy_from_slice(&data[..copy_len]); 545 if netsock_tx.try_push(&buf[..1 + copy_len]) { 546 syscall::notify_signal(shell_notif, 4); 547 } 548} 549 550fn teardown_session(conn_id: usize, session: &mut Session, tx: &PacketRingWriter) { 551 if session.shell_running { 552 syscall::proc_destroy(slot_proc(conn_id)); 553 cleanup_shell_caps(conn_id); 554 session.shell_running = false; 555 session.input_tx = None; 556 session.netsock_tx = None; 557 session.netsock_rx = None; 558 } 559 if let Some(ssh) = session.ssh.as_mut() { 560 ssh.close(); 561 } 562 let ctrl = [conn_id as u8, MSG_DISCONNECT]; 563 let _ = tx.try_push(&ctrl); 564 drop(session.ssh.take()); 565} 566 567#[unsafe(no_mangle)] 568pub extern "C" fn lancer_main() -> ! { 569 lancer_user::show!(rsh, "starting"); 570 571 if !(0..SHELL_RING_FRAME_COUNT).all(|i| syscall::frame_map(SHELL_RING_BASE_SLOT + i, RING_BASE + i * 4096, 1) >= 0) { 572 lancer_user::show!(rsh, error, "ring frame_map failed"); 573 syscall::exit(); 574 } 575 576 let rx_base = RING_BASE as *mut u8; 577 let tx_base = (RING_BASE + RING_HALF as u64) as *mut u8; 578 579 let rx = unsafe { PacketRingReader::attach(rx_base, RING_HALF) }; 580 let tx = unsafe { PacketRingWriter::init(tx_base, RING_HALF, 128) }; 581 582 let host_key = match sunset::SignKey::generate(sunset::KeyType::Ed25519, None) { 583 Ok(k) => k, 584 Err(_) => { 585 lancer_user::show!(rsh, error, "keygen failed"); 586 syscall::exit(); 587 } 588 }; 589 590 let shell_module_idx = find_module_by_name(b"shell"); 591 match shell_module_idx { 592 Some(_) => lancer_user::show!(rsh, "shell module found"), 593 None => lancer_user::show!(rsh, warn, "shell module not found"), 594 } 595 596 lancer_user::show!(rsh, "ready"); 597 598 let mut sessions: [Session; MAX_SESSIONS] = [ 599 Session::new(), 600 Session::new(), 601 Session::new(), 602 Session::new(), 603 ]; 604 let mut pop_buf = [0u8; 128]; 605 let mut plaintext_buf = [0u8; 256]; 606 607 syscall::ntfn_bind(OWN_NOTIF_SLOT); 608 609 loop { 610 let active_shell = (0..MAX_SESSIONS).find(|&i| sessions[i].shell_running); 611 let mut any_output = false; 612 613 let bits = match active_shell { 614 Some(cid) => { 615 let (status, msg) = syscall::recv(slot_output_ep(cid)); 616 match status == syscall::BOUND_NOTIFICATION_BADGE { 617 true => msg[1], 618 false => { 619 if status >= 0 { 620 let Session { ref mut ssh, .. } = sessions[cid]; 621 if let Some(ssh) = ssh.as_mut() { 622 let mut ipc_raw = [0u8; MAX_IPC_BYTES]; 623 let count = unpack_bytes(&msg, &mut ipc_raw); 624 if count > 0 { 625 let mut translated = [0u8; MAX_IPC_BYTES * 2]; 626 let tlen = (0..count).fold(0usize, |pos, i| match ipc_raw[i] { 627 b'\n' => { 628 translated[pos] = b'\r'; 629 translated[pos + 1] = b'\n'; 630 pos + 2 631 } 632 b => { 633 translated[pos] = b; 634 pos + 1 635 } 636 }); 637 send_ssh_bytes(ssh, &tx, cid as u8, &translated[..tlen]); 638 any_output = true; 639 } 640 } 641 } 642 let (_, poll_bits) = syscall::notify_poll(OWN_NOTIF_SLOT); 643 poll_bits 644 } 645 } 646 } 647 None => { 648 let (_, wait_bits) = syscall::notify_wait(OWN_NOTIF_SLOT); 649 wait_bits 650 } 651 }; 652 653 let now_ms = syscall::clock_monotonic_ms().max(0); 654 655 (0..MAX_SESSIONS).for_each(|i| { 656 let death_bit = NOTIFY_BIT_SHELL_DEATH_BASE << i as u64; 657 if bits & death_bit == 0 || !sessions[i].shell_running { 658 return; 659 } 660 661 if let Some(ssh) = sessions[i].ssh.as_mut() { 662 drain_shell_output(i, ssh, &tx); 663 } 664 syscall::proc_destroy(slot_proc(i)); 665 cleanup_shell_caps(i); 666 sessions[i].shell_running = false; 667 sessions[i].input_tx = None; 668 sessions[i].netsock_tx = None; 669 sessions[i].netsock_rx = None; 670 any_output = true; 671 672 if let Some(ssh) = sessions[i].ssh.as_mut() { 673 ssh.close(); 674 } 675 let ctrl = [i as u8, MSG_DISCONNECT]; 676 let _ = tx.try_push(&ctrl); 677 drop(sessions[i].ssh.take()); 678 }); 679 680 if bits & NOTIFY_BIT_SHELL_NETSOCK != 0 { 681 (0..MAX_SESSIONS).for_each(|i| { 682 if let Some(ref netsock_rx) = sessions[i].netsock_rx { 683 let relayed = drain_shell_netsock(i, netsock_rx, &tx); 684 if relayed { 685 syscall::notify_signal(NETSTACK_NOTIF_SLOT, 4); 686 any_output = true; 687 } 688 } 689 }); 690 } 691 692 (0..MAX_SESSIONS).for_each(|i| { 693 if let Some(ssh) = sessions[i].ssh.as_mut() { 694 any_output |= drive_ssh(ssh, &tx, i as u8); 695 } 696 }); 697 698 let mut sessions_to_drop: u8 = 0; 699 let mut need_spawn: u8 = 0; 700 701 core::iter::from_fn(|| match rx.try_pop(&mut pop_buf) { 702 Some(n) if n >= 2 => { 703 let conn_id = pop_buf[0] as usize; 704 let msg_type = pop_buf[1]; 705 if conn_id >= MAX_SESSIONS { 706 return Some(()); 707 } 708 709 match msg_type { 710 MSG_CONNECT => { 711 if sessions[conn_id].shell_running { 712 syscall::proc_destroy(slot_proc(conn_id)); 713 cleanup_shell_caps(conn_id); 714 sessions[conn_id].shell_running = false; 715 sessions[conn_id].input_tx = None; 716 sessions[conn_id].netsock_tx = None; 717 sessions[conn_id].netsock_rx = None; 718 } 719 drop(sessions[conn_id].ssh.take()); 720 let inbuf: &'static mut [u8; 35000] = unsafe { 721 &mut *((&raw mut SSH_INBUFS) as *mut [u8; 35000]).add(conn_id) 722 }; 723 let outbuf: &'static mut [u8; 35000] = unsafe { 724 &mut *((&raw mut SSH_OUTBUFS) as *mut [u8; 35000]).add(conn_id) 725 }; 726 inbuf.fill(0); 727 outbuf.fill(0); 728 sessions[conn_id].ssh = 729 Some(SshSession::new(inbuf, outbuf, host_key.clone())); 730 sessions[conn_id].last_activity_ms = now_ms; 731 if let Some(ssh) = sessions[conn_id].ssh.as_mut() { 732 any_output |= drive_ssh(ssh, &tx, conn_id as u8); 733 syscall::notify_signal(NETSTACK_NOTIF_SLOT, 4); 734 } 735 } 736 MSG_DISCONNECT => { 737 teardown_session(conn_id, &mut sessions[conn_id], &tx); 738 } 739 MSG_DATA if n > 2 => { 740 let Session { 741 ref mut ssh, 742 ref input_tx, 743 ref shell_running, 744 ref mut last_activity_ms, 745 .. 746 } = sessions[conn_id]; 747 *last_activity_ms = now_ms; 748 if let Some(ssh) = ssh.as_mut() { 749 let data = &pop_buf[2..n]; 750 let mut off = 0usize; 751 core::iter::from_fn(|| match off < data.len() { 752 true => { 753 let accepted = ssh.feed_input(&data[off..]); 754 match accepted { 755 0 => { 756 any_output |= drive_ssh(ssh, &tx, conn_id as u8); 757 if ssh.shell_ready && *shell_running { 758 let pt_n = ssh.read_plaintext(&mut plaintext_buf); 759 if pt_n > 0 760 && let Some(it) = input_tx 761 && it.try_push(&plaintext_buf[..pt_n]) 762 { 763 syscall::notify_signal( 764 slot_shell_notif(conn_id), 765 2, 766 ); 767 } 768 } 769 any_output |= flush_ssh_output(ssh, &tx, conn_id as u8); 770 let retry = ssh.feed_input(&data[off..]); 771 match retry { 772 0 => None, 773 n2 => { 774 off += n2; 775 Some(()) 776 } 777 } 778 } 779 n2 => { 780 off += n2; 781 Some(()) 782 } 783 } 784 } 785 false => None, 786 }) 787 .take(32) 788 .count(); 789 790 any_output |= drive_ssh(ssh, &tx, conn_id as u8); 791 if ssh.shell_ready && *shell_running { 792 let pt_n = ssh.read_plaintext(&mut plaintext_buf); 793 if pt_n > 0 794 && let Some(it) = input_tx 795 && it.try_push(&plaintext_buf[..pt_n]) 796 { 797 syscall::notify_signal(slot_shell_notif(conn_id), 2); 798 } 799 } 800 } 801 } 802 MSG_DNS_RESULT 803 | MSG_DNS_RESULT6 804 | MSG_PING_RESULT 805 | MSG_PING_DONE 806 | MSG_UDP_RECV 807 | MSG_UDP_CLOSE 808 | MSG_UDP_BOUND 809 | MSG_IFCONFIG_RESULT 810 | MSG_ARP_ENTRY 811 | MSG_ARP_DONE 812 | MSG_NETSTAT_ENTRY 813 | MSG_NETSTAT_ENTRY_UDP 814 | MSG_NETSTAT_DONE 815 if sessions[conn_id].shell_running => 816 { 817 if let Some(ref netsock_tx) = sessions[conn_id].netsock_tx { 818 relay_netstack_to_shell( 819 netsock_tx, 820 &pop_buf[1..n], 821 slot_shell_notif(conn_id), 822 ); 823 } 824 any_output = true; 825 } 826 _ => {} 827 } 828 Some(()) 829 } 830 _ => None, 831 }) 832 .take(64) 833 .count(); 834 835 (0..MAX_SESSIONS).for_each(|i| { 836 let Session { 837 ref mut ssh, 838 ref shell_running, 839 ref input_tx, 840 .. 841 } = sessions[i]; 842 if let Some(ssh) = ssh.as_mut() { 843 any_output |= drive_ssh(ssh, &tx, i as u8); 844 if ssh.shell_ready && !*shell_running { 845 need_spawn |= 1 << i; 846 } 847 if ssh.shell_ready && *shell_running { 848 let pt_n = ssh.read_plaintext(&mut plaintext_buf); 849 if pt_n > 0 850 && let Some(it) = input_tx 851 && it.try_push(&plaintext_buf[..pt_n]) 852 { 853 syscall::notify_signal(slot_shell_notif(i), 2); 854 } 855 } 856 any_output |= flush_ssh_output(ssh, &tx, i as u8); 857 } 858 }); 859 860 (0..MAX_SESSIONS).for_each(|i| { 861 if need_spawn & (1 << i) == 0 { 862 return; 863 } 864 match shell_module_idx { 865 Some(idx) => { 866 let ok = spawn_shell(i, idx, &mut sessions[i]); 867 if !ok { 868 if let Some(ssh) = sessions[i].ssh.as_mut() { 869 send_ssh_bytes(ssh, &tx, i as u8, b"Failed to start shell\r\n"); 870 flush_ssh_output(ssh, &tx, i as u8); 871 ssh.close(); 872 } 873 sessions_to_drop |= 1 << i; 874 } 875 } 876 None => { 877 if let Some(ssh) = sessions[i].ssh.as_mut() { 878 send_ssh_bytes(ssh, &tx, i as u8, b"Shell module not found\r\n"); 879 flush_ssh_output(ssh, &tx, i as u8); 880 ssh.close(); 881 } 882 sessions_to_drop |= 1 << i; 883 } 884 } 885 }); 886 887 (0..MAX_SESSIONS).for_each(|i| { 888 if sessions[i].shell_running 889 && let Some(ssh) = sessions[i].ssh.as_mut() 890 { 891 any_output |= drain_shell_output(i, ssh, &tx); 892 } 893 }); 894 895 (0..MAX_SESSIONS).for_each(|i| { 896 if sessions_to_drop & (1 << i) != 0 { 897 teardown_session(i, &mut sessions[i], &tx); 898 } 899 }); 900 901 (0..MAX_SESSIONS).for_each(|i| { 902 if sessions[i].ssh.is_none() { 903 return; 904 } 905 if now_ms - sessions[i].last_activity_ms > IDLE_TIMEOUT_MS { 906 teardown_session(i, &mut sessions[i], &tx); 907 } 908 }); 909 910 if any_output { 911 syscall::notify_signal(NETSTACK_NOTIF_SLOT, 4); 912 } 913 } 914}