Search code examples
linux-kernelelfattestations

How to take the hash of ELF binary in linux kernel?


I am implementing binary attestation from inside the kernel. I am reading the file using the kernel_read_from_file() function. The function definition is as follows:

int kernel_read_file_from_path(const char *path, void **buf, loff_t *size,
               loff_t max_size, enum kernel_read_file_id id)

The function is storing the file content in buf. The code is working fine when I read files with .c or .h extension. But for ELF binaries:

Value stored in buf = ELF

What am I missing here? How can I read ELF binary from inside the kernel?

Here's the relevant code:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/file.h>
// #include "sha256.h"
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Robert W. Oliver II");
MODULE_DESCRIPTION("A simple example Linux module.");
MODULE_VERSION("0.01");
 
 
static int __init lkm_example_init(void)
{
  void *data;
  loff_t size;
  int ret;
  char path1[50] = "/etc/bash.bashrc";
    char path2[50] = "/bin/sh";
 
  ret = kernel_read_file_from_path(path1, &data, &size, 0, READING_POLICY);
  printk(KERN_INFO "Hello, World!\n");
  printk(KERN_INFO "%lld\n", size);
  printk(KERN_INFO "%s", (char*)data);
 
  ret = kernel_read_file_from_path(path2, &data, &size, 0, READING_POLICY);
  printk(KERN_INFO "%lld\n", size);
  printk(KERN_INFO "%s", (char*)data);
  // vfree(data);
  return 0;
}
static void __exit lkm_example_exit(void)
{
  printk(KERN_INFO "Goodbye, World!\n");
}
module_init(lkm_example_init);
module_exit(lkm_example_exit);

And here's the Makefile:

# Save file as read_elf.c
obj-m += read_elf.o
# This line tells makefile that the given object files are part of module
 
all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Solution

  • What am I missing here? How can I read ELF binary from inside the kernel?

    You are missing the fact that an ELF file is not a text file, it's a binary file. However, you are trying to print it as a string (%s specifier in printk), which will only print the first few characters and stop at the first zero byte (\0) thinking it's the string terminator.

    As it turns out, as @Tsyvarev notes in the comments above, ELF files always start with the bytes 7f 45 4c 46, which in ASCII are ELF (that first byte 7f is not printable). That's what you see in your buffer after reading.

    If you take a look at size after reading you will indeed see that it's bigger than 4, meaning the file was correctly read. Though you might still want to check for errors and also make sure you read the entire file.