Skip to content

Commit c6862d5

Browse files
committed
fix: Reduce kill switch auth requirements
Upstream is unresponsive, see ProtonVPN/python-proton-vpn-api-core#10 copied below: To mitigate CVE-2025-9615, NetworkManager from 1.57.1 (at least) will remove the modify_system build option (a new option is available for backwards compatibility but is discouraged). See https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2324 Thus, users of Debian, NixOS, & Tumbleweed already experience constant polkit prompts, and others are likely to follow since NetworkManager discourages keeping the current behaviour in newer versions. When a non-permanent kill switch is enabled ("Standard" and/or IPv6) without modify_system, a polkit prompt appears for every manual (dis)connection of the VPN (except within auth timeout of previous prompt). This is because editing system connections uses the `org.freedesktop.NetworkManager.settings.modify.system` polkit action, which without modify_system defaults to `auth_admin_keep`. To fix this, a user connection is sufficient as on boot it is acceptable to wait for login like the VPN connection (also a user connection). When the user's regular connection is also a user connection, there will be no polkit prompt to manually (dis)connect the VPN. Only the permanent ("Advanced") kill switch needs to be a system connection so that there is no leak before user login on boot, and since it's permanent (written to disk) the polkit prompt is only required when enabling/disabling the permanent kill switch setting and not on every manual (dis)connection of the VPN.
1 parent d7b45fa commit c6862d5

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

com.protonvpn.www.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,8 @@ modules:
760760
tag-template: v$version
761761
- type: patch
762762
path: patches/python-proton-vpn-api-core/fix-ip-path.patch
763+
- type: patch
764+
path: patches/python-proton-vpn-api-core/fix-killswitch-auth.patch
763765

764766
- name: python-proton-vpn-network-manager
765767
buildsystem: simple
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
diff --git a/proton/vpn/backend/networkmanager/killswitch/default/killswitch_connection.py b/proton/vpn/backend/networkmanager/killswitch/default/killswitch_connection.py
2+
index 57ad6fa..49a21aa 100644
3+
--- a/proton/vpn/backend/networkmanager/killswitch/default/killswitch_connection.py
4+
+++ b/proton/vpn/backend/networkmanager/killswitch/default/killswitch_connection.py
5+
@@ -24,6 +24,7 @@ along with ProtonVPN. If not, see <https://www.gnu.org/licenses/>.
6+
7+
from dataclasses import dataclass, field
8+
import uuid
9+
+from getpass import getuser
10+
11+
import gi # pylint: disable=C0411
12+
gi.require_version("NM", "1.0")
13+
@@ -37,6 +38,7 @@ DEFAULT_METRIC = -1
14+
class KillSwitchGeneralConfig: # pylint: disable=missing-class-docstring
15+
human_readable_id: str
16+
interface_name: str
17+
+ permanent: bool
18+
19+
20+
@dataclass
21+
@@ -86,6 +88,11 @@ class KillSwitchConnection: # pylint: disable=too-few-public-methods
22+
s_con.set_property(NM.SETTING_CONNECTION_UUID, str(uuid.uuid4()))
23+
s_con.set_property(NM.SETTING_CONNECTION_TYPE, NM.SETTING_DUMMY_SETTING_NAME)
24+
25+
+ # Only permanent kill switch needs to be a system connection;
26+
+ # weaker kill switches can be user connections to avoid polkit auth.
27+
+ if not self._general_settings.permanent:
28+
+ s_con.add_permission(NM.SETTING_USER_SETTING_NAME, getuser(), None)
29+
+
30+
s_dummy = NM.SettingDummy.new()
31+
32+
s_ipv4 = self._generate_ipv4_settings()
33+
diff --git a/proton/vpn/backend/networkmanager/killswitch/default/killswitch_connection_handler.py b/proton/vpn/backend/networkmanager/killswitch/default/killswitch_connection_handler.py
34+
index 831d962..425adf5 100644
35+
--- a/proton/vpn/backend/networkmanager/killswitch/default/killswitch_connection_handler.py
36+
+++ b/proton/vpn/backend/networkmanager/killswitch/default/killswitch_connection_handler.py
37+
@@ -144,7 +144,8 @@ class KillSwitchConnectionHandler:
38+
interface_name = _get_interface_name(permanent)
39+
general_config = KillSwitchGeneralConfig(
40+
human_readable_id=connection_id,
41+
- interface_name=interface_name
42+
+ interface_name=interface_name,
43+
+ permanent=permanent
44+
)
45+
46+
kill_switch = KillSwitchConnection(
47+
@@ -174,7 +175,8 @@ class KillSwitchConnectionHandler:
48+
49+
general_config = KillSwitchGeneralConfig(
50+
human_readable_id=_get_connection_id(self._connection_prefix, permanent, routed=True),
51+
- interface_name=_get_interface_name(permanent, routed=True)
52+
+ interface_name=_get_interface_name(permanent, routed=True),
53+
+ permanent=permanent
54+
)
55+
kill_switch = KillSwitchConnection(
56+
general_config,
57+
@@ -204,7 +206,8 @@ class KillSwitchConnectionHandler:
58+
interface_name = _get_interface_name(permanent=False, ipv6=True)
59+
general_config = KillSwitchGeneralConfig(
60+
human_readable_id=connection_id,
61+
- interface_name=interface_name
62+
+ interface_name=interface_name,
63+
+ permanent=False
64+
)
65+
66+
kill_switch = KillSwitchConnection(
67+
diff --git a/proton/vpn/backend/networkmanager/killswitch/wireguard/killswitch_connection.py b/proton/vpn/backend/networkmanager/killswitch/wireguard/killswitch_connection.py
68+
index 4813fbc..59cf700 100644
69+
--- a/proton/vpn/backend/networkmanager/killswitch/wireguard/killswitch_connection.py
70+
+++ b/proton/vpn/backend/networkmanager/killswitch/wireguard/killswitch_connection.py
71+
@@ -24,6 +24,7 @@ along with ProtonVPN. If not, see <https://www.gnu.org/licenses/>.
72+
73+
from dataclasses import dataclass, field
74+
import uuid
75+
+from getpass import getuser
76+
77+
import gi
78+
gi.require_version("NM", "1.0")
79+
@@ -37,6 +38,7 @@ DEFAULT_METRIC = -1
80+
class KillSwitchGeneralConfig: # pylint: disable=missing-class-docstring
81+
human_readable_id: str
82+
interface_name: str
83+
+ permanent: bool
84+
85+
86+
@dataclass
87+
@@ -86,6 +88,11 @@ class KillSwitchConnection: # pylint: disable=too-few-public-methods
88+
s_con.set_property(NM.SETTING_CONNECTION_UUID, str(uuid.uuid4()))
89+
s_con.set_property(NM.SETTING_CONNECTION_TYPE, NM.SETTING_DUMMY_SETTING_NAME)
90+
91+
+ # Only permanent kill switch needs to be a system connection;
92+
+ # weaker kill switches can be user connections to avoid polkit auth.
93+
+ if not self._general_settings.permanent:
94+
+ s_con.add_permission(NM.SETTING_USER_SETTING_NAME, getuser(), None)
95+
+
96+
s_dummy = NM.SettingDummy.new()
97+
98+
s_ipv4 = self._generate_ipv4_settings()
99+
diff --git a/proton/vpn/backend/networkmanager/killswitch/wireguard/killswitch_connection_handler.py b/proton/vpn/backend/networkmanager/killswitch/wireguard/killswitch_connection_handler.py
100+
index 3dd755d..5f72b1b 100644
101+
--- a/proton/vpn/backend/networkmanager/killswitch/wireguard/killswitch_connection_handler.py
102+
+++ b/proton/vpn/backend/networkmanager/killswitch/wireguard/killswitch_connection_handler.py
103+
@@ -115,7 +115,8 @@ class KillSwitchConnectionHandler:
104+
105+
general_config = self._config or KillSwitchGeneralConfig(
106+
human_readable_id=_get_connection_id(permanent),
107+
- interface_name=_get_interface_name(permanent)
108+
+ interface_name=_get_interface_name(permanent),
109+
+ permanent=permanent
110+
)
111+
112+
connection = self.nm_client.get_active_connection(
113+
@@ -246,7 +247,8 @@ class KillSwitchConnectionHandler:
114+
interface_name = _get_interface_name(permanent=False, ipv6=True)
115+
general_config = KillSwitchGeneralConfig(
116+
human_readable_id=connection_id,
117+
- interface_name=interface_name
118+
+ interface_name=interface_name,
119+
+ permanent=False
120+
)
121+
122+
kill_switch = KillSwitchConnection(

0 commit comments

Comments
 (0)