]> git.proxmox.com Git - pve-container.git/blob - src/test/bindmount_test.pl
a6052dbda33890f76de5747c6fbfe01fcf56acd5
[pve-container.git] / src / test / bindmount_test.pl
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5
6 use Cwd;
7 use File::Path;
8
9 use lib qw(..);
10
11 use PVE::LXC;
12
13 my $pwd = getcwd();
14
15 my $rootdir = "./tmproot";
16 my $destdir = "/mnt";
17
18 my $sharedir = "/tmpshare";
19 my $a = "/tmpshare/a";
20 my $ab = "/tmpshare/a/b";
21 my $abc = "/tmpshare/a/b/c";
22 my $sym = "/tmpshare/sym";
23
24 my $secret = "/secret";
25
26 END {
27 my $ignore_error;
28 File::Path::rmtree("$pwd/$rootdir", {error => \$ignore_error});
29 File::Path::rmtree("$pwd/$sharedir", {error => \$ignore_error});
30 File::Path::rmtree("$pwd/$secret", {error => \$ignore_error});
31 };
32
33 # Create all the test paths...
34 PVE::LXC::walk_tree_nofollow('.', $rootdir, 1);
35 PVE::LXC::walk_tree_nofollow($rootdir, $destdir, 1);
36 PVE::LXC::walk_tree_nofollow('.', $abc, 1);
37 PVE::LXC::walk_tree_nofollow('.', $secret, 1);
38 # Create one evil symlink
39 symlink('a/b', "$pwd/$sym") or die "failed to prepare test folders: $!\n";
40
41 # Test walk_tree_nofollow:
42 eval { PVE::LXC::walk_tree_nofollow('.', $rootdir, 0) };
43 die "unexpected error: $@" if $@;
44 eval { PVE::LXC::walk_tree_nofollow('.', "$sym/c", 0) };
45 die "failed to catch symlink at $sym/c\n" if !$@;
46 die "unexpected test error: '$@'\n" if $@ ne "symlink encountered at: .$sym\n";
47
48 # Bindmount testing:
49 sub bindmount {
50 my ($from, $rootdir, $destdir, $inject, $ro, $inject_write) = @_;
51
52 my ($mpath, $mpfd, $parentfd, $last);
53 ($rootdir, $mpath, $mpfd, $parentfd, $last) =
54 PVE::LXC::__mount_prepare_rootdir($rootdir, $destdir);
55
56 my $srcdh = PVE::LXC::__bindmount_prepare('.', $from);
57
58 if ($inject) {
59 File::Path::rmtree(".$inject");
60 symlink("$pwd/$secret", ".$inject")
61 or die "failed to create symlink\n";
62 PVE::LXC::walk_tree_nofollow('.', $from, 1);
63 }
64 PVE::LXC::__bindmount_do(".$from", $mpath, $inject_write ? 0 : $ro);
65
66 my $res = PVE::LXC::__bindmount_verify($srcdh, $parentfd, $last, $ro);
67
68 system('umount', $mpath);
69 }
70
71 bindmount($a, $rootdir, $destdir, undef, 0, 0);
72 eval { bindmount($sym, $rootdir, $destdir, undef, 0, 0) };
73 die "illegal symlink bindmount went through\n" if !$@;
74 bindmount($abc, $rootdir, $destdir, undef, 0, 0);
75 # Race test: Assume someone exchanged 2 equivalent bind mounts between and
76 # after the bindmount_do()'s mount and remount calls.
77 # First: non-ro mount, should pass
78 bindmount($abc, $rootdir, $destdir, undef, 0, 1);
79 # Second: regular read-only mount, should pass.
80 bindmount($abc, $rootdir, $destdir, undef, 1, 0);
81 # Third: read-only requested with read-write injected
82 eval { bindmount($abc, $rootdir, $destdir, undef, 1, 1) };
83 die "read-write mount possible\n" if !$@;
84 die "unexpected test error: $@\n" if $@ ne "failed to mark bind mount read only\n";
85 # Race test: Replace /tmpshare/a/b with a symlink to /secret just before
86 # __bindmount_do().
87 eval { bindmount($abc, $rootdir, $destdir, $ab, 0, 0) };
88 die "injected symlink bindmount went through\n" if !$@;
89 die "unexpected test error: $@\n" if $@ ne "symlink encountered at: .$ab\n";