16
16
package linuxabi
17
17
18
18
import (
19
+ "errors"
20
+ "fmt"
21
+ "reflect"
19
22
"unsafe"
20
23
21
- "github.com/google/go-sev-guest/abi"
22
24
"golang.org/x/sys/unix"
23
25
)
24
26
@@ -34,7 +36,7 @@ const (
34
36
iocNrshift = 0
35
37
iocTypeshift = (iocNrshift + iocNrbits )
36
38
iocSizeshift = (iocTypeshift + iocTypebits )
37
- iocDirshift = (iocSizeshift + iocDirbits )
39
+ iocDirshift = (iocSizeshift + iocSizebits )
38
40
iocWrite = 1
39
41
iocRead = 2
40
42
@@ -43,14 +45,22 @@ const (
43
45
iocSnpWithoutNr = ((iocWrite | iocRead ) << iocDirshift ) |
44
46
(iocTypeSnpGuestReq << iocTypeshift ) |
45
47
// unsafe.Sizeof(snpUserGuestRequest)
46
- (24 << iocSizeshift )
48
+ (32 << iocSizeshift )
47
49
48
50
// IocSnpGetReport is the ioctl command for getting an attestation report
49
51
IocSnpGetReport = iocSnpWithoutNr | (0x0 << iocNrshift )
50
52
51
53
// IocSnpGetReport is the ioctl command for getting an extended attestation report that includes
52
54
// certificate information.
53
55
IocSnpGetExtendedReport = iocSnpWithoutNr | (0x2 << iocNrshift )
56
+
57
+ // The message version for MSG_REPORT_REQ in the SNP API. Specified as 1.
58
+ guestMsgVersion = 1
59
+
60
+ // These numbers are from the uapi header sev_guest.h
61
+ snpResportRespSize = 4000
62
+ msgReportReqHeaderSize = 0x20
63
+ SnpReportRespReportSize = snpResportRespSize - msgReportReqHeaderSize
54
64
)
55
65
56
66
const (
@@ -93,9 +103,9 @@ func (err SevEsErr) Error() string {
93
103
return "unknown error"
94
104
}
95
105
96
- // SnpReportReq is Linux's sev-guest ioctl abi for sending a GET_REPORT request. See
106
+ // SnpReportReqABI is Linux's sev-guest ioctl abi for sending a GET_REPORT request. See
97
107
// include/uapi/linux/sev-guest.h
98
- type SnpReportReq struct {
108
+ type SnpReportReqABI struct {
99
109
// UserData to be included in the report
100
110
UserData [64 ]uint8
101
111
@@ -106,87 +116,187 @@ type SnpReportReq struct {
106
116
reserved [28 ]byte
107
117
}
108
118
109
- // SnpReportResp is Linux's sev-guest ioctl abi for receiving a GET_REPORT response.
110
- type SnpReportResp struct {
119
+ // SnpReportRespABI is Linux's sev-guest ioctl abi for receiving a GET_REPORT response.
120
+ // The size is expected to be snpReportRespSize.
121
+ type SnpReportRespABI struct {
122
+ Status uint32
123
+ ReportSize uint32
124
+ reserved [0x20 - 8 ]byte
111
125
// Data is the response data, see SEV-SNP spec for the format
112
- Data [abi . ReportSize ]uint8
126
+ Data [SnpReportRespReportSize ]uint8
113
127
}
114
128
115
- // SnpExtendedReportReqSafe is close to Linux's sev-guest ioctl abi for sending a GET_EXTENDED_REPORT request,
116
- // but uses safer types for the Ioctl interface.
117
- type SnpExtendedReportReqSafe struct {
118
- Data SnpReportReq
129
+ // ABI returns the same object since it doesn't need a separate representation across the interface.
130
+ func (r * SnpReportReqABI ) ABI () BinaryConversion { return r }
131
+
132
+ // Pointer returns a pointer to the object itself.
133
+ func (r * SnpReportReqABI ) Pointer () unsafe.Pointer {
134
+ return unsafe .Pointer (r )
135
+ }
136
+
137
+ // Finish is a no-op.
138
+ func (r * SnpReportReqABI ) Finish (b BinaryConvertible ) error { return nil }
139
+
140
+ // ABI returns the same object since it doesn't need a separate representation across the interface.
141
+ func (r * SnpReportRespABI ) ABI () BinaryConversion { return r }
142
+
143
+ // Pointer returns a pointer to the object itself.
144
+ func (r * SnpReportRespABI ) Pointer () unsafe.Pointer {
145
+ return unsafe .Pointer (r )
146
+ }
147
+
148
+ // Finish checks the status of the message and translates it to a Golang error.
149
+ func (r * SnpReportRespABI ) Finish (b BinaryConvertible ) error {
150
+ if r .Status != 0 {
151
+ switch r .Status {
152
+ case 0x16 : // Value from MSG_REPORT_RSP specification in SNP API.
153
+ return errors .New ("get_report had invalid parameters" )
154
+ default :
155
+ return fmt .Errorf ("unknown status: 0x%x" , r .Status )
156
+ }
157
+ }
158
+ return nil
159
+ }
160
+
161
+ // SnpExtendedReportReqABI is Linux's sev-guest ioctl abi for sending a GET_EXTENDED_REPORT request.
162
+ type SnpExtendedReportReqABI struct {
163
+ Data SnpReportReqABI
119
164
120
165
// Where to copy the certificate blob.
121
- Certs [] byte
166
+ CertsAddress unsafe. Pointer
122
167
123
168
// length of the certificate blob
124
169
CertsLength uint32
125
170
}
126
171
127
- // SnpExtendedReportReq is Linux's sev-guest ioctl abi for sending a GET_EXTENDED_REPORT request.
172
+ // SnpExtendedReportReq is close to Linux's sev-guest ioctl abi for sending a GET_EXTENDED_REPORT request,
173
+ // but uses safer types for the Ioctl interface.
128
174
type SnpExtendedReportReq struct {
129
- Data SnpReportReq
175
+ Data SnpReportReqABI
130
176
131
- // Where to copy the certificate blob.
132
- CertsAddress uint64
177
+ // Certs receives the certificate blob after the extended report request .
178
+ Certs [] byte
133
179
134
- // length of the certificate blob
180
+ // CertsLength is the length of the certificate blob.
135
181
CertsLength uint32
136
182
}
137
183
138
- // SnpUserGuestRequest is Linux's sev-guest ioctl abi for issuing a guest message.
139
- type SnpUserGuestRequest struct {
184
+ // Pointer returns a pointer so the object itself.
185
+ func (r * SnpExtendedReportReqABI ) Pointer () unsafe.Pointer {
186
+ return unsafe .Pointer (r )
187
+ }
188
+
189
+ // Finish writes back the changed CertsLength value.
190
+ func (r * SnpExtendedReportReqABI ) Finish (b BinaryConvertible ) error {
191
+ s , ok := b .(* SnpExtendedReportReq )
192
+ if ! ok {
193
+ return fmt .Errorf ("Finish argument is %v. Expects a *SnpExtendedReportReq" , reflect .TypeOf (b ))
194
+ }
195
+ s .CertsLength = r .CertsLength
196
+ return nil
197
+ }
198
+
199
+ // ABI returns an object that can cross the ABI boundary and copy back changes to the original
200
+ // object.
201
+ func (r * SnpExtendedReportReq ) ABI () BinaryConversion {
202
+ var certsAddress unsafe.Pointer
203
+ if len (r .Certs ) != 0 {
204
+ certsAddress = unsafe .Pointer (& r .Certs [0 ])
205
+ }
206
+ return & SnpExtendedReportReqABI {
207
+ Data : r .Data ,
208
+ CertsAddress : certsAddress ,
209
+ CertsLength : r .CertsLength ,
210
+ }
211
+ }
212
+
213
+ // SnpUserGuestRequestABI is Linux's sev-guest ioctl abi for issuing a guest message.
214
+ type SnpUserGuestRequestABI struct {
215
+ GuestMsgVersion uint32
140
216
// Request and response structure address.
141
- ReqData uint64
142
- RespData uint64
217
+ ReqData unsafe. Pointer
218
+ RespData unsafe. Pointer
143
219
// firmware error code on failure (see psp-sev.h in Linux kernel)
144
220
FwErr uint64
145
221
}
146
222
147
- // SnpUserGuestRequestSafe is Linux's sev-guest ioctl interface for issuing a guest message. The
223
+ type snpUserGuestRequestConversion struct {
224
+ abi SnpUserGuestRequestABI
225
+ reqConv BinaryConversion
226
+ respConv BinaryConversion
227
+ }
228
+
229
+ // SnpUserGuestRequest is Linux's sev-guest ioctl interface for issuing a guest message. The
148
230
// types here enhance runtime safety when using Ioctl as an interface.
149
- type SnpUserGuestRequestSafe struct {
231
+ type SnpUserGuestRequest struct {
150
232
// Request and response structure address.
151
- ReqData interface {}
152
- RespData interface {}
233
+ ReqData BinaryConvertible
234
+ RespData BinaryConvertible
153
235
// firmware error code on failure (see psp-sev.h in Linux kernel)
154
236
FwErr uint64
155
237
}
156
238
239
+ // ABI returns an object that can cross the ABI boundary and copy back changes to the original
240
+ // object.
241
+ func (r * SnpUserGuestRequest ) ABI () BinaryConversion {
242
+ result := & snpUserGuestRequestConversion {
243
+ reqConv : r .ReqData .ABI (),
244
+ respConv : r .RespData .ABI (),
245
+ }
246
+ result .abi .GuestMsgVersion = guestMsgVersion
247
+ result .abi .ReqData = result .reqConv .Pointer ()
248
+ result .abi .RespData = result .respConv .Pointer ()
249
+ return result
250
+ }
251
+
252
+ // Pointer returns a pointer to the object that crosses the ABI boundary.
253
+ func (r * snpUserGuestRequestConversion ) Pointer () unsafe.Pointer {
254
+ return unsafe .Pointer (& r .abi )
255
+ }
256
+
257
+ // Finish writes back the FwErr and any changes to the request or response objects.
258
+ func (r * snpUserGuestRequestConversion ) Finish (b BinaryConvertible ) error {
259
+ s , ok := b .(* SnpUserGuestRequest )
260
+ if ! ok {
261
+ return fmt .Errorf ("Finish argument is %v. Expects a *SnpUserGuestRequestSafe" , reflect .TypeOf (b ))
262
+ }
263
+ if err := r .reqConv .Finish (s .ReqData ); err != nil {
264
+ return fmt .Errorf ("could not finalize request data: %v" , err )
265
+ }
266
+ if err := r .respConv .Finish (s .RespData ); err != nil {
267
+ return fmt .Errorf ("could not finalize response data: %v" , err )
268
+ }
269
+ s .FwErr = r .abi .FwErr
270
+ return nil
271
+ }
272
+
273
+ // BinaryConversion is an interface that abstracts a "stand-in" object that passes through an ABI
274
+ // boundary and can finalize changes to the original object.
275
+ type BinaryConversion interface {
276
+ Pointer () unsafe.Pointer
277
+ Finish (BinaryConvertible ) error
278
+ }
279
+
280
+ // BinaryConvertible is an interface for an object that can produce a partner BinaryConversion
281
+ // object to allow its representation to pass the ABI boundary.
282
+ type BinaryConvertible interface {
283
+ ABI () BinaryConversion
284
+ }
285
+
157
286
// Ioctl performs the ioctl Linux syscall with the sev-guest Linux ABI unsafe pointer
158
287
// manipulation contained all in this call.
159
- func Ioctl (fd int , command uintptr , sreq * SnpUserGuestRequestSafe ) (uintptr , error ) {
160
- // Limit unsafe pointers to this scope by converting internal types to ABI types before a
161
- // raw ioctl call, and converting back.
162
- safeReqData := sreq .ReqData
163
- var reqData interface {}
164
- switch extReq := safeReqData .(type ) {
165
- case * SnpExtendedReportReqSafe :
166
- var certsAddress uint64
167
- if len (extReq .Certs ) > 0 {
168
- certsAddress = uint64 (uintptr (unsafe .Pointer (& extReq .Certs [0 ])))
169
- }
170
- reqData = & SnpExtendedReportReq {
171
- Data : extReq .Data ,
172
- CertsAddress : certsAddress ,
173
- CertsLength : extReq .CertsLength ,
174
- }
175
- }
176
- abi := SnpUserGuestRequest {
177
- ReqData : uint64 (uintptr (unsafe .Pointer (& reqData ))),
178
- RespData : uint64 (uintptr (unsafe .Pointer (& sreq .RespData ))),
288
+ func Ioctl (fd int , command uintptr , req * SnpUserGuestRequest ) (uintptr , error ) {
289
+ abi := req .ABI ()
290
+ result , _ , errno := unix .Syscall (unix .SYS_IOCTL , uintptr (fd ), command , uintptr (abi .Pointer ()))
291
+ abi .Finish (req )
292
+
293
+ // TODO(Issue #5): remove the work around for the kernel bug that writes
294
+ // uninitialized memory back on non-EIO.
295
+ if errno != unix .EIO {
296
+ req .FwErr = 0
179
297
}
180
- ptr := uintptr (unsafe .Pointer (& abi ))
181
- result , _ , errno := unix .RawSyscall (unix .SYS_IOCTL , uintptr (fd ), command , ptr )
182
298
if errno != 0 {
183
299
return 0 , errno
184
300
}
185
- // Copy back the certsLength from the request copy if an extended report request.
186
- switch extReq := reqData .(type ) {
187
- case * SnpExtendedReportReq :
188
- safeReqData .(* SnpExtendedReportReqSafe ).CertsLength = extReq .CertsLength
189
- }
190
- sreq .FwErr = abi .FwErr
191
301
return result , nil
192
302
}
0 commit comments