]> glassweightruler.freedombox.rocks Git - waydroid.git/blob - tools/actions/container_manager.py
security: Verify session pid against DBus connection
[waydroid.git] / tools / actions / container_manager.py
1 # Copyright 2021 Erfan Abdi
2 # SPDX-License-Identifier: GPL-3.0-or-later
3 from shutil import which
4 import logging
5 import os
6 import time
7 import glob
8 import signal
9 import sys
10 import uuid
11 import tools.config
12 from tools import helpers
13 from tools import services
14 import dbus
15 import dbus.service
16 import dbus.exceptions
17 from gi.repository import GLib
18
19 class DbusContainerManager(dbus.service.Object):
20 def __init__(self, looper, bus, object_path, args):
21 self.args = args
22 self.looper = looper
23 dbus.service.Object.__init__(self, bus, object_path)
24
25 @dbus.service.method("id.waydro.ContainerManager", in_signature='a{ss}', out_signature='', sender_keyword="sender", connection_keyword="conn")
26 def Start(self, session, sender, conn):
27 dbus_info = dbus.Interface(conn.get_object("org.freedesktop.DBus", "/org/freedesktop/DBus/Bus", False), "org.freedesktop.DBus")
28 uid = dbus_info.GetConnectionUnixUser(sender)
29 if str(uid) not in ["0", session["user_id"]]:
30 raise RuntimeError("Cannot start a session on behalf of another user")
31 pid = dbus_info.GetConnectionUnixProcessID(sender)
32 if str(uid) != "0" and str(pid) != session["pid"]:
33 raise RuntimeError("Invalid session pid")
34 do_start(self.args, session)
35
36 @dbus.service.method("id.waydro.ContainerManager", in_signature='b', out_signature='')
37 def Stop(self, quit_session):
38 stop(self.args, quit_session)
39
40 @dbus.service.method("id.waydro.ContainerManager", in_signature='', out_signature='')
41 def Freeze(self):
42 freeze(self.args)
43
44 @dbus.service.method("id.waydro.ContainerManager", in_signature='', out_signature='')
45 def Unfreeze(self):
46 unfreeze(self.args)
47
48 @dbus.service.method("id.waydro.ContainerManager", in_signature='', out_signature='a{ss}')
49 def GetSession(self):
50 try:
51 session = self.args.session
52 session["state"] = helpers.lxc.status(self.args)
53 return session
54 except AttributeError:
55 return {}
56
57 def service(args, looper):
58 dbus_obj = DbusContainerManager(looper, dbus.SystemBus(), '/ContainerManager', args)
59 looper.run()
60
61 def set_permissions(args, perm_list=None, mode="777"):
62 def chmod(path, mode):
63 if os.path.exists(path):
64 command = ["chmod", mode, "-R", path]
65 tools.helpers.run.user(args, command, check=False)
66
67 # Nodes list
68 if not perm_list:
69 perm_list = [
70 "/dev/ashmem",
71
72 # sw_sync for HWC
73 "/dev/sw_sync",
74 "/sys/kernel/debug/sync/sw_sync",
75
76 # Media
77 "/dev/Vcodec",
78 "/dev/MTK_SMI",
79 "/dev/mdp_sync",
80 "/dev/mtk_cmdq",
81
82 # Graphics
83 "/dev/dri",
84 "/dev/graphics",
85 "/dev/pvr_sync",
86 "/dev/ion",
87 ]
88
89 # Framebuffers
90 perm_list.extend(glob.glob("/dev/fb*"))
91 # Videos
92 perm_list.extend(glob.glob("/dev/video*"))
93
94 for path in perm_list:
95 chmod(path, mode)
96
97 def start(args):
98 try:
99 name = dbus.service.BusName("id.waydro.Container", dbus.SystemBus(), do_not_queue=True)
100 except dbus.exceptions.NameExistsException:
101 logging.error("Container service is already running")
102 return
103
104 status = helpers.lxc.status(args)
105 if status == "STOPPED":
106 # Load binder and ashmem drivers
107 cfg = tools.config.load(args)
108 if cfg["waydroid"]["vendor_type"] == "MAINLINE":
109 if helpers.drivers.probeBinderDriver(args) != 0:
110 logging.error("Failed to load Binder driver")
111 helpers.drivers.probeAshmemDriver(args)
112 helpers.drivers.loadBinderNodes(args)
113 set_permissions(args, [
114 "/dev/" + args.BINDER_DRIVER,
115 "/dev/" + args.VNDBINDER_DRIVER,
116 "/dev/" + args.HWBINDER_DRIVER
117 ], "666")
118
119 mainloop = GLib.MainLoop()
120
121 def sigint_handler(data):
122 stop(args)
123 mainloop.quit()
124
125 GLib.unix_signal_add(GLib.PRIORITY_HIGH, signal.SIGINT, sigint_handler, None)
126 GLib.unix_signal_add(GLib.PRIORITY_HIGH, signal.SIGTERM, sigint_handler, None)
127 service(args, mainloop)
128 else:
129 logging.error("WayDroid container is {}".format(status))
130
131 def do_start(args, session):
132 if "session" in args:
133 raise RuntimeError("Already tracking a session")
134
135 # Networking
136 command = [tools.config.tools_src +
137 "/data/scripts/waydroid-net.sh", "start"]
138 tools.helpers.run.user(args, command)
139
140 # Sensors
141 if which("waydroid-sensord"):
142 tools.helpers.run.user(
143 args, ["waydroid-sensord", "/dev/" + args.HWBINDER_DRIVER], output="background")
144
145 # Mount rootfs
146 cfg = tools.config.load(args)
147 helpers.images.mount_rootfs(args, cfg["waydroid"]["images_path"], session)
148
149 helpers.protocol.set_aidl_version(args)
150
151 # Cgroup hacks
152 if which("start"):
153 command = ["start", "cgroup-lite"]
154 tools.helpers.run.user(args, command, check=False)
155 if os.path.ismount("/sys/fs/cgroup/schedtune"):
156 command = ["umount", "-l", "/sys/fs/cgroup/schedtune"]
157 tools.helpers.run.user(args, command, check=False)
158
159 #TODO: remove NFC hacks
160 if which("stop"):
161 command = ["stop", "nfcd"]
162 tools.helpers.run.user(args, command, check=False)
163
164 # Set permissions
165 set_permissions(args)
166
167 # Create session-specific LXC config file
168 helpers.lxc.generate_session_lxc_config(args, session)
169 # Backwards compatibility
170 with open(tools.config.defaults["lxc"] + "/waydroid/config") as f:
171 if "config_session" not in f.read():
172 helpers.mount.bind(args, session["waydroid_data"],
173 tools.config.defaults["data"])
174
175 helpers.lxc.start(args)
176 services.hardware_manager.start(args)
177
178 args.session = session
179
180 def stop(args, quit_session=True):
181 try:
182 services.hardware_manager.stop(args)
183 status = helpers.lxc.status(args)
184 if status != "STOPPED":
185 helpers.lxc.stop(args)
186 while helpers.lxc.status(args) != "STOPPED":
187 pass
188
189 # Networking
190 command = [tools.config.tools_src +
191 "/data/scripts/waydroid-net.sh", "stop"]
192 tools.helpers.run.user(args, command, check=False)
193
194 #TODO: remove NFC hacks
195 if which("start"):
196 command = ["start", "nfcd"]
197 tools.helpers.run.user(args, command, check=False)
198
199 # Sensors
200 if which("waydroid-sensord"):
201 command = ["pidof", "waydroid-sensord"]
202 pid = tools.helpers.run.user(args, command, check=False, output_return=True).strip()
203 if pid:
204 command = ["kill", "-9", pid]
205 tools.helpers.run.user(args, command, check=False)
206
207 # Umount rootfs
208 helpers.images.umount_rootfs(args)
209
210 # Backwards compatibility
211 try:
212 helpers.mount.umount_all(args, tools.config.defaults["data"])
213 except:
214 pass
215
216 if "session" in args:
217 if quit_session:
218 try:
219 os.kill(int(args.session["pid"]), signal.SIGUSR1)
220 except:
221 pass
222 del args.session
223 except:
224 pass
225
226 def restart(args):
227 status = helpers.lxc.status(args)
228 if status == "RUNNING":
229 helpers.lxc.stop(args)
230 helpers.lxc.start(args)
231 else:
232 logging.error("WayDroid container is {}".format(status))
233
234 def freeze(args):
235 status = helpers.lxc.status(args)
236 if status == "RUNNING":
237 helpers.lxc.freeze(args)
238 while helpers.lxc.status(args) == "RUNNING":
239 pass
240 else:
241 logging.error("WayDroid container is {}".format(status))
242
243 def unfreeze(args):
244 status = helpers.lxc.status(args)
245 if status == "FROZEN":
246 helpers.lxc.unfreeze(args)
247 while helpers.lxc.status(args) == "FROZEN":
248 pass