blob: b3ad80d1ea6f016db61dc1d335786ef66e34042d (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
{
name = "sandbox";
machine = { pkgs, lib, ... }: {
system.activationScripts.inject-link = ''
ln -svf ${pkgs.hello} /run/foo-test-sandbox
ln -svf ${pkgs.gnused} /run/bar-test-sandbox
ln -svf ${pkgs.gnugrep} /run/baz-test-sandbox
'';
environment.sessionVariables.COLLECT_ME = [
"/run/foo-test-sandbox"
"/run/bar-test-sandbox"
"/run/baz-test-sandbox"
];
# Only needed so we get the right XDG paths in the system path.
services.xserver.enable = true;
systemd.services.display-manager.enable = false;
systemd.sockets.netnstest = {
description = "Host Socket for Testing Network Namespaces";
requiredBy = [ "sockets.target" ];
socketConfig.ListenStream = "3000";
socketConfig.Accept = true;
};
systemd.services."netnstest@" = {
description = "Host Service for Testing Network Namespaces";
serviceConfig.StandardInput = "socket";
serviceConfig.ExecStart = "${pkgs.coreutils}/bin/tee /tmp/netns.log";
};
environment.systemPackages = let
mkNestedLinksTo = drv: let
mkLink = name: to: pkgs.runCommandLocal name { inherit to; } ''
ln -s "$to" "$out"
'';
in mkLink "nested-1" (mkLink "nested-2" (mkLink "nested-3" drv));
testPackage = pkgs.runCommand "test-sandbox" {
program = ''
#!${pkgs.stdenv.shell} -ex
if [ "$1" != canary ]; then
echo 'Canary check failed, so the test program probably' \
'was not executed via the XDG desktop entry.' >&2
exit 1
fi
# Should fail because we can't access the host's PATH
! echo foo | grep -qF foo
# No /bin/sh by default
test ! -e /bin
test ! -e /bin/sh
# Write PID information to files, so that we can later verify whether
# we were in a PID namespace.
echo $$ > /home/foo/.cache/xdg/ownpid
ls -d1 /proc/[0-9]* > /home/foo/.cache/xdg/procpids
# Check whether we can access files behind nested storepaths that are
# symlinks.
lfile="$(< ${mkNestedLinksTo (pkgs.writeText "target" "file")})"
test "$lfile" = file
ldir="$(< ${mkNestedLinksTo (pkgs.runCommandLocal "target" {} ''
mkdir -p "$out"
echo dir > "$out/canary"
'')}/canary)"
test "$ldir" = dir
export PATH=/run/baz-test-sandbox/bin
echo foo > /home/foo/existing/bar
test ! -d /home/foo/nonexisting
/run/foo-test-sandbox/bin/hello
echo aaa | /run/bar-test-sandbox/bin/sed -e 's/a/b/g'
echo XDG1 > /home/foo/.local/share/xdg/1
echo XDG2 > /home/foo/.config/xdg/2
echo XDG3 > /home/foo/.cache/xdg/3
echo > /home/foo/.cache/xdg/done
'';
} ''
mkdir -p "$out/bin" "$out/share/applications" "$out/share/test-sandbox"
echo -n "$program" > "$out/bin/test-sandbox"
chmod +x "$out/bin/test-sandbox"
echo '<svg xmlns="http://www.w3.org/2000/svg"/>' \
> "$out/share/test-sandbox/icon.svg"
cat > "$out/share/applications/test.desktop" <<EOF
[Desktop Entry]
Name=$fullName
Type=Application
Version=1.1
Exec=$out/bin/test-sandbox canary
Icon=$out/share/test-sandbox/icon.svg
Categories=Utility
EOF
'';
in [
# Unfortunately, "xdg-open test-sandbox.desktop" doesn't work, so let's
# use gtk-launch instead. We also need xvfb_run so that we can avoid to
# start a full-blown X server.
#
# See also:
#
# https://askubuntu.com/questions/5172
# https://bugs.launchpad.net/ubuntu/+source/gvfs/+bug/378783
#
(lib.getBin pkgs.gtk3) pkgs.xvfb_run
(pkgs.vuizvui.buildSandbox testPackage {
paths.required = [
"/home/foo/existing"
"$XDG_DATA_HOME/xdg"
"$XDG_CONFIG_HOME/xdg"
"$XDG_CACHE_HOME/xdg"
];
paths.wanted = [ "/home/foo/nonexisting" ];
paths.runtimeVars = [ "COLLECT_ME" ];
})
(pkgs.vuizvui.buildSandbox (pkgs.writeScriptBin "test-sandbox2" ''
#!/bin/sh
# Another /bin/sh just to be sure :-)
/bin/sh -c 'echo /bin/sh works'
'') { allowBinSh = true; })
(pkgs.vuizvui.buildSandbox (pkgs.writeScriptBin "test-sandbox3" ''
#!${pkgs.stdenv.shell}
echo hello network | ${pkgs.netcat-openbsd}/bin/nc -N 127.0.0.1 3000 \
|| echo netcat has failed
'') { namespaces.net = true; })
(pkgs.vuizvui.buildSandbox (pkgs.writeScriptBin "test-sandbox4" ''
#!${pkgs.stdenv.shell}
test $$ -gt 5 && echo no pid namespace
'') { namespaces.pid = false; })
];
users.users.foo.isNormalUser = true;
};
testScript = ''
# fmt: off
machine.wait_for_unit('multi-user.target')
machine.succeed('su - -c "xvfb-run gtk-launch test" foo >&2')
machine.wait_for_file('/home/foo/.cache/xdg/done')
machine.succeed('test -d /home/foo/existing')
machine.succeed('grep -qF foo /home/foo/existing/bar')
machine.fail('test -d /home/foo/nonexisting')
machine.succeed('grep -qF XDG1 /home/foo/.local/share/xdg/1')
machine.succeed('grep -qF XDG2 /home/foo/.config/xdg/2')
machine.succeed('grep -qF XDG3 /home/foo/.cache/xdg/3')
machine.succeed('test "$(< /home/foo/.cache/xdg/procpids)" = /proc/1')
machine.succeed('test "$(< /home/foo/.cache/xdg/ownpid)" = 1')
machine.succeed('test "$(su -c test-sandbox2 foo)" = "/bin/sh works"')
machine.succeed('su -c "echo root netns | nc -N 127.0.0.1 3000" foo')
machine.succeed('test "$(su -c test-sandbox3 foo)" = "netcat has failed"')
machine.fail('grep -F "hello network" /tmp/netns.log')
machine.succeed('grep -F "root netns" /tmp/netns.log')
machine.succeed('test "$(su -c test-sandbox4 foo)" = "no pid namespace"')
'';
}
|