add dbus and dri

This commit is contained in:
Martin 2021-06-27 16:46:29 +02:00
parent 0103df5ca9
commit 354ba05faa
Signed by: mawalu
GPG Key ID: BF556F989760A7C8
5 changed files with 122 additions and 10 deletions

View File

@ -16,6 +16,13 @@ type Config* = object
mountcwd*: Option[bool] mountcwd*: Option[bool]
privileged*: Option[bool] privileged*: Option[bool]
sethostname*: Option[bool] sethostname*: Option[bool]
allowdri*: Option[bool]
dbus*: Option[bool]
dbussee*: Option[seq[string]]
dbustalk*: Option[seq[string]]
dbusown*: Option[seq[string]]
dbuscall*: Option[seq[string]]
dbusbroadcast*: Option[seq[string]]
proc applyConfig*(call: var BwrapCall, config: Config) = proc applyConfig*(call: var BwrapCall, config: Config) =
for mount in config.mount.get(@[]): for mount in config.mount.get(@[]):
@ -39,10 +46,19 @@ proc extendConfig*(config: var Config): Config {.discardable.} =
var eConf = loadConfig(getProfilePath(config.extends.unsafeGet)) var eConf = loadConfig(getProfilePath(config.extends.unsafeGet))
eConf.extendConfig() eConf.extendConfig()
# todo: replace using macro / templates
config.mount = some(config.mount.get(@[]).concat(eConf.mount.get(@[]))) config.mount = some(config.mount.get(@[]).concat(eConf.mount.get(@[])))
config.romount = some(config.romount.get(@[]).concat(eConf.romount.get(@[]))) config.romount = some(config.romount.get(@[]).concat(eConf.romount.get(@[])))
config.symlinks = some(config.symlinks.get(@[]).concat(eConf.symlinks.get(@[]))) config.symlinks = some(config.symlinks.get(@[]).concat(eConf.symlinks.get(@[])))
config.mountcwd = some(config.mountcwd.get(eConf.mountcwd.get(false))) config.mountcwd = some(config.mountcwd.get(eConf.mountcwd.get(false)))
config.sethostname = some(config.sethostname.get(eConf.sethostname.get(false))) config.sethostname = some(config.sethostname.get(eConf.sethostname.get(false)))
config.allowdri = some(config.allowdri.get(eConf.allowdri.get(false)))
config.dbus = some(config.dbus.get(eConf.dbus.get(false)))
config.dbussee = some(config.dbussee.get(@[]).concat(eConf.dbussee.get(@[])))
config.dbustalk = some(config.dbustalk.get(@[]).concat(eConf.dbustalk.get(@[])))
config.dbusown = some(config.dbusown.get(@[]).concat(eConf.dbusown.get(@[])))
config.dbuscall = some(config.dbuscall.get(@[]).concat(eConf.dbuscall.get(@[])))
config.dbusbroadcast = some(config.dbusbroadcast.get(@[]).concat(eConf.dbusbroadcast.get(@[])))
return config return config

54
lib/dbus.nim Normal file
View File

@ -0,0 +1,54 @@
import strformat
import options
import config
import osproc
import random
import os
type DbusProxy* = object
process*: Process
socket*: string
args: seq[string]
proc exec*(proxy: DbusProxy): Process =
# todo: start dbus proxy in bwrap
# todo: pass arguments as fd
startProcess("xdg-dbus-proxy", args = proxy.args,
options = {poEchoCmd, poParentStreams, poUsePath})
proc startDBusProxy*(config: Config, hostname: string): DbusProxy =
let busPath = getEnv("DBUS_SESSION_BUS_ADDRESS")
let runtimeDir = getEnv("XDG_RUNTIME_DIR")
if busPath == "" or runtimeDir == "":
raise newException(IOError, "DBUS_SESSION_BUS_ADDRESS and XDG_RUNTIME_DIR are required")
let id = rand(1000)
let filterName = &"dbus-proxy-{hostname}-{id}"
var proxy = DbusProxy()
proxy.socket = &"{runtimeDir}/{filterName}"
proxy.args.add(busPath)
proxy.args.add(proxy.socket)
for name in config.dbussee.get(@[]):
proxy.args.add(&"--see={name}")
for name in config.dbustalk.get(@[]):
proxy.args.add(&"--talk={name}")
for name in config.dbuscall.get(@[]):
proxy.args.add(&"--call={name}")
for name in config.dbusown.get(@[]):
proxy.args.add(&"--own={name}")
for name in config.dbusbroadcast.get(@[]):
proxy.args.add(&"--broadcast={name}")
proxy.args.add("--filter")
proxy.args.add("--log")
proxy.process = proxy.exec()
proxy

View File

@ -1,16 +1,18 @@
import os import strutils
import args import options
import json import config
import utils import utils
import bwrap import bwrap
import config import args
import options import json
import dbus
import os
proc sandboxExec*(args: Args) = proc sandboxExec*(args: Args) =
var call = BwrapCall() var call = BwrapCall()
var configPath = none(string) var configPath = none(string)
let hostname = args.name.get(getProfile(argst )) let hostname = args.name.get(getProfile(args))
if args.name.isSome: if args.name.isSome:
let name = args.name.unsafeGet let name = args.name.unsafeGet
@ -18,7 +20,6 @@ proc sandboxExec*(args: Args) =
let sandboxFiles = sandboxPath.joinPath("files") let sandboxFiles = sandboxPath.joinPath("files")
let userConfig = sandboxPath.joinPath("config.json") let userConfig = sandboxPath.joinPath("config.json")
createDir(sandboxFiles) createDir(sandboxFiles)
call.addArg("--bind", sandboxFiles, getHomeDir()) call.addArg("--bind", sandboxFiles, getHomeDir())
@ -35,10 +36,11 @@ proc sandboxExec*(args: Args) =
config.extendConfig() config.extendConfig()
call call
.addMount("--dev-bind", "/dev/null") .addArg("--dev", "/dev")
.addMount("--dev-bind", "/dev/random") .addMount("--dev-bind", "/dev/random")
.addMount("--dev-bind", "/dev/urandom") .addMount("--dev-bind", "/dev/urandom")
.addArg("--tmpfs", "/tmp") .addArg("--tmpfs", "/tmp")
.addArg("--tmpfs", "/dev/shm")
.addArg("--proc", "/proc") .addArg("--proc", "/proc")
.addArg("--unshare-all") .addArg("--unshare-all")
.addArg("--share-net") .addArg("--share-net")
@ -46,6 +48,18 @@ proc sandboxExec*(args: Args) =
.addArg("--setenv", "BWSANDBOX", "1") .addArg("--setenv", "BWSANDBOX", "1")
.applyConfig(config) .applyConfig(config)
if config.dbus.get(false):
# todo: handle process and cleanup later
let proxy = startDBusProxy(config, hostname)
call.addArg("--ro-bind", proxy.socket,
getEnv("DBUS_SESSION_BUS_ADDRESS").split('=')[1])
# todo: use fd signaling instead of this
sleep(100)
if config.allowdri.get(false):
enableDri(call)
if config.mountcwd.get(false): if config.mountcwd.get(false):
call call
.addMount("--bind", getCurrentDir()) .addMount("--bind", getCurrentDir())

View File

@ -1,5 +1,8 @@
import os import strformat
import posix
import bwrap
import args import args
import os
const APP_NAME = "bwsandbox" const APP_NAME = "bwsandbox"
@ -22,4 +25,27 @@ proc getProfilePath*(args: Args): string =
proc getSandboxPath*(name: string): string = proc getSandboxPath*(name: string): string =
getDataDir() getDataDir()
.joinPath(APP_NAME) .joinPath(APP_NAME)
.joinPath(name) .joinPath(name)
proc deviceExists(path: string): bool =
var res: Stat
return stat(path, res) >= 0 and S_ISCHR(res.st_mode)
# https://github.com/flatpak/flatpak/blob/1bdbb80ac57df437e46fce2cdd63e4ff7704718b/common/flatpak-run.c#L1496
proc enableDri*(call: var BwrapCall) =
const mounts = [
"/dev/dri", # general
"/dev/mali", "/dev/mali0", "/dev/umplock", # mali
"/dev/nvidiactl", "/dev/nvidia-modeset", # nvidia
"/dev/nvidia-uvm", "/dev/nvidia-uvm-tools" # nvidia OpenCl/CUDA
]
for mount in mounts:
if deviceExists(mount):
call.addMount("--dev-bind", mount)
for i in 0..20:
let device = &"/dev/nvidia{i}"
if deviceExists(device):
call.addMount("--dev-bind", device)

View File

@ -1,6 +1,7 @@
import lib/sandbox import lib/sandbox
import lib/args import lib/args
import options import options
import random
proc main(): int = proc main(): int =
let args = parseArgs() let args = parseArgs()
@ -9,6 +10,7 @@ proc main(): int =
echo "Usage: bwshell --command=cmd --profile=profile <sandbox_name>" echo "Usage: bwshell --command=cmd --profile=profile <sandbox_name>"
return 1 return 1
else: else:
randomize()
sandboxExec(args.unsafeGet) sandboxExec(args.unsafeGet)
quit(main()) quit(main())