maint: silence deprecated module warning
[coreutils.git] / tests / cp / cp-a-selinux.sh
bloba31b96cce6bf2ae273a357f376ecb877238765af
1 #!/bin/sh
2 # Ensure that cp -Z, -a and cp --preserve=context work properly.
3 # In particular, test on a writable NFS partition.
4 # Check also locally if --preserve=context, -a and --preserve=all
5 # does work
7 # Copyright (C) 2007-2024 Free Software Foundation, Inc.
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <https://www.gnu.org/licenses/>.
22 . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
23 print_ver_ cp
24 require_root_
25 require_selinux_
27 cwd=$(pwd)
28 cleanup_() { cd /; umount "$cwd/mnt"; }
30 # This context is special: it works even when mcstransd isn't running.
31 ctx='root:object_r:tmp_t'
32 mls_enabled_ && ctx="$ctx:s0"
34 # Check basic functionality - before check on fixed context mount
35 touch c || framework_failure_
36 chcon $ctx c || skip_ "Failed to set context: $ctx"
37 cp -a c d 2>err || framework_failure_
38 cp --preserve=context c e || framework_failure_
39 cp --preserve=all c f || framework_failure_
40 ls -Z d | grep $ctx || fail=1
41 # there must be no stderr output for -a
42 compare /dev/null err || fail=1
43 ls -Z e | grep $ctx || fail=1
44 ls -Z f | grep $ctx || fail=1
45 rm -f f
47 # Check handling of existing dirs which requires specific handling
48 # due to recursion, and was handled incorrectly in coreutils-8.22
49 # Note standard permissions are updated for existing directories
50 # in the destination, so SELinux contexts should be updated too.
51 mkdir -p backup/existing_dir/ || framework_failure_
52 ls -Zd backup/existing_dir > ed_ctx || fail=1
53 grep $ctx ed_ctx && framework_failure_
54 touch backup/existing_dir/file || framework_failure_
55 chcon $ctx backup/existing_dir/file || framework_failure_
56 # Set the dir context to ensure it is reset
57 mkdir -p --context="$ctx" restore/existing_dir || framework_failure_
58 # Copy and ensure existing directories updated
59 cp -a backup/. restore/ || fail=1
60 ls -Zd restore/existing_dir > ed_ctx || fail=1
61 grep $ctx ed_ctx &&
62 { ls -lZd restore/existing_dir; fail=1; }
64 # Check context preserved with directories created with --parents,
65 # which was not handled before coreutils-8.27
66 mkdir -p parents/a/b || framework_failure_
67 ls -Zd parents/a/b > ed_ctx || fail=1
68 grep $ctx ed_ctx && framework_failure_
69 touch parents/a/b/file || framework_failure_
70 chcon $ctx parents/a/b || framework_failure_
71 # Set the dir context to ensure it is reset
72 mkdir -p --context="$ctx" parents_dest/parents/a || framework_failure_
73 # Copy and ensure existing directories updated
74 cp -r --parents --preserve=context parents/a/b/file parents_dest || fail=1
75 # Check new context
76 ls -Zd parents_dest/parents/a/b > ed_ctx || fail=1
77 grep $ctx ed_ctx ||
78 { ls -lZd parents_dest/parents/a/b; fail=1; }
79 # Check updated context
80 ls -Zd parents_dest/parents/a > ed_ctx || fail=1
81 grep $ctx ed_ctx &&
82 { ls -lZd parents_dest/parents/a; fail=1; }
84 # Check restorecon (-Z) functionality for file and directory
85 # Also make a dir with our known context
86 mkdir c_d || framework_failure_
87 chcon $ctx c_d || framework_failure_
88 # Get the type of this known context for file and dir for tracing
89 old_type_f=$(get_selinux_type c)
90 old_type_d=$(get_selinux_type c_d)
91 # Setup copies for manipulation with restorecon
92 # and get the adjusted type for comparison
93 cp -a c Z1 || fail=1
94 cp -a c_d Z1_d || fail=1
95 if restorecon Z1 Z1_d 2>restorecon.err \
96 && compare /dev/null restorecon.err; then
97 new_type_f=$(get_selinux_type Z1)
98 new_type_d=$(get_selinux_type Z1_d)
100 # Ensure -Z sets the type like restorecon does
101 cp -Z c Z2 || fail=1
102 cpZ_type_f=$(get_selinux_type Z2)
103 test "$cpZ_type_f" = "$new_type_f" || fail=1
105 # Ensure -Z overrides -a and that dirs are handled too
106 cp -aZ c Z3 || fail=1
107 cp -aZ c_d Z3_d || fail=1
108 cpaZ_type_f=$(get_selinux_type Z3)
109 cpaZ_type_d=$(get_selinux_type Z3_d)
110 test "$cpaZ_type_f" = "$new_type_f" || fail=1
111 test "$cpaZ_type_d" = "$new_type_d" || fail=1
113 # Ensure -Z sets the type for existing files
114 mkdir -p existing/c_d || framework_failure_
115 touch existing/c || framework_failure_
116 cp -aZ c c_d existing || fail=1
117 cpaZ_type_f=$(get_selinux_type existing/c)
118 cpaZ_type_d=$(get_selinux_type existing/c_d)
119 test "$cpaZ_type_f" = "$new_type_f" || fail=1
120 test "$cpaZ_type_d" = "$new_type_d" || fail=1
123 skip=0
124 # Create a file system, then mount it with the context=... option.
125 dd if=/dev/zero of=blob bs=8192 count=200 || skip=1
126 mkdir mnt || skip=1
127 mkfs -t ext2 -F blob ||
128 skip_ "failed to create an ext2 file system"
130 mount -oloop,context=$ctx blob mnt || skip=1
131 test $skip = 1 \
132 && skip_ "insufficient mount/ext2 support"
134 cd mnt || framework_failure_
136 # Create files with hopefully different contexts
137 echo > ../f || framework_failure_
138 echo > g || framework_failure_
139 test "$(stat -c%C ../f)" = "$(stat -c%C g)" &&
140 skip_ "files on separate file systems have the same security context"
142 # /bin/cp from coreutils-6.7-3.fc7 would fail this test by letting cp
143 # succeed (giving no diagnostics), yet leaving the destination file empty.
144 cp -a ../f g 2>err || fail=1
145 test -s g || fail=1 # The destination file must not be empty.
146 compare /dev/null err || fail=1
148 # =====================================================
149 # Here, we expect cp to succeed and not warn with "Operation not supported"
150 rm -f g
151 echo > g
152 cp --preserve=all ../f g 2>err || fail=1
153 test -s g || fail=1
154 grep "Operation not supported" err && fail=1
156 # =====================================================
157 # The same as above except destination does not exist
158 rm -f g
159 cp --preserve=all ../f g 2>err || fail=1
160 test -s g || fail=1
161 grep "Operation not supported" err && fail=1
163 # An alternative to the following approach would be to run in a confined
164 # domain (maybe creating/loading it) that lacks the required permissions
165 # to the file type.
166 # Note: this test could also be run by a regular (non-root) user in an
167 # NFS mounted directory. When doing that, I get this diagnostic:
168 # cp: failed to set the security context of 'g' to 'system_u:object_r:nfs_t': \
169 # Operation not supported
170 cat <<\EOF > exp || framework_failure_
171 cp: failed to set the security context of
174 rm -f g
175 echo > g
176 # =====================================================
177 # Here, we expect cp to fail, because it cannot set the SELinux
178 # security context through NFS or a mount with fixed context.
179 cp --preserve=context ../f g 2> out && fail=1
180 # Here, we *do* expect the destination to be empty.
181 compare /dev/null g || fail=1
182 sed "s/ .g'.*//" out > k
183 mv k out
184 compare exp out || fail=1
186 rm -f g
187 echo > g
188 # Check if -a option doesn't silence --preserve=context option diagnostics
189 cp -a --preserve=context ../f g 2> out2 && fail=1
190 # Here, we *do* expect the destination to be empty.
191 compare /dev/null g || fail=1
192 sed "s/ .g'.*//" out2 > k
193 mv k out2
194 compare exp out2 || fail=1
196 for no_g_cmd in '' 'rm -f g'; do
197 # restorecon equivalent. Note even though the context
198 # returned from matchpathcon() will not match $ctx
199 # the resulting ENOTSUP warning will be suppressed.
201 # With absolute path
202 $no_g_cmd
203 cp -Z ../f $(realpath g) || fail=1
204 # With relative path
205 $no_g_cmd
206 cp -Z ../f g || fail=1
207 # -Z overrides -a
208 $no_g_cmd
209 cp -Z -a ../f g || fail=1
210 # -Z doesn't take an arg
211 $no_g_cmd
212 returns_ 1 cp -Z "$ctx" ../f g || fail=1
214 # Explicit context
215 $no_g_cmd
216 # Explicitly defaulting to the global $ctx should work
217 cp --context="$ctx" ../f g || fail=1
218 # --context overrides -a
219 $no_g_cmd
220 cp -a --context="$ctx" ../f g || fail=1
221 done
223 # Mutually exclusive options
224 returns_ 1 cp -Z --preserve=context ../f g || fail=1
225 returns_ 1 cp --preserve=context -Z ../f g || fail=1
226 returns_ 1 cp --preserve=context --context="$ctx" ../f g || fail=1
228 Exit $fail