@@ -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
@@ -432,6 +437,11 @@ again:
432437 return false , err
433438 }
434439
440+ err = vtpm .SetupAppArmor ()
441+ if err != nil {
442+ return false , err
443+ }
444+
435445 tpmname := vtpm .GetTPMDevname ()
436446 fdstr := fmt .Sprintf ("%d" , vtpm .fd )
437447 tpmstate := fmt .Sprintf ("dir=%s" , vtpm .StatePath )
@@ -462,6 +472,8 @@ again:
462472 return false , err
463473 }
464474
475+ apparmor .ApplyProfileTid ("unconfined" )
476+
465477 cmd = exec .Command ("swtpm_bios" , "-n" , "-cs" , "-u" , "--tpm-device" , tpmname )
466478 if vtpm .Vtpmversion == VTPM_VERSION_2 {
467479 cmd .Args = append (cmd .Args , "--tpm2" )
@@ -503,6 +515,8 @@ func (vtpm *VTPM) Stop(deleteStatePath bool) error {
503515
504516 vtpm .CloseServer ()
505517
518+ vtpm .TeardownAppArmor ()
519+
506520 vtpm .Tpm_dev_num = VTPM_DEV_NUM_INVALID
507521
508522 if deleteStatePath {
@@ -551,5 +565,82 @@ func (vtpm *VTPM) CloseServer() error {
551565 os .NewFile (uintptr (vtpm .fd ), "[vtpm]" ).Close ()
552566 vtpm .fd = ILLEGAL_FD
553567 }
568+
569+ return nil
570+ }
571+
572+ // SetupAppArmor creates an apparmor profile for swtpm if AppArmor is enabled and
573+ // compiles it using apparmor_parser -r <filename> and activates it for the next
574+ // exec.
575+ func (vtpm * VTPM ) SetupAppArmor () error {
576+ var statefilepattern string
577+
578+ if ! apparmor .IsEnabled () {
579+ return nil
580+ }
581+
582+ profilename := fmt .Sprintf ("runc_%d_swtpm_tpm%d" ,os .Getpid (), vtpm .GetTPMDevNum ())
583+ if vtpm .Vtpmversion == VTPM_VERSION_1_2 {
584+ statefilepattern = "tpm-00.*"
585+ } else {
586+ statefilepattern = "tpm2-00.*"
587+ }
588+
589+ profile := fmt .Sprintf ("\n #include <tunables/global>\n " +
590+ "profile %s {\n " +
591+ " #include <abstractions/base>\n " +
592+ " capability setgid,\n " +
593+ " capability setuid,\n " +
594+ " /dev/tpm[0-9]* rw,\n " +
595+ " owner /etc/group r,\n " +
596+ " owner /etc/nsswitch.conf r,\n " +
597+ " owner /etc/passwd r,\n " +
598+ " %s/.lock wk,\n " +
599+ " %s/swtpm.log w,\n " +
600+ " %s/swtpm.pid rw,\n " +
601+ " %s/%s rw,\n " +
602+ "}\n " ,
603+ profilename ,
604+ vtpm .StatePath ,
605+ vtpm .StatePath ,
606+ vtpm .StatePath ,
607+ vtpm .StatePath ,
608+ statefilepattern )
609+
610+ vtpm .aaprofile = path .Join (vtpm .StatePath , "swtpm.apparmor" )
611+
612+ err := ioutil .WriteFile (vtpm .aaprofile , []byte (profile ), 0600 )
613+ if err != nil {
614+ return err
615+ }
616+ defer func () {
617+ if err != nil {
618+ vtpm .TeardownAppArmor ()
619+ }
620+ }()
621+
622+ cmd := exec .Command ("/sbin/apparmor_parser" , "-r" , vtpm .aaprofile )
623+ output , err := cmd .CombinedOutput ()
624+ if err != nil {
625+ return fmt .Errorf ("apparmor_parser -r failed: %s" , string (output ))
626+ }
627+
628+ err = apparmor .ApplyProfileTid (profilename )
629+ if err != nil {
630+ return err
631+ }
632+
554633 return nil
555634}
635+
636+ // TeardownAppArmor removes the AppArmor profile from the system and ensures
637+ // that the next time the process exec's no swtpm related profile is applied
638+ func (vtpm * VTPM ) TeardownAppArmor () {
639+ apparmor .ApplyProfileTid ("unconfined" )
640+ if len (vtpm .aaprofile ) > 0 {
641+ cmd := exec .Command ("/sbin/apparmor_parser" , "-R" , vtpm .aaprofile )
642+ cmd .Run ()
643+ os .Remove (vtpm .aaprofile )
644+ vtpm .aaprofile = ""
645+ }
646+ }
0 commit comments