diff --git a/lib/config.nim b/lib/config.nim index a25536c..35f250e 100644 --- a/lib/config.nim +++ b/lib/config.nim @@ -16,6 +16,13 @@ type Config* = object mountcwd*: Option[bool] privileged*: 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) = for mount in config.mount.get(@[]): @@ -39,10 +46,19 @@ proc extendConfig*(config: var Config): Config {.discardable.} = var eConf = loadConfig(getProfilePath(config.extends.unsafeGet)) eConf.extendConfig() + # todo: replace using macro / templates config.mount = some(config.mount.get(@[]).concat(eConf.mount.get(@[]))) config.romount = some(config.romount.get(@[]).concat(eConf.romount.get(@[]))) config.symlinks = some(config.symlinks.get(@[]).concat(eConf.symlinks.get(@[]))) config.mountcwd = some(config.mountcwd.get(eConf.mountcwd.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 diff --git a/lib/dbus.nim b/lib/dbus.nim new file mode 100644 index 0000000..30a2ae3 --- /dev/null +++ b/lib/dbus.nim @@ -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: var DbusProxy) = + # todo: start dbus proxy in bwrap + # todo: pass arguments as fd + proxy.process = 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.exec() + + proxy \ No newline at end of file diff --git a/lib/sandbox.nim b/lib/sandbox.nim index 160a3d9..d7241f2 100644 --- a/lib/sandbox.nim +++ b/lib/sandbox.nim @@ -1,16 +1,18 @@ -import os -import args -import json +import strutils +import options +import config import utils import bwrap -import config -import options +import args +import json +import dbus +import os proc sandboxExec*(args: Args) = var call = BwrapCall() var configPath = none(string) - let hostname = args.name.get(getProfile(argst )) + let hostname = args.name.get(getProfile(args)) if args.name.isSome: let name = args.name.unsafeGet @@ -18,7 +20,6 @@ proc sandboxExec*(args: Args) = let sandboxFiles = sandboxPath.joinPath("files") let userConfig = sandboxPath.joinPath("config.json") - createDir(sandboxFiles) call.addArg("--bind", sandboxFiles, getHomeDir()) @@ -35,10 +36,11 @@ proc sandboxExec*(args: Args) = config.extendConfig() call - .addMount("--dev-bind", "/dev/null") + .addArg("--dev", "/dev") .addMount("--dev-bind", "/dev/random") .addMount("--dev-bind", "/dev/urandom") .addArg("--tmpfs", "/tmp") + .addArg("--tmpfs", "/dev/shm") .addArg("--proc", "/proc") .addArg("--unshare-all") .addArg("--share-net") @@ -46,6 +48,18 @@ proc sandboxExec*(args: Args) = .addArg("--setenv", "BWSANDBOX", "1") .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): call .addMount("--bind", getCurrentDir()) diff --git a/lib/utils.nim b/lib/utils.nim index 08d39e4..3eaa065 100644 --- a/lib/utils.nim +++ b/lib/utils.nim @@ -1,5 +1,8 @@ -import os +import strformat +import posix +import bwrap import args +import os const APP_NAME = "bwsandbox" @@ -22,4 +25,27 @@ proc getProfilePath*(args: Args): string = proc getSandboxPath*(name: string): string = getDataDir() .joinPath(APP_NAME) - .joinPath(name) \ No newline at end of file + .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) \ No newline at end of file diff --git a/main.nim b/main.nim index c4fd8ec..8672157 100644 --- a/main.nim +++ b/main.nim @@ -1,6 +1,7 @@ import lib/sandbox import lib/args import options +import random proc main(): int = let args = parseArgs() @@ -9,6 +10,7 @@ proc main(): int = echo "Usage: bwshell --command=cmd --profile=profile " return 1 else: + randomize() sandboxExec(args.unsafeGet) quit(main())