Skip to content

Commit c529501

Browse files
committed
Harden IPC reply delivery
1 parent f45b6d2 commit c529501

1 file changed

Lines changed: 276 additions & 4 deletions

File tree

src/syscall/ipc.rs

Lines changed: 276 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ pub fn call(
233233
}
234234
return sent;
235235
}
236-
let result = recv_blocking_for_thread(caller, caller, reply_ptr, reply_len);
236+
let result = recv_blocking_reply_for_thread(caller, caller, reply_ptr, reply_len);
237237
let mut boxes = MAILBOXES.lock();
238238
if let Some((idx, _)) = crate::task::thread_slot_index_and_generation_by_u64(caller) {
239239
if idx < MAX_THREADS {
@@ -276,7 +276,210 @@ pub fn reply(dest_thread_id: u64, buf_ptr: u64, len: u64) -> u64 {
276276
None => return EINVAL,
277277
};
278278
let _ = caller_handle;
279-
send_to_thread_id(target_thread, caller_handle, buf_ptr, len)
279+
send_to_thread_id_with_kind(target_thread, caller_handle, buf_ptr, len, true)
280+
}
281+
282+
fn recv_blocking_from_sender_for_thread(
283+
sender_handle: u64,
284+
receiver_thread_id: u64,
285+
caller_thread_id: u64,
286+
buf_ptr: u64,
287+
max_len: u64,
288+
) -> u64 {
289+
let (idx, receiver_generation) =
290+
match crate::task::thread_slot_index_and_generation_by_u64(receiver_thread_id) {
291+
Some(v) => v,
292+
None => return EINVAL,
293+
};
294+
295+
if idx >= MAX_THREADS || idx > (u16::MAX as usize) {
296+
return EINVAL;
297+
}
298+
299+
let mut recv_buf = [0u8; MAX_MSG_SIZE];
300+
loop {
301+
let max_copy = core::cmp::min(max_len as usize, ipc_max_msg_size());
302+
let recv = {
303+
let mut boxes = MAILBOXES.lock();
304+
match boxes[idx].pop_from_sender_copy(
305+
sender_handle,
306+
receiver_thread_id,
307+
idx as u16,
308+
receiver_generation,
309+
&mut recv_buf[..max_copy],
310+
true,
311+
) {
312+
Some(v) => {
313+
if let Some((caller_idx, _)) =
314+
crate::task::thread_slot_index_and_generation_by_u64(caller_thread_id)
315+
{
316+
if caller_idx < MAX_THREADS {
317+
boxes[caller_idx].reply_to = v.0;
318+
}
319+
}
320+
Some(v)
321+
}
322+
None => {
323+
boxes[idx].waiter = caller_thread_id;
324+
None
325+
}
326+
}
327+
};
328+
329+
match recv {
330+
Some((from, copy_len)) => {
331+
if copy_len > 0 && buf_ptr != 0 {
332+
if let Err(err) = crate::syscall::copy_to_user(buf_ptr, &recv_buf[..copy_len]) {
333+
return err;
334+
}
335+
}
336+
return (from << 32) | (copy_len as u64);
337+
}
338+
None => {
339+
{
340+
let mut boxes = MAILBOXES.lock();
341+
if let Some((from, copy_len)) = boxes[idx].pop_from_sender_copy(
342+
sender_handle,
343+
receiver_thread_id,
344+
idx as u16,
345+
receiver_generation,
346+
&mut recv_buf[..max_copy],
347+
true,
348+
) {
349+
if boxes[idx].waiter == caller_thread_id {
350+
boxes[idx].waiter = 0;
351+
}
352+
if let Some((caller_idx, _)) =
353+
crate::task::thread_slot_index_and_generation_by_u64(caller_thread_id)
354+
{
355+
if caller_idx < MAX_THREADS {
356+
boxes[caller_idx].reply_to = from;
357+
}
358+
}
359+
drop(boxes);
360+
if copy_len > 0 && buf_ptr != 0 {
361+
if let Err(err) =
362+
crate::syscall::copy_to_user(buf_ptr, &recv_buf[..copy_len])
363+
{
364+
return err;
365+
}
366+
}
367+
return (from << 32) | (copy_len as u64);
368+
}
369+
}
370+
if crate::task::sleep_thread_unless_woken(crate::task::ThreadId::from_u64(
371+
caller_thread_id,
372+
)) {
373+
crate::task::yield_now();
374+
} else {
375+
let mut boxes = MAILBOXES.lock();
376+
if boxes[idx].waiter == caller_thread_id {
377+
boxes[idx].waiter = 0;
378+
}
379+
return EAGAIN;
380+
}
381+
}
382+
}
383+
}
384+
}
385+
386+
fn recv_blocking_reply_for_thread(
387+
receiver_thread_id: u64,
388+
caller_thread_id: u64,
389+
buf_ptr: u64,
390+
max_len: u64,
391+
) -> u64 {
392+
let (idx, receiver_generation) =
393+
match crate::task::thread_slot_index_and_generation_by_u64(receiver_thread_id) {
394+
Some(v) => v,
395+
None => return EINVAL,
396+
};
397+
398+
if idx >= MAX_THREADS || idx > (u16::MAX as usize) {
399+
return EINVAL;
400+
}
401+
402+
let mut recv_buf = [0u8; MAX_MSG_SIZE];
403+
loop {
404+
let max_copy = core::cmp::min(max_len as usize, ipc_max_msg_size());
405+
let recv = {
406+
let mut boxes = MAILBOXES.lock();
407+
match boxes[idx].pop_reply_copy(
408+
receiver_thread_id,
409+
idx as u16,
410+
receiver_generation,
411+
&mut recv_buf[..max_copy],
412+
) {
413+
Some(v) => {
414+
if let Some((caller_idx, _)) =
415+
crate::task::thread_slot_index_and_generation_by_u64(caller_thread_id)
416+
{
417+
if caller_idx < MAX_THREADS {
418+
boxes[caller_idx].reply_to = v.0;
419+
}
420+
}
421+
Some(v)
422+
}
423+
None => {
424+
boxes[idx].waiter = caller_thread_id;
425+
None
426+
}
427+
}
428+
};
429+
430+
match recv {
431+
Some((from, copy_len)) => {
432+
if copy_len > 0 && buf_ptr != 0 {
433+
if let Err(err) = crate::syscall::copy_to_user(buf_ptr, &recv_buf[..copy_len]) {
434+
return err;
435+
}
436+
}
437+
return (from << 32) | (copy_len as u64);
438+
}
439+
None => {
440+
{
441+
let mut boxes = MAILBOXES.lock();
442+
if let Some((from, copy_len)) = boxes[idx].pop_reply_copy(
443+
receiver_thread_id,
444+
idx as u16,
445+
receiver_generation,
446+
&mut recv_buf[..max_copy],
447+
) {
448+
if boxes[idx].waiter == caller_thread_id {
449+
boxes[idx].waiter = 0;
450+
}
451+
if let Some((caller_idx, _)) =
452+
crate::task::thread_slot_index_and_generation_by_u64(caller_thread_id)
453+
{
454+
if caller_idx < MAX_THREADS {
455+
boxes[caller_idx].reply_to = from;
456+
}
457+
}
458+
drop(boxes);
459+
if copy_len > 0 && buf_ptr != 0 {
460+
if let Err(err) =
461+
crate::syscall::copy_to_user(buf_ptr, &recv_buf[..copy_len])
462+
{
463+
return err;
464+
}
465+
}
466+
return (from << 32) | (copy_len as u64);
467+
}
468+
}
469+
if crate::task::sleep_thread_unless_woken(crate::task::ThreadId::from_u64(
470+
caller_thread_id,
471+
)) {
472+
crate::task::yield_now();
473+
} else {
474+
let mut boxes = MAILBOXES.lock();
475+
if boxes[idx].waiter == caller_thread_id {
476+
boxes[idx].waiter = 0;
477+
}
478+
return EAGAIN;
479+
}
480+
}
481+
}
482+
}
280483
}
281484

282485
pub fn wait(buf_ptr: u64, max_len: u64, blocking: u64) -> u64 {
@@ -345,6 +548,7 @@ pub struct Message {
345548
to: u64,
346549
to_slot: u16,
347550
to_generation: u64,
551+
is_reply: bool,
348552
len: usize,
349553
data: [u8; MAX_MSG_SIZE],
350554
ext_pages_count: u16,
@@ -358,6 +562,7 @@ impl Message {
358562
to: 0,
359563
to_slot: 0,
360564
to_generation: 0,
565+
is_reply: false,
361566
len: 0,
362567
data: [0; MAX_MSG_SIZE],
363568
ext_pages_count: 0,
@@ -463,6 +668,7 @@ impl Mailbox {
463668
to_slot: u16,
464669
to_generation: u64,
465670
data: &[u8],
671+
is_reply: bool,
466672
) -> Result<(), ()> {
467673
if data.len() > ipc_max_msg_size() {
468674
return Err(());
@@ -476,6 +682,7 @@ impl Mailbox {
476682
msg.to = to;
477683
msg.to_slot = to_slot;
478684
msg.to_generation = to_generation;
685+
msg.is_reply = is_reply;
479686
msg.len = data.len();
480687
msg.ext_pages_count = 0;
481688
if !data.is_empty() {
@@ -538,6 +745,7 @@ impl Mailbox {
538745
receiver_slot: u16,
539746
receiver_generation: u64,
540747
out: &mut [u8],
748+
reply_only: bool,
541749
) -> Option<(u64, usize)> {
542750
if self.count == 0 {
543751
return None;
@@ -551,6 +759,48 @@ impl Mailbox {
551759
|| msg.to != receiver
552760
|| msg.to_slot != receiver_slot
553761
|| msg.to_generation != receiver_generation
762+
|| (reply_only && !msg.is_reply)
763+
{
764+
if self.enqueue_slot(slot_idx).is_err() {
765+
let _ = self.free_slot(slot_idx);
766+
return None;
767+
}
768+
continue;
769+
}
770+
771+
let copy_len = core::cmp::min(msg.len, out.len());
772+
if copy_len > 0 {
773+
out[..copy_len].copy_from_slice(&msg.data[..copy_len]);
774+
}
775+
let from = msg.from;
776+
if !self.free_slot(slot_idx) {
777+
return None;
778+
}
779+
return Some((from, copy_len));
780+
}
781+
782+
None
783+
}
784+
785+
fn pop_reply_copy(
786+
&mut self,
787+
receiver: u64,
788+
receiver_slot: u16,
789+
receiver_generation: u64,
790+
out: &mut [u8],
791+
) -> Option<(u64, usize)> {
792+
if self.count == 0 {
793+
return None;
794+
}
795+
796+
let original = self.count;
797+
for _ in 0..original {
798+
let slot_idx = self.dequeue_slot()?;
799+
let msg = &self.slots[slot_idx];
800+
if msg.to != receiver
801+
|| msg.to_slot != receiver_slot
802+
|| msg.to_generation != receiver_generation
803+
|| !msg.is_reply
554804
{
555805
if self.enqueue_slot(slot_idx).is_err() {
556806
let _ = self.free_slot(slot_idx);
@@ -602,7 +852,14 @@ pub fn send_from_kernel(dest_thread_id: u64, data: &[u8]) -> bool {
602852
.unwrap_or(0);
603853
MAILBOXES.lock().get_mut(idx).map_or(false, |mb| {
604854
if mb
605-
.push_message(sender, dest_thread_id, idx as u16, dest_generation, data)
855+
.push_message(
856+
sender,
857+
dest_thread_id,
858+
idx as u16,
859+
dest_generation,
860+
data,
861+
false,
862+
)
606863
.is_ok()
607864
{
608865
let waiter = mb.take_waiter();
@@ -649,6 +906,7 @@ pub fn send_pages_from_kernel(
649906
msg.to = dest_thread_id;
650907
msg.to_slot = idx as u16;
651908
msg.to_generation = dest_generation;
909+
msg.is_reply = false;
652910
// serialize map_start, total only.
653911
// 物理ページ配列は data に露出させず ext_pages 側だけに保持する。
654912
let mut off = 0usize;
@@ -703,6 +961,7 @@ pub fn send_map_header_from_kernel(dest_thread_id: u64, map_start: u64, total: u
703961
msg.to = dest_thread_id;
704962
msg.to_slot = idx as u16;
705963
msg.to_generation = dest_generation;
964+
msg.is_reply = false;
706965
// New format: [magic:u32][map_start:u64][total:u64] (20 bytes)
707966
let mut off = 0usize;
708967
if 20 > ipc_max_msg_size() {
@@ -748,6 +1007,16 @@ pub fn send_map_header_from_kernel(dest_thread_id: u64, map_start: u64, total: u
7481007
}
7491008

7501009
fn send_to_thread_id(dest_thread_id: u64, sender_handle: u64, buf_ptr: u64, len: u64) -> u64 {
1010+
send_to_thread_id_with_kind(dest_thread_id, sender_handle, buf_ptr, len, false)
1011+
}
1012+
1013+
fn send_to_thread_id_with_kind(
1014+
dest_thread_id: u64,
1015+
sender_handle: u64,
1016+
buf_ptr: u64,
1017+
len: u64,
1018+
is_reply: bool,
1019+
) -> u64 {
7511020
if dest_thread_id == 0 {
7521021
return EINVAL;
7531022
}
@@ -782,7 +1051,6 @@ fn send_to_thread_id(dest_thread_id: u64, sender_handle: u64, buf_ptr: u64, len:
7821051
return err;
7831052
}
7841053
}
785-
7861054
let mut boxes = MAILBOXES.lock();
7871055
if boxes[idx]
7881056
.push_message(
@@ -791,6 +1059,7 @@ fn send_to_thread_id(dest_thread_id: u64, sender_handle: u64, buf_ptr: u64, len:
7911059
idx as u16,
7921060
dest_generation,
7931061
&data[..len],
1062+
is_reply,
7941063
)
7951064
.is_err()
7961065
{
@@ -1353,6 +1622,7 @@ pub fn recv_from_sender_for_kernel_nonblocking(
13531622
idx as u16,
13541623
receiver_generation,
13551624
buf,
1625+
false,
13561626
)
13571627
.map(|(_, n)| n)
13581628
};
@@ -1392,6 +1662,7 @@ pub fn recv_blocking_from_sender_for_kernel(
13921662
idx as u16,
13931663
receiver_generation,
13941664
buf,
1665+
false,
13951666
) {
13961667
Some((_, n)) => Some(n),
13971668
None => {
@@ -1412,6 +1683,7 @@ pub fn recv_blocking_from_sender_for_kernel(
14121683
idx as u16,
14131684
receiver_generation,
14141685
buf,
1686+
false,
14151687
) {
14161688
if boxes[idx].waiter == receiver_u64 {
14171689
boxes[idx].waiter = 0;

0 commit comments

Comments
 (0)