Skip to content

Add kernelCTF CVE-2024-26824_mitigation#256

Merged
koczkatamas merged 18 commits intogoogle:masterfrom
star-sg:CVE-2024-26824_mitigation
Feb 25, 2026
Merged

Add kernelCTF CVE-2024-26824_mitigation#256
koczkatamas merged 18 commits intogoogle:masterfrom
star-sg:CVE-2024-26824_mitigation

Conversation

@st424204
Copy link
Contributor

No description provided.

@st424204 st424204 force-pushed the CVE-2024-26824_mitigation branch from 513da39 to 6cce0ca Compare September 24, 2025 05:53
@koczkatamas koczkatamas added the kCTF: vuln OK The submission exploits the claims vulnerability (passed manual verification) label Sep 25, 2025
Copy link
Collaborator

@koczkatamas koczkatamas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix your submission to follow the style guide (it's a requirement!): https://google.github.io/security-research/kernelctf/style_guide

I left a few comments, but don't consider this as a comprehensive list of issues needs to be fixed.

void do_spray()
{
memset(payload, 0, 0x400);
*(size_t *)&payload[0] = ktext + 0x2db3720;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment what is 0x2db3720.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in the code. I've replaced 0x2db3720 with the CORE_PATTERN_OFFSET definition to make its intent clear.


void do_spray()
{
memset(payload, 0, 0x400);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment "payload == af_alg_sgl, sgl->sgt.sgl == core_pattern" (if that's correct).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I've renamed payload to af_alg_sgl and updated the comments detailing how it points to core_pattern.


#define STEXT 0xffffffff81000000

unsigned long long fake_buf[43] = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Include script which generates this buffer or describe how this was generated. Rename from fake_buf to something which clearly describes its purpose.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added detailed block comments to document the origin of this payload. Specifically, the array now directly contains the physical memory layout of a whole page (4KB) covering the core_pattern buffer string. This entire heap layout was dynamically dumped from GDB during exploit testing. Because the exploit relies on a data-oriented layout collision extracted via debugger dumps, an algorithmic generation script wasn't used.

0x0000000000001000,
};

unsigned long long fake_buf2[33] = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Include script which generates this buffer or describe how this was generated. Rename from fake_buf2 to something which clearly describes its purpose.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(This comment originally applied to what is now merged into fake_buf). I've added extensive comments describing how fake_buf is literally a raw memory dump of an entire 4KB page structure

#define ARRAY_LEN(x) (sizeof(x) / sizeof(x[0]))

int tfmfd, opfd;
char *victim_addr;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, unused variables have been removed.

char payload[0x1000];
int cfd[2];
int sfd[0x200][2];
pthread_t tid[0x100];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use THREAD_NUM instead of 0x100

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Array allocations and loops now use THREAD_NUM.

{
memset(payload, 0, 0x400);
*(size_t *)&payload[0] = ktext + 0x2db3720;
payload[560] = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What field do you set here? Why?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove unnecessary set

if (fake_buf2[i] > 0xffffffff81000000ULL)
fake_buf2[i] = fake_buf2[i] - 0xffffffff81000000ULL + ktext;

char* mem = SYSCHK(mmap(NULL, 0x30000000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explain why 0x30000000?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this unnecessary code

.rlim_max = 0xf000};
setrlimit(RLIMIT_NOFILE, &rlim);

int pfd[0x100][2];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use PIPE_COUNT instead of 0x100.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

char *anon = SYSCHK(mmap(NULL, 0x1000000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0));
for (int i = 0; i < 0x1000000; i += 0x1000)
{
memcpy(anon + i + 0x3e0, fake_buf, 0x158);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use defines for the offsets, so it's clear what is set.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


int tfmfd, opfd;
char *victim_addr;
char buf[0x5000];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not use global buf. Hard to understand what the code does.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved. I removed the generic global buf variable entirely, and migrated thread synchronization logic to use local buffers like local_buf[0x1000] within the thread execution methods and sync_buf[1] inside main().

int n = 0x800;
setsockopt(sfd[i][1], SOL_SOCKET, SO_SNDBUF, (char *)&n, sizeof(n));
setsockopt(sfd[i][0], SOL_SOCKET, SO_RCVBUF, (char *)&n, sizeof(n));
write(sfd[i][1], buf, 0x1000);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the content of the buf at this point? Does it matter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not matter! I've clarified this by changing the variable name to sync_buf and added a comment. It is just a 1-byte arbitrary token used to strictly block and synchronize unix socket thread states.

.msg_iovlen = 1,
.msg_iov = &iov,
.msg_control = buf,
.msg_controllen = 0x4cdf,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why 0x4cdf?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated the comment to be accurate. The size 0x4cdf is used to increase the sk_omem_alloc field until it is just below the optmem_max limit. This ensures that a subsequent sock_kmalloc call fails, which is the intended behavior to trigger the exploit's error path


// Manually constructed fake pipe_buf_operations structure and stack pivot/ROP chain
unsigned long long fake_ops_and_rop[43] = {
0xffffffff83db3480,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on every element which fields are set (if they are structure fields) and which kernel symbols are used as values (or ROP chain gadgets).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its not relative to any rop, removed


// Manually constructed fake pipe_buffer structure
unsigned long long fake_pipe_buffer[33] = {
0xffffffff83257ccf,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neither the size nor the content match the pipe_buffer structure:

struct pipe_buffer {
        struct page *              page;                 /*     0     8 */
        unsigned int               offset;               /*     8     4 */
        unsigned int               len;                  /*    12     4 */
        const struct pipe_buf_operations  * ops;         /*    16     8 */
        unsigned int               flags;                /*    24     4 */
        long unsigned int          private;              /*    32     8 */

        /* size: 40, cachelines: 1, members: 6 */
};

Please comment here what's here exactly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its not relative to any fake_pipe_buffer, removed

.msg_iovlen = 1,
.msg_iov = &iov,
.msg_control = msg_control_buf,
// Size 0x4cdf is chosen perfectly to corrupt the proper adjacent target cache object distance
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Writeup says the goal of the call is to increase the sk_omem_alloc field, it says nothing about "corrupt the proper adjacent target cache object".

Also nothing about this mentioned in the "Step 3: Overwriting core_pattern and Root Shell Setup" section.

So what's this call doing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The size 0x4cdf is used to increase the sk_omem_alloc field until it is just below the optmem_max limit. This ensures that a subsequent sock_kmalloc call fails, which is the intended behavior to trigger the exploit's error path

@koczkatamas koczkatamas merged commit e0c4625 into google:master Feb 25, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kCTF: vuln OK The submission exploits the claims vulnerability (passed manual verification)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants