1#	$OpenBSD: OpenBSD-Unveil.t,v 1.1 2019/07/09 20:41:54 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	ok OpenBSD::Unveil::_unveil('/dev/random', 'r'),
86	    "Unveiled /dev/random r";
87	ok OpenBSD::Unveil::_unveil('/dev/null',   'wc'),
88	    "Unvailed /dev/null wc";
89
90	ok !-e '/dev/zero',   "Can't see /dev/zero";
91	ok !-w '/dev/random', "Can't write to /dev/random";
92	ok !-r '/dev/null',   "Can't read from /dev/null";
93
94	ok open(my $rfh, '<', '/dev/random'), "Opened /dev/random for reading";
95	ok read( $rfh, my $data, 64),         "Read from /dev/random";
96	ok close($rfh),                       "Closed /dev/random";
97
98	{
99		ok open(my $wfh, '>', '/dev/null'),
100		                              "Opened /dev/null for writing";
101		ok print($wfh $data),         "Printed to /dev/null";
102		ok close($wfh),               "Closed /dev/null";
103	}
104
105	ok OpenBSD::Unveil::_unveil('/dev/null',   'w'),
106	    "Unvailed /dev/null w";
107	ok OpenBSD::Unveil::_unveil(),
108		"locked unveil";
109
110	{
111		ok sysopen(my $wfh, '/dev/null', O_WRONLY),
112		                              "Sysopened /dev/null for writing";
113		ok syswrite($wfh, $data),     "Wrote to /dev/null";
114		ok close($wfh),               "Closed /dev/null";
115	}
116
117	{
118		ok !open(my $wfh, '>', '/dev/null'),
119			"Unable to 'open' without 'create'";
120	}
121};
122
123xsunveil_ok "Invalid Path" => sub {
124	chdir "/tmp" or die "Unable to chdir to /tmp";
125	my $dir = File::Temp->newdir('OpenBSD-Unveil-XXXXXXXXX');
126	ok !OpenBSD::Unveil::_unveil("$dir/nonexist/file", 'r'),
127	    "Unable to unveil with incorrect permissions";
128	is $!, 'No such file or directory', "Expected ERRNO from _unveil";
129};
130
131xsunveil_ok "Invalid Permissions" => sub {
132	ok !OpenBSD::Unveil::_unveil('/dev/null', 'abc'),
133	    "Unable to unveil with incorrect permissions";
134	is $!, 'Invalid argument', "Expected ERRNO from _unveil";
135};
136
137xsunveil_ok "Try to increase permissions" => sub {
138	ok OpenBSD::Unveil::_unveil('/dev/null', 'r'),
139	    "Set /dev/null to r";
140	TODO: { local $TODO = "Not sure why this fails";
141	ok !OpenBSD::Unveil::_unveil('/dev/null', 'rwc'),
142	    "Unable to increase permissions on /dev/null";
143	is $!, 'Operation not permitted', "Expected ERRNO from _unveil";
144	}
145};
146
147xsunveil_ok "Try to change veil after lock" => sub {
148	ok OpenBSD::Unveil::_unveil(), "Locked unveil";
149	ok !OpenBSD::Unveil::_unveil('/dev/null', 'r'),
150	    "Unable to unveil after lock";
151	is $!, 'Operation not permitted', "Expected ERRNO from _unveil";
152};
153
154#########################
155done_testing;
156
1571;    # to shut up critic
158