cos-gpu-installer: remove code of modifying kernel command line

As discussed, cos-gpu-installer won't be responsible of
modifying kernel command line. It's caller's responsibility to make sure
kernel command line is configured correctly.

Besides, correct a few errors in the code.
1) fix some compiling error
2) fix a bug that environment variables were not set if toolchain was
preloaded.
3) fix a bug that the error of first calling Nvidia installer should not
be checked.

Change-Id: I18cc451da12d14178f5df59743db4df01daedfb5
diff --git a/src/cmd/cos_gpu_installer/internal/commands/install.go b/src/cmd/cos_gpu_installer/internal/commands/install.go
index 75a988c..2ef3611 100644
--- a/src/cmd/cos_gpu_installer/internal/commands/install.go
+++ b/src/cmd/cos_gpu_installer/internal/commands/install.go
@@ -3,6 +3,8 @@
 
 import (
 	"context"
+	"fmt"
+	"io/ioutil"
 	"path/filepath"
 
 	"flag"
@@ -28,7 +30,7 @@
 type InstallCommand struct {
 	driverVersion    string
 	hostInstallDir   string
-	enforceSigning   bool
+	unsignedDriver   bool
 	internalDownload bool
 	debug            bool
 }
@@ -48,8 +50,10 @@
 		"The GPU driver verion to install. It will install the default GPU driver if the flag is not set explicitly.")
 	f.StringVar(&c.hostInstallDir, "dir", "/var/lib/nvidia",
 		"Host directory that GPU drivers should be installed to")
-	f.BoolVar(&c.enforceSigning, "enforce-signing", true,
-		"Whether to enforce GPU drivers being signed. Setting to false will disable kernel module signing security feature.")
+	f.BoolVar(&c.unsignedDriver, "allow-unsigned-driver", false,
+		"Whether to allow load unsigned GPU drivers. "+
+			"If this flag is set to true, module signing security features must be disabled on the host for driver installation to succeed. "+
+			"This flag is only for debugging.")
 	// TODO(mikewu): change this flag to a bucket prefix string.
 	f.BoolVar(&c.internalDownload, "internal-download", false,
 		"Whether to try to download files from Google internal server. This is only useful for internal developing.")
@@ -67,7 +71,7 @@
 
 	log.Infof("Running on COS build id %s", envReader.BuildNumber())
 
-	downloader := &cos.GCSDownloader{envReader, c.internalDownload}
+	downloader := cos.NewGCSDownloader(envReader, c.internalDownload)
 	if c.driverVersion == "" {
 		defaultVersion, err := installer.GetDefaultGPUDriverVersion(downloader)
 		if err != nil {
@@ -78,19 +82,20 @@
 	}
 	log.Infof("Installing GPU driver version %s", c.driverVersion)
 
-	if !c.enforceSigning {
-		log.Info("Doesn't enforce signing. Need to disable module locking.")
-		if err := cos.DisableKernelModuleLocking(); err != nil {
-			c.logError(errors.Wrap(err, "failed to configure kernel module locking"))
-			return subcommands.ExitFailure
+	if c.unsignedDriver {
+		kernelCmdline, err := ioutil.ReadFile("/proc/cmdline")
+		if err != nil {
+			c.logError(fmt.Errorf("failed to read kernel command line: %v", err))
+		}
+		if !cos.CheckKernelModuleSigning(string(kernelCmdline)) {
+			log.Warning("Current kernel command line does not support unsigned kernel modules. Not enforcing kernel module signing may cause installation fail.")
 		}
 	}
-
 	hostInstallDir := filepath.Join(hostRootPath, c.hostInstallDir)
 	cacher := installer.NewCacher(hostInstallDir, envReader.BuildNumber(), c.driverVersion)
 	if isCached, err := cacher.IsCached(); isCached && err == nil {
 		log.Info("Found cached version, NOT building the drivers.")
-		if err := installer.ConfigureCachedInstalltion(hostInstallDir, c.enforceSigning); err != nil {
+		if err := installer.ConfigureCachedInstalltion(hostInstallDir, !c.unsignedDriver); err != nil {
 			c.logError(errors.Wrap(err, "failed to configure cached installation"))
 			return subcommands.ExitFailure
 		}
@@ -121,7 +126,7 @@
 	}
 	defer func() { callback <- 0 }()
 
-	if c.enforceSigning {
+	if !c.unsignedDriver {
 		if err := signing.DownloadDriverSignatures(downloader, c.driverVersion); err != nil {
 			return errors.Wrap(err, "failed to download driver signature")
 		}
@@ -140,7 +145,7 @@
 		return errors.Wrap(err, "failed to install toolchain")
 	}
 
-	if err := installer.RunDriverInstaller(installerFile, c.enforceSigning); err != nil {
+	if err := installer.RunDriverInstaller(installerFile, !c.unsignedDriver); err != nil {
 		return errors.Wrap(err, "failed to run GPU driver installer")
 	}
 	if err := cacher.Cache(); err != nil {
diff --git a/src/cmd/cos_gpu_installer/internal/commands/list.go b/src/cmd/cos_gpu_installer/internal/commands/list.go
index 63ec447..4b4e095 100644
--- a/src/cmd/cos_gpu_installer/internal/commands/list.go
+++ b/src/cmd/cos_gpu_installer/internal/commands/list.go
@@ -47,7 +47,7 @@
 		return subcommands.ExitFailure
 	}
 	log.Infof("Running on COS build id %s", envReader.BuildNumber())
-	downloader := &cos.GCSDownloader{envReader, c.internalDownload}
+	downloader := cos.NewGCSDownloader(envReader, c.internalDownload)
 	artifacts, err := downloader.ListExtensionArtifacts("gpu")
 	if err != nil {
 		c.logError(errors.Wrap(err, "failed to list gpu extension artifacts"))
diff --git a/src/cmd/cos_gpu_installer/internal/installer/installer.go b/src/cmd/cos_gpu_installer/internal/installer/installer.go
index 0b8d6b4..654240c 100644
--- a/src/cmd/cos_gpu_installer/internal/installer/installer.go
+++ b/src/cmd/cos_gpu_installer/internal/installer/installer.go
@@ -22,7 +22,7 @@
 
 const (
 	gpuInstallDirContainer        = "/usr/local/nvidia"
-	defaultGPUDriverFile          = "default_version"
+	defaultGPUDriverFile          = "gpu_default_version"
 	precompiledInstallerURLFormat = "https://storage.googleapis.com/nvidia-drivers-%s-public/nvidia-cos-project/%s/tesla/%s_00/%s/NVIDIA-Linux-x86_64-%s_%s-%s.cos"
 	defaultFilePermission         = 0755
 )
@@ -140,9 +140,8 @@
 
 	if needSigned {
 		// Run installer to compile drivers. Expect the command to fail as the drivers are not signed yet.
-		if err := utils.RunCommandAndLogOutput(cmd, true); err != nil {
-			return errors.Wrap(err, "failed to run GPU driver installer")
-		}
+		utils.RunCommandAndLogOutput(cmd, true)
+
 		// sign GPU drivers.
 		kernelFiles, err := ioutil.ReadDir(filepath.Join(extractDir, "kernel"))
 		if err != nil {
@@ -184,9 +183,9 @@
 }
 
 // GetDefaultGPUDriverVersion gets the default GPU driver version.
-func GetDefaultGPUDriverVersion(downloader cos.ExtensionsDownloader) (string, error) {
+func GetDefaultGPUDriverVersion(downloader cos.ArtifactsDownloader) (string, error) {
 	log.Info("Getting the default GPU driver version")
-	content, err := downloader.GetExtensionArtifact(cos.GpuExtension, defaultGPUDriverFile)
+	content, err := downloader.GetArtifact(defaultGPUDriverFile)
 	if err != nil {
 		return "", errors.Wrapf(err, "failed to get default GPU driver version")
 	}
diff --git a/src/pkg/cos/artifacts.go b/src/pkg/cos/artifacts.go
index 616778e..bb2f0bb 100644
--- a/src/pkg/cos/artifacts.go
+++ b/src/pkg/cos/artifacts.go
@@ -42,6 +42,11 @@
 	Internal  bool
 }
 
+// NewGCSDownloader creates a GCSDownloader instance.
+func NewGCSDownloader(e *EnvReader, i bool) *GCSDownloader {
+	return &GCSDownloader{e, i}
+}
+
 // DownloadKernelSrc downloads COS kernel sources to destination directory.
 func (d *GCSDownloader) DownloadKernelSrc(destDir string) error {
 	return d.DownloadArtifact(destDir, kernelSrcArchive)
diff --git a/src/pkg/cos/cos.go b/src/pkg/cos/cos.go
index c431c00..c75f7c5 100644
--- a/src/pkg/cos/cos.go
+++ b/src/pkg/cos/cos.go
@@ -8,7 +8,6 @@
 	"os/exec"
 	"path/filepath"
 	"strings"
-	"syscall"
 
 	"cos.googlesource.com/cos/tools/src/pkg/utils"
 
@@ -25,63 +24,20 @@
 	execCommand = exec.Command
 )
 
-// DisableKernelModuleLocking disables kernel modules signing enforcement and loadpin so that unsigned kernel modules
-// can be loaded to COS kernel.
-func DisableKernelModuleLocking() error {
-	log.Info("Checking if third party kernel modules can be installed")
+// CheckKernelModuleSigning checks whether kernel module signing related options present.
+func CheckKernelModuleSigning(kernelCmdline string) bool {
+	log.Info("Checking kernel module signing.")
 
-	mountDir, err := ioutil.TempDir("", "mountdir")
-	if err != nil {
-		return errors.Wrap(err, "failed to create mount dir")
-	}
-
-	if err := syscall.Mount(espPartition, mountDir, "vfat", 0, ""); err != nil {
-		return errors.Wrap(err, "failed to mount path")
-	}
-
-	grubCfgPath := filepath.Join(mountDir, "esp/efi/boot/grub.cfg")
-	grubCfg, err := ioutil.ReadFile(grubCfgPath)
-	if err != nil {
-		return errors.Wrapf(err, "failed to read grub config from %s", grubCfgPath)
-	}
-
-	grubCfgStr := string(grubCfg)
-	needReboot := false
 	for _, kernelOption := range []string{
-		"module.sig_enforce",
-		"loadpin.enforce",
-		"loadpin.enabled",
+		"loadpin.exclude=kernel-module",
+		"modules-load=loadpin_trigger",
+		"module.sig_enforce=1",
 	} {
-		if newGrubCfgStr, needRebootOption := disableKernelOptionFromGrubCfg(kernelOption, grubCfgStr); needRebootOption {
-			needReboot = true
-			grubCfgStr = newGrubCfgStr
+		if !strings.Contains(kernelCmdline, kernelOption) {
+			return false
 		}
 	}
-
-	if needReboot {
-		log.Info("Modifying grub config to disable module locking.")
-		if err := os.Rename(grubCfgPath, grubCfgPath+".orig"); err != nil {
-			return errors.Wrapf(err, "failed to rename file %s", grubCfgPath)
-		}
-		if err := ioutil.WriteFile(grubCfgPath, []byte(grubCfgStr), 0644); err != nil {
-			return errors.Wrapf(err, "failed to write to file %s", grubCfgPath)
-		}
-	} else {
-		log.Info("Module locking has been disabled.")
-	}
-
-	syscall.Sync()
-	if err := syscall.Unmount(mountDir, 0); err != nil {
-		return err
-	}
-
-	if needReboot {
-		log.Warning("Rebooting")
-		if err := syscall.Reboot(syscall.LINUX_REBOOT_CMD_RESTART); err != nil {
-			return errors.Wrap(err, "failed to reboot")
-		}
-	}
-	return nil
+	return true
 }
 
 // SetCompilationEnv sets compilation environment variables (e.g. CC, CXX) for third-party kernel module compilation.
@@ -119,15 +75,14 @@
 	}
 	if empty, _ := utils.IsDirEmpty(destDir); !empty {
 		log.Info("Found existing toolchain. Skipping download and installation")
-		return nil
-	}
+	} else {
+		if err := downloader.DownloadToolchain(destDir); err != nil {
+			return errors.Wrap(err, "failed to download toolchain")
+		}
 
-	if err := downloader.DownloadToolchain(destDir); err != nil {
-		return errors.Wrap(err, "failed to download toolchain")
-	}
-
-	if err := exec.Command("tar", "xf", filepath.Join(destDir, toolchainArchive), "-C", destDir).Run(); err != nil {
-		return errors.Wrap(err, "failed to extract toolchain archive tarball")
+		if err := exec.Command("tar", "xf", filepath.Join(destDir, toolchainArchive), "-C", destDir).Run(); err != nil {
+			return errors.Wrap(err, "failed to extract toolchain archive tarball")
+		}
 	}
 
 	log.Info("Configuring environment variables for cross-compilation")
diff --git a/src/pkg/cos/cos_test.go b/src/pkg/cos/cos_test.go
index f031491..e28ac2b 100644
--- a/src/pkg/cos/cos_test.go
+++ b/src/pkg/cos/cos_test.go
@@ -207,55 +207,65 @@
 
 func TestDisableKernelOptionFromGrubCfg(t *testing.T) {
 	for _, tc := range []struct {
-		testName           string
-		kernelOption       string
-		grubCfg            string
-		expectedNewGrubCfg string
-		expectedNeedReboot bool
+		testName       string
+		kernelCmdLine  string
+		expectedReturn bool
 	}{
 		{
-			"LoadPin",
-			"loadpin.enabled",
-
-			`BOOT_IMAGE=/syslinux/vmlinuz.A init=/usr/lib/systemd/systemd boot=local rootwait ro noresume noswap ` +
-				`loglevel=7 noinitrd console=ttyS0 security=apparmor virtio_net.napi_tx=1 ` +
-				`systemd.unified_cgroup_hierarchy=false systemd.legacy_systemd_cgroup_controller=false csm.disabled=1 ` +
-				`dm_verity.error_behavior=3 dm_verity.max_bios=-1 dm_verity.dev_wait=1 i915.modeset=1 cros_efi root=/dev/dm-0 ` +
-				`"dm=1 vroot none ro 1,0 2539520 verity payload=PARTUUID=36547742-9356-EF4E-B9AD-F8DED2F6D087 ` +
-				`hashtree=PARTUUID=36547742-9356-EF4E-B9AD-F8DED2F6D087 hashstart=2539520 alg=sha256 ` +
-				`root_hexdigest=0ff80250bd97ad47a65e7cd330ab70bcf5013d7a86817dca59fcac77f0ba1a8f ` +
-				`salt=414038a6ed9b1f528c327aff4eac16ad5ca4a6699d142ae096e90374af907c34`,
-
-			`BOOT_IMAGE=/syslinux/vmlinuz.A init=/usr/lib/systemd/systemd boot=local rootwait ro noresume noswap ` +
-				`loglevel=7 noinitrd console=ttyS0 security=apparmor virtio_net.napi_tx=1 ` +
-				`systemd.unified_cgroup_hierarchy=false systemd.legacy_systemd_cgroup_controller=false csm.disabled=1 ` +
-				`dm_verity.error_behavior=3 dm_verity.max_bios=-1 dm_verity.dev_wait=1 i915.modeset=1 cros_efi loadpin.enabled=0 root=/dev/dm-0 ` +
-				`"dm=1 vroot none ro 1,0 2539520 verity payload=PARTUUID=36547742-9356-EF4E-B9AD-F8DED2F6D087 ` +
-				`hashtree=PARTUUID=36547742-9356-EF4E-B9AD-F8DED2F6D087 hashstart=2539520 alg=sha256 ` +
-				`root_hexdigest=0ff80250bd97ad47a65e7cd330ab70bcf5013d7a86817dca59fcac77f0ba1a8f ` +
-				`salt=414038a6ed9b1f528c327aff4eac16ad5ca4a6699d142ae096e90374af907c34`,
-			true,
+			testName: "OptionsPresent",
+			kernelCmdLine: `BOOT_IMAGE=/syslinux/vmlinuz.A init=/usr/lib/systemd/systemd boot=local rootwait ro noresume noswap loglevel=7 ` +
+				`noinitrd console=ttyS0 security=apparmor virtio_net.napi_tx=1 systemd.unified_cgroup_hierarchy=false ` +
+				`systemd.legacy_systemd_cgroup_controller=false csm.disabled=1 dm_verity.error_behavior=3 dm_verity.max_bios=-1 ` +
+				`dm_verity.dev_wait=1 i915.modeset=1 cros_efi module.sig_enforce=1 modules-load=loadpin_trigger ` +
+				`loadpin.exclude=kernel-module root=/dev/dm-0 "dm=1 vroot none ro 1,0 4077568 verity ` +
+				`payload=PARTUUID=00CE255B-DB42-1E47-A62B-735C7A9A7397 hashtree=PARTUUID=00CE255B-DB42-1E47-A62B-735C7A9A7397 ` +
+				`hashstart=4077568 alg=sha256 root_hexdigest=8a2cfc7097aa7ddfe4101611fad9dd1df59f9c29cfa9b1a5d18f55ae68c9eed5 ` +
+				`salt=65697f247db9275b9e9830d275ca6b830c156187403f6210b2ebcb11c8beaa57"`,
+			expectedReturn: true,
 		},
 		{
-			"LoadPinEnabled",
-			"loadpin.enabled",
-			"cros_efi loadpin.enabled=1",
-			"cros_efi loadpin.enabled=0",
-			true,
+			testName: "MissingLoadpinExclude",
+			kernelCmdLine: `BOOT_IMAGE=/syslinux/vmlinuz.A init=/usr/lib/systemd/systemd boot=local rootwait ro noresume noswap loglevel=7 ` +
+				`noinitrd console=ttyS0 security=apparmor virtio_net.napi_tx=1 systemd.unified_cgroup_hierarchy=false ` +
+				`systemd.legacy_systemd_cgroup_controller=false csm.disabled=1 dm_verity.error_behavior=3 dm_verity.max_bios=-1 ` +
+				`dm_verity.dev_wait=1 i915.modeset=1 cros_efi module.sig_enforce=1 modules-load=loadpin_trigger ` +
+				`root=/dev/dm-0 "dm=1 vroot none ro 1,0 4077568 verity ` +
+				`payload=PARTUUID=00CE255B-DB42-1E47-A62B-735C7A9A7397 hashtree=PARTUUID=00CE255B-DB42-1E47-A62B-735C7A9A7397 ` +
+				`hashstart=4077568 alg=sha256 root_hexdigest=8a2cfc7097aa7ddfe4101611fad9dd1df59f9c29cfa9b1a5d18f55ae68c9eed5 ` +
+				`salt=65697f247db9275b9e9830d275ca6b830c156187403f6210b2ebcb11c8beaa57"`,
+			expectedReturn: false,
 		},
 		{
-			"LoadPinDisabled",
-			"loadpin.enabled",
-			"cros_efi loadpin.enabled=0",
-			"cros_efi loadpin.enabled=0",
-			false,
+			testName: "MissingLoadpinTrigger",
+			kernelCmdLine: `BOOT_IMAGE=/syslinux/vmlinuz.A init=/usr/lib/systemd/systemd boot=local rootwait ro noresume noswap loglevel=7 ` +
+				`noinitrd console=ttyS0 security=apparmor virtio_net.napi_tx=1 systemd.unified_cgroup_hierarchy=false ` +
+				`systemd.legacy_systemd_cgroup_controller=false csm.disabled=1 dm_verity.error_behavior=3 dm_verity.max_bios=-1 ` +
+				`dm_verity.dev_wait=1 i915.modeset=1 cros_efi module.sig_enforce=1 ` +
+				`loadpin.exclude=kernel-module root=/dev/dm-0 "dm=1 vroot none ro 1,0 4077568 verity ` +
+				`payload=PARTUUID=00CE255B-DB42-1E47-A62B-735C7A9A7397 hashtree=PARTUUID=00CE255B-DB42-1E47-A62B-735C7A9A7397 ` +
+				`hashstart=4077568 alg=sha256 root_hexdigest=8a2cfc7097aa7ddfe4101611fad9dd1df59f9c29cfa9b1a5d18f55ae68c9eed5 ` +
+				`salt=65697f247db9275b9e9830d275ca6b830c156187403f6210b2ebcb11c8beaa57"`,
+			expectedReturn: false,
+		},
+		{
+			testName: "MissingSigEnforce",
+			kernelCmdLine: `BOOT_IMAGE=/syslinux/vmlinuz.A init=/usr/lib/systemd/systemd boot=local rootwait ro noresume noswap loglevel=7 ` +
+				`noinitrd console=ttyS0 security=apparmor virtio_net.napi_tx=1 systemd.unified_cgroup_hierarchy=false ` +
+				`systemd.legacy_systemd_cgroup_controller=false csm.disabled=1 dm_verity.error_behavior=3 dm_verity.max_bios=-1 ` +
+				`dm_verity.dev_wait=1 i915.modeset=1 cros_efi modules-load=loadpin_trigger ` +
+				`loadpin.exclude=kernel-module root=/dev/dm-0 "dm=1 vroot none ro 1,0 4077568 verity ` +
+				`payload=PARTUUID=00CE255B-DB42-1E47-A62B-735C7A9A7397 hashtree=PARTUUID=00CE255B-DB42-1E47-A62B-735C7A9A7397 ` +
+				`hashstart=4077568 alg=sha256 root_hexdigest=8a2cfc7097aa7ddfe4101611fad9dd1df59f9c29cfa9b1a5d18f55ae68c9eed5 ` +
+				`salt=65697f247db9275b9e9830d275ca6b830c156187403f6210b2ebcb11c8beaa57"`,
+			expectedReturn: false,
 		},
 	} {
-		newGrubCfg, needReboot := disableKernelOptionFromGrubCfg(tc.kernelOption, tc.grubCfg)
-		if newGrubCfg != tc.expectedNewGrubCfg || needReboot != tc.expectedNeedReboot {
-			t.Errorf("%v: Unexpected output:\nexpect grubcfg: %v\ngot grubcfg: %v\nexpect needReboot: %v, got needReboot: %v",
-				tc.testName, tc.expectedNewGrubCfg, newGrubCfg, tc.expectedNeedReboot, needReboot)
-		}
+		t.Run(tc.testName, func(t *testing.T) {
+			ret := CheckKernelModuleSigning(tc.kernelCmdLine)
+			if ret != tc.expectedReturn {
+				t.Errorf("Unexpected output:%v, expect: %v", ret, tc.expectedReturn)
+			}
+		})
 	}
 }