This repository was archived by the owner on Feb 23, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 74
Rneri/umip #140
Open
dznguyen98023
wants to merge
109
commits into
master
Choose a base branch
from
rneri/umip
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Rneri/umip #140
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]>
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]>
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.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Need to pull out umpi tests for testing