diff --git a/CHANGELOG.md b/CHANGELOG.md
index b4329a12d..3d1d1a3d9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,10 @@
* Dropped the PIN database
+### Bugs fixed
+
+* blueman-mechanism accepted arbitrary file paths and returned the errors from trying to open them, see https://github.com/blueman-project/blueman/security/advisories/GHSA-3r9p-m5c8-8mw8
+
## 2.2.3
### Bugs fixed
diff --git a/blueman/plugins/applet/PPPSupport.py b/blueman/plugins/applet/PPPSupport.py
index 5130121fc..8af2811b4 100644
--- a/blueman/plugins/applet/PPPSupport.py
+++ b/blueman/plugins/applet/PPPSupport.py
@@ -28,7 +28,7 @@ def on_ppp_connected(self, device: Device, rfcomm: str, ppp_port: str) -> None:
class Connection:
- def __init__(self, applet: "BluemanApplet", service: DialupNetwork, port: str,
+ def __init__(self, applet: "BluemanApplet", service: DialupNetwork, port: int,
ok: Callable[[str], None], err: Callable[[GLib.Error], None]):
self.reply_handler = ok
self.error_handler = err
@@ -48,26 +48,26 @@ def connect(self) -> bool:
c = Config("org.blueman.gsmsetting", f"/org/blueman/gsmsettings/{self.service.device['Address']}/")
m = Mechanism()
- m.PPPConnect('(sss)', self.port, c["number"], c["apn"], result_handler=self.on_connected,
+ m.PPPConnect('(uss)', self.port, c["number"], c["apn"], result_handler=self.on_connected,
error_handler=self.on_error)
return False
def on_error(self, _obj: Mechanism, result: GLib.Error, _user_data: None) -> None:
logging.info(f"Failed {result}")
- # FIXME confusingly self.port is the full rfcomm device path but the service expects the number only
self.error_handler(result)
def _connect() -> bool:
- self.service.disconnect(int(self.port[-1]))
+ self.service.disconnect(self.port)
return False
GLib.timeout_add(1000, _connect)
def on_connected(self, _obj: Mechanism, result: str, _user_data: None) -> None:
- self.reply_handler(self.port)
+ rfcomm_dev = f"/dev/rfcomm{self.port:d}"
+ self.reply_handler(rfcomm_dev)
for plugin in self.parent.Plugins.get_loaded_plugins(PPPConnectedListener):
- plugin.on_ppp_connected(self.service.device, self.port, result)
+ plugin.on_ppp_connected(self.service.device, rfcomm_dev, result)
msg = _("Successfully connected to DUN service on %(0)s.\n"
"Network is now available through %(1)s") % {"0": self.service.device['Alias'], "1": result}
@@ -85,7 +85,7 @@ class PPPSupport(AppletPlugin, RFCOMMConnectHandler):
def rfcomm_connect_handler(self, service: SerialService, reply: Callable[[str], None],
err: Callable[[Union[RFCOMMError, GLib.Error]], None]) -> bool:
if isinstance(service, DialupNetwork):
- def local_reply(port: str) -> None:
+ def local_reply(port: int) -> None:
assert isinstance(service, DialupNetwork) # https://github.com/python/mypy/issues/2608
Connection(self.parent, service, port, reply, err)
diff --git a/blueman/plugins/mechanism/Ppp.py b/blueman/plugins/mechanism/Ppp.py
index a9e31aa1c..25d5a592e 100644
--- a/blueman/plugins/mechanism/Ppp.py
+++ b/blueman/plugins/mechanism/Ppp.py
@@ -6,7 +6,7 @@
class Ppp(MechanismPlugin):
def on_load(self) -> None:
- self.parent.add_method("PPPConnect", ("s", "s", "s"), "s", self._ppp_connect, pass_sender=True, is_async=True)
+ self.parent.add_method("PPPConnect", ("u", "s", "s"), "s", self._ppp_connect, pass_sender=True, is_async=True)
def _ppp_connected(self, _ppp: PPPConnection, port: str, ok: Callable[[str], None]) -> None:
ok(port)
@@ -16,12 +16,12 @@ def _ppp_error(self, _ppp: PPPConnection, message: str, err: Callable[[str], Non
err(message)
self.timer.resume()
- def _ppp_connect(self, port: str, number: str, apn: str, caller: str,
+ def _ppp_connect(self, port: int, number: str, apn: str, caller: str,
ok: Callable[[str], None], err: Callable[[str], None]) -> None:
self.confirm_authorization(caller, "org.blueman.pppd.pppconnect")
self.timer.stop()
- ppp = PPPConnection(port, number, apn)
+ ppp = PPPConnection(f"/dev/rfcomm{port:d}", number, apn)
ppp.connect("error-occurred", self._ppp_error, err)
ppp.connect("connected", self._ppp_connected, ok)
diff --git a/blueman/services/meta/SerialService.py b/blueman/services/meta/SerialService.py
index 4195306da..28f84f9c3 100644
--- a/blueman/services/meta/SerialService.py
+++ b/blueman/services/meta/SerialService.py
@@ -70,7 +70,7 @@ def try_replace_root_watcher(self, monitor: Gio.FileMonitor, path: str, port: in
def connect(
self,
- reply_handler: Optional[Callable[[str], None]] = None,
+ reply_handler: Optional[Callable[[int], None]] = None,
error_handler: Optional[Callable[[RFCOMMError], None]] = None
) -> bool:
# We expect this service to have a reserved UUID
@@ -96,7 +96,7 @@ def connect(
self.try_replace_root_watcher(mon, filename, port_id)
if reply_handler:
- reply_handler(filename)
+ reply_handler(port_id)
except RFCOMMError as e:
if error_handler:
error_handler(e)