Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b5c9d10e authored by Ying Hsu's avatar Ying Hsu Committed by Automerger Merge Worker
Browse files

Merge "Floss: Implement admin policy for Rfcomm socket" am: 655056f9 am: 44b0743f

parents 7a1796ee 44b0743f
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -176,7 +176,10 @@ fn main() -> Result<(), Box<dyn Error>> {
        bluetooth_media.clone(),
        tx.clone(),
    ))));
    let bt_sock_mgr = Arc::new(Mutex::new(Box::new(BluetoothSocketManager::new(tx.clone()))));
    let bt_sock_mgr = Arc::new(Mutex::new(Box::new(BluetoothSocketManager::new(
        tx.clone(),
        bluetooth_admin.clone(),
    ))));
    let qa = Arc::new(Mutex::new(Box::new(BluetoothQA::new(tx.clone()))));
    let dis =
        Arc::new(Mutex::new(Box::new(DeviceInformation::new(bluetooth_gatt.clone(), tx.clone()))));
+7 −0
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ pub struct BluetoothAdmin {
    allowed_services: HashSet<Uuid128Bit>,
    callbacks: Callbacks<dyn IBluetoothAdminPolicyCallback + Send>,
    device_policy_affect_cache: HashMap<BluetoothDevice, Option<PolicyEffect>>,
    tx: Sender<Message>,
}

impl BluetoothAdmin {
@@ -75,6 +76,7 @@ impl BluetoothAdmin {
            allowed_services: HashSet::new(), //empty means allowed all services
            callbacks: Callbacks::new(tx.clone(), Message::AdminCallbackDisconnected),
            device_policy_affect_cache: HashMap::new(),
            tx: tx.clone(),
        };

        if admin.load_config().is_err() {
@@ -227,6 +229,11 @@ impl IBluetoothAdmin for BluetoothAdmin {
                cb.on_service_allowlist_changed(allowed_services.clone());
            });

            let txl = self.tx.clone();
            tokio::spawn(async move {
                let _ = txl.send(Message::AdminPolicyChanged).await;
            });

            for (device, effect) in self.device_policy_affect_cache.clone().iter() {
                let uuids = adapter.lock().unwrap().get_remote_uuids(device.clone());
                let new_effect = self.new_device_policy_effect(Some(uuids));
+4 −0
Original line number Diff line number Diff line
@@ -120,6 +120,7 @@ pub enum Message {
    // Admin policy related
    AdminCallbackDisconnected(u32),
    HidHostEnable,
    AdminPolicyChanged,

    // Dis callbacks
    Dis(ServiceCallbacks),
@@ -342,6 +343,9 @@ impl Stack {
                Message::HidHostEnable => {
                    bluetooth.lock().unwrap().enable_hidhost();
                }
                Message::AdminPolicyChanged => {
                    bluetooth_socketmgr.lock().unwrap().handle_admin_policy_changed();
                }
                Message::Dis(callback) => {
                    bluetooth_dis.lock().unwrap().handle_callbacks(&callback);
                }
+60 −4
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ use tokio::task::JoinHandle;
use tokio::time;

use crate::bluetooth::BluetoothDevice;
use crate::bluetooth_admin::{BluetoothAdmin, IBluetoothAdmin};
use crate::callbacks::Callbacks;
use crate::uuid::UuidHelper;
use crate::Message;
@@ -396,11 +397,19 @@ struct InternalListeningSocket {

    /// Channel to future that listens for `accept` and `close` signals.
    tx: Sender<SocketRunnerActions>,

    /// Used by admin
    uuid: Option<Uuid>,
}

impl InternalListeningSocket {
    fn new(_callback_id: CallbackId, socket_id: SocketId, tx: Sender<SocketRunnerActions>) -> Self {
        InternalListeningSocket { _callback_id, socket_id, tx }
    fn new(
        _callback_id: CallbackId,
        socket_id: SocketId,
        tx: Sender<SocketRunnerActions>,
        uuid: Option<Uuid>,
    ) -> Self {
        InternalListeningSocket { _callback_id, socket_id, tx, uuid }
    }
}

@@ -492,11 +501,14 @@ pub struct BluetoothSocketManager {

    /// Channel TX for the mainloop for topstack.
    tx: Sender<Message>,

    /// Admin
    admin: Arc<Mutex<Box<BluetoothAdmin>>>,
}

impl BluetoothSocketManager {
    /// Constructs the IBluetooth implementation.
    pub fn new(tx: Sender<Message>) -> Self {
    pub fn new(tx: Sender<Message>, admin: Arc<Mutex<Box<BluetoothAdmin>>>) -> Self {
        let callbacks = Callbacks::new(tx.clone(), Message::SocketManagerCallbackDisconnected);
        let socket_counter: u64 = 1000;
        let futures = HashMap::new();
@@ -518,6 +530,7 @@ impl BluetoothSocketManager {
            sock: None,
            socket_counter,
            tx,
            admin,
        }
    }

@@ -549,6 +562,13 @@ impl BluetoothSocketManager {
        mut socket_info: BluetoothServerSocket,
        cbid: CallbackId,
    ) -> SocketResult {
        if let Some(uuid) = socket_info.uuid {
            if !self.admin.lock().unwrap().is_service_allowed(uuid.into()) {
                log::debug!("service {} is blocked by admin policy", uuid);
                return SocketResult::new(BtStatus::AuthRejected, INVALID_SOCKET_ID);
            }
        }

        // Create listener socket pair
        let (mut status, result) =
            self.sock.as_ref().expect("Socket Manager not initialized").listen(
@@ -578,7 +598,7 @@ impl BluetoothSocketManager {
                let (runner_tx, runner_rx) = channel::<SocketRunnerActions>(10);

                // Keep track of active listener sockets.
                let listener = InternalListeningSocket::new(cbid, id, runner_tx);
                let listener = InternalListeningSocket::new(cbid, id, runner_tx, socket_info.uuid);
                self.listening.entry(cbid).or_default().push(listener);

                // Push a listening task to local runtime to wait for device to
@@ -632,6 +652,13 @@ impl BluetoothSocketManager {
        mut socket_info: BluetoothSocket,
        cbid: CallbackId,
    ) -> SocketResult {
        if let Some(uuid) = socket_info.uuid {
            if !self.admin.lock().unwrap().is_service_allowed(uuid.into()) {
                log::debug!("service {} is blocked by admin policy", uuid);
                return SocketResult::new(BtStatus::AuthRejected, INVALID_SOCKET_ID);
            }
        }

        let addr = match RawAddress::from_string(socket_info.remote_device.address.clone()) {
            Some(v) => v,
            None => {
@@ -1135,6 +1162,35 @@ impl BluetoothSocketManager {
        }
    }

    /// Close Rfcomm sockets whose UUID is not allowed by policy
    pub fn handle_admin_policy_changed(&mut self) {
        let forbidden_sockets = self
            .listening
            .values()
            .into_iter()
            .flatten()
            .filter(|sock| {
                sock.uuid
                    // Don't need to close L2cap socket (indicated by no uuid).
                    .map_or(false, |uuid| {
                        !self.admin.lock().unwrap().is_service_allowed(uuid.into())
                    })
            })
            .map(|sock| (sock.socket_id, sock.tx.clone(), sock.uuid.unwrap()))
            .collect::<Vec<(u64, Sender<SocketRunnerActions>, Uuid)>>();

        self.runtime.spawn(async move {
            for (id, tx, uuid) in forbidden_sockets {
                log::debug!(
                    "socket id {} is not allowed by admin policy due to uuid {}, closing",
                    id,
                    uuid
                );
                let _ = tx.send(SocketRunnerActions::Close(id)).await;
            }
        });
    }

    pub fn remove_callback(&mut self, callback: CallbackId) {
        // Remove any associated futures and sockets waiting to accept.
        self.futures.remove(&callback);
+6 −0
Original line number Diff line number Diff line
@@ -396,6 +396,12 @@ impl From<[u8; 16]> for Uuid {
    }
}

impl From<Uuid> for [u8; 16] {
    fn from(uuid: Uuid) -> Self {
        uuid.uu
    }
}

impl Hash for Uuid {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.uu.hash(state);