• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 use alloc::rc::{Rc, Weak};
18 use core::array;
19 use core::ffi::c_void;
20 use core::fmt;
21 use log::error;
22 
23 use super::{Channel, Dispatcher};
24 use crate::sys;
25 use crate::{Handle, Result, TipcError};
26 
27 /// A handle set is a collection of tipc service ports, along with their
28 /// respective connections to clients.
29 ///
30 /// A handle set is specific to a particular service, with a fixed set of ports
31 /// and a maximum number of allowed concurrent connections
32 /// `MAX_CONNECTION_COUNT`.
33 pub(super) struct HandleSet<
34     D: Dispatcher,
35     const PORT_COUNT: usize,
36     const MAX_CONNECTION_COUNT: usize,
37 > {
38     ports: [Rc<Channel<D>>; PORT_COUNT],
39     connections: [Option<Rc<Channel<D>>>; MAX_CONNECTION_COUNT],
40     connection_count: usize,
41     handle: Handle,
42 }
43 
44 impl<D: Dispatcher, const PORT_COUNT: usize, const MAX_CONNECTION_COUNT: usize>
45     HandleSet<D, PORT_COUNT, MAX_CONNECTION_COUNT>
46 {
try_new(ports: [Rc<Channel<D>>; PORT_COUNT]) -> Result<Self>47     pub fn try_new(ports: [Rc<Channel<D>>; PORT_COUNT]) -> Result<Self> {
48         // SAFETY: syscall, return value is either a negative error code or a
49         // valid handle.
50         let rc = unsafe { trusty_sys::handle_set_create() };
51         if rc < 0 {
52             Err(TipcError::from_uapi(rc))
53         } else {
54             for port in &ports {
55                 if !port.is_port() {
56                     return Err(TipcError::InvalidData);
57                 }
58             }
59 
60             let handle_set = Self {
61                 ports,
62                 connections: array::from_fn(|_| None),
63                 connection_count: 0,
64                 handle: Handle::from_raw(rc as i32)?,
65             };
66 
67             for port in &handle_set.ports {
68                 handle_set.do_set_ctrl(
69                     sys::HSET_ADD as u32,
70                     trusty_sys::uevent::ALL_EVENTS,
71                     port,
72                 )?;
73             }
74 
75             Ok(handle_set)
76         }
77     }
78 
79     /// Register a new connection in this handle set
80     ///
81     /// This function does not need to be unsafe because we do not dereference
82     /// the opaque pointer. However, the handler must agree on the type of this
83     /// cookie.
add_connection(&mut self, connection: Rc<Channel<D>>) -> Result<()>84     pub fn add_connection(&mut self, connection: Rc<Channel<D>>) -> Result<()> {
85         if !connection.is_connection() {
86             return Err(TipcError::InvalidData);
87         }
88 
89         // We should never exceed this count since the port is masked when
90         // we hit the max
91         assert!(!self.at_max_connections(), "Too many connections");
92         self.do_set_ctrl(sys::HSET_ADD as u32, trusty_sys::uevent::ALL_EVENTS, &connection)?;
93 
94         let _ = self
95             .connections
96             .iter_mut()
97             .find(|c| c.is_none())
98             .expect("No empty slot found, shouldn't happen because we checked at_max_connections")
99             .replace(connection);
100 
101         self.connection_count += 1;
102 
103         if self.at_max_connections() {
104             self.mask_all_ports();
105         }
106         Ok(())
107     }
108 
109     /// Wait for an event on this handle set
110     ///
111     /// Waits for `timeout` milliseconds or indefinitely if `None`.
wait(&self, timeout: Option<u32>) -> Result<trusty_sys::uevent>112     pub fn wait(&self, timeout: Option<u32>) -> Result<trusty_sys::uevent> {
113         self.handle.wait(timeout)
114     }
115 
116     /// Close a connection in this handle set.
117     ///
118     /// This should only be used to close active connections, not ports.
close(&mut self, connection: Rc<Channel<D>>)119     pub fn close(&mut self, connection: Rc<Channel<D>>) {
120         assert!(connection.is_connection());
121 
122         let _ = self
123             .connections
124             .iter_mut()
125             .find(|c| c.as_ref() == Some(&connection))
126             .expect("Could not find connection")
127             .take();
128         self.do_set_ctrl(sys::HSET_DEL as u32, 0, &connection).unwrap_or_else(|e| {
129             error!("Failed to remove channel {:?} from handle set: {:?}", connection, e)
130         });
131 
132         // This should be the last instance of the channel
133         assert_eq!(Rc::strong_count(&connection), 1);
134         let _ = connection;
135 
136         if self.at_max_connections() {
137             self.unmask_all_ports();
138         }
139 
140         self.connection_count -= 1;
141     }
142 
mask_all_ports(&self)143     fn mask_all_ports(&self) {
144         for port in &self.ports {
145             self.do_set_ctrl(sys::HSET_MOD as u32, 0, &port).expect("Failed to mask port");
146         }
147     }
148 
unmask_all_ports(&self)149     fn unmask_all_ports(&self) {
150         for port in &self.ports {
151             self.do_set_ctrl(sys::HSET_MOD as u32, trusty_sys::uevent::ALL_EVENTS, &port)
152                 .expect("Failed to unmask port");
153         }
154     }
155 
do_set_ctrl(&self, cmd: u32, event: u32, channel: &Rc<Channel<D>>) -> Result<()>156     fn do_set_ctrl(&self, cmd: u32, event: u32, channel: &Rc<Channel<D>>) -> Result<()> {
157         let cookie = Rc::downgrade(&channel).into_raw();
158 
159         let mut uevt = trusty_sys::uevent {
160             handle: channel.handle().as_raw_fd(),
161             event,
162             cookie: cookie as *mut c_void,
163         };
164         // SAFETY: syscall. The uevent pointer points to a correctly initialized
165         // structure that is borrowed and valid across the call. The handle for
166         // the handle set is valid for the same lifetime as self, so will remain
167         // valid at least as long as the channel being added/modified.
168         let rc = unsafe { trusty_sys::handle_set_ctrl(self.handle.as_raw_fd(), cmd, &mut uevt) };
169 
170         if cmd != sys::HSET_ADD as u32 || trusty_sys::Error::is_err(rc) {
171             // SAFETY: We are constructing the raw pointer to drop here using
172             // Weak::into_raw(), so we know that it is valid to turn back into a
173             // Weak pointer. We transfer ownership of the weak reference to the
174             // kernel when adding a handle to the handle set, so we want to drop
175             // that reference only when the handle is then removed from the set.
176             // We do this by dropping the weak reference twice on a successful
177             // HSET_DEL. This is safe because the weak reference cookie from the
178             // kernel will never be again provided by this handle set in a poll
179             // operation because we have removed the handle from the set, and we
180             // check that the connection has at least one weak reference
181             // outstanding to remove.
182             unsafe {
183                 drop(Weak::from_raw(cookie));
184                 if cmd == sys::HSET_DEL as u32
185                     && !trusty_sys::Error::is_err(rc)
186                     && Rc::weak_count(&channel) >= 1
187                 {
188                     drop(Weak::from_raw(cookie));
189                 }
190             }
191         }
192         if rc < 0 {
193             Err(TipcError::from_uapi(rc))
194         } else {
195             Ok(())
196         }
197     }
198 
at_max_connections(&self) -> bool199     fn at_max_connections(&self) -> bool {
200         self.connection_count >= MAX_CONNECTION_COUNT
201     }
202 }
203 
204 impl<D: Dispatcher, const PORT_COUNT: usize, const MAX_CONNECTION_COUNT: usize> fmt::Debug
205     for HandleSet<D, PORT_COUNT, MAX_CONNECTION_COUNT>
206 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result207     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208         write!(f, "HandleSet: [{:?}", self.ports)
209     }
210 }
211