Commit 81fa32bd7e ("drivers/linux: enforce address requirement for
IOCTL_ALLOC_PHYSMEM") tried to enforce the physical address constraints
provided by the user. However, it's broken for the memory range 16M-4G
as there's no DMA32 kmalloc cache, making the request allocate from the
normal zone which is free to return an address above 4GB for systems
with enough RAM.
Commit d010b82b0d ("Fix malloc issue in Linux driver") worked around
that issue by simple dropping the DMA32 allocation and only using DMA
allocations for which kmalloc slabs do exist.
As the DMA zone is a scarce resource and might be exhausted already, use
a different allocation scheme for chipsec that directly allocates memory
from the page allocator which honours both, DMA and DMA32 requests.
Also fix the allocation list handling while at it. The stored physical
address might be truncated on 32-bit PAE systems because of the use of
'physaddr_t' instead of 'phys_addr_t'.
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Try harder to fulfill the physical address constraint for the
IOCTL_ALLOC_PHYSMEM ioctl by trying to allocate memory from the zones
that fit the maximum address best, but fall-back to the normal zone in
case the allocation fails.
If we fail to allocate memory that fulfills the maximum physical address
constraint, make the ioctl() fail as well instead of emitting a warning.
This is safer then making, e.g., the tools.smm.smm_ptr module corrupt
unrelated memory just because the allocation happens to be above 4GB but
the pointer passed to SMM is truncated to 32 bit.
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
With the addition of a bounce buffer both functions are nearly
identical. They only differ in the direction of copy.
Merge them into a common helper function that gets the copy direction
passed as an argument.
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
If we try to write to an address that's not allowed by USERCOPY, the
copy will fail.
Use a bounce buffer to work around that, just like read_mem() does.
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
If we get passed an invalid virtual address, make IOCTL_VA2PA fail
instead of returning a bogus address.
Also simplify the code. No need to use 'PHYSICAL_ADDRESS' here,
'phys_addr_t' is just fine.
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
chipsec_km.c is mostly self-contained and thereby has no need to export
symbols.
Make almost all of them 'static' and leave only the (config dependent)
unused ones non-static.
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
If we fail to allocate memory for chaining the user requested allocation
to our accounting list, we leak 'va.'
Fix that. Also fix the return code to be -ENOMEM instead of -EFAULT for
failing memory allocations.
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
In case my_xlate_dev_mem_ptr() fails for a given physical address, we
should return an error instead of trying to read/write to NULL.
Also fix whitespace issues around this code section.
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Commit 397b1b8d8b ("drivers/linux: simplify and fix symbol resolving
for kernels >= 5.10") introduced a method for finding the address of
kallsyms_lookup_name() by scanning kernel code around 'sprint_symbol.'
However, it only looked "backwards" which would be fine, as
kallsyms_lookup_name() gets defined before sprint_symbol() in
kallsyms.c. However, gcc's '-freorder-functions' (which is enabled by
default at -O2 / -Os) may put kallsyms_lookup_name() *after*
sprint_symbol() in the object file, making our search fail to find it.
Account for that and search around sprint_symbol() in both directions.
32kB is more than enough to cover all of kallsyms.o.
Fixes: 397b1b8d8b ("drivers/linux: simplify and fix symbol resolving for kernels >= 5.10")
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
grsecurity kernels stub out the kallsyms family of functions when the
feature CONFIG_GRKERNSEC_HIDESYM is enabled. This destroys out attempt
to find the address of 'kallsyms_lookup_name' via sprint_symbol().
Prevent that by making use of the '__INCLUDED_BY_HIDESYM' define
grsecurity provides for this exact purpose.
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
The current implementation of __swsmi__ for x86-64 is rather complicated
as it uses more registers than needed. Simplyfy it.
We can use the passed SMI_CTX buffer as scratch space without the need
to use intermediate registers (beside for RDI, for which we use R10 -- a
callee clobbered register).
Bring the implementation more in line with its OS X counterpart and
adapt the comments and code to reflect reality, namely:
- change the C type members to mirror the used (and intended) registers,
- mark the registers as in/out parameters in the comments,
- drop the bogus comment about clobbering DX, as we don't do that and
- fix and tweak the comment about split i/o because of picky firmwares.
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Currently Linux driver uses `memcpy` when reading physical memory. This
causes a kernel panic on some systems when trying to access "forbidden"
physical memory. The Linux kernel provides function
`copy_from_kernel_nofault` (previously named `probe_kernel_read`) to read
memory without crashing (and this function is used by the implementation
of `/dev/mem`).
Replace `memcpy` with `copy_from_kernel_nofault`, providing a simple
wrapper for older kernels.
While at it:
- Move the allocation of a bounce buffer outside of the while loop. As
memory is always read one page at a time, a `PAGE_SIZE` buffer is
enough.
- Use `size_t` as the type of `sz` instead of the signed type `ssize_t`.
- Replace calls to `min_t` with `if` statements which are easier to read.
- Name the number of written bytes `written` instead of `read`, in
`write_mem`.
- Remove stray spaces in various places.
By the way, the `write_mem` function was not updated to use
`copy_to_kernel_nofault`, as this function has no longer been exported
since Linux 5.8.
Fixes: https://github.com/chipsec/chipsec/issues/1094
Signed-off-by: Nicolas Iooss <nicolas.iooss_git@polytechnique.org>
Since kernel version 4.12 the GDT as seen by SGDT is only an r/o alias
mapping located at a fixed address not backed by a dedicated kernel
memory allocation. Later kernels moved it further to the "cpu entry
area", yet another alias mapping. All, just to mitigate all too easy
kernel address leaking in the name of KASLR. Anyhow, the fact that these
virtual addresses have no 'struct page' attached prevents us from using
virt_to_phys() to resolve its physical address. A full software page
table walk is required instead.
Luckily, slow_virt_to_phys() does just that. It was introduced in kernel
v3.9 so covers all affected kernels.
This fixes github issue #608.
While at it, extend the switch block to reject invalid descriptor code
arguments to not operate on uninitialized descriptor.
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
Reduce the visibility of my_[un]xlate_dev_mem_ptr() by making them
static, allowing the compiler to optimize their use.
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
If the user provides an invalid size for the EFI variable name, we leak
the buffer used for the usercopy operation.
Fix that!
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
d_ioctl() makes excessive use of '-EFAULT' as an error code. This error
should be used for invalid userland addresses only, as otherwise
userland might be confused what the real error might be.
Use appropriate error codes instead:
- memory allocation failed: -ENOMEM
- unsupported feature: -EOPNOTSUPP
- invalid argument: -EINVAL
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
If the symbol lookup via find_symbols() fails, init_module() returns
with -1 as an error code. This is unfortunate, however, as that value
will be passed up to userland as an error code, so should rather be a
symbolic one that can be grep'ed for (-1 would be -EPERM which doesn't
seem fitting).
Use -EOPNOTSUPP instead.
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
For kernels <= 2.6.33 we rely on module parameters to get the addresses
of 'page_is_ram' and 'phys_mem_access_prot'. However, if a user loads
the module without providing these arguments they will be left at zero
and lead to a NULL function pointer dereference on use.
Prevent that by always testing they're non-null.
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
On kernels >= 5.10 that have CONFIG_KPROBES disabled the kprobes based
approach to get the address of kallsyms_lookup_name() won't work. While
it should still be the preferred option (as it gets us a precise
address), add another method that makes use of "code scanning" within
kernel/kallsyms.o to find the address with the help of sprint_symbol().
We scan backwards, starting at '&sprint_symbol' itself to find
kallsyms_lookup_name() by getting a symbolic representation of the
current address via sprint_symbol(). We lower the address with the
offset+1 sprint_symbol() provides us as long as we haven't found our
target function.
As kallsyms_lookup_name() is preceding sprint_symbol(), this search
should succeed. Still, to account for future code refactoring, limit the
search to 32kB at most to not run out of kernel text.
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
There's no need to have a 'return 0' stub for the static calls. Simply
make them call an initialization function that will do the necessary
lookup and static call updates. This avoids the need for callers to do
the update themselves prior to making use of the functions, as the first
user will now do it for us implicitly.
Right now we would be doing it ahead of time for 'page_is_ram' users and
*always* for users of chipsec_lookup_name(). The latter is clearly
unintentional.
For kernels that have CONFIG_KPROBES disabled the kprobe based method to
get the address of kallsyms_lookup_name() will fail with '-ENOSYS'.
Returning this error code in chipsec_lookup_name() isn't appropriate as
users will wrongly use it as a function pointer as they expect only NULL
as a possible error value.
On top of fixing that, remove the ugly #ifdef'ery for 'page_is_ram'
users by providing a helper function that does "The Right Thing"
depending on the kernel version -- either use the static call or a
direct function pointer dereference.
Fix a few adjacent whitespace errors while touching the code. Also
reduce the visibility of the related symbols by making them static.
Last but not least lower the printk level to DEBUG when we fail to
register the kprobe. It's not important enough to warrant an "alert".
The already existing follow up handling of the failing symbol resolving
will provide meaningful messages already.
Signed-off-by: Mathias Krause <minipli@grsecurity.net>