optee_teec/
extension.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use crate::{
19    raw::size_t,
20    {ErrorKind, Result},
21};
22use core::ffi::c_void;
23
24/// Parameters for a plugin invocation, carrying the command, sub-command,
25/// and the inout buffer.
26///
27/// The core design goal of this struct is to prevent developers from forgetting
28/// to set `out_len`. In the C ABI, `out_len` is a raw pointer that the plugin
29/// must write to in order to report how many bytes it actually
30/// produced. Forgetting to set it is a silent bug — the TA caller receives
31/// garbage (uninitialized or stale) length, leading to buffer over-reads or
32/// truncated output that is extremely hard to diagnose.
33///
34/// To eliminate this class of bugs, `PluginParameters` ties `out_len` to
35/// every output-writing operation: `write_output_at` and `set_buf_from_slice`,
36/// both automatically update `out_len` on success, so the plugin developers
37/// never has to do it manually. If plugin developers need full control, they
38/// can use `get_buffer_mut` and `set_out_len` explicitly.
39pub struct PluginParameters<'a, 'b> {
40    /// Command identifier for the plugin invocation.
41    pub cmd: u32,
42    /// Sub-command identifier for the plugin invocation.
43    pub sub_cmd: u32,
44    /// Inout buffer that carries input data into the plugin and receives
45    /// output data from it.
46    buf: &'a mut [u8],
47    /// Pointer to the output length that the plugin must set.
48    /// Wrapped in `Option` because the C API allows it to be NULL
49    /// (meaning the caller does not expect output). When present,
50    /// every output-writing method automatically updates this value,
51    /// ensuring `out_len` is never left unset.
52    out_len: Option<&'b mut size_t>,
53}
54
55impl<'a, 'b> PluginParameters<'a, 'b> {
56    /// Constructs a `PluginParameters` from raw C pointers.
57    ///
58    /// # Safety
59    /// - `buf` must be valid for reads/writes of `in_len` bytes if not null
60    /// - `out_len` must be valid for writes if not null
61    /// - both pointers must remain alive for the lifetime of the returned
62    ///   `PluginParameters`
63    ///
64    /// When `out_len` is non-null, it will be tracked by the returned struct
65    /// so that output-writing methods can update it automatically — this is
66    /// the key mechanism that prevents the "forgot to set out_len" bug.
67    pub unsafe fn from_raw(
68        cmd: u32,
69        sub_cmd: u32,
70        buf: *mut c_void,
71        in_len: size_t,
72        out_len: *mut size_t,
73    ) -> Result<Self> {
74        // Reject obviously invalid parameter combinations:
75        // a non-zero in_len or a present out_len implies the caller expects
76        // to use the buffer, so a null buf pointer is illegal.
77        if (in_len != 0 || !out_len.is_null()) && buf.is_null() {
78            return Err(ErrorKind::BadParameters.into());
79        }
80        // Wrap the raw buffer pointer into a safe slice.
81        // For current OP-TEE, buf should always be non-null.
82        let buf = match buf.is_null() {
83            true => &mut [],
84            false => unsafe { core::slice::from_raw_parts_mut(buf as *mut _, in_len) },
85        };
86        // Track the out_len pointer so output-writing methods can update it
87        // automatically — this is what prevents "forgot to set out_len" bugs.
88        let out_len = unsafe { out_len.as_mut() };
89
90        Ok(Self {
91            cmd,
92            sub_cmd,
93            buf,
94            out_len,
95        })
96    }
97
98    /// Copies the entire `sendslice` into the inout buffer starting at offset
99    /// 0, and automatically sets `out_len` to `sendslice.len()`.
100    ///
101    /// This is the primary safe way to write output — callers do not need to
102    /// update `out_len` separately.
103    ///
104    /// Returns `ShortBuffer` if the buffer is too small, or `BadState` if
105    /// the output length pointer is not available.
106    pub fn set_buf_from_slice(&mut self, sendslice: &[u8]) -> Result<()> {
107        self.write_output_at(0, sendslice)
108    }
109
110    /// Writes `data` into the inout buffer at the given `pos`, and
111    /// automatically updates `out_len` to `pos + data.len()`.
112    ///
113    /// By always updating `out_len` on a successful write, this method
114    /// eliminates the risk of the developer forgetting to set it.
115    ///
116    /// Returns `ShortBuffer` if the buffer is too small, or `BadState` if
117    /// the output length pointer is not available.
118    pub fn write_output_at(&mut self, pos: usize, data: &[u8]) -> Result<()> {
119        if let Some(out_len) = self.out_len.as_mut() {
120            let dest_len = pos + data.len();
121            if self.buf.len() < dest_len {
122                // Buffer overflow: not enough space for the write
123                log::debug!("Overflow: Input length is less than output length");
124                return Err(ErrorKind::ShortBuffer.into());
125            }
126            self.buf[pos..dest_len].copy_from_slice(data);
127            (**out_len) = dest_len;
128            return Ok(());
129        }
130        log::debug!("output is not allowed");
131        Err(ErrorKind::BadState.into())
132    }
133
134    /// Returns a shared reference to the inout buffer.
135    pub fn get_buffer(&self) -> &[u8] {
136        self.buf
137    }
138
139    /// Returns a mutable reference to the inout buffer.
140    ///
141    /// # Safety
142    /// The caller is responsible for updating `out_len` (via [`set_out_len`])
143    /// after writing to the buffer.
144    pub unsafe fn get_buffer_mut(&mut self) -> &mut [u8] {
145        self.buf
146    }
147
148    /// Explicitly sets `out_len` to the given value.
149    ///
150    /// This is an escape hatch for cases where the caller needs full control
151    /// over the output length (e.g. after using `get_buffer_mut`). In most
152    /// cases should prefer `write_output_at` or `set_buf_from_slice`, which set
153    /// `out_len` automatically and avoid the "forgot to set out_len" bug.
154    ///
155    /// Returns `BadParameters` if `out_len` exceeds the buffer size, or
156    /// `BadState` if the output length pointer is not available.
157    pub fn set_out_len(&mut self, out_len: usize) -> Result<()> {
158        if out_len > self.buf.len() {
159            return Err(ErrorKind::BadParameters.into());
160        }
161        match self.out_len.as_mut() {
162            None => Err(ErrorKind::BadState.into()),
163            Some(v) => {
164                **v = out_len;
165                Ok(())
166            }
167        }
168    }
169}