Whamcloud - gitweb
d86c11c8a6ddb25ee4ce6496a904ef00cf5820b1
[fs/lustre-release.git] / lustre / tests / sanity-selinux.sh
1 #!/bin/bash
2 #
3 # Run select tests by setting ONLY, or as arguments to the script.
4 # Skip specific tests by setting EXCEPT.
5 #
6 # e.g. ONLY="22 23" or ONLY="`seq 32 39`" or EXCEPT="31"
7 set -e
8
9 ONLY=${ONLY:-"$*"}
10 # bug number for skipped test:
11 ALWAYS_EXCEPT=${ALWAYS_EXCEPT:-"$SANITY_SELINUX_EXCEPT"}
12 # UPDATE THE COMMENT ABOVE WITH BUG NUMBERS WHEN CHANGING ALWAYS_EXCEPT!
13
14 SRCDIR=$(dirname $0)
15 SAVE_PWD=$PWD
16
17 LUSTRE=${LUSTRE:-$(dirname $0)/..}
18 . $LUSTRE/tests/test-framework.sh
19 init_test_env $@
20 . ${CONFIG:=$LUSTRE/tests/cfg/$NAME.sh}
21 init_logging
22
23 require_dsh_mds || exit 0
24
25 [ "$SLOW" = "no" ] && EXCEPT_SLOW="xxx"
26
27 # $RUNAS_ID may get set incorrectly somewhere else
28 [ $UID -eq 0 -a $RUNAS_ID -eq 0 ] &&
29         error "RUNAS_ID set to 0, but UID is also 0!"
30
31 #
32 # global variables of this sanity
33 #
34
35 check_selinux() {
36         echo -n "Checking SELinux environment... "
37         local selinux_status=$(getenforce)
38         if [ "$selinux_status" != "Enforcing" ]; then
39             skip "SELinux is currently in $selinux_status mode," \
40                  "but it must be enforced to run sanity-selinux" && exit 0
41         fi
42         local selinux_policy=$(sestatus |
43                                awk -F':' '$1 == "Loaded policy name" {print $2}' |
44                                xargs)
45         if [ -z "$selinux_policy" ]; then
46             selinux_policy=$(sestatus |
47                              awk -F':' '$1 == "Policy from config file"
48                                      {print $2}' |
49                              xargs)
50         fi
51         [ "$selinux_policy" == "targeted" ] ||
52                 error "Accepting only targeted policy"
53         echo "$selinux_status, $selinux_policy"
54 }
55
56 check_selinux
57
58 # we want double mount
59 MOUNT_2=${MOUNT_2:-"yes"}
60 check_and_setup_lustre
61
62 rm -rf $DIR/[df][0-9]*
63
64 check_runas_id $RUNAS_ID $RUNAS_ID $RUNAS
65
66 build_test_filter
67
68 umask 077
69
70 check_selinux_xattr() {
71         local mds=$1
72         local mds_path=$2
73         local mds_dev=$(facet_device $mds)
74         local mntpt="/tmp/mdt_"
75         local opts
76
77         do_facet $mds mkdir -p $mntpt  || error "mkdir $mntpt failed"
78         mount_fstype $mds $mntpt  || error "mount $mds failed"
79
80         local xattrval=$(do_facet $mds getfattr -n security.selinux \
81                                 ${mntpt}/ROOT/$mds_path |
82                          awk -F"=" '$1=="security.selinux" {print $2}')
83
84         unmount_fstype $mds $mntpt || error "umount $mds failed"
85         do_facet $mds rmdir $mntpt || error "rmdir $mntpt failed"
86
87         echo $xattrval
88 }
89
90
91 test_1() {
92         local devname=$(mdsdevname 1)
93         local filename=${DIR}/${tdir}/df1
94         local mds_path=${filename#$MOUNT}
95
96         mds_path=${mds_path#/}
97
98         $LFS setdirstripe -i0 -c1 ${DIR}/$tdir || error "create dir $tdir failed"
99         touch $filename || error "cannot touch $filename"
100
101         local xattrval=$(check_selinux_xattr "mds1" $mds_path)
102
103         [ -n "$xattrval" -a "$xattrval" != '""' ] ||
104                 error "security.selinux xattr is not set"
105 }
106 run_test 1 "create file and check security.selinux xattr is set on MDT"
107
108 test_2a() {
109         local devname=$(mdsdevname 1)
110         local dirname=${DIR}/${tdir}/dir2a
111         local mds_path=${dirname#$MOUNT}
112
113         mds_path=${mds_path#/}
114
115         $LFS setdirstripe -i0 -c1 ${DIR}/$tdir || error "create dir failed"
116         mkdir $dirname || error "cannot mkdir $dirname"
117
118         local xattrval=$(check_selinux_xattr "mds1" $mds_path)
119
120         [ -n "$xattrval" -a "$xattrval" != '""' ] ||
121                 error "security.selinux xattr is not set"
122 }
123 run_test 2a "create dir (mkdir) and check security.selinux xattr is set on MDT"
124
125 test_2b() {
126         local devname=$(mdsdevname 1)
127         local dirname1=${DIR}/$tdir/dir2b1
128         local dirname2=${DIR}/$tdir/dir2b2
129         local mds_path=${dirname1#$MOUNT}
130
131         mds_path=${mds_path#/}
132
133         $LFS setdirstripe -i0 -c1 ${DIR}/$tdir || error "create dir failed"
134         $LFS mkdir -c0 $dirname1 || error "cannot 'lfs mkdir' $dirname1"
135
136         local xattrval=$(check_selinux_xattr "mds1" $mds_path)
137
138         mds_path=${dirname2#$MOUNT}
139         mds_path=${mds_path#/}
140
141         [ -n "$xattrval" -a "$xattrval" != '""' ] ||
142                 error "security.selinux xattr is not set"
143
144         $LFS setdirstripe -i0 $dirname2 ||
145             error "cannot 'lfs setdirstripe' $dirname2"
146
147         xattrval=$(check_selinux_xattr "mds1" $mds_path)
148
149         [ -n "$xattrval" -a "$xattrval" != '""' ] ||
150                 error "security.selinux xattr is not set"
151 }
152 run_test 2b "create dir with lfs and check security.selinux xattr is set on MDT"
153
154 test_3() {
155         local filename=$DIR/df3
156
157         # get current mapping of runasid, and save it
158         local uname=$(getent passwd $RUNAS_ID | cut -d: -f1)
159         local sename=$(semanage login -l |
160                        awk -v uname=$uname '$1==uname {print $2}')
161         local serange=$(semanage login -l |
162                         awk -v uname=$uname '$1==uname {print $3}')
163
164         # change mapping of runasid to unconfined_u
165         semanage login -a -s unconfined_u $uname ||
166                 error "unable to map $uname to unconfined_u"
167
168         # "access" Lustre
169         echo "${uname} mapped as unconfined_u: touch $filename"
170         $PDSH ${uname}@localhost "touch $filename" ||
171                 error "can't touch $filename"
172         echo "${uname} mapped as unconfined_u: rm -f $filename"
173         $PDSH ${uname}@localhost "rm -f $filename" ||
174                 error "can't remove $filename"
175
176         # restore original mapping of runasid
177         if [ -n "$sename" ]; then
178                 if [ -n "$serange" ]; then
179                         semanage login -a -s $sename -r $serange $uname ||
180                                 error "unable to restore mapping for $uname"
181                 else
182                         semanage login -a -s $sename $uname ||
183                                 error "unable to restore mapping for $uname"
184                 fi
185         else
186                 semanage login -d $uname
187         fi
188
189         return 0
190 }
191 run_test 3 "access with unconfined user"
192
193 test_4() {
194         local filename=$DIR/df4
195
196         # get current mapping of runasid, and save it
197         local uname=$(getent passwd $RUNAS_ID | cut -d: -f1)
198         local sename=$(semanage login -l |
199                               awk -v uname=$uname '$1==uname {print $2}')
200         local serange=$(semanage login -l |
201                          awk -v uname=$uname '$1==uname {print $3}')
202
203         # change mapping of runasid to guest_u
204         semanage login -a -s guest_u $uname ||
205                 error "unable to map $uname to guest_u"
206
207         # "access" Lustre
208         echo "${uname} mapped as guest_u: touch $filename"
209         $PDSH ${uname}@localhost "touch $filename" &&
210                 error "touch $filename should have failed"
211
212         # change mapping of runasid to user_u
213         semanage login -a -s user_u $uname ||
214                 error "unable to map $uname to user_u"
215
216         # "access" Lustre
217         echo "${uname} mapped as user_u: touch $filename"
218         $PDSH ${uname}@localhost "touch $filename" ||
219                 error "can't touch $filename"
220         echo "${uname} mapped as user_u: rm -f $filename"
221         $PDSH ${uname}@localhost "rm -f $filename" ||
222                 error "can't remove $filename"
223
224         # restore original mapping of runasid
225         if [ -n "$sename" ]; then
226                 if [ -n "$serange" ]; then
227                         semanage login -a -s $sename -r $serange $uname ||
228                                 error "unable to restore mapping for $uname"
229                 else
230                         semanage login -a -s $sename $uname ||
231                                 error "unable to restore mapping for $uname"
232                 fi
233         else
234                 semanage login -d $uname
235         fi
236
237         return 0
238 }
239 run_test 4 "access with specific SELinux user"
240
241 test_5() {
242         local filename=$DIR/df5
243         local newsecctx="nfs_t"
244
245         # create file
246         touch $filename || error "cannot touch $filename"
247
248         # change sec context
249         chcon -t $newsecctx $filename
250         ls -lZ $filename
251
252         # purge client's cache
253         sync ; echo 3 > /proc/sys/vm/drop_caches
254
255         # get sec context
256         ls -lZ $filename
257         local secctxseen=$(ls -lZ $filename | awk '{print $4}' | cut -d: -f3)
258
259         [ "$newsecctx" == "$secctxseen" ] ||
260                 error "sec context seen from 1st mount point is not correct"
261
262         return 0
263 }
264 run_test 5 "security context retrieval from MDT xattr"
265
266 test_10() {
267         local filename1=$DIR/df10
268         local filename2=$DIR2/df10
269         local newsecctx="nfs_t"
270
271         # create file from 1st mount point
272         touch $filename1 || error "cannot touch $filename1"
273         ls -lZ $filename1
274
275         # change sec context from 2nd mount point
276         chcon -t $newsecctx $filename2
277         ls -lZ $filename2
278
279         # get sec context from 1st mount point
280         ls -lZ $filename1
281         local secctxseen=$(ls -lZ $filename1 | awk '{print $4}' | cut -d: -f3)
282
283         [ "$newsecctx" == "$secctxseen" ] ||
284                 error "sec context seen from 1st mount point is not correct"
285
286         return 0
287 }
288 run_test 10 "[consistency] concurrent security context change"
289
290 test_20a() {
291         local uname=$(getent passwd $RUNAS_ID | cut -d: -f1)
292         local filename1=$DIR/df20a
293         local filename2=$DIR2/df20a
294         local req_delay=20
295
296         # sleep some time in ll_create_nd()
297         #define OBD_FAIL_LLITE_CREATE_FILE_PAUSE   0x1409
298         do_facet client "$LCTL set_param fail_val=$req_delay fail_loc=0x1409"
299
300         # create file on first mount point
301         $PDSH ${uname}@localhost "touch $filename1" &
302         local touchpid=$!
303         sleep 5
304
305         if [[ -z "$(ps h -o comm -p $touchpid)" ]]; then
306                 error "touch failed to sleep, pid=$touchpid"
307         fi
308
309         # get sec info on second mount point
310         if [ -e "$filename2" ]; then
311                 secinfo2=$(ls -lZ $filename2 | awk '{print $4}')
312         fi
313
314         # get sec info on first mount point
315         wait $touchpid
316         secinfo1=$(ls -lZ $filename1 | awk '{print $4}')
317
318         # compare sec contexts
319         [ -z "$secinfo2" -o "$secinfo1" == "$secinfo2" ] ||
320                 error "sec context seen from 2nd mount point is not correct"
321
322         return 0
323 }
324 run_test 20a "[atomicity] concurrent access from another client (file)"
325
326 test_20b() {
327         local uname=$(getent passwd $RUNAS_ID | cut -d: -f1)
328         local dirname1=$DIR/dd20b
329         local dirname2=$DIR2/dd20b
330         local req_delay=20
331
332         # sleep some time in ll_create_nd()
333         #define OBD_FAIL_LLITE_NEWNODE_PAUSE     0x140a
334         do_facet client "$LCTL set_param fail_val=$req_delay fail_loc=0x140a"
335
336         # create file on first mount point
337         $PDSH ${uname}@localhost "mkdir $dirname1" &
338         local mkdirpid=$!
339         sleep 5
340
341         if [[ -z "$(ps h -o comm -p $mkdirpid)" ]]; then
342                 error "mkdir failed to sleep, pid=$mkdirpid"
343         fi
344
345         # get sec info on second mount point
346         if [ -e "$dirname2" ]; then
347                 secinfo2=$(ls -ldZ $dirname2 | awk '{print $4}')
348         else
349                 secinfo2=""
350         fi
351
352         # get sec info on first mount point
353         wait $mkdirpid
354         secinfo1=$(ls -ldZ $dirname1 | awk '{print $4}')
355
356         # compare sec contexts
357         [ -z "$secinfo2" -o "$secinfo1" == "$secinfo2" ] ||
358                 error "sec context seen from 2nd mount point is not correct"
359
360         return 0
361 }
362 run_test 20b "[atomicity] concurrent access from another client (dir)"
363
364 test_20c() {
365         local dirname1=$DIR/dd20c
366         local dirname2=$DIR2/dd20c
367         local req_delay=20
368
369         # sleep some time in ll_create_nd()
370         #define OBD_FAIL_LLITE_SETDIRSTRIPE_PAUSE     0x140b
371         do_facet client "$LCTL set_param fail_val=$req_delay fail_loc=0x140b"
372
373         # create file on first mount point
374         lfs mkdir -c0 $dirname1 &
375         local mkdirpid=$!
376         sleep 5
377
378         if [[ -z "$(ps h -o comm -p $mkdirpid)" ]]; then
379                 error "lfs mkdir failed to sleep, pid=$mkdirpid"
380         fi
381
382         # get sec info on second mount point
383         if [ -e "$dirname2" ]; then
384                 secinfo2=$(ls -ldZ $dirname2 | awk '{print $4}')
385         else
386                 secinfo2=""
387         fi
388
389         # get sec info on first mount point
390         wait $mkdirpid
391         secinfo1=$(ls -ldZ $dirname1 | awk '{print $4}')
392
393         # compare sec contexts
394         [ -z "$secinfo2" -o "$secinfo1" == "$secinfo2" ] ||
395                 error "sec context seen from 2nd mount point is not correct"
396
397         return 0
398 }
399 run_test 20c "[atomicity] concurrent access from another client (dir via lfs)"
400
401
402 complete $SECONDS
403 check_and_cleanup_lustre
404 exit_status
405