Disclaimer: this is completely mad science, and mostly a learning exercise.
I recently updated the Wine package to a recent stable version, and now want to play some old Windows games on NetBSD.
It's current year, my machine runs amd64, and Wine needs to be built with 32-bit libraries to run a lot of older Windows applications.
"Mainline pkgsrc" can't do strange multi-arch Wine builds yet, so a 32-bit sandbox seems like a reasonable way to use 32-bit Wine on amd64 without resorting to running real Windows in NVMM. We'll see if this was a viable alternative to re-reviewing the multi-arch support in pkgsrc-wip...
We're using
sandboxctl,
which is a neat tool for quickly shelling into a different NetBSD userspace.
Maybe you also don't trust the Windows applications you're running
too much - sandboxctl
creates a chroot
based on a fresh system image,
and chroot
on NetBSD is
fairly bombproof.
I learned a little bit more about how X11 works while trying this, too, which was nice!
First, install the sandboxctl
package:
# pkgin install sandboxctl
You'll need to enable some sysctl
variables.
This one will allow multiple system users to play audio, and will save you some debugging if you're wondering why things are mysteriously silent:
# sysctl -w hw.audio0.multiuser=1
This one will allow Wine to map the null
page (which it needs to do for cursed reasons):
# sysctl -w vm.user_va0_disable=0
Add them to /etc/sysctl.conf
to make them permanent.
Download some i386 NetBSD sets into a directory:
$ mkdir -p ~/netbsd-i386/binary/sets && cd ~/netbsd-i386/binary/sets
$ ftp https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.0/i386/binary/sets/base.tgz
$ ftp https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.0/i386/binary/sets/etc.tgz
$ ftp https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.0/i386/binary/sets/xbase.tgz
$ ftp https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.0/i386/binary/sets/xetc.tgz
$ ftp https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.0/i386/binary/sets/xfont.tgz
Create a new config file for sandboxctl
in /usr/pkg/etc/sandboxctl/wine.conf
:
SANDBOX_TYPE=netbsd-release
SANDBOX_ROOT="/var/chroot/wine-i386"
NETBSD_RELEASE_RELEASEDIR="/home/washbear/netbsd-i386"
NETBSD_RELEASE_SETS="base etc xbase xetc xfont"
Let's create the sandbox and Wine user:
# sandboxctl -c wine create
# sandboxctl -c wine run useradd -m -d /home/wine wine
Wine needs to abuse the system, because it needs to run Windows applications. You'll need to reconfigure NetBSD to allow this abuse, because by default NetBSD is fairly strict.
Running NetBSD 10 or -current? Then you don't need to do this.
Running NetBSD 9.x? Make sure your kernel has the necessary security
features disabled to run Wine. You'll need fresh netbsd-9
sources.
$ vi sys/arch/amd64/conf/GENERIC
These options matter:
# USER_LDT. You need to disable SVS to use it.
options USER_LDT # user-settable LDT; used by WINE
no options SVS
Build a new kernel. Shouldn't take too long :D
$ ./build.sh -U -j4 tools
$ ./build.sh -U -j4 kernel=GENERIC
Back up the old kernel, copy the new one into place and reboot:
# mv /netbsd /onetbsd
# cp sys/arch/amd64/compile/obj/GENERIC/netbsd /netbsd
# shutdown -r now
We need some way to allow X11 applications inside the sandbox to communicate with the X server.
This is required if /tmp
is not on the same filesystem as the sandbox.
It took me far too long to realize this.
Start the X server on the host machine with TCP connections and indirect GLX enabled:
$ startx -- -listen tcp +iglx
Once you're in X11, disable access control, and hopefully you're either behind a firewall or on a trusted network...
$ xhost +
I gave up with TCP and removed my tmpfs
mount in /etc/fstab
so
that /tmp
could reside on the same filesystem as the sandbox.
I actually don't like this at all.
This allows us to use hard links to the X11 Unix socket once X is started:
# mkdir -m 777 -p /var/chroot/wine-i386/tmp/.X11-unix
# ln -f /tmp/.X11-unix/X0 /var/chroot/wine-i386/tmp/.X11-unix/X0
# chmod 777 /var/chroot/wine-i386/tmp/.X11-unix/X0
Then use xauth
to grant access to your user's X server to the sandbox:
$ xauth extract /var/chroot/wine-i386/home/wine/.Xauthority :0
I quickly discovered Direct Rendering from a 32-bit sandbox isn't all that viable.
In the sense that glxgears
immediately segfaults,
regardless of whether the connection to X11 is over TCP or Unix socket.
I honestly wonder why, but debugging this further is probably too much pain
for today.
So,
$ export LIBGL_ALWAYS_SOFTWARE=1
(Makes OpenGL use llvmpipe instead of the GPU, might be slow depending on the age of the software and your hardware. You do not need +iglx for this. llvmpipe is surprisingly good even on my 5 year old CPU.)
or
$ export LIBGL_ALWAYS_INDIRECT=1
(Seems to work briefly, but then my X server crashes - ymmv.)
The Xserver(1)
man page has some interesting things to say about +iglx
and LIBGL_ALWAYS_INDIRECT=1
...
Indirect GLX is of limited use, since it lacks support for many modern OpenGL features and extensions; it's slower than direct contexts; and it opens a large attack surface for protocol parsing errors.
Ouch.
Shell into your sandbox:
# sandboxctl -c wine shell
Install the Wine package, and any others you desire in your 32-bit sandbox:
# export PKG_PATH=http://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/i386/9.0/All
# pkg_add pkgin
# pkgin update
# pkgin install wine
(I prefer to always use pkgin even for simple cases like this, it's just better.)
su
into your user account:
# su -l wine
From outside the sandbox, copy some files, maybe. In this case, I'm copying the DRM-free version of Red Faction from GOG.com:
# cp ~/Downloads/setup_red_faction_2.0.0.7.exe /var/chroot/wine-i386/home/wine/
Inside the sandbox, I can now run my 32-bit executable:
$ export DISPLAY=:0
$ winecfg
$ wine setup_red_faction_2.0.0.7.exe
When you're done, exit the sandbox with ^D
.
compat_linux
when
I can. It's much less janky.Making sure the sandbox user has the same uid
as your normal user
account probably helps with permissions nonsense.
In my case, it was the first ordinary user created on both systems, so that was automatic.