Secret Memory โ€” `memfd_secret(2)` ์‹œ์Šคํ…œ ํ˜ธ์ถœ

๊ฐœ์š”

Secret Memory๋Š” Linux ์ปค๋„์—์„œ _userspace๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ_์„ ์ƒ์„ฑํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด๋‹ค. memfd_secret(2) ์‹œ์Šคํ…œ ํ˜ธ์ถœ์„ ํ†ตํ•ด ์ƒ์„ฑ๋œ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋ฅผ mmapํ•˜๋ฉด, ํ•ด๋‹น ๋ฉ”๋ชจ๋ฆฌ๋Š” ์ปค๋„์˜ ์ง์ ‘ ๋งคํ•‘(direct map)์—์„œ ์ œ์™ธ๋œ๋‹ค. ์ฆ‰, ์ปค๋„์ด ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”์—์„œ ํ•ด๋‹น ํŽ˜์ด์ง€๋ฅผ ์ œ๊ฑฐํ•˜์—ฌ ์ž์ฒด์ ์œผ๋กœ๋„ ์ฝ์„ ์ˆ˜ ์—†๊ฒŒ ๋œ๋‹ค. ์ด๋Š” ๋น„๋ฐ€ํ‚ค ์ €์žฅ์†Œ, ์•”ํ˜ธํ™” ํ‚ค ๊ด€๋ฆฌ,TEE(Trusted Execution Environment) ๋Ÿฐํƒ€์ž„๊ณผ ๊ฐ™์€ ๋ณด์•ˆ์ด ์ค‘์š”ํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€์— ํ™œ์šฉ๋œ๋‹ค.

ํ•ต์‹ฌ ์›๋ฆฌ๋Š” ๊ฐ„๋‹จํ•˜๋‹ค: ํŽ˜์ด์ง€๋ฅผ ํ• ๋‹นํ•œ ๋’ค set_direct_map_invalid_noflush()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ปค๋„์˜ linear map์—์„œ ํ•ด๋‹น ํŽ˜์ด์ง€๋ฅผ unmapํ•˜๊ณ , TLB ํ”Œ๋Ÿฌ์‹œ๋ฅผ ํ†ตํ•ด ์‹ค์ œ ๋งคํ•‘์„ ๋ฌดํšจํ™”ํ•œ๋‹ค. ์ดํ›„ ์‚ฌ์šฉ์ž ๊ณต๊ฐ„๋งŒ์ด ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ์—”ํŠธ๋ฆฌ๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค. GUP(Get User Pages) ๊ฒฝ๋กœ์—์„œ๋„ secretmem ํŽ˜์ด์ง€๋Š” ๋ช…์‹œ์ ์œผ๋กœ ๊ฑฐ๋ถ€๋˜์–ด ์ปค๋„์ด ์šฐํšŒํ•  ์ˆ˜ ์—†๋„๋ก ์ฐจ๋‹จ๋œ๋‹ค.

์†Œ์Šค ํŒŒ์ผ ๊ฒฝ๋กœ:
mm/secretmem.c                           โ† ๋ฉ”์ธ ๊ตฌํ˜„ (270์ค„)
include/linux/secretmem.h                โ† ํ—ค๋” (36์ค„)
mm/gup.c                                 โ† GUP-fast secretmem ๊ฑฐ๋ถ€ ๋กœ์ง
mm/mlock.c                               โ† VM_LOCKED ํ”Œ๋ž˜๊ทธ ์ฒ˜๋ฆฌ
arch/x86/mm/pat/set_memory.c             โ† set_direct_map_invalid_noflush ๊ตฌํ˜„
fs/anon_inodes.c                         โ† anon_inode_make_secure_inode

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

# 1. secretmem ํ™œ์„ฑํ™” ์—ฌ๋ถ€ ํ™•์ธ (์ปค๋„ ๋นŒ๋“œ ์˜ต์…˜)
cat /boot/config-$(uname -r) | grep SECRETMEM

# 2. memfd_secret ์‹œ์Šคํ…œ ํ˜ธ์ถœ ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ
grep -c memfd_secret /usr/include/asm/unistd_64.h

# 3. ํ˜„์žฌ secretmem ์‚ฌ์šฉ์ž ์ˆ˜ (ํ™œ์„ฑ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ)
sudo cat /proc/sys/kernel/secretmem_users 2>/dev/null || echo "sysctl ๋ฏธ์ง€์›"

# 4. ์ปค๋„ ๋ชจ๋“ˆ/ํŒŒ๋ผ๋ฏธํ„ฐ ํ™•์ธ
cat /sys/module/secretmem/parameters/enable 2>/dev/null || echo "๋ชจ๋“ˆ ๋ฏธ๋กœ๋“œ"

# 5. /proc/meminfo์—์„œ secretmem ๊ด€๋ จ ํ™•์ธ
grep -i secret /proc/meminfo 2>/dev/null || echo "secretmem ์ „์šฉ ํ•ญ๋ชฉ ์—†์Œ"

# 6. ์‹ค์ œ ํ…Œ์ŠคํŠธ ํ”„๋กœ๊ทธ๋žจ ์ปดํŒŒ์ผ ๋ฐ ์‹คํ–‰
cat > /tmp/test_secretmem.c << 'EOF'
#include <stdio.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <fcntl.h>

int main() {
int fd = syscall(SYS_memfd_secret, O_CLOEXEC);
if (fd < 0) { perror("memfd_secret"); return 1; }
void *p = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (p == MAP_FAILED) { perror("mmap"); return 1; }
/* ์‚ฌ์šฉ์ž ๊ณต๊ฐ„์—์„œ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅ โ€” ์ปค๋„ ์ง์ ‘ ๋งคํ•‘์—์„œ ์ œ์™ธ๋จ */
printf("secretmem ํŽ˜์ด์ง€ ํ• ๋‹น ์„ฑ๊ณต: %p\n", p);
munmap(p, 4096);
close(fd);
return 0;
}
EOF
gcc /tmp/test_secretmem.c -o /tmp/test_secretmem && /tmp/test_secretmem

# 7. ARM64 ๋“ฑ ์•„ํ‚คํ…์ฒ˜๋ณ„ direct map ์ œํ•œ ํ™•์ธ
zgrep CONFIG_ARCH_HAS_SET_DIRECT_MAP /proc/config.gz 2>/dev/null || echo "config ๋ฏธ์ง€์›"

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

`secretmem_vm_ops` โ€” VMA ์—ฐ์‚ฐ ํ…Œ์ด๋ธ”

// mm/secretmem.c:111-113
static const struct vm_operations_struct secretmem_vm_ops = {
.fault = secretmem_fault,  /* ํŽ˜์ด์ง€ ํดํŠธ ๋ฐœ์ƒ ์‹œ ํ˜ธ์ถœ๋˜๋Š” ํ•ธ๋“ค๋Ÿฌ */
};
  • ์—ญํ• : secretmem VMA์— ํŽ˜์ด์ง€ ํดํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด secretmem_fault()๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
  • ์‹๋ณ„์ž: vma->vm_ops == &secretmem_vm_ops๋กœ secretmem VMA ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•œ๋‹ค.
  • `secretmem_fops` โ€” ํŒŒ์ผ ์—ฐ์‚ฐ ํ…Œ์ด๋ธ”

    // mm/secretmem.c:141-144
    static const struct file_operations secretmem_fops = {
    .release       = secretmem_release,       /* fd close ์‹œ ์‚ฌ์šฉ์ž ์ˆ˜ ๊ฐ์†Œ */
    .mmap_prepare  = secretmem_mmap_prepare,  /* mmap ์ค€๋น„ ๋‹จ๊ณ„์—์„œ VMA ์„ค์ • */
    };
  • ์—ญํ• : ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ์˜ mmap๊ณผ close ๋™์ž‘์„ ์ •์˜ํ•œ๋‹ค.
  • mmap_prepare์€ Linux 7.0์—์„œ ๋„์ž…๋œ ์ƒˆ๋กœ์šด mmap ๊ฒฝ๋กœ๋กœ, VMA ์ƒ์„ฑ ์ „์— ๊ฒ€์ฆ๊ณผ ์„ค์ •์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  • `secretmem_aops` โ€” ์ฃผ์†Œ ๊ณต๊ฐ„ ์—ฐ์‚ฐ ํ…Œ์ด๋ธ”

    // mm/secretmem.c:158-162
    const struct address_space_operations secretmem_aops = {
    .dirty_folio    = noop_dirty_folio,          /* ๋”ํ‹ฐ ํŠธ๋ž˜ํ‚น ๋ถˆํ•„์š” */
    .free_folio     = secretmem_free_folio,      /* ํ•ด์ œ ์‹œ direct map ๋ณต์› + ์ œ๋กœํ™” */
    .migrate_folio  = secretmem_migrate_folio,   /* ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฑฐ๋ถ€ (-EBUSY) */
    };
  • ์—ญํ• : secretmem ํŽ˜์ด์ง€์˜ lifecycle์„ ๊ด€๋ฆฌํ•œ๋‹ค.
  • migrate_folio๊ฐ€ -EBUSY๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ด์œ : secretmem ํŽ˜์ด์ง€๋Š” ์ปค๋„์ด ์ง์ ‘ ์ ‘๊ทผํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.
  • free_folio์—์„œ set_direct_map_default_noflush()๋กœ direct map์„ ๋ณต์›ํ•œ ๋’ค folio_zero_segment()๋กœ ๋‚ด์šฉ์„ ์ œ๋กœํ™”ํ•œ๋‹ค.
  • `secretmem_fs` โ€” Pseudo ํŒŒ์ผ ์‹œ์Šคํ…œ

    // mm/secretmem.c:253-257
    static struct file_system_type secretmem_fs = {
    .name             = "secretmem",
    .init_fs_context  = secretmem_init_fs_context,
    .kill_sb          = kill_anon_super,
    };
  • ์—ญํ• : memfd_secret์ด ์‚ฌ์šฉํ•˜๋Š” ๊ฐ€์ƒ ํŒŒ์ผ ์‹œ์Šคํ…œ์ด๋‹ค.
  • SB_I_NOEXEC | SB_I_NODEV ํ”Œ๋ž˜๊ทธ๋กœ ์‹คํ–‰/์žฅ์น˜ ์ ‘๊ทผ์„ ์ฐจ๋‹จํ•œ๋‹ค.
  • ์‹ค์ œ ๋””์Šคํฌ์— ์—ฐ๊ฒฐ๋˜์ง€ ์•Š๋Š” pseudo-fs ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.
  • `secretmem_enable` โ€” ๋ชจ๋“ˆ ํŒŒ๋ผ๋ฏธํ„ฐ

    // mm/secretmem.c:38-41
    static bool secretmem_enable __ro_after_init = 1;
    module_param_named(enable, secretmem_enable, bool, 0400);
    MODULE_PARM_DESC(secretmem_enable,
    "Enable secretmem and memfd_secret(2) system call");
  • ์—ญํ• : ๋ถ€ํŒ… ์‹œ secretmem ๊ธฐ๋Šฅ์˜ ํ™œ์„ฑํ™”/๋น„ํ™œ์„ฑํ™”๋ฅผ ์ œ์–ดํ•œ๋‹ค.
  • __ro_after_init์œผ๋กœ ์ดˆ๊ธฐํ™” ํ›„ ์ฝ๊ธฐ ์ „์šฉ์ด ๋˜์–ด ๋Ÿฐํƒ€์ž„ ๋ณ€๊ฒฝ์„ ๋ฐฉ์ง€ํ•œ๋‹ค.
  • ์ปค๋„ ๋นŒ๋“œ ์‹œ CONFIG_SECRETMEM=n์œผ๋กœ ์™„์ „ํžˆ ๋น„ํ™œ์„ฑํ™”ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
  • `secretmem_users` โ€” ํ™œ์„ฑ ์‚ฌ์šฉ์ž ์นด์šดํ„ฐ

    // mm/secretmem.c:43
    static atomic_t secretmem_users;
  • ์—ญํ• : ํ˜„์žฌ ์—ด๋ ค ์žˆ๋Š” secretmem ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ ์ˆ˜๋ฅผ ์ถ”์ ํ•œ๋‹ค.
  • secretmem_active()๋กœ ์ปค๋„ ์ „์ฒด์—์„œ secretmem์ด ์‚ฌ์šฉ ์ค‘์ธ์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
  • memfd_secret ์‹œ์Šคํ…œ ํ˜ธ์ถœ์—์„œ atomic_read(&secretmem_users) < 0 ๊ฒ€์‚ฌ๋กœ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๋ฅผ ๋ฐฉ์ง€ํ•œ๋‹ค.

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

    1. `secretmem_fault()` โ€” ํŽ˜์ด์ง€ ํดํŠธ ํ•ธ๋“ค๋Ÿฌ

    // mm/secretmem.c:50-109
    static vm_fault_t secretmem_fault(struct vm_fault *vmf)

    ์—ญํ• : secretmem VMA์—์„œ ํŽ˜์ด์ง€ ํดํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ, ์ƒˆ folio๋ฅผ ํ• ๋‹นํ•˜๊ณ  ์ปค๋„ direct map์—์„œ ์ œ๊ฑฐํ•œ๋‹ค.

    // mm/secretmem.c:61-100
    if (((loff_t)vmf->pgoff << PAGE_SHIFT) >= i_size_read(inode))
    return vmf_error(-EINVAL);
    
    filemap_invalidate_lock_shared(mapping);
    
    retry:
    folio = filemap_lock_folio(mapping, offset);
    if (IS_ERR(folio)) {
    folio = folio_alloc(gfp | __GFP_ZERO, 0);
    if (!folio) {
    ret = VM_FAULT_OOM;
    goto out;
    }
    
    err = set_direct_map_invalid_noflush(folio_page(folio, 0));
    if (err) {
    folio_put(folio);
    ret = vmf_error(err);
    goto out;
    }
    
    __folio_mark_uptodate(folio);
    err = filemap_add_folio(mapping, folio, offset, gfp);
    if (unlikely(err)) {
    /* ํฐ ํŽ˜์ด์ง€ ๋ถ„ํ• ์ด ํ•„์š”ํ–ˆ๋‹ค๋ฉด, ๋ฌดํšจํ™” ํ‘œ์‹œ ์‹œ์ ์— ์ด๋ฏธ ์ˆ˜ํ–‰๋จ */
    set_direct_map_default_noflush(folio_page(folio, 0));
    folio_put(folio);
    if (err == -EEXIST)
    goto retry;
    
    ret = vmf_error(err);
    goto out;
    }
    
    addr = (unsigned long)folio_address(folio);
    flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
    }

    ํ๋ฆ„:

    1. ํŒŒ์ผ ๋ฒ”์œ„ ์ดˆ๊ณผ ๊ฒ€์‚ฌ (i_size_read)

    2. filemap_lock_folio()๋กœ ๊ธฐ์กด folio ํƒ์ƒ‰

    3. ์—†์œผ๋ฉด folio_alloc(gfp | __GFP_ZERO, 0)๋กœ ์ƒˆ folio ํ• ๋‹น

    4. set_direct_map_invalid_noflush()๋กœ ์ปค๋„ ์ง์ ‘ ๋งคํ•‘ ์ œ๊ฑฐ

    5. filemap_add_folio()๋กœ ๋งคํ•‘์— ์ถ”๊ฐ€

    6. flush_tlb_kernel_range()๋กœ TLB ๋ฌดํšจํ™”

    7. ๊ธฐ์กด folio๊ฐ€ ์žˆ์œผ๋ฉด ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ (VM_FAULT_LOCKED)

    ๋ฐ˜๋ณต ๋กœ์ง: filemap_add_folio()๊ฐ€ -EEXIST๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด goto retry๋กœ ์žฌ์‹œ๋„ํ•œ๋‹ค.

    2. `secretmem_mmap_prepare()` โ€” mmap ์‚ฌ์ „ ์„ค์ •

    // mm/secretmem.c:121-134
    static int secretmem_mmap_prepare(struct vm_area_desc *desc)

    ์—ญํ• : mmap ์‹œ VMA ํ”Œ๋ž˜๊ทธ๋ฅผ ์„ค์ •ํ•˜๊ณ  secretmem ์ „์šฉ vm_ops๋ฅผ ์—ฐ๊ฒฐํ•œ๋‹ค.

    // mm/secretmem.c:123-133
    const unsigned long len = vma_desc_size(desc);
    
    if (!vma_desc_test_flags(desc, VMA_SHARED_BIT, VMA_MAYSHARE_BIT))
    return -EINVAL;
    
    vma_desc_set_flags(desc, VMA_LOCKED_BIT, VMA_DONTDUMP_BIT);
    if (!mlock_future_ok(desc->mm, /* VMA ๊ณ ์ • ์—ฌ๋ถ€ = */ true, len))
    return -EAGAIN;
    desc->vm_ops = &secretmem_vm_ops;
    
    return 0;

    ํ๋ฆ„:

    1. VMA_SHARED_BIT | VMA_MAYSHARE_BIT ํ™•์ธ โ†’ ๊ณต์œ  ๋งคํ•‘๋งŒ ํ—ˆ์šฉ

    2. VMA_LOCKED_BIT | VMA_DONTDUMP_BIT ์„ค์ • โ†’ VMA ๊ณ ์ • + ์ฝ”์–ด ๋คํ”„ ์ œ์™ธ

    3. mlock_future_ok() ํ™•์ธ โ†’ mlock ํ•œ๋„ ์ดˆ๊ณผ ์‹œ -EAGAIN

    4. desc->vm_ops = &secretmem_vm_ops ์—ฐ๊ฒฐ

    ์ œ์•ฝ ์กฐ๊ฑด: secretmem์€ ๋ฐ˜๋“œ์‹œ shared ๋งคํ•‘์œผ๋กœ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

    3. `secretmem_file_create()` โ€” ํŒŒ์ผ ์ƒ์„ฑ

    // mm/secretmem.c:190-222
    static struct file *secretmem_file_create(unsigned long flags)

    ์—ญํ• : memfd_secret ์‹œ์Šคํ…œ ํ˜ธ์ถœ์˜ ํ•ต์‹ฌ์œผ๋กœ, anonymous inode ๊ธฐ๋ฐ˜ ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ๋‹ค.

    // mm/secretmem.c:196-215
    inode = anon_inode_make_secure_inode(secretmem_mnt->mnt_sb, anon_name, NULL);
    if (IS_ERR(inode))
    return ERR_CAST(inode);
    
    file = alloc_file_pseudo(inode, secretmem_mnt, "secretmem",
    O_RDWR | O_LARGEFILE, &secretmem_fops);
    if (IS_ERR(file))
    goto err_free_inode;
    
    mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);
    mapping_set_unevictable(inode->i_mapping);
    
    inode->i_op = &secretmem_iops;
    inode->i_mapping->a_ops = &secretmem_aops;
    
    /* zero size์ธ ์ผ๋ฐ˜ ํŒŒ์ผ์ฒ˜๋Ÿผ ๋ณด์ด๊ฒŒ ์ฒ˜๋ฆฌ */
    inode->i_mode |= S_IFREG;
    inode->i_size = 0;
    
    atomic_inc(&secretmem_users);

    ํ๋ฆ„:

    1. anon_inode_make_secure_inode()๋กœ ๋ณด์•ˆ ์ปจํ…์ŠคํŠธ๊ฐ€ ์ ์šฉ๋œ anonymous inode ์ƒ์„ฑ

    2. alloc_file_pseudo()๋กœ pseudo ํŒŒ์ผ ํ• ๋‹น

    3. mapping_set_gfp_mask(GFP_HIGHUSER) โ†’ ๊ณ ์œ  ๋ฉ”๋ชจ๋ฆฌ์—์„œ๋งŒ ํ• ๋‹น

    4. mapping_set_unevictable() โ†’ ํšŒ์ˆ˜ ๋ถˆ๊ฐ€๋Šฅํ•˜๋„๋ก ์„ค์ •

    5. inode์— secretmem_iops, secretmem_aops ์—ฐ๊ฒฐ

    6. atomic_inc(&secretmem_users)๋กœ ์‚ฌ์šฉ์ž ์ˆ˜ ์ฆ๊ฐ€

    4. `memfd_secret()` โ€” ์‹œ์Šคํ…œ ํ˜ธ์ถœ ์ง„์ž…์ 

    // mm/secretmem.c:224-238
    SYSCALL_DEFINE1(memfd_secret, unsigned int, flags)

    ์—ญํ• : ์‚ฌ์šฉ์ž ๊ณต๊ฐ„์˜ memfd_secret(2) ์‹œ์Šคํ…œ ํ˜ธ์ถœ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.

    // mm/secretmem.c:226-237
    /* ๋กœ์ปฌ flags๊ฐ€ ์ „์—ญ fcntl.h์™€ ์ถฉ๋Œํ•˜์ง€ ์•Š๋Š”์ง€ ํ™•์ธ */
    BUILD_BUG_ON(SECRETMEM_FLAGS_MASK & O_CLOEXEC);
    
    if (!secretmem_enable || !can_set_direct_map())
    return -ENOSYS;
    
    if (flags & ~(SECRETMEM_FLAGS_MASK | O_CLOEXEC))
    return -EINVAL;
    if (atomic_read(&secretmem_users) < 0)
    return -ENFILE;
    
    return FD_ADD(flags & O_CLOEXEC, secretmem_file_create(flags));

    ํ๋ฆ„:

    1. secretmem_enable ๋ฐ can_set_direct_map() ํ™•์ธ โ†’ ๋ฏธ์ง€์› ์‹œ -ENOSYS

    2. ํ”Œ๋ž˜๊ทธ ์œ ํšจ์„ฑ ๊ฒ€์ฆ (mode/flag ๋งˆ์Šคํฌ + O_CLOEXEC)

    3. secretmem_user ์ˆ˜ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ ๊ฒ€์‚ฌ

    4. secretmem_file_create() ํ˜ธ์ถœ ํ›„ FD_ADD()๋กœ fd ๋ฐ˜ํ™˜

    ๋ฐ˜ํ™˜: ์„ฑ๊ณต ์‹œ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ, ์‹คํŒจ ์‹œ errno.

    5. `secretmem_free_folio()` โ€” folio ํ•ด์ œ

    // mm/secretmem.c:152-156
    static void secretmem_free_folio(struct folio *folio)

    ์—ญํ• : secretmem folio๊ฐ€ ํ•ด์ œ๋  ๋•Œ direct map์„ ๋ณต์›ํ•˜๊ณ  ๋‚ด์šฉ์„ ์ œ๋กœํ™”ํ•œ๋‹ค.

    ํ๋ฆ„:

    1. set_direct_map_default_noflush() โ†’ ์ปค๋„ ์ง์ ‘ ๋งคํ•‘ ๋ณต์›

    2. folio_zero_segment() โ†’ ๋ฉ”๋ชจ๋ฆฌ ๋‚ด์šฉ ์™„์ „ ์ œ๊ฑฐ (๋ฐ์ดํ„ฐ ๋ˆ„์ถœ ๋ฐฉ์ง€)

    ๋ณด์•ˆ ์ค‘์š”์„ฑ: ํ•ด์ œ ์ „ ์ œ๋กœํ™”ํ•˜์ง€ ์•Š์œผ๋ฉด ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค๊ฐ€ ํ•ด๋‹น ๋ฌผ๋ฆฌ ํŽ˜์ด์ง€๋ฅผ ํ• ๋‹น๋ฐ›์•„ ์ž”์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค.


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

    ์‚ฌ์šฉ์ž ๊ณต๊ฐ„: memfd_secret(O_CLOEXEC)
    โ”‚
    โ–ผ
    SYSCALL_DEFINE1(memfd_secret)
    โ”œโ”€ secretmem_enable / can_set_direct_map() ํ™•์ธ
    โ”œโ”€ ํ”Œ๋ž˜๊ทธ ๊ฒ€์ฆ
    โ””โ”€ secretmem_file_create()
    โ”œโ”€ anon_inode_make_secure_inode()     โ† LSM ๋ณด์•ˆ ์ปจํ…์ŠคํŠธ ์ ์šฉ
    โ”œโ”€ alloc_file_pseudo()                 โ† pseudo ํŒŒ์ผ ํ• ๋‹น
    โ”œโ”€ mapping_set_gfp_mask(GFP_HIGHUSER) โ† ์ปค๋„ ํ• ๋‹น ์ œํ•œ
    โ”œโ”€ mapping_set_unevictable()           โ† ํšŒ์ˆ˜ ๋ถˆ๊ฐ€ ์„ค์ •
    โ””โ”€ atomic_inc(secretmem_users)
    
    ์‚ฌ์šฉ์ž ๊ณต๊ฐ„: mmap(fd, ...)
    โ”‚
    โ–ผ
    secretmem_mmap_prepare()
    โ”œโ”€ VMA_SHARED ๊ฒ€์ฆ
    โ”œโ”€ VM_LOCKED | VM_DONTDUMP ์„ค์ •
    โ”œโ”€ mlock_future_ok() ํ™•์ธ
    โ””โ”€ vm_ops = &secretmem_vm_ops
    
    ์‚ฌ์šฉ์ž ๊ณต๊ฐ„: ์ ‘๊ทผ (ํŽ˜์ด์ง€ ํดํŠธ)
    โ”‚
    โ–ผ
    secretmem_fault()
    โ”œโ”€ filemap_lock_folio() ํƒ์ƒ‰
    โ”œโ”€ [์—†์œผ๋ฉด] folio_alloc(__GFP_ZERO)
    โ”œโ”€ set_direct_map_invalid_noflush()     โ† ์ปค๋„ ๋งคํ•‘ ์ œ๊ฑฐ
    โ”œโ”€ filemap_add_folio()                  โ† ๋งคํ•‘์— ์ถ”๊ฐ€
    โ””โ”€ flush_tlb_kernel_range()            โ† TLB ๋ฌดํšจํ™”
    
    GUP ๊ฒฝ๋กœ (์ปค๋„ ์ง์ ‘ ์ ‘๊ทผ ์ฐจ๋‹จ):
    โ”œโ”€ vma_is_secretmem(vma) โ†’ -EFAULT     โ† gup.c:1219
    โ””โ”€ secretmem_mapping(mapping) โ†’ false   โ† gup_fast_folio_allowed():2803
    
    ํ•ด์ œ ์‹œ:
    close(fd)
    โ””โ”€ secretmem_release()
    โ””โ”€ atomic_dec(secretmem_users)
    
    folio ํ•ด์ œ ์‹œ:
    secretmem_free_folio()
    โ”œโ”€ set_direct_map_default_noflush()    โ† direct map ๋ณต์›
    โ””โ”€ folio_zero_segment()               โ† ๋ฐ์ดํ„ฐ ์ œ๋กœํ™”

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

    memfd_secret ํ”Œ๋ž˜๊ทธ๋ณ„ ๋™์ž‘

    ํ”Œ๋ž˜๊ทธํ—ˆ์šฉ ์—ฌ๋ถ€์„ค๋ช…
    `O_CLOEXEC`ํ—ˆ์šฉexec() ์‹œ fd ์ž๋™ ๋‹ซ๊ธฐ
    `O_RDWR`ํ—ˆ์šฉ (๊ธฐ๋ณธ๊ฐ’)์ฝ๊ธฐ/์“ฐ๊ธฐ ๋ชจ๋“œ
    ๊ธฐํƒ€ flags๊ฑฐ๋ถ€ (`-EINVAL`)mode ํ”Œ๋ž˜๊ทธ๋Š” ํ˜„์žฌ ๋ฏธ์‚ฌ์šฉ (0x0)

    ์•„ํ‚คํ…์ฒ˜๋ณ„ direct map ์ œ์–ด ์ง€์›

    ์•„ํ‚คํ…์ฒ˜`can_set_direct_map()``set_direct_map_invalid_noflush()`๋น„๊ณ 
    x86_64`true` (๊ธฐ๋ณธ๊ฐ’)`__set_pages_np()`์™„์ „ ์ง€์›
    ARM64์กฐ๊ฑด๋ถ€์กฐ๊ฑด๋ถ€`rodata_full` ๋˜๋Š” KFENCE ๋˜๋Š” Realm
    RISC-V`true` (๊ธฐ๋ณธ๊ฐ’)์ง€์›๊ธฐ๋ณธ ์ง€์›
    s390`true` (๊ธฐ๋ณธ๊ฐ’)์ง€์›๊ธฐ๋ณธ ์ง€์›
    LoongArch`true` (๊ธฐ๋ณธ๊ฐ’)์ง€์›๊ธฐ๋ณธ ์ง€์›

    GUP ๊ฒฝ๋กœ์—์„œ์˜ secretmem ์ฒ˜๋ฆฌ

    ๊ฒฝ๋กœ๋™์ž‘์ฝ”๋“œ ์œ„์น˜
    GUP (slow path)`vma_is_secretmem()` โ†’ `-EFAULT` ๋ฐ˜ํ™˜`gup.c:1219`
    GUP-fast (order-0 folio)`secretmem_mapping()` โ†’ `false` ๋ฐ˜ํ™˜ (๊ฑฐ๋ถ€)`gup.c:2803`
    GUP-fast (large folio)๊ฒ€์‚ฌ ๊ฑด๋„ˆ๋œ€ (secretmem์€ order-0๋งŒ ์‚ฌ์šฉ)`gup.c:2756`
    GUP-fast (hugetlb)๊ฑด๋„ˆ๋œ€ (secretmem ๋ถˆ๊ฐ€)`gup.c:2766`

    secretmem vs ๋‹ค๋ฅธ ๋ฉ”๋ชจ๋ฆฌ ๊ฒฉ๋ฆฌ ๋ฉ”์ปค๋‹ˆ์ฆ˜

    ํŠน์„ฑSecret Memorymlockmemfd_createsealed memfd
    ์ปค๋„ ์ง์ ‘ ๋งคํ•‘ ์ œ๊ฑฐ**์˜ˆ**์•„๋‹ˆ์˜ค์•„๋‹ˆ์˜ค์•„๋‹ˆ์˜ค
    GUP ์ฐจ๋‹จ**์˜ˆ**์•„๋‹ˆ์˜ค์•„๋‹ˆ์˜ค์•„๋‹ˆ์˜ค
    ํšŒ์ˆ˜ ๋ถˆ๊ฐ€**์˜ˆ**์•„๋‹ˆ์˜ค์•„๋‹ˆ์˜ค์•„๋‹ˆ์˜ค
    ์ฝ”์–ด ๋คํ”„ ์ œ์™ธ**์˜ˆ**์•„๋‹ˆ์˜ค์•„๋‹ˆ์˜ค์•„๋‹ˆ์˜ค
    LSM ๋ณด์•ˆ ์ปจํ…์ŠคํŠธ**์˜ˆ**์•„๋‹ˆ์˜ค์•„๋‹ˆ์˜ค์•„๋‹ˆ์˜ค
    ์‚ฌ์šฉ ์‚ฌ๋ก€์•”ํ˜ธํ™” ํ‚ค ์ €์žฅ์Šค์™‘ ๋ฐฉ์ง€์ž„์˜ ํŒŒ์ผ๋ฆฌ์†Œ์Šค ๋ณดํ˜ธ

    ํ˜ธ์ถœ ํ๋ฆ„ ๋‹ค์ด์–ด๊ทธ๋žจ

    Secret Memory ํ˜ธ์ถœ ํ๋ฆ„

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

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

    ๊ด€๋ จ ๋ฌธ์„œ

  • 00-overview.html โ€” ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊ฐœ์š”
  • 03-vma_mmap.html โ€” VMA / mmap
  • 05-page_reclaim.html โ€” ํŽ˜์ด์ง€ ํšŒ์ˆ˜
  • 12-folio.html โ€” Folio / Page Cache
  • 25-mseal.html โ€” Sealing (VMA ๋ด‰์ธ)
  • 26-secretmem.html โ€” Secret Memory (์ด ๋ฌธ์„œ)

  • ์ฐธ๊ณ  ์ž๋ฃŒ

  • ์ปค๋„ ์†Œ์Šค: mm/secretmem.c (์ „์ฒด 270์ค„ โ€” ๋น„๊ต์  ์ž‘๊ณ  ์ง‘์ค‘์ ์ธ ๊ตฌํ˜„)
  • ์„ค๊ณ„ ๋ฌธ์„œ: Documentation/mm/secretmem.rst
  • ์‹œ์Šคํ…œ ํ˜ธ์ถœ: memfd_secret(2) man page
  • ๊ด€๋ จ ์ปค๋ฐ‹: Mike Rapoport (IBM) โ€” 2021๋…„ ์ดˆ๊ธฐ ๊ตฌํ˜„, Linux 5.14์—์„œ ๋จธ์ง€
  • ๋ณด์•ˆ ๊ณ ๋ ค์‚ฌํ•ญ: anon_inode_make_secure_inode()๋ฅผ ํ†ตํ•œ SELinux/AppArmor ์ปจํ…์ŠคํŠธ ์ ์šฉ