|
1 | | -//go:build linux |
2 | | -// +build linux |
3 | | - |
4 | 1 | package amdsevsnp |
5 | 2 |
|
6 | 3 | import ( |
7 | 4 | "bytes" |
8 | 5 | "encoding/binary" |
9 | 6 | "encoding/hex" |
10 | | - "errors" |
11 | | - "fmt" |
12 | | - "os" |
13 | | - "unsafe" |
14 | | - |
15 | | - "github.com/Microsoft/hcsshim/internal/guest/linux" |
16 | | -) |
17 | | - |
18 | | -const ( |
19 | | - msgTypeInvalid = iota |
20 | | - msgCPUIDRequest |
21 | | - msgCPUIDResponse |
22 | | - msgKeyRequest |
23 | | - msgKeyResponse |
24 | | - msgReportRequest |
25 | | - msgReportResponse |
26 | | - msgExportRequest |
27 | | - msgExportResponse |
28 | | - msgImportRequest |
29 | | - msgImportResponse |
30 | | - msgAbsorbRequest |
31 | | - msgAbsorbResponse |
32 | | - msgVMRKRequest |
33 | | - msgVMRKResponse |
34 | | - msgTypeMax |
35 | | -) |
36 | | - |
37 | | -type guestRequest5 struct { |
38 | | - RequestMsgType byte |
39 | | - ResponseMsgType byte |
40 | | - MsgVersion byte |
41 | | - RequestLength uint16 |
42 | | - RequestUAddr unsafe.Pointer |
43 | | - ResponseLength uint16 |
44 | | - ResponseUAddr unsafe.Pointer |
45 | | - Error uint32 |
46 | | -} |
47 | | - |
48 | | -type guestRequest6 struct { |
49 | | - MsgVersion byte |
50 | | - RequestData unsafe.Pointer |
51 | | - ResponseData unsafe.Pointer |
52 | | - Error uint64 |
53 | | -} |
54 | | - |
55 | | -// AMD SEV ioctl definitions for kernel 5.x. |
56 | | -const ( |
57 | | - snpGetReportIoctlCode5 = 3223868161 |
58 | 7 | ) |
59 | 8 |
|
60 | | -// AMD SEV ioctl definitions for kernel 6.x. |
61 | | -const ( |
62 | | - snpGetReportIoctlCode6 = 3223343872 |
63 | | -) |
64 | | - |
65 | | -// reportRequest used to issue SEV-SNP request |
66 | | -// https://www.amd.com/system/files/TechDocs/56860.pdf |
67 | | -// MSG_REPORT_REQ Table 20. |
68 | | -type reportRequest struct { |
69 | | - ReportData [64]byte |
70 | | - VMPL uint32 |
71 | | - _ [28]byte |
72 | | -} |
73 | | - |
74 | 9 | // report is an internal representation of SEV-SNP report |
75 | 10 | // https://www.amd.com/system/files/TechDocs/56860.pdf |
76 | 11 | // ATTESTATION_REPORT Table 21. |
@@ -131,133 +66,6 @@ func (sr *report) report() Report { |
131 | 66 | } |
132 | 67 | } |
133 | 68 |
|
134 | | -// reportResponse is the attestation response struct |
135 | | -// https://www.amd.com/system/files/TechDocs/56860.pdf |
136 | | -// MSG_REPORT_RSP Table 23. |
137 | | -// NOTE: reportResponse.Report is a byte slice, to have the original |
138 | | -// response in bytes. The conversion to internal struct happens inside |
139 | | -// convertRawReport. |
140 | | -// |
141 | | -// NOTE: the additional 64 bytes are reserved, without them, the ioctl fails. |
142 | | -type reportResponse struct { |
143 | | - Status uint32 |
144 | | - ReportSize uint32 |
145 | | - reserved1 [24]byte |
146 | | - Report [1184]byte |
147 | | - reserved2 [64]byte // padding to the size of SEV_SNP_REPORT_RSP_BUF_SZ (i.e., 1280 bytes) |
148 | | -} |
149 | | - |
150 | | -// Size of `snp_report_resp` in include/uapi/linux/sev-guest.h. |
151 | | -// It's used only for Linux 6.x. |
152 | | -// It will have the conteints of reportResponse in the first unsafe.Sizeof(reportResponse{}) bytes. |
153 | | -const reportResponseContainerLength6 = 4000 |
154 | | - |
155 | | -const snpDevicePath5 = "/dev/sev" |
156 | | -const snpDevicePath6 = "/dev/sev-guest" |
157 | | - |
158 | | -func IsSNP() bool { |
159 | | - return isSNPVM5() || isSNPVM6() |
160 | | -} |
161 | | - |
162 | | -// Check if the code is being run in SNP VM for Linux kernel version 5.x. |
163 | | -func isSNPVM5() bool { |
164 | | - _, err := os.Stat(snpDevicePath5) |
165 | | - return !errors.Is(err, os.ErrNotExist) |
166 | | -} |
167 | | - |
168 | | -// Check if the code is being run in SNP VM for Linux kernel version 6.x. |
169 | | -func isSNPVM6() bool { |
170 | | - _, err := os.Stat(snpDevicePath6) |
171 | | - return !errors.Is(err, os.ErrNotExist) |
172 | | -} |
173 | | - |
174 | | -// FetchRawSNPReport returns attestation report bytes. |
175 | | -func FetchRawSNPReport(reportData []byte) ([]byte, error) { |
176 | | - if isSNPVM5() { |
177 | | - return fetchRawSNPReport5(reportData) |
178 | | - } else if isSNPVM6() { |
179 | | - return fetchRawSNPReport6(reportData) |
180 | | - } else { |
181 | | - return nil, fmt.Errorf("SEV device is not found") |
182 | | - } |
183 | | -} |
184 | | - |
185 | | -func fetchRawSNPReport5(reportData []byte) ([]byte, error) { |
186 | | - f, err := os.OpenFile(snpDevicePath5, os.O_RDWR, 0) |
187 | | - if err != nil { |
188 | | - return nil, err |
189 | | - } |
190 | | - defer func() { |
191 | | - _ = f.Close() |
192 | | - }() |
193 | | - |
194 | | - var ( |
195 | | - msgReportIn reportRequest |
196 | | - msgReportOut reportResponse |
197 | | - ) |
198 | | - |
199 | | - if reportData != nil { |
200 | | - if len(reportData) > len(msgReportIn.ReportData) { |
201 | | - return nil, fmt.Errorf("reportData too large: %s", reportData) |
202 | | - } |
203 | | - copy(msgReportIn.ReportData[:], reportData) |
204 | | - } |
205 | | - |
206 | | - payload := &guestRequest5{ |
207 | | - RequestMsgType: msgReportRequest, |
208 | | - ResponseMsgType: msgReportResponse, |
209 | | - MsgVersion: 1, |
210 | | - RequestLength: uint16(unsafe.Sizeof(msgReportIn)), |
211 | | - RequestUAddr: unsafe.Pointer(&msgReportIn), |
212 | | - ResponseLength: uint16(unsafe.Sizeof(msgReportOut)), |
213 | | - ResponseUAddr: unsafe.Pointer(&msgReportOut), |
214 | | - Error: 0, |
215 | | - } |
216 | | - |
217 | | - if err := linux.Ioctl(f, snpGetReportIoctlCode5, unsafe.Pointer(payload)); err != nil { |
218 | | - return nil, err |
219 | | - } |
220 | | - return msgReportOut.Report[:], nil |
221 | | -} |
222 | | - |
223 | | -func fetchRawSNPReport6(reportData []byte) ([]byte, error) { |
224 | | - f, err := os.OpenFile(snpDevicePath6, os.O_RDWR, 0) |
225 | | - if err != nil { |
226 | | - return nil, err |
227 | | - } |
228 | | - defer func() { |
229 | | - _ = f.Close() |
230 | | - }() |
231 | | - |
232 | | - var ( |
233 | | - msgReportIn reportRequest |
234 | | - msgReportOut reportResponse |
235 | | - ) |
236 | | - reportOutContainer := [reportResponseContainerLength6]byte{} |
237 | | - |
238 | | - if reportData != nil { |
239 | | - if len(reportData) > len(msgReportIn.ReportData) { |
240 | | - return nil, fmt.Errorf("reportData too large: %s", reportData) |
241 | | - } |
242 | | - copy(msgReportIn.ReportData[:], reportData) |
243 | | - } |
244 | | - |
245 | | - payload := &guestRequest6{ |
246 | | - MsgVersion: 1, |
247 | | - RequestData: unsafe.Pointer(&msgReportIn), |
248 | | - ResponseData: unsafe.Pointer(&reportOutContainer), |
249 | | - Error: 0, |
250 | | - } |
251 | | - |
252 | | - if err := linux.Ioctl(f, snpGetReportIoctlCode6, unsafe.Pointer(payload)); err != nil { |
253 | | - return nil, err |
254 | | - } |
255 | | - |
256 | | - msgReportOut = *(*reportResponse)(unsafe.Pointer(&reportOutContainer[0])) |
257 | | - |
258 | | - return msgReportOut.Report[:], nil |
259 | | -} |
260 | | - |
261 | 69 | // Report represents parsed attestation report. |
262 | 70 | type Report struct { |
263 | 71 | Version uint32 |
|
0 commit comments