From 6eefa33f7f4cd4e214443aad2a3835941260c7d5 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Fri, 3 Jan 2020 18:14:06 +0000 Subject: [PATCH] vtpm: Run swtpm with an AppArmor profile Create an AppArmor profile and apply it so that swtpm runs with an AppArmor profile. Signed-off-by: Stefan Berger --- libcontainer/vtpm/vtpm.go | 95 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/libcontainer/vtpm/vtpm.go b/libcontainer/vtpm/vtpm.go index 8141aa14b12..a12114a568f 100644 --- a/libcontainer/vtpm/vtpm.go +++ b/libcontainer/vtpm/vtpm.go @@ -15,6 +15,8 @@ import ( "time" "unsafe" + "github.com/opencontainers/runc/libcontainer/apparmor" + "github.com/sirupsen/logrus" ) @@ -53,6 +55,9 @@ type VTPM struct { // The minor number of the created device minor uint32 + + // The AppArmor profile's full path + aaprofile string } // ioctl @@ -435,6 +440,11 @@ again: return false, err } + err = vtpm.setupAppArmor() + if err != nil { + return false, err + } + tpmname := vtpm.GetTPMDevname() fdstr := fmt.Sprintf("%d", vtpm.fd) tpmstate := fmt.Sprintf("dir=%s", vtpm.StatePath) @@ -465,6 +475,8 @@ again: return false, err } + vtpm.resetAppArmor() + cmd = exec.Command("swtpm_bios", "-n", "-cs", "-u", "--tpm-device", tpmname) if vtpm.Vtpmversion == VTPM_VERSION_2 { cmd.Args = append(cmd.Args, "--tpm2") @@ -506,6 +518,8 @@ func (vtpm *VTPM) Stop(deleteStatePath bool) error { vtpm.CloseServer() + vtpm.teardownAppArmor() + vtpm.Tpm_dev_num = VTPM_DEV_NUM_INVALID if deleteStatePath { @@ -554,5 +568,86 @@ func (vtpm *VTPM) CloseServer() error { os.NewFile(uintptr(vtpm.fd), "[vtpm]").Close() vtpm.fd = ILLEGAL_FD } + + return nil +} + +// setupAppArmor creates an apparmor profile for swtpm if AppArmor is enabled and +// compiles it using apparmor_parser -r and activates it for the next +// exec. +func (vtpm *VTPM) setupAppArmor() error { + var statefilepattern string + + if !apparmor.IsEnabled() { + return nil + } + + profilename := fmt.Sprintf("runc_%d_swtpm_tpm%d", os.Getpid(), vtpm.GetTPMDevNum()) + if vtpm.Vtpmversion == VTPM_VERSION_1_2 { + statefilepattern = "tpm-00.*" + } else { + statefilepattern = "tpm2-00.*" + } + + profile := fmt.Sprintf("\n#include \n"+ + "profile %s {\n"+ + " #include \n"+ + " capability setgid,\n"+ + " capability setuid,\n"+ + " /dev/tpm[0-9]* rw,\n"+ + " owner /etc/group r,\n"+ + " owner /etc/nsswitch.conf r,\n"+ + " owner /etc/passwd r,\n"+ + " %s/.lock wk,\n"+ + " %s/swtpm.log w,\n"+ + " %s/swtpm.pid rw,\n"+ + " %s/%s rw,\n"+ + "}\n", + profilename, + vtpm.StatePath, + vtpm.StatePath, + vtpm.StatePath, + vtpm.StatePath, + statefilepattern) + + vtpm.aaprofile = path.Join(vtpm.StatePath, "swtpm.apparmor") + + err := ioutil.WriteFile(vtpm.aaprofile, []byte(profile), 0600) + if err != nil { + return err + } + defer func() { + if err != nil { + vtpm.teardownAppArmor() + } + }() + + cmd := exec.Command("/sbin/apparmor_parser", "-r", vtpm.aaprofile) + output, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("apparmor_parser -r failed: %s", string(output)) + } + + err = apparmor.ApplyProfileThread(profilename) + if err != nil { + return err + } + return nil } + +func (vtpm *VTPM) resetAppArmor() { + apparmor.ApplyProfileThread("unconfined") +} + +// teardownAppArmor removes the AppArmor profile from the system and ensures +// that the next time the process exec's no swtpm related profile is applied +func (vtpm *VTPM) teardownAppArmor() { + vtpm.resetAppArmor() + if len(vtpm.aaprofile) > 0 { + cmd := exec.Command("/sbin/apparmor_parser", "-R", vtpm.aaprofile) + cmd.Run() + os.Remove(vtpm.aaprofile) + vtpm.aaprofile = "" + } +}