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}