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