๏ปฟ# 34. memfd โ€” ๋ฉ”๋ชจ๋ฆฌ ๊ธฐ๋ฐ˜ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ

๊ฐœ์š” (Overview)

memfd๋Š” tmpfs ๋˜๋Š” hugetlbfs ์œ„์— ์ต๋ช… ๋ฉ”๋ชจ๋ฆฌ ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๋Š” ์‹œ์Šคํ…œ ํ˜ธ์ถœ์ด๋‹ค. memfd_create()๋กœ ์ƒ์„ฑ๋œ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋Š” unnamed memory object๋กœ, ํŒŒ์ผ ์‹œ์Šคํ…œ์— ๋งˆ์šดํŠธ๋˜์ง€ ์•Š์ง€๋งŒ ์ผ๋ฐ˜ ํŒŒ์ผ์ฒ˜๋Ÿผ mmap(), read(), write()๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค. ์ฃผ์š” ์‚ฌ์šฉ ์‚ฌ๋ก€๋กœ๋Š” IPC, ์„ธ์ดํ”„ ์ƒŒ๋“œ๋ฐ•์Šค, SECCOMP ํ•„ํ„ฐ์™€์˜ ์กฐํ•ฉ ๋“ฑ์ด ์žˆ๋‹ค.

memfd์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ์€ ํŒŒ์ผ ๋ด‰์ธ(File Sealing)์ด๋‹ค. ์—ฌ๋Ÿฌ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ต๋ช… ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ณต์œ ํ•  ๋•Œ, ์ƒ๋Œ€๋ฐฉ์ด ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์—ฐ์‚ฐ์„ ์ œํ•œํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด๋‹ค. ๋ด‰์ธ์€ ์ถ”๊ฐ€๋งŒ ๊ฐ€๋Šฅํ•˜๊ณ  ์ œ๊ฑฐํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ, ์„œ๋กœ ์‹ ๋ขฐํ•˜์ง€ ์•Š๋Š” ํ”„๋กœ์„ธ์Šค ์‚ฌ์ด์—์„œ๋„ ์•ˆ์ „ํ•œ ๋ฉ”๋ชจ๋ฆฌ ๊ณต์œ ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

ํ˜ธ์ถœ ํ๋ฆ„:

memfd_create ํ˜ธ์ถœ ํ๋ฆ„

์ž๋ฃŒ๊ตฌ์กฐ ๊ด€๊ณ„:

memfd ์ž๋ฃŒ๊ตฌ์กฐ ๊ด€๊ณ„๋„

์†Œ์Šค ํŒŒ์ผ ๊ฒฝ๋กœ:

mm/memfd.c                          โ† memfd_create ์‹œ์Šคํ…œ ํ˜ธ์ถœ, ๋ด‰์ธ ๊ด€๋ฆฌ
include/linux/memfd.h               โ† memfd API ์„ ์–ธ
include/linux/shmem_fs.h            โ† shmem_inode_info (๋ด‰์ธ ์ €์žฅ)
include/linux/hugetlb.h             โ† hugetlbfs_inode_info (๋ด‰์ธ ์ €์žฅ)
include/uapi/linux/memfd.h          โ† MFD_* ํ”Œ๋ž˜๊ทธ ์ •์˜
include/uapi/linux/fcntl.h          โ† F_SEAL_* ํ”Œ๋ž˜๊ทธ ์ •์˜

๋น ๋ฅธ ์ ๊ฒ€ ๋ช…๋ น

# memfd ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ ํ™•์ธ
ls -la /proc/<pid>/fd | grep memfd

# memfd ํŒŒ์ผ ์ •๋ณด ํ™•์ธ
cat /proc/<pid>/fdinfo/<fd>

# ์‹œ์Šคํ…œ ์ „์ฒด memfd ์นด์šดํŠธ ํ™•์ธ
cat /proc/sys/fs/memfd_noexec       # noexec ๋ฒ”์œ„ ํ™•์ธ

# tmpfs ๋งˆ์šดํŠธ ํ™•์ธ (memfd์˜ ๊ธฐ๋ณธ ๋ฐฑ์—”๋“œ)
mount | grep tmpfs

# HugeTLBFS ๋งˆ์šดํŠธ ํ™•์ธ (MFD_HUGETLB์šฉ)
mount | grep hugetlb

# memfd ์‹œ์Šคํ…œ ํ˜ธ์ถœ ํ˜ธ์ถœ ์ˆ˜ ํ™•์ธ
cat /proc/kallsyms | grep sys_memfd_create

# ํ˜„์žฌ ํ”„๋กœ์„ธ์Šค์˜ memfd ์—ด๊ธฐ
python3 -c "import os; fd = os.memfd_create('test', 0); print(fd); input()"

# memfd ๋ด‰์ธ ์ƒํƒœ ํ™•์ธ (Python)
python3 -c "
import fcntl, os
fd = os.memfd_create('test', os.MFD_ALLOW_SEALING)
print('seals:', fcntl.fcntl(fd, fcntl.F_GET_SEALS))
"

ํ•ต์‹ฌ ์ž๋ฃŒ๊ตฌ์กฐ

shmem_inode_info โ€” tmpfs inode ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ (๋ด‰์ธ ์ €์žฅ)

// include/linux/shmem_fs.h:36-59
struct shmem_inode_info {
spinlock_t          lock;
unsigned int        seals;      // memfd ๋ด‰์ธ ๋น„ํŠธ๋งˆ์Šคํฌ ์ €์žฅ
unsigned long       flags;
unsigned long       alloced;    // ํŒŒ์ผ์— ํ• ๋‹น๋œ ๋ฐ์ดํ„ฐ ํŽ˜์ด์ง€ ์ˆ˜
unsigned long       swapped;    // swap์— ํ• ๋‹น๋œ ํ•˜์œ„ ํ•ฉ๊ณ„
union {
struct offset_ctx dir_offsets;
struct {
struct list_head shrinklist;
struct list_head swaplist;
};
};
struct timespec64   i_crtime;   // ํŒŒ์ผ ์ƒ์„ฑ ์‹œ๊ฐ„
struct shared_policy policy;    // NUMA ๋ฉ”๋ชจ๋ฆฌ ์ •์ฑ…
struct simple_xattrs xattrs;
pgoff_t             fallocend;
unsigned int        fsflags;
atomic_t            stop_eviction;
struct inode        vfs_inode;
};

hugetlbfs_inode_info โ€” HugeTLB inode ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ

// include/linux/hugetlb.h:519-522
struct hugetlbfs_inode_info {
struct inode vfs_inode;
unsigned int seals;  // memfd ๋ด‰์ธ ๋น„ํŠธ๋งˆ์Šคํฌ (shmem๊ณผ ๋™์ผ ํ˜•์‹)
};

F_SEAL_* ํ”Œ๋ž˜๊ทธ โ€” ํŒŒ์ผ ๋ด‰์ธ ์œ ํ˜•

// include/uapi/linux/fcntl.h:47-52
#define F_SEAL_SEAL          0x0001  // ์ถ”๊ฐ€ ๋ด‰์ธ ๋ฐฉ์ง€
#define F_SEAL_SHRINK        0x0002  // ํŒŒ์ผ ์ถ•์†Œ ๋ฐฉ์ง€
#define F_SEAL_GROW          0x0004  // ํŒŒ์ผ ํ™•์žฅ ๋ฐฉ์ง€
#define F_SEAL_WRITE         0x0008  // ์“ฐ๊ธฐ ๋ฐฉ์ง€
#define F_SEAL_FUTURE_WRITE  0x0010  // ๋งคํ•‘๋œ ์ƒํƒœ์—์„œ ํ–ฅํ›„ ์“ฐ๊ธฐ ๋ฐฉ์ง€
#define F_SEAL_EXEC          0x0020  // exec ๋น„ํŠธ ๋ณ€๊ฒฝ ๋ฐฉ์ง€

MFD_* ํ”Œ๋ž˜๊ทธ โ€” memfd_create ์˜ต์…˜

// include/uapi/linux/memfd.h:8-14
#define MFD_CLOEXEC          0x0001  // exec ์‹œ ๋‹ซ๊ธฐ
#define MFD_ALLOW_SEALING    0x0002  // ๋ด‰์ธ ํ—ˆ์šฉ
#define MFD_HUGETLB          0x0004  // HugeTLB ๋ฐฑ์—”๋“œ ์‚ฌ์šฉ
#define MFD_NOEXEC_SEAL      0x0008  // ์‹คํ–‰ ๋ถˆ๊ฐ€ + ๋ด‰์ธ
#define MFD_EXEC             0x0010  // ์‹คํ–‰ ๊ฐ€๋Šฅ

MEMFD_TAG_PINNED โ€” XArray ํƒœ๊ทธ

// mm/memfd.c:29-30
#define MEMFD_TAG_PINNED    PAGECACHE_TAG_TOWRITE  // ์ถ”๊ฐ€ ์ฐธ์กฐ๊ฐ€ ์žˆ๋Š” folio ํƒœ๊ทธ
#define LAST_SCAN           4                       // ์ตœ๋Œ€ ์Šค์บ” ํšŸ์ˆ˜ (~150ms)

ํ•ต์‹ฌ ํ•จ์ˆ˜

1. SYSCALL_DEFINE2(memfd_create) โ€” ์‹œ์Šคํ…œ ํ˜ธ์ถœ ์ง„์ž…์ 

// mm/memfd.c:505-523
SYSCALL_DEFINE2(memfd_create,
const char __user *, uname,
unsigned int, flags)
{
char *name __free(kfree) = NULL;
unsigned int fd_flags;
int error;

error = sanitize_flags(&flags);     // ํ”Œ๋ž˜๊ทธ ์œ ํšจ์„ฑ ๊ฒ€์ฆ
if (error < 0)
return error;

name = alloc_name(uname);           // "memfd:" ์ ‘๋‘์‚ฌ ์ถ”๊ฐ€
if (IS_ERR(name))
return PTR_ERR(name);

fd_flags = (flags & MFD_CLOEXEC) ? O_CLOEXEC : 0;
return FD_ADD(fd_flags, memfd_alloc_file(name, flags));  // fd ๋ฐ˜ํ™˜
}
  • ์—ญํ• : ์‚ฌ์šฉ์ž็ฉบ้—ด์—์„œ memfd_create("name", flags) ํ˜ธ์ถœ ์‹œ ์ง„์ž…
  • ๋ถ„๊ธฐ: MFD_CLOEXEC โ†’ O_CLOEXEC ์„ค์ •, MFD_HUGETLB โ†’ hugetlbfs ๋ฐฑ์—”๋“œ ์„ ํƒ
  • 2. memfd_alloc_file โ€” ํŒŒ์ผ ์ƒ์„ฑ

    // mm/memfd.c:458-503
    struct file *memfd_alloc_file(const char *name, unsigned int flags)
    {
    // MFD_HUGETLB์ด๋ฉด hugetlb_file_setup, ์•„๋‹ˆ๋ฉด shmem_file_setup
    if (flags & MFD_HUGETLB) {
    file = hugetlb_file_setup(name, 0, mk_vma_flags(VMA_NORESERVE_BIT),
    HUGETLB_ANONHUGE_INODE,
    (flags >> MFD_HUGE_SHIFT) & MFD_HUGE_MASK);
    } else {
    file = shmem_file_setup(name, 0, mk_vma_flags(VMA_NORESERVE_BIT));
    }
    // ๋ณด์•ˆ ์ดˆ๊ธฐํ™”, ํŒŒ์ผ ๋ชจ๋“œ ์„ค์ • (FMODE_LSEEK, FMODE_PREAD ๋“ฑ)
    // MFD_NOEXEC_SEAL โ†’ exec ๋น„ํŠธ ์ œ๊ฑฐ + F_SEAL_EXEC ์„ค์ •
    // MFD_ALLOW_SEALING โ†’ F_SEAL_SEAL ํ•ด์ œ (๋ด‰์ธ ํ—ˆ์šฉ)
    }
  • ์—ญํ• : ๋ฐฑ์—”๋“œ ํŒŒ์ผ ์‹œ์Šคํ…œ(tmpfs/hugetlbfs)์— ์ต๋ช… ํŒŒ์ผ ์ƒ์„ฑ
  • ๋ถ„๊ธฐ: MFD_HUGETLB โ†’ HugeTLB ํ• ๋‹น, MFD_NOEXEC_SEAL โ†’ exec ๋น„ํŠธ ์ œ๊ฑฐ
  • 3. memfd_add_seals โ€” ํŒŒ์ผ ๋ด‰์ธ ์ถ”๊ฐ€

    // mm/memfd.c:230-310
    static int memfd_add_seals(struct file *file, unsigned int seals)
    {
    // ์“ฐ๊ธฐ ๊ถŒํ•œ ํ™•์ธ
    if (!(file->f_mode & FMODE_WRITE))
    return -EPERM;
    
    // ๊ธฐ์กด SEAL_SEAL์ด ์„ค์ •๋˜์–ด ์žˆ์œผ๋ฉด ์ถ”๊ฐ€ ๋ด‰์ธ ๋ถˆ๊ฐ€
    if (*file_seals & F_SEAL_SEAL)
    return -EPERM;
    
    // SEAL_WRITE ์ถ”๊ฐ€ ์‹œ: ๋งคํ•‘ ๊ฑฐ๋ถ€ โ†’ pinned folio ๋Œ€๊ธฐ
    if ((seals & F_SEAL_WRITE) && !(*file_seals & F_SEAL_WRITE)) {
    error = mapping_deny_writable(file->f_mapping);
    error = memfd_wait_for_pins(file->f_mapping);
    }
    
    // SEAL_EXEC: exec ๋น„ํŠธ๊ฐ€ ์žˆ์œผ๋ฉด SHRINK/GROW/WRITE/FUTURE_WRITE๋„ ์ถ”๊ฐ€
    if (seals & F_SEAL_EXEC && inode->i_mode & 0111)
    seals |= F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE|F_SEAL_FUTURE_WRITE;
    }
  • ์—ญํ• : ํŒŒ์ผ์— ๋ด‰์ธ ๋น„ํŠธ ์ถ”๊ฐ€ (์ œ๊ฑฐ ๋ถˆ๊ฐ€)
  • ๋ถ„๊ธฐ: F_SEAL_WRITE โ†’ mapping_deny_writable + memfd_wait_for_pins, F_SEAL_EXEC โ†’ W^X ์ •์ฑ… ์ž๋™ ์ ์šฉ
  • 4. memfd_wait_for_pins โ€” pinned folio ๋Œ€๊ธฐ

    // mm/memfd.c:155-208
    static int memfd_wait_for_pins(struct address_space *mapping)
    {
    // 1๋‹จ๊ณ„: ๋ชจ๋“  folio ์Šค์บ”ํ•˜์—ฌ extra ref๊ฐ€ ์žˆ๋Š” ๊ฒƒ ํƒœ๊ทธ
    memfd_tag_pins(&xas);
    
    // 2๋‹จ๊ณ„: ์ตœ๋Œ€ 4ํšŒ ์Šค์บ” (์ง€์ˆ˜ ๋ฐฑ์˜คํ”„)
    for (scan = 0; scan <= LAST_SCAN; scan++) {
    if (!scan)
    lru_add_drain_all();        // ์ฒซ ์Šค์บ”: LRU ํ”Œ๋Ÿฌ์‹œ
    else
    schedule_timeout_killable((HZ << scan) / 200);  // ๋ฐฑ์˜คํ”„ ๋Œ€๊ธฐ
    
    // MEMFD_TAG_PINNED ํƒœ๊ทธ๊ฐ€ ๋‚จ์•„์žˆ์œผ๋ฉด ๊ณ„์† ๋Œ€๊ธฐ
    // ๋งˆ์ง€๋ง‰ ์Šค์บ”์—์„œ still pinned โ†’ -EBUSY ๋ฐ˜ํ™˜
    }
    }
  • ์—ญํ• : GUP(direct I/O, AIO ๋“ฑ)๋กœ pin๋œ folio๊ฐ€ ํ•ด์ œ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
  • ๋ถ„๊ธฐ: ํƒœ๊ทธ ์—†์Œ โ†’ ์ฆ‰์‹œ ๋ฐ˜ํ™˜, ๋ฐฑ์˜คํ”„ ์Šค์บ” ํ›„ไปๆœ‰ โ†’ -EBUSY
  • 5. memfd_check_seals_mmap โ€” mmap ์‹œ ๋ด‰์ธ ๊ฒ€์ฆ

    // mm/memfd.c:397-407
    int memfd_check_seals_mmap(struct file *file, vm_flags_t *vm_flags_ptr)
    {
    unsigned int seals = *memfd_file_seals_ptr(file);
    
    if (is_write_sealed(seals))
    err = check_write_seal(vm_flags_ptr);  // ์“ฐ๊ธฐ ๋งคํ•‘ ์ฐจ๋‹จ
    return err;
    }
  • ์—ญํ• : mmap() ํ˜ธ์ถœ ์‹œ write ๋ด‰์ธ ์—ฌ๋ถ€ ํ™•์ธ
  • ๋ถ„๊ธฐ: VM_SHARED | VM_WRITE โ†’ -EPERM, ์ฝ๊ธฐ ์ „์šฉ โ†’ VM_MAYWRITE ์ œ๊ฑฐ
  • ํ˜ธ์ถœ ํ๋ฆ„

    memfd_create("test", MFD_CLOEXEC | MFD_ALLOW_SEALING)
    โ”‚
    โ”œโ”€ sanitize_flags()          โ† MFD_* ํ”Œ๋ž˜๊ทธ ์œ ํšจ์„ฑ ๊ฒ€์ฆ
    โ”œโ”€ alloc_name()              โ† "memfd:test" ์ด๋ฆ„ ์ƒ์„ฑ
    โ””โ”€ memfd_alloc_file()
    โ”œโ”€ shmem_file_setup()   โ† tmpfs ์ต๋ช… ํŒŒ์ผ ์ƒ์„ฑ (๊ธฐ๋ณธ)
    โ”‚   ๋˜๋Š”
    โ”œโ”€ hugetlb_file_setup() โ† HugeTLB ํŒŒ์ผ ์ƒ์„ฑ (MFD_HUGETLB)
    โ”œโ”€ security_inode_init_security_anon()
    โ””โ”€ ํŒŒ์ผ ๋ชจ๋“œ ์„ค์ • (FMODE_LSEEK ๋“ฑ)
    
    fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE)
    โ”‚
    โ””โ”€ memfd_add_seals()
    โ”œโ”€ mapping_deny_writable()      โ† ์“ฐ๊ธฐ ๋งคํ•‘ ๊ฑฐ๋ถ€
    โ””โ”€ memfd_wait_for_pins()
    โ”œโ”€ memfd_tag_pins()        โ† pinned folio ํƒœ๊น…
    โ””โ”€ ์Šค์บ” + ๋ฐฑ์˜คํ”„ ๋Œ€๊ธฐ (์ตœ๋Œ€ ~150ms)
    
    mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)
    โ”‚
    โ””โ”€ memfd_check_seals_mmap()
    โ””โ”€ check_write_seal()           โ† write ๋ด‰์ธ ์‹œ -EPERM

    ์กฐ๊ฑด๋ณ„ ๋น„๊ต

    ๊ตฌ๋ถ„tmpfs ๋ฐฑ์—”๋“œ (๊ธฐ๋ณธ)hugetlbfs ๋ฐฑ์—”๋“œ (MFD_HUGETLB)
    **์ƒ์„ฑ ํ•จ์ˆ˜**`shmem_file_setup()``hugetlb_file_setup()`
    **ํ• ๋‹น ์‹œ์ **demand paging (ํดํŠธ ์‹œ)์ฆ‰์‹œ ์˜ˆ์•ฝ (fallocate)
    **์ปค๋„ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ**์‹ค์ œ ์‚ฌ์šฉ๋Ÿ‰๋งŒ์‚ฌ์ „ ํ• ๋‹น (๊ณ ์ •)
    **์„ฑ๋Šฅ**์ผ๋ฐ˜ ๋ฉ”๋ชจ๋ฆฌ ์ˆ˜์ค€๊ณ ์„ฑ๋Šฅ DMA ๊ฐ€๋Šฅ
    **Swappable**๊ฐ€๋Šฅ๋ถˆ๊ฐ€๋Šฅ
    **๋ด‰์ธ ๊ตฌ์กฐ์ฒด**`shmem_inode_info.seals``hugetlbfs_inode_info.seals`
    ๋ด‰์ธ ํ”Œ๋ž˜๊ทธํšจ๊ณผSEAL_EXEC ์‹œ ์ž๋™ ์ถ”๊ฐ€
    `F_SEAL_SEAL`์ถ”๊ฐ€ ๋ด‰์ธ ๋ฐฉ์ง€-
    `F_SEAL_SHRINK`ํŒŒ์ผ ์ถ•์†Œ ๋ฐฉ์ง€โœ“
    `F_SEAL_GROW`ํŒŒ์ผ ํ™•์žฅ ๋ฐฉ์ง€โœ“
    `F_SEAL_WRITE`ํ˜„์žฌ ์“ฐ๊ธฐ ๋ฐฉ์ง€โœ“
    `F_SEAL_FUTURE_WRITE`ํ–ฅํ›„ ์“ฐ๊ธฐ ๋ฐฉ์ง€โœ“
    `F_SEAL_EXEC`exec ๋น„ํŠธ ๋ณ€๊ฒฝ ๋ฐฉ์ง€-
    noexec ๋ฒ”์œ„ (sysctl)๋™์ž‘
    `MEMFD_NOEXEC_SCOPE_EXEC` (0)`MFD_EXEC` ๊ธฐ๋ณธ, noexec ์—†์Œ
    `MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL` (1)`MFD_NOEXEC_SEAL` ์ž๋™ ์ ์šฉ
    `MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED` (2)`MFD_NOEXEC_SEAL` ํ•„์ˆ˜, ์—†์œผ๋ฉด `-EACCES`

    ๊ด€๋ จ ๋ฌธ์„œ

  • 16-shmem.html โ€” tmpfs/shmem ๋ฐฑ์—”๋“œ ์ƒ์„ธ
  • 43-hugetlb.html โ€” HugeTLBFS ๋ฐฑ์—”๋“œ ์ƒ์„ธ
  • 25-mseal.html โ€” VMA ๋ด‰์ธ (mseal)๊ณผ ๋น„๊ต
  • 00-overview.html โ€” ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊ฐœ์š”