Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion efi/preinstall/check_host_security.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,12 @@ func checkDiscreteTPMPartialResetAttackMitigationStatusAMD64(env internal_efi.Ho
// checkHostSecurityARM64Platform selects the platform-specific firmware
// integrity check. Tests replace this to supply synthetic platforms.
var checkHostSecurityARM64Platform = func(env internal_efi.HostEnvironmentARM64, cpuManufacturer string) (platformFirmwareIntegrityConfig, error) {
return platformFirmwareIntegrityNone, &UnsupportedPlatformError{fmt.Errorf("unsupported CPU manufacturer: %s", cpuManufacturer)}
switch cpuManufacturer {
case "NVIDIA":
return checkHostSecurityNVIDIA(env)
default:
return platformFirmwareIntegrityNone, &UnsupportedPlatformError{fmt.Errorf("unsupported CPU manufacturer: %s", cpuManufacturer)}
}
}

func checkHostSecurityARM64(env internal_efi.HostEnvironment, log *tcglog.Log) (platformFirmwareIntegrityConfig, error) {
Expand Down
61 changes: 61 additions & 0 deletions efi/preinstall/check_host_security_nvidia.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// -*- Mode: Go; indent-tabs-mode: t -*-

/*
* Copyright (C) 2026 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

package preinstall

import (
"fmt"
"strings"

internal_efi "github.com/snapcore/secboot/internal/efi"
)

const nvidiaDGXSparkCPUVersion = "GB10"
const nvidiaRTXSparkCPUVersionPrefix = "NVIDIA RTX Spark"

// isNvidiaSparkCPUVersion reports whether cpuVersion identifies a supported NVIDIA
// Spark platform: either the DGX Spark (exact match on "GB10") or any RTX Spark
// variant (prefix match on "NVIDIA RTX Spark").
func isNvidiaSparkCPUVersion(cpuVersion string) bool {
return cpuVersion == nvidiaDGXSparkCPUVersion || strings.HasPrefix(cpuVersion, nvidiaRTXSparkCPUVersionPrefix)
}

func checkHostSecurityNVIDIA(env internal_efi.HostEnvironmentARM64) (platformFirmwareIntegrityConfig, error) {
cpuVersion, err := env.CPUVersion()
if err != nil {
return platformFirmwareIntegrityNone, &UnsupportedPlatformError{fmt.Errorf("cannot determine CPU version: %w", err)}
}

switch {
case isNvidiaSparkCPUVersion(cpuVersion):
return checkHostSecurityNVIDIASpark(env)
default:
return platformFirmwareIntegrityNone, &UnsupportedPlatformError{fmt.Errorf("unsupported NVIDIA CPU version: %s", cpuVersion)}
}
}

func checkHostSecurityNVIDIASpark(env internal_efi.HostEnvironmentARM64) (platformFirmwareIntegrityConfig, error) {
// TODO: Implement proper HW ROT fusing checks, once we have the documentation
// from NVIDIA to do so. This will involve checking fuses and will return
// platformFirmwareIntegrityVerified if set correctly.

// TODO: Implement proper debug authentication checks, once we have the documentation
// from NVIDIA to do so.
return platformFirmwareIntegrityVerified, nil
}
74 changes: 74 additions & 0 deletions efi/preinstall/check_host_security_nvidia_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// -*- Mode: Go; indent-tabs-mode: t -*-

/*
* Copyright (C) 2026 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

package preinstall_test

import (
"errors"

. "github.com/snapcore/secboot/efi/preinstall"
"github.com/snapcore/secboot/internal/efitest"
"github.com/snapcore/secboot/internal/testutil"
. "gopkg.in/check.v1"
)

func (s *hostSecurityARM64Suite) TestCheckHostSecurityGoodDGXSparkVerified(c *C) {
env := efitest.NewMockHostEnvironmentWithOpts(
efitest.WithARM64Environment("NVIDIA", "GB10"),
efitest.WithSysfsDevices(makeArm64IOMMUDevices()...),
)
log := efitest.NewLog(c, &efitest.LogOptions{})

integrity, err := CheckHostSecurity(env, log)
c.Check(err, IsNil)
c.Check(integrity, Equals, PlatformFirmwareIntegrityVerified)
}

func (s *hostSecurityARM64Suite) TestCheckHostSecurityGoodRTXSparkVerified(c *C) {
env := efitest.NewMockHostEnvironmentWithOpts(
efitest.WithARM64Environment("NVIDIA", "NVIDIA RTX Spark N1X (5120-core GPU, 18-core CPU)"),
efitest.WithSysfsDevices(makeArm64IOMMUDevices()...),
)
log := efitest.NewLog(c, &efitest.LogOptions{})

integrity, err := CheckHostSecurity(env, log)
c.Check(err, IsNil)
c.Check(integrity, Equals, PlatformFirmwareIntegrityVerified)
}

func (s *hostSecurityARM64Suite) TestCheckHostSecurityGoodRTXSparkAlternativeSKUVerified(c *C) {
env := efitest.NewMockHostEnvironmentWithOpts(
efitest.WithARM64Environment("NVIDIA", "NVIDIA RTX Spark N1X (4096-core GPU, 16-core CPU)"),
efitest.WithSysfsDevices(makeArm64IOMMUDevices()...),
)
log := efitest.NewLog(c, &efitest.LogOptions{})

integrity, err := CheckHostSecurity(env, log)
c.Check(err, IsNil)
c.Check(integrity, Equals, PlatformFirmwareIntegrityVerified)
}

func (s *hostSecurityARM64Suite) TestCheckHostSecurityErrUnsupportedNVIDIACPUVersion(c *C) {
env := efitest.NewMockHostEnvironmentWithOpts(efitest.WithARM64Environment("NVIDIA", "N2X"))

_, err := CheckHostSecurity(env, nil)
c.Check(err, ErrorMatches, `unsupported platform: unsupported NVIDIA CPU version: N2X`)
var upe *UnsupportedPlatformError
c.Check(errors.As(err, &upe), testutil.IsTrue)
}
11 changes: 11 additions & 0 deletions efi/preinstall/check_host_security_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,17 @@ func (s *hostSecurityARM64Suite) TestCheckDiscreteTPMPartialResetAttackMitigatio
c.Check(status, Equals, DtpmPartialResetAttackMitigationNotRequired)
}

func (s *hostSecurityARM64Suite) TestCheckDiscreteTPMPartialResetAttackMitigationStatusUnavailableForNvidiaDGXSpark(c *C) {
env := efitest.NewMockHostEnvironmentWithOpts(
efitest.WithARM64Environment("NVIDIA", "GB10"),
efitest.WithSysfsDevices(makeArm64TPMDevice("tpm_crb")),
)

status, err := CheckDiscreteTPMPartialResetAttackMitigationStatus(env, makeArm64PCRResults(c))
c.Check(err, IsNil)
c.Check(status, Equals, DtpmPartialResetAttackMitigationUnavailable)
}

func (s *hostSecuritySuite) TestCheckHostSecurityUnsupportedArchitecture(c *C) {
restore := MockRuntimeGOARCH("ppc64le")
defer restore()
Expand Down
7 changes: 6 additions & 1 deletion efi/preinstall/check_tpm.go
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,12 @@ func isTPMDiscreteARM64(env internal_efi.HostEnvironment) (bool, error) {
return false, &UnsupportedPlatformError{fmt.Errorf("cannot determine CPU manufacturer: %w", err)}
}

return false, &UnsupportedPlatformError{fmt.Errorf("unsupported CPU manufacturer: %s", cpuManufacturer)}
switch cpuManufacturer {
case "NVIDIA":
return isTPMDiscreteNvidia(arm64Env)
default:
return false, &UnsupportedPlatformError{fmt.Errorf("unsupported CPU manufacturer: %s", cpuManufacturer)}
}
}

// isTPMFirmwareOptee determines whether the default TPM is an OP-TEE firmware TPM,
Expand Down
42 changes: 42 additions & 0 deletions efi/preinstall/check_tpm_nvidia.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// -*- Mode: Go; indent-tabs-mode: t -*-

/*
* Copyright (C) 2026 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

package preinstall

import (
"fmt"

internal_efi "github.com/snapcore/secboot/internal/efi"
)

// isTPMDiscreteNvidia determines whether the default TPM is discrete on NVIDIA systems
func isTPMDiscreteNvidia(env internal_efi.HostEnvironmentARM64) (bool, error) {
cpuVersion, err := env.CPUVersion()
if err != nil {
return false, &UnsupportedPlatformError{fmt.Errorf("cannot determine CPU version: %w", err)}
}

switch {
// We just happen to know that the NVIDIA DGX Spark and RTX Spark have a dTPM
case isNvidiaSparkCPUVersion(cpuVersion):
return true, nil
default:
return false, &UnsupportedPlatformError{fmt.Errorf("unsupported NVIDIA CPU version: %s", cpuVersion)}
}
}
74 changes: 74 additions & 0 deletions efi/preinstall/check_tpm_nvidia_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// -*- Mode: Go; indent-tabs-mode: t -*-

/*
* Copyright (C) 2026 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

package preinstall_test

import (
"errors"

. "github.com/snapcore/secboot/efi/preinstall"
"github.com/snapcore/secboot/internal/efitest"
"github.com/snapcore/secboot/internal/testutil"
. "gopkg.in/check.v1"
)

func (s *tpmARM64Suite) TestIsTPMDiscreteDGXSpark(c *C) {
env := efitest.NewMockHostEnvironmentWithOpts(
efitest.WithARM64Environment("NVIDIA", "GB10"),
efitest.WithSysfsDevices(makeArm64TPMDevice("tpm_crb")),
)

discrete, err := IsTPMDiscrete(env)
c.Check(err, IsNil)
c.Check(discrete, testutil.IsTrue)
}

func (s *tpmARM64Suite) TestIsTPMDiscreteRTXSpark(c *C) {
env := efitest.NewMockHostEnvironmentWithOpts(
efitest.WithARM64Environment("NVIDIA", "NVIDIA RTX Spark N1X (5120-core GPU, 18-core CPU)"),
efitest.WithSysfsDevices(makeArm64TPMDevice("tpm_crb")),
)

discrete, err := IsTPMDiscrete(env)
c.Check(err, IsNil)
c.Check(discrete, testutil.IsTrue)
}

func (s *tpmARM64Suite) TestIsTPMDiscreteRTXSparkAlternativeSKU(c *C) {
env := efitest.NewMockHostEnvironmentWithOpts(
efitest.WithARM64Environment("NVIDIA", "NVIDIA RTX Spark N1X (4096-core GPU, 16-core CPU)"),
efitest.WithSysfsDevices(makeArm64TPMDevice("tpm_crb")),
)

discrete, err := IsTPMDiscrete(env)
c.Check(err, IsNil)
c.Check(discrete, testutil.IsTrue)
}

func (s *tpmARM64Suite) TestIsTPMDiscreteErrUnsupportedNVIDIACPUVersion(c *C) {
env := efitest.NewMockHostEnvironmentWithOpts(
efitest.WithARM64Environment("NVIDIA", "N2X"),
efitest.WithSysfsDevices(makeArm64TPMDevice("tpm_crb")),
)

_, err := IsTPMDiscrete(env)
c.Check(err, ErrorMatches, `unsupported platform: unsupported NVIDIA CPU version: N2X`)
var upe *UnsupportedPlatformError
c.Check(errors.As(err, &upe), testutil.IsTrue)
}
14 changes: 14 additions & 0 deletions efi/preinstall/checks_fixture_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,5 +267,19 @@ func runChecksPlatformHostFixtures() []runChecksHostFixture {
additionalExpectedFlags: RequireLockToPlatformFirmware,
arch: "arm64",
},
{
name: "nvidia-dgx-spark-tpm-crb",
capabilities: runChecksHostCapabilityValid |
runChecksHostCapabilityNotVirtualMachine |
runChecksHostCapabilityDiscreteTPM |
runChecksHostCapabilityStartupLocality0AccessibleFromOS |
runChecksHostCapabilityStartupLocality3AccessibleFromOS |
runChecksHostCapabilityStartupLocality4AccessibleFromOS,
environment: efitest.WithARM64Environment("NVIDIA", "GB10"),
virtualizationMode: internal_efi.VirtModeNone,
virtualizationDetection: internal_efi.DetectVirtModeAll,
sysfsDevices: newDevices("tpm_crb", true),
arch: "arm64",
},
}
}
Loading