File: client_linux.go

package info (click to toggle)
golang-github-google-go-tdx-guest 0.3.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 544 kB
  • sloc: makefile: 3
file content (131 lines) | stat: -rw-r--r-- 3,795 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build linux

// Package client provides an interface to the Intel TDX guest device commands.
package client

import (
	"fmt"

	"unsafe"

	"github.com/google/go-configfs-tsm/configfs/linuxtsm"
	"github.com/google/go-configfs-tsm/report"
	labi "github.com/google/go-tdx-guest/client/linuxabi"
	"golang.org/x/sys/unix"
)

// defaultTdxGuestDevicePath is the platform's usual device path to the TDX guest.
const defaultTdxGuestDevicePath = "/dev/tdx_guest"

// LinuxDevice implements the Device interface with Linux ioctls.
type LinuxDevice struct {
	fd int
}

// Open opens the TDX guest device from a given path
func (d *LinuxDevice) Open(path string) error {
	fd, err := unix.Open(path, unix.O_RDWR|unix.O_SYNC, 0)
	if err != nil {
		d.fd = -1
		return fmt.Errorf("could not open Intel TDX guest device at %q: %v", path, err)
	}
	d.fd = fd
	return nil
}

// OpenDevice opens the TDX guest device.
func OpenDevice() (*LinuxDevice, error) {
	result := &LinuxDevice{}
	path := *tdxGuestPath
	if UseDefaultTdxGuestDevice() {
		path = defaultTdxGuestDevicePath
	}
	if err := result.Open(path); err != nil {
		return nil, err
	}
	return result, nil
}

// Close closes the TDX guest device.
func (d *LinuxDevice) Close() error {
	if d.fd == -1 { // Not open
		return nil
	}
	if err := unix.Close(d.fd); err != nil {
		return err
	}
	// Prevent double-close.
	d.fd = -1
	return nil
}

// Ioctl sends a command with its wrapped request and response values to the Linux device.
func (d *LinuxDevice) Ioctl(command uintptr, req any) (uintptr, error) {
	if d.fd == -1 {
		return 0, fmt.Errorf("intel TDX Guest Device is not open")
	}
	switch sreq := req.(type) {
	case *labi.TdxQuoteReq:
		abi := sreq.ABI()
		result, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(d.fd), command, uintptr(abi.Pointer()))
		abi.Finish(sreq)
		if errno == unix.EBUSY {
			return 0, errno
		} else if errno == unix.ENOTTY {
			return 0, fmt.Errorf("invalid ioctl! use QuoteProvider to fetch attestation quote")
		} else if errno != 0 {
			return 0, errno
		}
		return result, nil
	case *labi.TdxReportReq:
		result, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(d.fd), command, uintptr(unsafe.Pointer(req.(*labi.TdxReportReq))))
		if errno != 0 {
			return 0, errno
		}
		return result, nil
	}
	return 0, fmt.Errorf("unexpected request value: %v", req)
}

// LinuxConfigFsQuoteProvider implements the QuoteProvider interface to fetch
// attestation quote via ConfigFS.
type LinuxConfigFsQuoteProvider struct{}

// IsSupported checks if TSM client can be created to use ConfigFS system.
func (p *LinuxConfigFsQuoteProvider) IsSupported() error {
	_, err := linuxtsm.MakeClient()
	return err
}

// GetRawQuote returns byte format attestation quote via ConfigFS.
func (p *LinuxConfigFsQuoteProvider) GetRawQuote(reportData [64]byte) ([]uint8, error) {
	req := &report.Request{
		InBlob:     reportData[:],
		GetAuxBlob: false,
	}
	resp, err := linuxtsm.GetReport(req)
	if err != nil {
		return nil, err
	}
	tdReport := resp.OutBlob
	return tdReport, nil
}

// GetQuoteProvider returns an instance of LinuxConfigFsQuoteProvider.
func GetQuoteProvider() (*LinuxConfigFsQuoteProvider, error) {
	return &LinuxConfigFsQuoteProvider{}, nil
}