1515// specific language governing permissions and limitations
1616// under the License.
1717
18- use crate :: { Error , ErrorKind , Result } ;
19- use core:: { marker, slice} ;
18+ use crate :: {
19+ access:: { Accessible , NoAccess , Read , ReadWrite , Writable , Write } ,
20+ volatile:: VolatileBuf ,
21+ Error , ErrorKind , Result ,
22+ } ;
23+ use core:: {
24+ fmt:: { Debug , Display } ,
25+ marker,
26+ ptr:: { addr_of_mut, NonNull } ,
27+ } ;
2028use optee_utee_sys as raw;
2129
2230pub type RawParamType = u32 ;
@@ -69,27 +77,137 @@ impl<'parameter> ParamValue<'parameter> {
6977 }
7078}
7179
72- pub struct ParamMemref < ' parameter > {
73- raw : * mut raw:: Memref ,
80+ /// A [`Parameter`] that is a reference to CA-controlled shared memory.
81+ ///
82+ /// Note: The memory it points to is volatile and can contain maliciously crafted
83+ /// data, so care should be taken when accessing it. For a safe api, first check
84+ /// the type of the memref via [`Self::in_`], [`Self::out`], or [`Self::inout`].
85+ ///
86+ /// These will return type type-safe versions that unsure that read or write access
87+ /// is only allowed based on the underlying [`ParamType`].
88+ ///
89+ /// Then, call [`Self::buffer`] which returns a [`VolatileBuf`] that can be accessed
90+ /// safely.
91+ pub struct ParamMemref < ' parameter , A = NoAccess > {
92+ raw : NonNull < raw:: Memref > ,
7493 param_type : ParamType ,
75- _marker : marker:: PhantomData < & ' parameter mut [ u8 ] > ,
94+ capacity : usize ,
95+ _phantom_param : marker:: PhantomData < & ' parameter mut [ u8 ] > ,
96+ _phantom_access : marker:: PhantomData < A > ,
7697}
7798
78- impl < ' parameter > ParamMemref < ' parameter > {
79- pub fn buffer ( & mut self ) -> & mut [ u8 ] {
80- unsafe { slice:: from_raw_parts_mut ( ( * self . raw ) . buffer as * mut u8 , ( * self . raw ) . size ) }
99+ impl < ' parameter , A > ParamMemref < ' parameter , A > {
100+ // Helper function to cast access.
101+ fn access < NewAccess > (
102+ self ,
103+ expected_param_type : ParamType ,
104+ ) -> Result < ParamMemref < ' parameter , NewAccess > , InvalidAccessErr < Self , NewAccess > > {
105+ if self . param_type != expected_param_type {
106+ return Err ( InvalidAccessErr {
107+ param_type : self . param_type ,
108+ value : self ,
109+ _phantom : marker:: PhantomData ,
110+ } ) ;
111+ }
112+
113+ Ok ( ParamMemref :: < ' parameter , NewAccess > {
114+ raw : self . raw ,
115+ param_type : self . param_type ,
116+ capacity : self . capacity ,
117+ _phantom_param : marker:: PhantomData ,
118+ _phantom_access : marker:: PhantomData ,
119+ } )
120+ }
121+
122+ /// Checks that this param is a [`ParamType::MemrefInput`] and casts access to [`Read`].
123+ pub fn in_ ( self ) -> Result < ParamMemref < ' parameter , Read > , InvalidAccessErr < Self , Read > > {
124+ self . access ( ParamType :: MemrefInput )
125+ }
126+
127+ /// Checks that this param is a [`ParamType::MemrefOutput`] and casts access to [`Write`].
128+ pub fn out ( self ) -> Result < ParamMemref < ' parameter , Write > , InvalidAccessErr < Self , Write > > {
129+ self . access ( ParamType :: MemrefOutput )
130+ }
131+
132+ /// Checks that this param is a [`ParamType::MemrefInout`] and casts access to [`ReadWrite`].
133+ pub fn inout (
134+ self ,
135+ ) -> Result < ParamMemref < ' parameter , ReadWrite > , InvalidAccessErr < Self , ReadWrite > > {
136+ self . access ( ParamType :: MemrefInout )
137+ }
138+
139+ /// Casts access type to [`NoAccess`], preventing anyone from accessing the buffer
140+ /// it points to (except by c-style pointer).
141+ pub fn noaccess ( self ) -> ParamMemref < ' parameter , NoAccess > {
142+ ParamMemref {
143+ raw : self . raw ,
144+ param_type : self . param_type ,
145+ capacity : self . capacity ,
146+ _phantom_param : marker:: PhantomData ,
147+ _phantom_access : marker:: PhantomData ,
148+ }
149+ }
150+
151+ pub fn raw ( & mut self ) -> NonNull < raw:: Memref > {
152+ self . raw
153+ }
154+
155+ /// The size of the allocated memory region (i.e. the original value of `self.size`)
156+ pub fn capacity ( & self ) -> usize {
157+ self . capacity
81158 }
82159
83160 pub fn param_type ( & self ) -> ParamType {
84161 self . param_type
85162 }
163+ }
86164
87- pub fn raw ( & mut self ) -> * mut raw:: Memref {
88- self . raw
165+ impl < ' parameter , A : Accessible > ParamMemref < ' parameter , A > {
166+ /// Can return `None` if the buffer is null, which is a valid state that can happen
167+ /// in OP-TEE.
168+ pub fn buffer ( & mut self ) -> Option < VolatileBuf < ' parameter , A > > {
169+ let memref = unsafe { self . raw . read ( ) } ;
170+ let buf_ptr = memref. buffer . cast :: < u8 > ( ) ;
171+ let buf_ptr = NonNull :: new ( buf_ptr) ?;
172+
173+ Some ( unsafe { VolatileBuf :: new ( buf_ptr, self . capacity ) } )
174+ }
175+ }
176+
177+ impl < ' parameter , A : Writable > ParamMemref < ' parameter , A > {
178+ /// Errors if the new size would be bigger than `self.capacity()`
179+ pub fn set_updated_size ( & mut self , size : usize ) -> Result < ( ) , BiggerThanCapacityErr > {
180+ if size > self . capacity {
181+ return Err ( BiggerThanCapacityErr {
182+ requested_size : size,
183+ capacity : self . capacity ,
184+ } ) ;
185+ }
186+ let memref = unsafe { self . raw . as_mut ( ) } ;
187+ memref. size = size;
188+
189+ Ok ( ( ) )
89190 }
90191
91- pub fn set_updated_size ( & mut self , size : usize ) {
92- unsafe { ( * self . raw ) . size = size } ;
192+ /// By convention, setting the raw size to something larger than what was initially passed by OP-TEE, is a signal to
193+ /// the CA that there is insufficient memory allocated to output a result, and that the CA should invoke the function again
194+ /// with a larger buffer. See section `4.3.6.4` of the Global Platform TEE Internal Core API.
195+ /// Note that this does *not* update `self.capacity()`.
196+ /// Returns an error if the requested amount is not any bigger than the existing capacity.
197+ pub fn request_more_capacity (
198+ & mut self ,
199+ new_capacity : usize ,
200+ ) -> Result < ( ) , NotBiggerThanCapacityErr > {
201+ if new_capacity <= self . capacity {
202+ return Err ( NotBiggerThanCapacityErr {
203+ requested_capacity : new_capacity,
204+ capacity : self . capacity ,
205+ } ) ;
206+ }
207+ let memref = unsafe { self . raw . as_mut ( ) } ;
208+ memref. size = new_capacity;
209+
210+ Ok ( ( ) )
93211 }
94212}
95213
@@ -127,9 +245,11 @@ impl Parameter {
127245 match self . param_type {
128246 ParamType :: MemrefInout | ParamType :: MemrefInput | ParamType :: MemrefOutput => {
129247 Ok ( ParamMemref {
130- raw : & mut ( * self . raw ) . memref ,
248+ raw : NonNull :: new_unchecked ( addr_of_mut ! ( ( * self . raw) . memref) ) ,
131249 param_type : self . param_type ,
132- _marker : marker:: PhantomData ,
250+ capacity : unsafe { * self . raw } . memref . size ,
251+ _phantom_access : marker:: PhantomData ,
252+ _phantom_param : marker:: PhantomData ,
133253 } )
134254 }
135255 _ => Err ( Error :: new ( ErrorKind :: BadParameters ) ) ,
@@ -160,7 +280,7 @@ impl From<u32> for ParamTypes {
160280 }
161281}
162282
163- #[ derive( Copy , Clone ) ]
283+ #[ derive( Copy , Clone , Debug , Eq , PartialEq ) ]
164284pub enum ParamType {
165285 None = 0 ,
166286 ValueInput = 1 ,
@@ -171,6 +291,20 @@ pub enum ParamType {
171291 MemrefInout = 7 ,
172292}
173293
294+ impl Display for ParamType {
295+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
296+ match self {
297+ ParamType :: None => write ! ( f, "None" ) ,
298+ ParamType :: ValueInput => write ! ( f, "ValueInput" ) ,
299+ ParamType :: ValueOutput => write ! ( f, "ValueOutput" ) ,
300+ ParamType :: ValueInout => write ! ( f, "ValueInout" ) ,
301+ ParamType :: MemrefInput => write ! ( f, "MemrefInput" ) ,
302+ ParamType :: MemrefOutput => write ! ( f, "MemrefOutput" ) ,
303+ ParamType :: MemrefInout => write ! ( f, "MemrefInout" ) ,
304+ }
305+ }
306+ }
307+
174308impl From < u32 > for ParamType {
175309 fn from ( value : u32 ) -> Self {
176310 match value {
@@ -185,3 +319,69 @@ impl From<u32> for ParamType {
185319 }
186320 }
187321}
322+
323+ #[ derive( Debug ) ]
324+ pub struct BiggerThanCapacityErr {
325+ requested_size : usize ,
326+ capacity : usize ,
327+ }
328+
329+ impl Display for BiggerThanCapacityErr {
330+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
331+ write ! (
332+ f,
333+ "requested size {} but this is bigger than the capacity {}" ,
334+ self . requested_size, self . capacity,
335+ )
336+ }
337+ }
338+
339+ impl core:: error:: Error for BiggerThanCapacityErr { }
340+
341+ #[ derive( Debug ) ]
342+ pub struct NotBiggerThanCapacityErr {
343+ requested_capacity : usize ,
344+ capacity : usize ,
345+ }
346+
347+ impl Display for NotBiggerThanCapacityErr {
348+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
349+ write ! (
350+ f,
351+ "requested capacity {} but should have been bigger the original capacity {}" ,
352+ self . requested_capacity, self . capacity,
353+ )
354+ }
355+ }
356+
357+ impl core:: error:: Error for NotBiggerThanCapacityErr { }
358+
359+ /// Error while attempting to cast access
360+ #[ derive( Debug , Clone ) ]
361+ pub struct InvalidAccessErr < T , NewAccess > {
362+ param_type : ParamType ,
363+ value : T ,
364+ _phantom : marker:: PhantomData < NewAccess > ,
365+ }
366+
367+ impl < T , NewAccess > Display for InvalidAccessErr < T , NewAccess > {
368+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
369+ write ! (
370+ f,
371+ "unable to cast access to {}, param_type was {}" ,
372+ core:: any:: type_name:: <NewAccess >( ) ,
373+ self . param_type
374+ )
375+ }
376+ }
377+
378+ impl < T : Debug + Display , NewAccess : Debug + Display > core:: error:: Error
379+ for InvalidAccessErr < T , NewAccess >
380+ {
381+ }
382+
383+ impl < T , NewAccess > InvalidAccessErr < T , NewAccess > {
384+ pub fn into_inner ( self ) -> T {
385+ self . value
386+ }
387+ }
0 commit comments