1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use twizzler_abi::object::{MAX_SIZE, NULLPAGE_SIZE};
use twizzler_runtime_api::ObjectHandle;

/// A simple buffer to use for transferring bytes between compartments, using shared memory via
/// objects underneath.
pub struct SimpleBuffer {
    handle: ObjectHandle,
}

impl core::fmt::Debug for SimpleBuffer {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("SimpleBuffer")
            .field("id", &self.handle.id)
            .finish_non_exhaustive()
    }
}

impl SimpleBuffer {
    fn ptr_to_base(&self) -> *const u8 {
        unsafe { self.handle.start.add(NULLPAGE_SIZE) }
    }

    fn mut_ptr_to_base(&mut self) -> *mut u8 {
        unsafe { self.handle.start.add(NULLPAGE_SIZE) }
    }

    /// Build a new SimpleBuffer from an object handle.
    pub fn new(handle: ObjectHandle) -> Self {
        Self { handle }
    }

    /// Returns the maximum length of a read or write.
    pub fn max_len(&self) -> usize {
        MAX_SIZE - NULLPAGE_SIZE * 2
    }

    /// Get the underlying object handle.
    pub fn handle(&self) -> &ObjectHandle {
        &self.handle
    }

    /// Read bytes from the SimpleBuffer into `buffer`, up to the size of the supplied buffer. The
    /// actual number of bytes copied is returned.
    pub fn read(&self, buffer: &mut [u8]) -> usize {
        let base_raw = self.ptr_to_base();
        // Note that our len is not bounded by a previous write. But Twizzler objects are
        // 0-initialized by default, so all bytes are initialized to 0u8. If any other data _was_
        // written to the object, that still can be read as bytes.
        let len = core::cmp::min(buffer.len(), self.max_len());
        // Safety: technically, we cannot statically assert that no one else is writing this memory.
        // However, since we are reading bytes directly, we will assert that this is safe,
        // up to seeing torn writes. That is still UB, but it's the best we can do before
        // having to introduce synchronization overhead, but since this is intended to be
        // used by secure gates, that synchronization will have occurred via the secure gate call.
        // While we cannot stop another compartment from violating this assumption, we are still
        // reading bytes from object memory and not interpreting them. If a consumer of this
        // interface chooses to cast those bytes into another type, or process them
        // as UTF-8, or something, it is up to them to uphold safety guarantees (e.g. we cannot
        // assume it is valid UTF-8).
        let base = unsafe { core::slice::from_raw_parts(base_raw, len) };
        (&mut buffer[0..len]).copy_from_slice(base);
        len
    }

    /// Write bytes from `buffer` into the SimpleBuffer, up to the size of the supplied buffer. The
    /// actual number of bytes copied is returned.
    pub fn write(&mut self, buffer: &[u8]) -> usize {
        let base_raw = self.mut_ptr_to_base();
        let len = core::cmp::min(buffer.len(), self.max_len());
        // Safety: See read function.
        let base = unsafe { core::slice::from_raw_parts_mut(base_raw, len) };
        base.copy_from_slice(&buffer[0..len]);
        len
    }
}

#[cfg(test)]
mod test {
    use twizzler_abi::syscall::{
        sys_object_create, BackingType, LifetimeType, ObjectCreate, ObjectCreateFlags,
    };
    use twizzler_runtime_api::{get_runtime, MapFlags, ObjectHandle};

    use super::*;

    fn new_handle() -> ObjectHandle {
        let id = sys_object_create(
            ObjectCreate::new(
                BackingType::Normal,
                LifetimeType::Volatile,
                None,
                ObjectCreateFlags::empty(),
            ),
            &[],
            &[],
        )
        .unwrap();
        get_runtime()
            .map_object(id, MapFlags::READ | MapFlags::WRITE)
            .unwrap()
    }

    #[test]
    fn transfer() {
        let obj = new_handle();
        let mut sb = SimpleBuffer::new(obj);

        let data = b"simple buffer test!";
        let wlen = sb.write(data);
        let mut buf = [0u8; 19];
        assert_eq!(buf.len(), data.len());
        assert_eq!(buf.len(), wlen);

        let rlen = sb.read(&mut buf);
        assert_eq!(rlen, wlen);
        assert_eq!(&buf, data);
    }
}