Skip to content

Commit 1d5379d

Browse files
Michael Sterrittsuryasaimadhu
authored andcommitted
x86/sev: Fix SEV-ES INS/OUTS instructions for word, dword, and qword
Properly type the operands being passed to __put_user()/__get_user(). Otherwise, these routines truncate data for dependent instructions (e.g., INSW) and only read/write one byte. This has been tested by sending a string with REP OUTSW to a port and then reading it back in with REP INSW on the same port. Previous behavior was to only send and receive the first char of the size. For example, word operations for "abcd" would only read/write "ac". With change, the full string is now written and read back. Fixes: f980f9c (x86/sev-es: Compile early handler code into kernel image) Signed-off-by: Michael Sterritt <sterritt@google.com> Signed-off-by: Borislav Petkov <bp@suse.de> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Reviewed-by: Marc Orr <marcorr@google.com> Reviewed-by: Peter Gonda <pgonda@google.com> Reviewed-by: Joerg Roedel <jroedel@suse.de> Link: https://lkml.kernel.org/r/20211119232757.176201-1-sterritt@google.com
1 parent 51523ed commit 1d5379d

File tree

1 file changed

+39
-18
lines changed

1 file changed

+39
-18
lines changed

arch/x86/kernel/sev.c

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -294,11 +294,6 @@ static enum es_result vc_write_mem(struct es_em_ctxt *ctxt,
294294
char *dst, char *buf, size_t size)
295295
{
296296
unsigned long error_code = X86_PF_PROT | X86_PF_WRITE;
297-
char __user *target = (char __user *)dst;
298-
u64 d8;
299-
u32 d4;
300-
u16 d2;
301-
u8 d1;
302297

303298
/*
304299
* This function uses __put_user() independent of whether kernel or user
@@ -320,26 +315,42 @@ static enum es_result vc_write_mem(struct es_em_ctxt *ctxt,
320315
* instructions here would cause infinite nesting.
321316
*/
322317
switch (size) {
323-
case 1:
318+
case 1: {
319+
u8 d1;
320+
u8 __user *target = (u8 __user *)dst;
321+
324322
memcpy(&d1, buf, 1);
325323
if (__put_user(d1, target))
326324
goto fault;
327325
break;
328-
case 2:
326+
}
327+
case 2: {
328+
u16 d2;
329+
u16 __user *target = (u16 __user *)dst;
330+
329331
memcpy(&d2, buf, 2);
330332
if (__put_user(d2, target))
331333
goto fault;
332334
break;
333-
case 4:
335+
}
336+
case 4: {
337+
u32 d4;
338+
u32 __user *target = (u32 __user *)dst;
339+
334340
memcpy(&d4, buf, 4);
335341
if (__put_user(d4, target))
336342
goto fault;
337343
break;
338-
case 8:
344+
}
345+
case 8: {
346+
u64 d8;
347+
u64 __user *target = (u64 __user *)dst;
348+
339349
memcpy(&d8, buf, 8);
340350
if (__put_user(d8, target))
341351
goto fault;
342352
break;
353+
}
343354
default:
344355
WARN_ONCE(1, "%s: Invalid size: %zu\n", __func__, size);
345356
return ES_UNSUPPORTED;
@@ -362,11 +373,6 @@ static enum es_result vc_read_mem(struct es_em_ctxt *ctxt,
362373
char *src, char *buf, size_t size)
363374
{
364375
unsigned long error_code = X86_PF_PROT;
365-
char __user *s = (char __user *)src;
366-
u64 d8;
367-
u32 d4;
368-
u16 d2;
369-
u8 d1;
370376

371377
/*
372378
* This function uses __get_user() independent of whether kernel or user
@@ -388,26 +394,41 @@ static enum es_result vc_read_mem(struct es_em_ctxt *ctxt,
388394
* instructions here would cause infinite nesting.
389395
*/
390396
switch (size) {
391-
case 1:
397+
case 1: {
398+
u8 d1;
399+
u8 __user *s = (u8 __user *)src;
400+
392401
if (__get_user(d1, s))
393402
goto fault;
394403
memcpy(buf, &d1, 1);
395404
break;
396-
case 2:
405+
}
406+
case 2: {
407+
u16 d2;
408+
u16 __user *s = (u16 __user *)src;
409+
397410
if (__get_user(d2, s))
398411
goto fault;
399412
memcpy(buf, &d2, 2);
400413
break;
401-
case 4:
414+
}
415+
case 4: {
416+
u32 d4;
417+
u32 __user *s = (u32 __user *)src;
418+
402419
if (__get_user(d4, s))
403420
goto fault;
404421
memcpy(buf, &d4, 4);
405422
break;
406-
case 8:
423+
}
424+
case 8: {
425+
u64 d8;
426+
u64 __user *s = (u64 __user *)src;
407427
if (__get_user(d8, s))
408428
goto fault;
409429
memcpy(buf, &d8, 8);
410430
break;
431+
}
411432
default:
412433
WARN_ONCE(1, "%s: Invalid size: %zu\n", __func__, size);
413434
return ES_UNSUPPORTED;

0 commit comments

Comments
 (0)