@@ -15,6 +15,8 @@ import (
1515 "time"
1616 "unsafe"
1717
18+ "github.com/opencontainers/runc/libcontainer/apparmor"
19+
1820 "github.com/sirupsen/logrus"
1921)
2022
@@ -53,6 +55,9 @@ type VTPM struct {
5355
5456 // The minor number of the created device
5557 minor uint32
58+
59+ // The AppArmor profile's full path
60+ aaprofile string
5661}
5762
5863// ioctl
@@ -435,6 +440,11 @@ again:
435440 return false , err
436441 }
437442
443+ err = vtpm .setupAppArmor ()
444+ if err != nil {
445+ return false , err
446+ }
447+
438448 tpmname := vtpm .GetTPMDevname ()
439449 fdstr := fmt .Sprintf ("%d" , vtpm .fd )
440450 tpmstate := fmt .Sprintf ("dir=%s" , vtpm .StatePath )
@@ -465,6 +475,8 @@ again:
465475 return false , err
466476 }
467477
478+ vtpm .resetAppArmor ()
479+
468480 cmd = exec .Command ("swtpm_bios" , "-n" , "-cs" , "-u" , "--tpm-device" , tpmname )
469481 if vtpm .Vtpmversion == VTPM_VERSION_2 {
470482 cmd .Args = append (cmd .Args , "--tpm2" )
@@ -506,6 +518,8 @@ func (vtpm *VTPM) Stop(deleteStatePath bool) error {
506518
507519 vtpm .CloseServer ()
508520
521+ vtpm .teardownAppArmor ()
522+
509523 vtpm .Tpm_dev_num = VTPM_DEV_NUM_INVALID
510524
511525 if deleteStatePath {
@@ -554,5 +568,86 @@ func (vtpm *VTPM) CloseServer() error {
554568 os .NewFile (uintptr (vtpm .fd ), "[vtpm]" ).Close ()
555569 vtpm .fd = ILLEGAL_FD
556570 }
571+
572+ return nil
573+ }
574+
575+ // setupAppArmor creates an apparmor profile for swtpm if AppArmor is enabled and
576+ // compiles it using apparmor_parser -r <filename> and activates it for the next
577+ // exec.
578+ func (vtpm * VTPM ) setupAppArmor () error {
579+ var statefilepattern string
580+
581+ if ! apparmor .IsEnabled () {
582+ return nil
583+ }
584+
585+ profilename := fmt .Sprintf ("runc_%d_swtpm_tpm%d" , os .Getpid (), vtpm .GetTPMDevNum ())
586+ if vtpm .Vtpmversion == VTPM_VERSION_1_2 {
587+ statefilepattern = "tpm-00.*"
588+ } else {
589+ statefilepattern = "tpm2-00.*"
590+ }
591+
592+ profile := fmt .Sprintf ("\n #include <tunables/global>\n " +
593+ "profile %s {\n " +
594+ " #include <abstractions/base>\n " +
595+ " capability setgid,\n " +
596+ " capability setuid,\n " +
597+ " /dev/tpm[0-9]* rw,\n " +
598+ " owner /etc/group r,\n " +
599+ " owner /etc/nsswitch.conf r,\n " +
600+ " owner /etc/passwd r,\n " +
601+ " %s/.lock wk,\n " +
602+ " %s/swtpm.log w,\n " +
603+ " %s/swtpm.pid rw,\n " +
604+ " %s/%s rw,\n " +
605+ "}\n " ,
606+ profilename ,
607+ vtpm .StatePath ,
608+ vtpm .StatePath ,
609+ vtpm .StatePath ,
610+ vtpm .StatePath ,
611+ statefilepattern )
612+
613+ vtpm .aaprofile = path .Join (vtpm .StatePath , "swtpm.apparmor" )
614+
615+ err := ioutil .WriteFile (vtpm .aaprofile , []byte (profile ), 0600 )
616+ if err != nil {
617+ return err
618+ }
619+ defer func () {
620+ if err != nil {
621+ vtpm .teardownAppArmor ()
622+ }
623+ }()
624+
625+ cmd := exec .Command ("/sbin/apparmor_parser" , "-r" , vtpm .aaprofile )
626+ output , err := cmd .CombinedOutput ()
627+ if err != nil {
628+ return fmt .Errorf ("apparmor_parser -r failed: %s" , string (output ))
629+ }
630+
631+ err = apparmor .ApplyProfileThread (profilename )
632+ if err != nil {
633+ return err
634+ }
635+
557636 return nil
558637}
638+
639+ func (vtpm * VTPM ) resetAppArmor () {
640+ apparmor .ApplyProfileThread ("unconfined" )
641+ }
642+
643+ // teardownAppArmor removes the AppArmor profile from the system and ensures
644+ // that the next time the process exec's no swtpm related profile is applied
645+ func (vtpm * VTPM ) teardownAppArmor () {
646+ vtpm .resetAppArmor ()
647+ if len (vtpm .aaprofile ) > 0 {
648+ cmd := exec .Command ("/sbin/apparmor_parser" , "-R" , vtpm .aaprofile )
649+ cmd .Run ()
650+ os .Remove (vtpm .aaprofile )
651+ vtpm .aaprofile = ""
652+ }
653+ }
0 commit comments