1#	$OpenBSD: OpenBSD-Unveil.t,v 1.2 2023/07/07 02:07:35 afresh1 Exp $	#
2## no critic 'version'
3## no critic 'package'
4# Before 'make install' is performed this script should be runnable with
5# 'make test'. After 'make install' it should work as 'perl OpenBSD-Unveil.t'
6
7#########################
8
9use strict;
10use warnings;
11
12use Test2::IPC;
13use Test::More;
14
15use Fcntl qw< O_RDONLY O_WRONLY >;
16use File::Temp;
17
18use POSIX qw< :errno_h >;
19
20BEGIN { use_ok('OpenBSD::Unveil') }
21
22#########################
23# UNVEIL
24#########################
25{
26	my @calls;
27	no warnings 'redefine';    ## no critic 'warnings';
28	local *OpenBSD::Unveil::_unveil = sub { push @calls, \@_; return 1 };
29	use warnings 'redefine';
30
31	{
32		local $@;
33		eval { local $SIG{__DIE__};
34		    OpenBSD::Unveil::unveil(qw< ab cx yz >) };
35 		my $at = sprintf "at %s line %d.\n", __FILE__, __LINE__ - 1;
36		is $@,
37		    "Usage: OpenBSD::Unveil::unveil([path, permissions]) $at",
38		    "Expected exception when too many params"
39	}
40
41	{
42		local $@;
43		eval { local $SIG{__DIE__};
44		    OpenBSD::Unveil::unveil(qw< ab >) };
45 		my $at = sprintf "at %s line %d.\n", __FILE__, __LINE__ - 1;
46		is $@,
47		    "Usage: OpenBSD::Unveil::unveil([path, permissions]) $at",
48		    "Expected exception when not enough params"
49	}
50
51	ok OpenBSD::Unveil::unveil( qw< foo bar > ), "Used two args";
52	ok OpenBSD::Unveil::unveil(),                "Used zero args";
53
54	is_deeply \@calls, [ [ qw< foo bar > ], [] ],
55	    "No modification to params";
56}
57
58## no critic 'private'
59## no critic 'punctuation'
60#########################
61# _UNVEIL
62#########################
63
64sub xsunveil_ok ($$)    ## no critic 'prototypes'
65{
66	my ( $name, $code ) = @_;
67	local $Test::Builder::Level =
68	    $Test::Builder::Level + 1;    ## no critic 'package variable'
69
70	my $pid = fork // die "Unable to fork for $name: $!\n";
71
72	if ( !$pid ) {
73		# for Test2::IPC
74		OpenBSD::Unveil::_unveil('/tmp', 'rwc') || die $!;
75		subtest $name, $code;
76		exit 0;
77	}
78
79	waitpid $pid, 0;
80	return $? >> 8;
81}
82
83
84xsunveil_ok "Basic Usage" => sub {
85	my $tmpfile = File::Temp->new("OpenBSD-Unveil-XXXXXXXXX", TMPDIR => 1);
86	$tmpfile->printflush("This is a test\n");
87
88	ok OpenBSD::Unveil::_unveil("$tmpfile", 'r'),
89	    "Unveiled tempfile r";
90	ok OpenBSD::Unveil::_unveil('/dev/null',   'wc'),
91	    "Unvailed /dev/null wc";
92
93	{
94		ok open(my $wfh, '>', '/dev/null'),
95		                         "Opened /dev/null for writing";
96		ok print($wfh "Test\n"), "Printed to /dev/null";
97		ok close($wfh),          "Closed /dev/null";
98	}
99
100	ok OpenBSD::Unveil::_unveil('/dev/null',   'w'),
101	    "Unvailed /dev/null w";
102	ok OpenBSD::Unveil::_unveil(),
103	    "locked unveil";
104
105	ok !-e '/dev/zero', "Stat says we can't see /dev/zero";
106	ok  -w $tmpfile,    "Stat says we can write to tempfile";
107	ok !-r '/dev/null', "Stat says we can't read from /dev/null";
108
109	{
110		ok sysopen(my $wfh, '/dev/null', O_WRONLY),
111		                              "Sysopened /dev/null for writing";
112		ok syswrite($wfh, "Test\n"),  "Wrote to /dev/null";
113		ok close($wfh),               "Closed /dev/null";
114	}
115
116	{
117		ok open(my $rfh, '<', $tmpfile), "Opened tempfile for reading";
118		ok read( $rfh, my $data, 64),    "Read from tempfile";
119		ok close($rfh),                  "Closed tempfile";
120	}
121
122	{
123		ok !open(my $wfh, '>', $tmpfile),
124			"Unable to 'open' tempfile for writing";
125		is $!, 'Permission denied', "Expected ERRNO from open";
126	}
127
128	{
129		ok !open(my $wfh, '>', '/dev/null'),
130			"Unable to 'open' /dev/null without 'create'";
131		is $!, 'Permission denied', "Expected ERRNO from open";
132	}
133};
134
135xsunveil_ok "Invalid Path" => sub {
136	my $dir = File::Temp->newdir('OpenBSD-Unveil-XXXXXXXXX', TMPDIR => 1);
137	ok !OpenBSD::Unveil::_unveil("$dir/nonexist/file", 'r'),
138	    "Unable to unveil with incorrect permissions";
139	is $!, 'No such file or directory', "Expected ERRNO from _unveil";
140};
141
142xsunveil_ok "Invalid Permissions" => sub {
143	ok !OpenBSD::Unveil::_unveil('/dev/null', 'abc'),
144	    "Unable to unveil with incorrect permissions";
145	is $!, 'Invalid argument', "Expected ERRNO from _unveil";
146};
147
148xsunveil_ok "Try to increase permissions" => sub {
149	ok OpenBSD::Unveil::_unveil('/dev/null', 'r'),
150	    "Set /dev/null to r";
151	TODO: { local $TODO = "Not sure why this fails";
152	ok !OpenBSD::Unveil::_unveil('/dev/null', 'rwc'),
153	    "Unable to increase permissions on /dev/null";
154	is $!, 'Operation not permitted', "Expected ERRNO from _unveil";
155	}
156};
157
158xsunveil_ok "Try to change veil after lock" => sub {
159	ok OpenBSD::Unveil::_unveil(), "Locked unveil";
160	ok !OpenBSD::Unveil::_unveil('/dev/null', 'r'),
161	    "Unable to unveil after lock";
162	is $!, 'Operation not permitted', "Expected ERRNO from _unveil";
163};
164
165#########################
166done_testing;
167
1681;    # to shut up critic
169