]> git.proxmox.com Git - swtpm.git/blob - tests/common
tests: Extend tests cases with test for active seccomp profiles
[swtpm.git] / tests / common
1
2 SWTPM=swtpm
3 SWTPM_EXE=${SWTPM_EXE:-${ROOT}/src/swtpm/${SWTPM}}
4 SWTPM_IOCTL=${SWTPM_IOCTL:-${ROOT}/src/swtpm_ioctl/swtpm_ioctl}
5 SWTPM_BIOS=${SWTPM_BIOS:-${ROOT}/src/swtpm_bios/swtpm_bios}
6 ECHO=$(type -P echo)
7
8 # Note: Do not use file descriptors above 127 due to OpenBSD.
9
10 # Kill a process quietly
11 # @1: signal, e.g. -9
12 # @2: pid
13 function kill_quiet()
14 {
15 local sig="$1"
16 local pid="$2"
17
18 bash -c "kill $sig $pid &>/dev/null"
19 return $?
20 }
21
22 # Wait for a regular file to appear; give the process 0.2s to write
23 # into the file
24 #
25 # @1: filename
26 # @2: timeout in seconds
27 function wait_for_file()
28 {
29 local filename="$1"
30 local timeout="$2"
31
32 local loops=$((timeout * 10)) loop
33
34 for ((loop=0; loop<loops; loop++)); do
35 [ -f "${filename}" ] && {
36 sleep 0.2
37 return 1
38 }
39 sleep 0.1
40 done
41 return 0
42 }
43
44 # Wait for a regular file to disappear
45 #
46 # @1: filename
47 # @2: timeout in seconds
48 function wait_file_gone()
49 {
50 local filename="$1"
51 local timeout="$2"
52
53 local loops=$((timeout * 10)) loop
54
55 for ((loop=0; loop<loops; loop++)); do
56 [ -f "${filename}" ] || return 1
57 sleep 0.1
58 done
59 return 0
60 }
61
62 # Wait for a process with given PID to be gone
63 #
64 # @1: pid
65 # @2: timeout in seconds
66 function wait_process_gone()
67 {
68 local pid="$1"
69 local timeout="$2"
70
71 local loops=$((timeout * 10)) loop
72
73 for ((loop=0; loop<loops; loop++)); do
74 kill_quiet -0 ${pid} || return 1
75 sleep 0.1
76 done
77 return 0
78 }
79
80 # Wait for a chardev to appear
81 #
82 # @1: filename
83 # @2: timeout in seconds
84 function wait_for_chardev()
85 {
86 local filename="$1"
87 local timeout="$2"
88
89 local loops=$((timeout * 10)) loop
90
91 for ((loop=0; loop<loops; loop++)); do
92 [ -c "${filename}" ] && return 1
93 sleep 0.1
94 done
95 return 0
96 }
97
98 # Wait for a chardev to disappear
99 #
100 # @1: filename
101 # @2: timeout in seconds
102 function wait_chardev_gone()
103 {
104 local filename="$1"
105 local timeout="$2"
106
107 local loops=$((timeout * 10)) loop
108
109 for ((loop=0; loop<loops; loop++)); do
110 [ -c "${filename}" ] || return 1
111 sleep 0.1
112 done
113 return 0
114 }
115
116 # Wait for a socket file to appear
117 #
118 # @1: filename
119 # @2: timeout in seconds
120 function wait_for_socketfile()
121 {
122 local filename="$1"
123 local timeout="$2"
124
125 local loops=$((timeout * 10)) loop
126
127 for ((loop=0; loop<loops; loop++)); do
128 [ -S "${filename}" ] && return 1
129 sleep 0.1
130 done
131 return 0
132 }
133
134 # Wait for a socket file to disappear
135 #
136 # @1: filename
137 # @2: timeout in seconds
138 function wait_socketfile_gone()
139 {
140 local filename="$1"
141 local timeout="$2"
142
143 local loops=$((timeout * 10)) loop
144
145 for ((loop=0; loop<loops; loop++)); do
146 [ -S "${filename}" ] || return 1
147 sleep 0.1
148 done
149 return 0
150 }
151
152 # Wait for a server socket to appear
153 #
154 # @1: port
155 # @2: host
156 # @3: timeout in seconds
157 function wait_for_serversocket()
158 {
159 local port="$1"
160 local host="$2"
161 local timeout="$3"
162
163 local loops=$((timeout * 10)) loop
164
165 for ((loop=0; loop<loops; loop++)); do
166 (exec 127<>/dev/tcp/${host}/${port}) &>/dev/null
167 [ $? -eq 0 ] && return 1
168 sleep 0.1
169 done
170 return 0
171 }
172
173 # Wait for a server socket to disappear
174 #
175 # @1: port
176 # @2: host
177 # @3: timeout in seconds
178 function wait_serversocket_gone()
179 {
180 local port="$1"
181 local host="$2"
182 local timeout="$3"
183
184 local loops=$((timeout * 10)) loop
185
186 for ((loop=0; loop<loops; loop++)); do
187 (exec 127<>/dev/tcp/${host}/${port}) &>/dev/null
188 [ $? -eq 0 ] || return 1
189 sleep 0.1
190 done
191 return 0
192 }
193
194 # Run the swtpm_ioctl command
195 #
196 # @param1: type of interface
197 function run_swtpm_ioctl()
198 {
199 local iface=$1; shift
200
201 case "${iface}" in
202 cuse)
203 [ -z "${SWTPM_DEV_NAME}" ] && {
204 echo "SWTPM_DEV_NAME not defined"
205 exit 1
206 }
207 ${SWTPM_IOCTL} $@ ${SWTPM_DEV_NAME}
208 return $?
209 ;;
210 socket+socket|unix+socket)
211 [ -z "${SWTPM_SERVER_NAME}" ] && {
212 echo "SWTPM_SERVER_NAME not defined"
213 exit 1
214 }
215 [ -z "${SWTPM_SERVER_PORT}" ] && {
216 echo "SWTPM_SERVER_PORT not defined"
217 exit 1
218 }
219 ${SWTPM_IOCTL} \
220 --tcp ${SWTPM_SERVER_NAME}:${SWTPM_CTRL_PORT} \
221 $@
222 return $?
223 ;;
224 socket+unix|unix+unix)
225 [ -z "${SWTPM_CTRL_UNIX_PATH}" ] && {
226 echo "SWTPM_CTRL_UNIX_PATH not defined"
227 exit 1
228 }
229 ${SWTPM_IOCTL} \
230 --unix ${SWTPM_CTRL_UNIX_PATH} \
231 $@
232 return $?
233 ;;
234 esac
235 }
236
237 # Start the swtpm in the background
238 #
239 # @param1: type of interface
240 # @param2.. : parameters to pass to 'swtpm'
241 function run_swtpm()
242 {
243 local iface=$1; shift
244 local swtpm_server_disconnect=""
245
246 echo "==== Starting swtpm with interfaces ${iface} ===="
247 if [ -z "${SWTPM_SERVER_NO_DISCONNECT}" ]; then
248 swtpm_server_disconnect=",disconnect"
249 fi
250
251 case "${iface}" in
252 cuse)
253 [ -z "${SWTPM_DEV_NAME}" ] && {
254 echo "SWTPM_DEV_NAME not defined"
255 exit 1
256 }
257
258 if wait_chardev_gone ${SWTPM_DEV_NAME} 2; then
259 echo "${SWTPM_DEV_NAME} is still there and may be used."
260 exit 1
261 fi
262
263 ${SWTPM_EXE} cuse $@ -n ${SWTPM_DEV_NAME##*/}
264 rc=$?
265 if [ $rc -ne 0 ]; then
266 echo "Could not run ${SWTPM_EXE} using ${iface}"
267 exit 1
268 fi
269 if wait_for_chardev ${SWTPM_DEV_NAME} 2; then
270 echo "$SWTPM_DEV_NAME did not appear"
271 exit 1
272 fi
273
274 SWTPM_PID=$(ps aux |
275 grep "cuse" |
276 grep -E " ${SWTPM_DEV_NAME##*/}\$" |
277 grep -v grep |
278 gawk '{print $2}')
279 return $?
280 ;;
281 socket+socket)
282 [ -z "${SWTPM_SERVER_PORT}" ] && {
283 echo "SWTPM_SERVER_PORT not defined"
284 exit 1
285 }
286 [ -z "${SWTPM_CTRL_PORT}" ] && {
287 echo "SWTPM_CTRL_PORT not defined"
288 exit 1
289 }
290
291 if wait_serversocket_gone "${SWTPM_SERVER_PORT}" 127.0.0.1 2; then
292 echo "Port ${SWTPM_SERVER_PORT} is still used"
293 exit 1
294 fi
295 if wait_serversocket_gone "${SWTPM_CTRL_PORT}" 127.0.0.1 1; then
296 echo "Port ${SWTPM_CTRL_PORT} is still used"
297 exit 1
298 fi
299
300 ${SWTPM_EXE} socket $@ \
301 --server type=tcp,port=${SWTPM_SERVER_PORT}${swtpm_server_disconnect} \
302 --ctrl type=tcp,port=${SWTPM_CTRL_PORT} &
303 rc=$?
304 if [ $rc -ne 0 ]; then
305 echo "Could not run ${SWTPM_EXE} using ${iface}"
306 exit 1
307 fi
308 SWTPM_PID=$!
309 if wait_for_serversocket "${SWTPM_SERVER_PORT}" 127.0.0.1 2; then
310 echo "Server did not open port ${SWTPM_SERVER_PORT}"
311 kill -9 ${SWTPM_PID}
312 exit 1
313 fi
314 if wait_for_serversocket "${SWTPM_CTRL_PORT}" 127.0.0.1 1; then
315 echo "Server did not open port ${SWTPM_CTRL_PORT}"
316 kill -9 ${SWTPM_PID}
317 exit 1
318 fi
319 return 0
320 ;;
321 socket+unix)
322 [ -z "${SWTPM_SERVER_PORT}" ] && {
323 echo "SWTPM_SERVER_PORT not defined"
324 exit 1
325 }
326 [ -z "${SWTPM_CTRL_UNIX_PATH}" ] && {
327 echo "SWTPM_CTRL_UNIX_PATH not defined"
328 exit 1
329 }
330
331 if wait_serversocket_gone "${SWTPM_SERVER_PORT}" 127.0.0.1 2; then
332 echo "Port ${SWTPM_SERVER_PORT} is still used"
333 exit 1
334 fi
335 if wait_socketfile_gone "${SWTPM_CTRL_UNIX_PATH}" 2; then
336 echo "Unix socket ${SWTPM_CTRL_UNIX_PATH} is still there"
337 exit 1
338 fi
339
340 ${SWTPM_EXE} socket $@ \
341 --server type=tcp,port=${SWTPM_SERVER_PORT}${swtpm_server_disconnect} \
342 --ctrl type=unixio,path=${SWTPM_CTRL_UNIX_PATH} &
343 rc=$?
344 if [ $rc -ne 0 ]; then
345 echo "Could not run ${SWTPM_EXE} using ${iface}"
346 exit 1
347 fi
348 [ $rc -ne 0 ] && return $rc
349 SWTPM_PID=$!
350 if wait_for_serversocket "${SWTPM_SERVER_PORT}" 127.0.0.1 2; then
351 echo "Server did not open port ${SWTPM_SERVER_PORT}"
352 kill -9 ${SWTPM_PID}
353 exit 1
354 fi
355 if wait_for_socketfile ${SWTPM_CTRL_UNIX_PATH} 1; then
356 echo "Server did not create UnixIO socket ${SWTPM_CTRL_UNIX_PATH}"
357 kill -9 ${SWTPM_PID}
358 exit 1
359 fi
360 return 0
361 ;;
362 unix+socket)
363 [ -z "${SWTPM_CMD_UNIX_PATH}" ] && {
364 echo "SWTPM_CMD_UNIX_PATH not defined"
365 exit 1
366 }
367 [ -z "${SWTPM_CTRL_PORT}" ] && {
368 echo "SWTPM_CTRL_PORT not defined"
369 exit 1
370 }
371
372 if wait_socketfile_gone "${SWTPM_CMD_UNIX_PATH}" 2; then
373 echo "Unix socket ${SWTPM_CMD_UNIX_PATH} is still there"
374 exit 1
375 fi
376 if wait_serversocket_gone "${SWTPM_CTRL_PORT}" 127.0.0.1 1; then
377 echo "Port ${SWTPM_CTRL_PORT} is still used"
378 exit 1
379 fi
380
381 ${SWTPM_EXE} socket $@ \
382 --server type=unixio,path=${SWTPM_CMD_UNIX_PATH} \
383 --ctrl type=tcp,port=${SWTPM_CTRL_PORT} &
384 rc=$?
385 if [ $rc -ne 0 ]; then
386 echo "Could not run ${SWTPM_EXE} using ${iface}"
387 exit 1
388 fi
389 SWTPM_PID=$!
390 if wait_for_socketfile ${SWTPM_CMD_UNIX_PATH} 2; then
391 echo "Server did not create UnixIO socket ${SWTPM_CMD_UNIX_PATH}"
392 kill -9 ${SWTPM_PID}
393 exit 1
394 fi
395 if wait_for_serversocket "${SWTPM_CTRL_PORT}" 127.0.0.1 1; then
396 echo "Server did not open port ${SWTPM_CTRL_PORT}"
397 kill -9 ${SWTPM_PID}
398 exit 1
399 fi
400 return 0
401 ;;
402 unix+unix)
403 [ -z "${SWTPM_CMD_UNIX_PATH}" ] && {
404 echo "SWTPM_CMD_UNIX_PATH not defined"
405 exit 1
406 }
407 [ -z "${SWTPM_CTRL_UNIX_PATH}" ] && {
408 echo "SWTPM_CTRL_UNIX_PATH not defined"
409 exit 1
410 }
411
412 if wait_socketfile_gone "${SWTPM_CMD_UNIX_PATH}" 2; then
413 echo "Unix socket ${SWTPM_CMD_UNIX_PATH} is still there"
414 exit 1
415 fi
416 if wait_socketfile_gone "${SWTPM_CTRL_UNIX_PATH}" 2; then
417 echo "Unix socket ${SWTPM_CTRL_UNIX_PATH} is still there"
418 exit 1
419 fi
420
421 ${SWTPM_EXE} socket $@ \
422 --server type=unixio,path=${SWTPM_CMD_UNIX_PATH} \
423 --ctrl type=unixio,path=${SWTPM_CTRL_UNIX_PATH} &
424 rc=$?
425 if [ $rc -ne 0 ]; then
426 echo "Could not run ${SWTPM_EXE} using ${iface}"
427 exit 1
428 fi
429 SWTPM_PID=$!
430 if wait_for_socketfile ${SWTPM_CMD_UNIX_PATH} 2; then
431 echo "Server did not create UnixIO socket ${SWTPM_CMD_UNIX_PATH}"
432 kill -9 ${SWTPM_PID}
433 exit 1
434 fi
435 if wait_for_socketfile ${SWTPM_CTRL_UNIX_PATH} 1; then
436 echo "Server did not create UnixIO socket ${SWTPM_CTRL_UNIX_PATH}"
437 kill -9 ${SWTPM_PID}
438 exit 1
439 fi
440 return 0
441 ;;
442 esac
443 }
444
445 # Open the command channel/device on fd 100
446 #
447 # @param1: type of interface
448 # @param2: must be '100'
449 function swtpm_open_cmddev()
450 {
451 local iface=$1; shift
452
453 [ "$1" != "100" ] && {
454 echo "swtpm_opendev: Filedescriptor must be 100"
455 exit 1
456 }
457
458 case "${iface}" in
459 cuse)
460 [ -z "${SWTPM_DEV_NAME}" ] && {
461 echo "SWTPM_DEV_NAME not defined"
462 exit 1
463 }
464 exec 100<>${SWTPM_DEV_NAME}
465 return $?
466 ;;
467 socket+socket|socket+unix)
468 [ -z "${SWTPM_SERVER_NAME}" ] && {
469 echo "SWTPM_SERVER_NAME not defined"
470 exit 1
471 }
472 [ -z "${SWTPM_SERVER_PORT}" ] && {
473 echo "SWTPM_SERVER_PORT not defined"
474 exit 1
475 }
476 # Must first close on OS/X
477 exec 100>&-
478 exec 100<>/dev/tcp/${SWTPM_SERVER_NAME}/${SWTPM_SERVER_PORT}
479 return $?
480 ;;
481 unix+socket|unix+unix)
482 ;;
483 *)
484 echo "swtpm_opendev: unsupported interface $iface"
485 exit 1
486 esac
487 }
488
489 # Transmit a command on fd 100
490 #
491 # @param1: type of interface
492 function swtpm_cmd_tx()
493 {
494 local iface=$1
495 local cmd_path resp_path
496
497 cmd_path=$(mktemp)
498
499 case "${iface}" in
500 cuse)
501 echo -en "$2" > ${cmd_path}
502 cat ${cmd_path} >&100
503 dd if=/proc/self/fd/100 2>/dev/null | \
504 od -t x1 -A n | \
505 tr -s ' ' | \
506 tr -d '\n' | \
507 sed 's/ $//g'
508 ;;
509 socket+socket|socket+unix)
510 echo -en "$2" > ${cmd_path}
511 cat ${cmd_path} >&100
512 cat <&100 | od -t x1 -A n | \
513 tr -s ' ' | \
514 tr -d '\n' | \
515 sed 's/ $//g'
516 ;;
517 unix+socket|unix+unix)
518 echo -en "$2" > ${cmd_path}
519 socat -x -t50 \
520 FILE:${cmd_path},rdonly \
521 UNIX-CLIENT:${SWTPM_CMD_UNIX_PATH} 2>&1 | \
522 sed -n '/^ /p' | \
523 tail -n1
524 ;;
525 *)
526 echo "swtpm_opendev: unsupported interface $iface"
527 rm -f ${cmd_path}
528 exit 1
529 esac
530
531 rm -f ${cmd_path}
532 }
533
534 # Transmit a control command on fd 101
535 #
536 # @param1: type of interface
537 function swtpm_ctrl_tx()
538 {
539 local iface=$1
540 local ctrl_path resp_path
541
542 case "${iface}" in
543 socket+socket|unix+socket)
544 $ECHO -en "$2" >&101
545 cat <&101 | od -t x1 -A n -w128
546 ;;
547 socket+unix|unix+unix)
548 ctrl_path=$(mktemp)
549 echo -en "$2" > ${ctrl_path}
550 socat -x -t50 \
551 FILE:${ctrl_path},rdonly \
552 UNIX-CLIENT:${SWTPM_CTRL_UNIX_PATH} 2>&1 | \
553 sed -n '/^ /p' | \
554 tail -n1
555 rm -f ${ctrl_path}
556 ;;
557 *)
558 echo "swtpm_opendev: unsupported interface $iface"
559 exit 1
560 esac
561 }
562
563
564 # Run swtpm_bios
565 #
566 # @param1: type of interface
567 # @param2 ...: parameters to pass to swtpm_bios
568 function run_swtpm_bios()
569 {
570 local iface=$1
571
572 shift
573
574 case "${iface}" in
575 cuse)
576 [ -z "${SWTPM_DEV_NAME}" ] && {
577 echo "SWTPM_DEV_NAME not defined"
578 exit 1
579 }
580 ${SWTPM_BIOS} --tpm-device ${SWTPM_DEV_NAME} $@
581 return $?
582 ;;
583 unix+unix|unix+socket)
584 [ -z "${SWTPM_CMD_UNIX_PATH}" ] && {
585 echo "SWTPM_CMD_UNIX_PATH not defined"
586 exit 1
587 }
588 ${SWTPM_BIOS} --unix ${SWTPM_CMD_UNIX_PATH} $@
589 return $?
590 ;;
591 socket+unix|socket+socket)
592 [ -z "${SWTPM_SERVER_PORT}" ] && {
593 echo "SWTPM_SERVER_PORT not defined"
594 exit 1
595 }
596 ${SWTPM_BIOS} --tcp ${SWTPM_SERVER_NAME}:${SWTPM_SERVER_PORT} $@
597 return $?
598 ;;
599 *)
600 echo "run_swtpm_bios: unsupported interface $iface"
601 exit 1
602 esac
603 }
604
605 # Get the size of a file in bytes
606 #
607 # @1: filename
608 function get_filesize()
609 {
610 if [[ "$(uname -s)" =~ (Linux|CYGWIN_NT-) ]]; then
611 stat -c%s $1
612 else
613 # OpenBSD
614 stat -f%z $1
615 fi
616 }
617
618 # Get the SHA1 of a file
619 #
620 # @1: filename
621 function get_sha1_file()
622 {
623 if ! [ -r $1 ]; then
624 echo "[file $1 does not exist]"
625 return
626 fi
627 case "$(uname -s)" in
628 Linux|CYGWIN*)
629 sha1sum $1 | cut -f1 -d" "
630 ;;
631 Darwin)
632 shasum $1 | cut -f1 -d" "
633 ;;
634 *)
635 # OpenBSD
636 sha1 $1 | cut -d "=" -f2 | tr -d " "
637 esac
638 }
639
640 # Display process that have the same name
641 #
642 # @1: process name to match
643 function display_processes_by_name()
644 {
645 local name="$1"
646
647 if [ 1 -eq 0 ]; then
648 ps aux | grep "${name}" | grep -v grep
649 fi
650 }
651
652 # Check whether seccomp support is compiled in
653 #
654 # @1: path to swtpm
655 #
656 # Returns 0 if seccomp is supported, 1 otherwise
657 function has_seccomp_support()
658 {
659 local swtpm_exe="$1"
660
661 local tmp=$(${swtpm_exe} socket --help | grep -E "\-\-seccomp")
662
663 [ -n "${tmp}" ] && return 0
664 return 1
665 }
666
667 # Check whether the given process runs with the given seccomp
668 # profile type IF the given swtpm executable has seccomp support
669 #
670 # @1: Path to swtpm executable from which process was started
671 # @2: The process ID
672 # @3: The expected seccomp profile type
673 function check_seccomp_profile()
674 {
675 local swtpm_exe="$1"
676 local swtpm_pid="$2"
677 local profile="$3"
678
679 local tmp
680
681 if ! has_seccomp_support "${swtpm_exe}"; then
682 return 0
683 fi
684
685 tmp=$(grep -E "^Seccomp" /proc/${swtpm_pid}/status |
686 cut -d":" -f2 |
687 tr -d '\t')
688 if [ "${tmp}" != ${profile} ]; then
689 echo "Process ${swtpm_pid} has wrong seccomp profile type"
690 echo "Expected: ${profile}"
691 echo "Actual : ${tmp}"
692 return 1
693 fi
694 return 0
695 }