• Apr 5, 2025

Detecting in-memory modification of kernel.yama.ptrace_scope with bpftrace

  • cr0nx

As a Linux Security Expert, you probably know about kernel.yama.ptrace_scope. It is a Linux kernel security parameter that controls which processes can use the ptrace system call to attach to and trace other processes. This setting helps protect against certain types of attacks where malicious processes could use ptrace to access or modify the memory of other running processes. Usually, you can find mentions of kernel.yama.ptrace_scope in Linux Hardening recommendations and writeups.

When kernel.yama.ptrace_scope=3: No ptrace is allowed, completely disables process tracing. To change this setting, a machine reboot is required - it's supposed to be impossible to change it to any other value without a reboot.

During one of my research sessions, I found an amazing @Bishopfox asminject project:

There is a mod_set_ptrace_scope POC capable of changing kernel.yama.ptrace_scope to 0 directly in memory without rebooting, pretty cool, huh? OFC you need root privs and have the ability to load kernel modules via init_module or finit_module

Then, I asked myself how to effectively monitor such in-memory modifications. As always, I would like to know when such a critical change/event is generated within my critical Linux boxes.

As for a detection Proof of Concept, I created a bpftrace script capable of raising an alert on such in-memory modification. Nothing special, just researching eBPF and Linux internals. I think Linux EDR engines could have such telemetry easily implemented at some point (even with protection/kill mode):

1. Check kernel.yama.ptrace_scope status:

# sysctl -a | grep yama
kernel.yama.ptrace_scope = 3

2. Check if ptrace is possible:

# strace -p 1
strace: test_ptrace_get_syscall_info: PTRACE_TRACEME: Operation not permitted
strace: attach: ptrace(PTRACE_ATTACH, 1): Operation not permitted

3. Get the address of ptrace_scope from /proc/kallsyms:

# cat /proc/kallsyms | grep ptrace_scope
ffffffff83c983b0 d ptrace_scope

4. Create the alert-on-change-kernel.yama.ptrace_scope.bt script and replace the $data_addr within the script:

#!/usr/bin/env bpftrace

BEGIN
{
    // Replace with the actual address from dmesg
    $data_addr = 0xffffffff83c983b0;  // Example: yama_sysctl_table->data address
    @last_val = *(int32*)$data_addr;  // Initial value
    printf("Monitoring kernel.yama.ptrace_scope at address 0x%x (initial value: %d)\n",
           $data_addr, @last_val);
}

interval:s:1
{
    $data_addr = 0xffffffff83c983b0;  // Same address
    $current = *(int32*)$data_addr;
    if (@last_val != $current) {
        time("%H:%M:%S ");
        printf("ALERT: kernel.yama.ptrace_scope changed from %d to %d!\n",
               @last_val, $current);
        @last_val = $current;
    }
}

END
{
    clear(@last_val);
    printf("Monitoring stopped\n");
}

5. Start the script:

# bpftrace alert-on-change-kernel.yama.ptrace_scope.bt
WARNING: Addrspace is not set
Attaching 3 probes...
Monitoring kernel.yama.ptrace_scope at address 0x83c983b0 (initial value: 3)

6. Load the LKM:

# insmod mod_set_ptrace_scope.ko

7. Check the bpftrace script output:

14:11:26 ALERT: kernel.yama.ptrace_scope changed from 3 to 0!

8. Check the profit:

# strace -p 1
ptrace_scope_kernel_module]# strace -p 1
strace: Process 1 attached
gettid()                      


9. Check sysctl:

# sysctl -a | grep yama
kernel.yama.ptrace_scope = 0


The alert-on-change-kernel.yama.ptrace_scope.bt gist is available here:

Looking for more similar stuff? Check out my offer:

In case you like live training, you can find me here:


May the syscalls be with you!