Skip to content
This repository was archived by the owner on Feb 23, 2021. It is now read-only.

Rneri/umip #140

Open
wants to merge 109 commits into
base: master
Choose a base branch
from
Open

Rneri/umip #140

wants to merge 109 commits into from

Conversation

dznguyen98023
Copy link

Need to pull out umpi tests for testing

This is a special flavor of LUV for UMIP. Remove all the unneeded packages.

Signed-off-by: Ricardo Neri <[email protected]>
I need this file to increase the size of the boot partition, whose
size is calculated by the files it contains. The extra space created by
this file makes it easy to add/replace files that are bigger than the
originals.

Signed-off-by: Ricardo Neri <[email protected]>
User-Mode Instruction Prevention (UMIP) is a security feature present in
new Intel Processors. If enabled, it prevents the execution of certain
instructions if the Current Privilege Level (CPL) is greater than 0. If
these instructions were executed while in CPL > 0, user space applications
could have access to system-wide settings such as the global and local
descriptor tables, the task register and the interrupt descriptor table.

These are the instructions covered by UMIP:
* SGDT - Store Global Descriptor Table
* SIDT - Store Interrupt Descriptor Table
* SLDT - Store Local Descriptor Table
* SMSW - Store Machine Status Word
* STR - Store Task Register

If any of these instructions is executed with CPL > 0, a general protection
exception is issued when UMIP is enbled.

This recipe adds two sample user-space programs that exercises all
the possible combinations of memory and register operands for the
aforementioned instructions. This helps to validate the emulation code
for such instuctions within the Linux kernel.

Signed-off-by: Ricardo Neri <[email protected]>
Ideally, we might want to add these patches in the vm86-test recipe. Unfortunately,
such recipe uses the kernel-source directory to build its artifacts. Thus, we have
no option but to apply the patches here.

The first patch contains tests that are representative of UMIP use cases. The
second patch test UMIP emulation extensively by exercising all the possible
combinations of operands and displacement in 16-bit addressing encodings.

Signed-off-by: Ricardo Neri <[email protected]>
When checking for the return values of SMSW, SLDT and STR, we
use memory operands. Thus, the expected return values are 16-bit.
There is no need to use a long lenght field.

This helps us to prevent build warnings such as:

umip_test2.c:262:2: warning: format ‘%lx’ expects argument of type
‘long unsigned int’, but argument 2 has type ‘int’ [-Wformat=]
  pr_info("====Checking SLDT. Expected value: [0x%lx]====\n", expected_ldt);
  ^

Signed-off-by: Ricardo Neri <[email protected]>

umip_test2.c:262:2: warning: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 2 has type ‘int’ [-Wformat=]
  pr_info("====Checking SLDT. Expected value: [0x%lx]====\n", expected_ldt);
  ^

Signed-off-by: Ricardo Neri <[email protected]>
The family of macros CHECK_ALLreg and CHECK_ALLmem can use operands
of 16, 32 and 64 bits. Thus, the variables we pass should be the
largest of them: longs.

Otherwise, we see warnings such as:

umip_test2.c:252:2: warning: format ‘%lx’ expects argument of type
‘long unsigned int’, but argument 6 has type ‘int’ [-Wformat=]
  CHECK_ALLmem("smsw", val, INIT_MSW, expected_msw);
  ^

Signed-off-by: Ricardo Neri <[email protected]>
There were many variables that we don't use. Remove them.

Signed-off-by: Ricardo Neri <[email protected]>
Instead of returning nothing, have the main functions of test
programs to return an integer.

This makes warnings like this go away:

normal_pf.c:58:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]
 void main (void)

Signed-off-by: Ricardo Neri <[email protected]>
This function is not used anywhere. Get rid of it.

Signed-off-by: Ricardo Neri <[email protected]>
This makes warning like this go away:

umip_test.c:61:2: warning: format ‘%lx’ expects argument of type
‘long unsigned int’, but argument 2 has type ‘unsigned char *’ [-Wformat=]
  pr_info("Will issue SGDT and save at [0x%lx]\n", val);
  ^

Signed-off-by: Ricardo Neri <[email protected]>
Apparently, it is not sufficient to include sys/syscall.h as it cannot
find the prototype of syscall. Include also unistd.h and make this warning
go away:

umip_ldt_16.c:117:2: warning: implicit declaration of function ‘syscall’
[-Wimplicit-function-declaration]
  ret = syscall(SYS_modify_ldt, 1, &desc, sizeof(desc));
  ^

Signed-off-by: Ricardo Neri <[email protected]>
We meant to check the return value of setup_data_segments. However,
we did not save its return value in the variable we use to print the
error. Correct this and avoid seeing this warning:

umip_test_defs.h:13:23: warning: ‘ret’ may be used uninitialized in
this function [-Wmaybe-uninitialized]
 #define pr_error(...) printf(TEST_ERROR __VA_ARGS__)
                       ^
umip_ldt_64.c:97:6: note: ‘ret’ was declared here
  int ret;
      ^
gcc -Wall -o umip_ldt_64 test_umip_ldt_64.o umip_ldt_64.o

Signed-off-by: Ricardo Neri <[email protected]>
Old compilers will complain that 32-bit longs are too large to contains
64-bit long values. This is true even when they are OR'ed with a 32-bit
mask. Thus, instead of OR'ing the value, take the 32-bit value and use it
fill the most significant bytes of a 64-bit long.

Signed-off-by: Ricardo Neri <[email protected]>
Python appends an L to any long number and Python decides what type
of variable use based on its value. In most of the cases we will not
implicitly deal with longs (i.e., most of the time our variables will
have small values). However, to represent negative numbers we will
rely on 2's complements and thus we will need long variables. To
avoid the trailing L, use a custom my_hex function to convert a number
to its hex representation.

Reported-by: Qian Ouyang <[email protected]>
Signed-off-by: Ricardo Neri <[email protected]>
This option only makes sense when buiding in x86_64 builds for 64-bit
programs. umip_ldt_32 and umip_ldt_16 are 32-bit programs.

Reported-by: Qian Ouyang <[email protected]>
Signed-off-by: Ricardo Neri <[email protected]>
For reasons beyond my comprehension, certain versions of gcc
use esp, not ebp, to refer to automatic variables in main. This
is only true for main. This is a problem for these programs as
they manipulate the stack. Hence, introduce a new function, called
from main, that executes the actual tests.

Reported-by: Qian Ouyang <[email protected]>
Signed-off-by: Ricardo Neri <[email protected]>
We do this for two reasons: a) some versions of gcc use r/esp, not r/ebp,
to reference automatic variables. This has shown to cause problems in
the past if we need to update r/esp. b) more exception handling tests
will be added to this file. This is preparatory work.

Signed-off-by: Ricardo Neri <[email protected]>
Add support in the signal handler for SIGILL.

Signed-off-by: Ricardo Neri <[email protected]>
Add tests to verify that the UMIP-protected instructions generate
a SIGILL when the LOCK instruction prefix is used.

Signed-off-by: Ricardo Neri <[email protected]>
The instructions SGDT and SIDT generate an #UD exception if the
operands are registers. Tests that this actually happens.

Signed-off-by: Ricardo Neri <[email protected]>
In 32-bit programs, the use of null segment selectors should cause
a #GP(0) exception. Verify that this indeed happens.

Signed-off-by: Ricardo Neri <[email protected]>
…imits

When the effective address is outside of the segment limits, a
general protection fault should be issues. Test that this is the case.

Signed-off-by: Ricardo Neri <[email protected]>
Test cases were reworked and new test cases were added.

Signed-off-by: Ricardo Neri <[email protected]>
umip_pf has been updated to test for more exceptions in addition
to page faults. Reflect the documentation accordingly.

Signed-off-by: Ricardo Neri <[email protected]>
Now that normal_pf.c supports testing for other exceptiosn in addition
to page faults, rename files accordingly.

Signed-off-by: Ricardo Neri <[email protected]>
We have removed BITS from the ramdisk. Thus, we don't need to build it.
Yet, we get an error when constructing the disk image.

TODO: We should use an environment variable to decide whether we want
to include (and build BITS).

Signed-off-by: Ricardo Neri <[email protected]>
It is good to have a count of the test that passed/failed or completed
with error. Thus, update our definitions to also increment a counter
when the status of a test result is known.

Signed-off-by: Ricardo Neri <[email protected]>
Count the number of test cases that failed, passed or had errors.

Also, print the test results whenever we exit.

Signed-off-by: Ricardo Neri <[email protected]>
We use a mask to determine what parts of the returned results changed.
When operands are registers, instructions can return up to 64-bit values.
Thus, it is not sufficient to have a 16-bit mask.

Signed-off-by: Ricardo Neri <[email protected]>
ricardon and others added 30 commits August 11, 2017 17:48
We were using %(r|e)ax register as a scratch register for register-indirect
addressing tests. The scratch register is used to copy the test result into
a local variable. However, the test register is restored at the end of the
test before saving the test result. This means that when %(r|e)ax is the
test register, its value is retored at the end of the test and we lose the
test result. Hence, add the ability to specify which register is used
as scratch.

When using the macro, we use mostly registers %(r|e)ax, %(r|e)cx and
%(r|e)dx as scratch registers. These registers do no need to be preserved
in the System V calling convention. Also, our function is simple enough
to not use these registers to operate.

Signed-off-by: Ricardo Neri <[email protected]>
…d %(r|e)sp

Assembly test code must handle the stack pointer carefully so that it has
the same value it had before entering the test code. This is important as
we handle several automatic variables. Some compilers reference local
variables as offsets from the base pointer; others do it as offsets from
the stack pointer.

This patch focuses on making sure the stack pointer is preserved. We need
not to worry about the case when the base pointer is the test register; the
test code already restores the test regiter after the test.

When testing instruction that use registers as operands, two scratch
registers are needed. The first scratch register is used to initialize the
test register and to retrieve the test result. The second one is used
solely to restor the stack pointer. This is needed in case the register
under test is such register. After testing we must immediately restore it
in order to keep our stack operations as well as our references to local
variables correct.

Signed-off-by: Ricardo Neri <[email protected]>
In order to have a readable test output, test results are prefixed
with a zeros so that they reflect the size of the data being printed.
However, in 32-bit builds, it does not make sense to print numbers
of 16 digits. Hence, only print as many as prepend zeros as needed.

Signed-off-by: Ricardo Neri <[email protected]>
Print the value with which test registers and memory are initialized.
This helps to verify that the portion of the test register/memory
holds a test result of correct size. This is:

 * Only 2 bytes for memory operands
 * Only 2 bytes for register operands such as %ax, %cx, %dx, ...
 * Only 4 bytes for register operands such as %eax, %ecx, %edx, ...
 * Only 8 bytes for register operands such as %rax, %rcx, %rdx, ...

Signed-off-by: Ricardo Neri <[email protected]>
Tests for register operand incorrectly print the obtained value instead
of the expected value. The correct way of printing the expected value
is to AND the expected value with the mask of changed bytes. The
result is ORed with intit value ANDed with the mask of bytes that are
not expected to change.

Signed-off-by: Ricardo Neri <[email protected]>
Emulation code generates the 64-bit value of 0x80050033. This means
that the bits CR0.PE, CR0.MP, CR0.ET, CR0.NE, CR0.WP, CR0.AM and
CR0.PG are enabled.

Signed-off-by: Ricardo Neri <[email protected]>
Some of the tests involve 64-bit operands. Hence, we should use
64-bit variables to store the expected results in order to perform
results' validation correctly.

Also, update printf modifiers accordingly.

Signed-off-by: Ricardo Neri <[email protected]>
These tests write results to memory locations. In these cases, the
instructions STR, SMSW and SLDT return a 16-bit value. Hence, we need
to verify that only those 16-bit values, not a whole 32-bit or 64-bit
value is written to memory.

Signed-off-by: Ricardo Neri <[email protected]>
This makes it easier to read variable assignments.

Signed-off-by: Ricardo Neri <[email protected]>
Local variables are referenced via the frame pointer, (e|r)bp or the
stack pointer, (e|r)sp. Even though we have sanitized some of our
programs to restore the stack pointer before using local variables, it
is not possible to do this for all test programs (e.g., programs for
local descriptor tables). Hence, tell compiler to refer to local
variables using the frame pointer instead.

Signed-off-by: Ricardo Neri <[email protected]>
Some of the instructions that UMIP protects are not always emulated
(i.e., str and sldt). In such cases, a SIGSEGV with SI_KERNEL code is
received instead of the page fault.

Update the tests for page-faults to take the expected signal number
and signal code as arguments to be used when inspecting the received
signal.

This also requires having two sets of signal number and signal code:
one for smsw, sgdt and sidt, for which SIGSEGV/SEG_MAPERR is always
expected; and another for sldt and sidt, for which SIGSEGV/SEG_MAPERR
or SIGSEGV/SI_KERNEL are expected, depending on whether str and sldt
are emulated.

Signed-off-by: Ricardo Neri <[email protected]>
If a test generates a signal, subsequent tests should initialize the
variables that hold the signal number and code. Otherwise, if no
signal is received, the old, wrong, values will be used when
when comparing with the expected values for a particular tests.

Signed-off-by: Ricardo Neri <[email protected]>
Unless the kernel is patched, the instructions str and sldt will
not be emulated. In such cases, these instructions will generate
a SIGSEGV/SI_KERNEL signa number and code pair. Hence, use the
macro INIT_EXPECTED_SIGNAL_STR_SLDT. This macro initializes the
expected values with the correct values.

Signed-off-by: Ricardo Neri <[email protected]>
If a program needs to exit on signal, it is considered that the test
program failed and needs to terminate. However, there may be cases
in which receiving a signal is expected (e.g, when a test program
is built without -DEMULATE_ALL). In that case, exit_on_signal can
be used to determine if the test generating the signal passed or
failed.

Signed-off-by: Ricardo Neri <[email protected]>
When this program is run with EMULATE_ALL undefined, no emulation
for any of the UMIP-protected instructions is expected. Thus, it is
expected to receive SIGSEGV/SI_KERNEL; the test passs. On the other
hand, if EMULATE_ALL is defined, the test programs should not receive
any signal and should exit if one is received. In this case, the test
failed.

Signed-off-by: Ricardo Neri <[email protected]>
Command line arguments are great for below 3 umip c files:
umip_test_basic.c add arguments:
Usage: [g][i][l][m][t][a]
g      Test sgdt
i      Test sidt
l      Test sldt
m      Test smsw
t      Test str
a      Test all

umip_test_opnds.c add arguments:
Usage: [l][m][t][a]
l      Test sldt register operands
m      Test smsw register operands
t      Test str register operands
a      Test all

umip_exceptions.c add arguments:
Usage: [m][l][r][n][d][a]
m      Test test_maperr_pf
l      Test test_lock_prefix
r      Test test_register_operand
n      Test test_null_segment_selectors(TODO)
d      Test test_addresses_outside_segment(TODO)
a      Test all

Signed-off-by: Pengfei Xu <[email protected]>
Signed-off-by: Ricardo Neri <[email protected]>
Unlike ARCH_GET_FS/GS, ARCH_SET_FS/GS take as argument the actual value
to be used as the bases of these two segments, not a pointer to a variable
containing the value.

Reported-by: Pengfei Xu <[email protected]>
Signed-off-by: Ricardo Neri <[email protected]>
…efaults to 'int'"

Fix below warning when "cc -fno-omit-frame-pointer -c umip_utils.c -o umip_utils_64.o"
umip_utils.c: In function 'inspect_signal':
umip_utils.c:55:5: warning: type of 'exp_signum' defaults to 'int' [-Wimplicit-int]
 int inspect_signal(exp_signum, exp_sigcode)
     ^~~~~~~~~~~~~~
umip_utils.c:55:5: warning: type of 'exp_sigcode' defaults to 'int' [-Wimplicit-int]

Signed-off-by: Pengfei Xu <[email protected]>
Signed-off-by: Ricardo Neri <[email protected]>
…s_outside_segment

cc -fno-omit-frame-pointer -m32 -o umip_exceptions_32 umip_utils_32.o umip_exceptions.c
...
umip_exceptions.c:296:3: warning: 'return' with no value, in function returning non-void
   return;
   ^~~~~~
umip_exceptions.c:290:12: note: declared here
 static int test_addresses_outside_segment(void)
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Signed-off-by: Pengfei Xu <[email protected]>
Signed-off-by: Ricardo Neri <[email protected]>
There are cases in which some cleanup may be need to be done when exiting
from a signal. Our signal handler cannot know what kind of cleanup is
needed. Thus, simply call a function that users of the handler can
implement as needed.

The cleanup function is NULL by default. Thus, users of our handler does
not need to implement it if not needed.

Signed-off-by: Ricardo Neri <[email protected]>
The signal handler provides functionality to invoke a cleanup function
before exiting. In the case of this program, we must ensure that we
restore the FS/GS base addresses for glibc to work properly.

This cleanup the same that is needed when tests run successfully. Thus,
this same function is called once tests are complete.

Reported-by: Pengfei Xu <[email protected]>
Signed-off-by: Ricardo Neri <[email protected]>
Add -m32 when "make i686_minimal" or "make i686_emul_all" for 32bit
and 16bit .o and program.

Signed-off-by: Pengfei Xu <[email protected]>
Signed-off-by: Ricardo Neri <[email protected]>
These test programs can be built either stand-alone or via bitbake. The
-m32 option for 32-bit programs is only needed when building in stand-
alone mode as we need to tell gcc to cross-compile and use 32-bit
libraries.

When building via bitbake, bitbake takes care of building with the
appropriate native 32-bit libraries.

Signed-off-by: Ricardo Neri <[email protected]>
Some local variables are tracked using the %r[8-15] registers. Thus,
we need to restore their value after testing. Otherwise, errors such
as segmentation faults can be observed.

Signed-off-by: Ricardo Neri <[email protected]>
test_fs and test_gs are not used in the assembly code that prepares
everything for testing. Remove them.

Signed-off-by: Ricardo Neri <[email protected]>
In order to not forget, start a list of things that need to be done.

Signed-off-by: Ricardo Neri <[email protected]>
In order to verify that code that emulates the UMIP instructions works
correctly, we initialize the memory arrays we use for segments with
a known pattern. We were failing to correctly initialize data_fs and
data_gs.

Signed-off-by: Ricardo Neri <[email protected]>
This causes grub to fail to load any ramdisk and then Linux does not
boot.y

Signed-off-by: Ricardo Neri <[email protected]>
Add a tool that prints the contents of CPUID leaves. Leaves are selected
in the command line as values of the EAX and ECX registers.

Signed-off-by: Ricardo Neri <[email protected]>
There was some abonormal situation, which caused umip test tool in infinite
loop, added one judgement: if signal handling reached 1000 times(some normal
test would reach 60+ times signal handling), would stop the test and return
failed information, which would not cause some confusing in usage.

Signed-off-by: Pengfei Xu <[email protected]>
Signed-off-by: Ricardo Neri <[email protected]>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants