๏ปฟ# mprotect ๐ก๏ธ
๊ด๋ จ ์์ค:mm/mprotect.c,include/linux/mman.h,include/linux/mm.h
๊ฐ์ (Overview)
mprotect๋ ํ๋ก์ธ์ค์ ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ ์์ญ(VMA)์ ๋ํ ๋ณดํธ ์์ฑ(์ฝ๊ธฐ/์ฐ๊ธฐ/์คํ)์ ๋ฐํ์์ ๋ณ๊ฒฝํ๋ ์์คํ
ํธ์ถ์ด๋ค. Linux 7.0์์ mprotect๋ ๋จ์ํ PTE ๋ณดํธ ๋ณ๊ฒฝ์ ๋์ด NUMA ๋ฐธ๋ฐ์ฑ, userfaultfd-wp(write-protect), softdirty ํธ๋ํน, memory sealing ๋ฑ ๋ค์ํ ์๋ธ์์คํ
๊ณผ ๊น์ด ํตํฉ๋์ด ์๋ค. ํต์ฌ ๊ฒฝ๋ก๋ do_mprotect_pkey() โ mprotect_fixup() โ change_protection() โ ํ์ด์ง ํ
์ด๋ธ ๊ณ์ธต(PGDโP4DโPUDโPMDโPTE) ์ํ์ด๋ค.
์์ค ํ์ผ์ mm/mprotect.c(1007์ค) ํ๋๋ก, ์์คํ
ํธ์ถ ์ ์(SYSCALL_DEFINE3)๋ถํฐ PTE ๋ฐฐ์น(batching) ์ต์ ํ, HugePMD/HugePUD ๋ถํ , PROT_NONE ๊ถํ ๊ฒ์ฆ๊น์ง ๋ชจ๋ ํฌํจํ๋ค. pkey_mprotect/pkey_alloc/pkey_free ์์คํ
ํธ์ถ๋ ํจ๊ป ์ ์๋์ด ์์ด ๋ฉ๋ชจ๋ฆฌ ๋ณดํธ ํค(per-process protection key) ์ง์๋ ๋ด๋นํ๋ค.
์ฑ
์ฅ์ ๋ถ์ ์ถ์
๊ท์น์ ๋ฐ๊พธ๋ ์ผ๋ก ๋ณด๋ฉด ์ดํด๊ฐ ์ฝ๋ค. ์ฑ
์ฅ(VMA)์ ๊ทธ๋๋ก ๋๊ณ , "์ฝ๊ธฐ๋ง", "์ฐ๊ธฐ ํ์ฉ", "์คํ ํ์ฉ" ๊ฐ์ ํ์งํ๋ง ๋ฐ๊พธ๋ ์์
์ด mprotect์ด๊ณ , ์ค์ ์ฑ
(PTE)์ ํ์ํ ๋๋ง ๋ค์ ์ ๋ฆฌ๋๋ค.
# ์์ค ํ์ผ ๊ฒฝ๋ก
mm/mprotect.c โ ๋ฉ์ธ ์์ค (1007์ค)
include/linux/mman.h โ calc_vm_prot_bits, map_deny_write_exec
include/linux/mm.h โ VM_* ํ๋๊ทธ, MM_CP_* ํ๋๊ทธ, can_change_pte_writable
include/linux/mm_types.h โ struct vm_area_struct
mm/internal.h โ folio_can_map_prot_numa
include/linux/pgtable.h โ modify_prot_start_ptes, modify_prot_commit_ptes
๋น ๋ฅธ ์ ๊ฒ ๋ช ๋ น
# 1. ํน์ ํ๋ก์ธ์ค์ VMA ๊ถํ๊ณผ pkey ํ์ธ
grep -nE '^VmFlags:|^ProtectionKey:' /proc/<pid>/smaps | head -40
# 2. mprotect ์์คํ
ํธ์ถ ์นด์ดํธ ํ์ธ
perf stat -e 'syscalls:sys_enter_mprotect' -p <pid> sleep 5
# 3. mprotect ๊ด๋ จ strace ์ถ์
strace -e mprotect -p <pid>
# 4. ํ์ฌ ๋ฉ๋ชจ๋ฆฌ ๋ณดํธ ์ํ (rwxp ๋ฑ)
cat /proc/<pid>/maps | head -20
# 5. pkey๊ฐ ๋ถ์ ๋งคํ ํ์ธ
grep -E '^ProtectionKey:' /proc/<pid>/smaps | sort | uniq -c
# 6. ํ์ด์ง ํ
์ด๋ธ ์ฌ์ฉ๋ ์ถ์
cat /proc/<pid>/status | grep VmPTE
# 7. mprotect ํธ์ถ ์ ํธ๋ ์ด์ฑ (ftrace)
echo 1 > /sys/kernel/debug/tracing/events/syscalls/sys_enter_mprotect/enable
# 8. pkey_mprotect ํธ์ถ ๋น๋ ํ์ธ
perf stat -e 'syscalls:sys_enter_pkey_mprotect' -p <pid> sleep 5
# 9. ๋ฉ๋ชจ๋ฆฌ ๋ณดํธ ๊ด๋ จ ์ปค๋ ๋ก๊ทธ
dmesg | grep -i "mprotect\|pkey\|protection"
# 10. x86์์ MDWE(Memory Deny Write Execute) ์ํ ํ์ธ
cat /proc/<pid>/status | grep -i mdwe
ํต์ฌ ์๋ฃ๊ตฌ์กฐ
struct vm_area_struct (์ ํ ํ๋)
// include/linux/mm_types.h:913
struct vm_area_struct {
unsigned long vm_start; // VMA ์์ ์ฃผ์
unsigned long vm_end; // VMA ์ข
๋ฃ ์ฃผ์ (ํฌํจ ์ ํจ)
struct mm_struct *vm_mm; // ์์ mm_struct
pgprot_t vm_page_prot; // ํ๋์จ์ด PTE์ ์ฌ์ฉ๋ ๋ณดํธ ์์ฑ
union {
const vm_flags_t vm_flags; // VM_READ, VM_WRITE, VM_EXEC ๋ฑ
vma_flags_t flags;
};
const struct vm_operations_struct *vm_ops; // mprotect ์ฝ๋ฐฑ (ํ์ผ ์์คํ
๋ณ)
struct anon_vma *anon_vma; // ์ต๋ช
๋งคํ์ฉ anon_vma
unsigned long vm_pgoff; // ์คํ์
(PAGE_SIZE ๋จ์)
struct file *vm_file; // ๋งคํ๋ ํ์ผ (์์ผ๋ฉด NULL)
struct mempolicy *vm_policy; // NUMA ์ ์ฑ
(CONFIG_NUMA)
};
* ํ์ผ: include/linux/mm_types.h:913-986 (ํต์ฌ ํ๋)
VM_* ํ๋๊ทธ โ mprotect ๊ด๋ จ ํต์ฌ
// include/linux/mm.h:402-545 (์ ํ)
#define VM_READ INIT_VM_FLAG(READ) // ์ฝ๊ธฐ ๊ฐ๋ฅ
#define VM_WRITE INIT_VM_FLAG(WRITE) // ์ฐ๊ธฐ ๊ฐ๋ฅ
#define VM_EXEC INIT_VM_FLAG(EXEC) // ์คํ ๊ฐ๋ฅ
#define VM_SHARED INIT_VM_FLAG(SHARED) // ๊ณต์ ๋งคํ
#define VM_MAYREAD INIT_VM_FLAG(MAYREAD) // ์ฝ๊ธฐ ํ์ฉ ๊ฐ๋ฅ
#define VM_MAYWRITE INIT_VM_FLAG(MAYWRITE) // ์ฐ๊ธฐ ํ์ฉ ๊ฐ๋ฅ
#define VM_MAYEXEC INIT_VM_FLAG(MAYEXEC) // ์คํ ํ์ฉ ๊ฐ๋ฅ
#define VM_LOCKED INIT_VM_FLAG(LOCKED) // ๊ณ ์ (์ค์ ์์ ์ ๋จ)
#define VM_SEALED INIT_VM_FLAG(SEALED) // ๋ด์ธ (mprotect ๊ฑฐ๋ถ)
#define VM_PFNMAP INIT_VM_FLAG(PFNMAP) // ์ปค๋ ์ง์ ๋งคํ
#define VM_ACCOUNT INIT_VM_FLAG(ACCOUNT) // ์ค๋ฒ์ปค๋ฐ ๊ณ์
* ํ์ผ: include/linux/mm.h:402-545
* mprotect์์ VM_ACCESS_FLAGS(VM_READ|VM_WRITE|VM_EXEC)๊ฐ VMA์ ์ค์ ๋จ
* VM_SEALED๊ฐ ์ค์ ๋ VMA๋ mprotect๊ฐ -EPERM์ผ๋ก ๊ฑฐ๋ถ (mseal ์ฐ๋)
MM_CP_* ํ๋๊ทธ โ change_protection ์ ์ด
// include/linux/mm.h:3031-3038
#define MM_CP_TRY_CHANGE_WRITABLE (1UL << 0) // ์ฐ๊ธฐ ๊ฐ๋ฅํ PTE๋ก ๋ณ๊ฒฝ ์๋
#define MM_CP_PROT_NUMA (1UL << 1) // NUMA ๋ฐธ๋ฐ์ฑ์ฉ PROT_NONE
#define MM_CP_UFFD_WP (1UL << 2) // userfaultfd ์ฐ๊ธฐ ๋ณดํธ
#define MM_CP_UFFD_WP_RESOLVE (1UL << 3) // userfaultfd ์ฐ๊ธฐ ๋ณดํธ ํด์
#define MM_CP_UFFD_WP_ALL (MM_CP_UFFD_WP | MM_CP_UFFD_WP_RESOLVE)
* ํ์ผ: include/linux/mm.h:3031-3038
* MM_CP_TRY_CHANGE_WRITABLE: vma_wants_manual_pte_write_upgrade()๊ฐ true์ผ ๋ ์ค์
* MM_CP_PROT_NUMA: NUMA ๋ฐธ๋ฐ์ฑ์ด PROT_NONE์ผ๋ก ํ์ด์ง๋ฅผ ๋นํ์ฑํํ ๋ ์ฌ์ฉ
can_change_pte_writable โ PTE ์ฐ๊ธฐ ๋ณ๊ฒฝ ์กฐ๊ฑด
// mm/mprotect.c:97-104
bool can_change_pte_writable(struct vm_area_struct *vma, unsigned long addr,
pte_t pte)
{
if (!(vma->vm_flags & VM_SHARED))
return can_change_private_pte_writable(vma, addr, pte); // ๋น๊ณต์ : anon exclusive๋ง
return can_change_shared_pte_writable(vma, pte); // ๊ณต์ : dirty๋ฉด ํ์ฉ
}
* ํ์ผ: mm/mprotect.c:97-104
* MAP_PRIVATE: PageAnon(page) && PageAnonExclusive(page)์ธ ๊ฒฝ์ฐ๋ง ์ฐ๊ธฐ ๊ฐ๋ฅ
* MAP_SHARED: pte_dirty(pte)์ด๋ฉด writenotify ๋ถํ์ํ๋ฏ๋ก ์ฐ๊ธฐ ๊ฐ๋ฅ
ํต์ฌ ํจ์
1. do_mprotect_pkey() โ ์์คํ ํธ์ถ ์ง์ ์
// mm/mprotect.c:801-946
static int do_mprotect_pkey(unsigned long start, size_t len,
unsigned long prot, int pkey)
* ์ญํ : mprotect()/pkey_mprotect() ์์คํ
ํธ์ถ์ ๊ณตํต ์ฒ๋ฆฌ ํจ์
* ๋ถ๊ธฐ ๋ก์ง:
1. PROT_GROWSDOWN|PROT_GROWSUP ๋์ ์ค์ ์ EINVAL
2. mmap_write_lock_killable()๋ก mmap_lock ํ๋
3. pkey๊ฐ -1์ด ์๋๋ฉด mm_pkey_is_allocated()๋ก ํ ๋น ๊ฒ์ฆ
4. vma_find()๋ก ๋์ VMA ํ์, ์์ผ๋ฉด ENOMEM
5. PROT_GROWSDOWN/PROT_GROWSUP ์ฒ๋ฆฌ๋ก start/end ๋ฒ์ ํ์ฅ
6. for_each_vma_range()๋ก ๊ฐ VMA์ ๋ํด:
- rier(READ_IMPLIES_EXEC) ์ฒ๋ฆฌ
- calc_vm_prot_bits()๋ก newflags ๊ณ์ฐ
- VM_ACCESS_FLAGS ๊ฒ์ฆ โ ๊ถํ ์๋ ํ๋๊ทธ ์์ฒญ ์ EACCES
- map_deny_write_exec()๋ก MDWE ์๋ฐ ๊ฒ์ฌ
- security_file_mprotect()๋ก LSM ๊ฒ์ฆ
- vma->vm_ops->mprotect() ์ฝ๋ฐฑ ํธ์ถ (ํ์ผ ์์คํ
๋ณ)
- mprotect_fixup()๋ก ์ค์ VMA ์์
7. tlb_finish_mmu()๋ก TLB ํ๋ฌ์
2. mprotect_fixup() โ VMA ๋ณดํธ ์์
// mm/mprotect.c:695-796
int mprotect_fixup(struct vma_iterator *vmi, struct mmu_gather *tlb,
struct vm_area_struct *vma, struct vm_area_struct **pprev,
unsigned long start, unsigned long end, vm_flags_t newflags)
* ์ญํ : ๋จ์ผ VMA์ ๋ณดํธ ์์ฑ์ ์ค์ ๋ก ๋ณ๊ฒฝ
* ๋ถ๊ธฐ ๋ก์ง:
1. vma_is_sealed(vma) โ EPERM (๋ด์ธ๋ VMA ๊ฑฐ๋ถ)
2. newflags == oldflags โ ์ฆ์ ๋ฐํ
3. VM_PFNMAP|VM_MIXEDMAP์ด๊ณ VM_ACCESS_FLAGS ์ ๊ฑฐ ์ walk_page_range()๋ก PROT_NONE ์ฌ์ ๊ฒ์ฆ
4. VM_WRITE ์ถ๊ฐ ์ ์ค๋ฒ์ปค๋ฐ ๊ฒ์ฆ (may_expand_vm, security_vm_enough_memory_mm)
5. VM_ACCOUNT ํด์ ์ vm_unacct_memory()
6. vma_modify_flags()๋ก VMA ๋ณํฉ/๋ถํ ์ฒ๋ฆฌ
7. vma_start_write() โ vm_flags_reset_once() โ vma_set_page_prot()
8. change_protection()๋ก ํ์ด์ง ํ
์ด๋ธ ์
๋ฐ์ดํธ
9. VM_LOCKED โ writable ์ ํ ์ populate_vma_page_range()๋ก COW ํธ๋ฆฌ๊ฑฐ
3. change_protection() โ ํ์ด์ง ํ ์ด๋ธ ๋ณดํธ ๋ณ๊ฒฝ
// mm/mprotect.c:633-662
long change_protection(struct mmu_gather *tlb,
struct vm_area_struct *vma, unsigned long start,
unsigned long end, unsigned long cp_flags)
* ์ญํ : ์ง์ ๋ ์ฃผ์ ๋ฒ์์ ํ์ด์ง ํ ์ด๋ธ ๋ณดํธ ์์ฑ์ ๋ณ๊ฒฝ
* ๋ถ๊ธฐ ๋ก์ง:
1. NUMA ๋ฐธ๋ฐ์ฑ์ด๋ฉด newprot = PAGE_NONE (PROT_NONE์ผ๋ก ๋นํ์ฑํ)
2. Hugetlb ํ์ด์ง๋ฉด hugetlb_change_protection() ๋ถ๊ธฐ
3. ์ผ๋ฐ ํ์ด์ง๋ฉด change_protection_range() ํธ์ถ
4. change_protection_range() โ change_pmd_range() โ change_pte_range()
ํ์ด์ง ํ ์ด๋ธ 5๋จ๊ณ(PGDโP4DโPUDโPMDโPTE)๋ฅผ ์ํํ๋ฉฐ ๋ณดํธ๋ฅผ ๋ณ๊ฒฝํ๋ ์ฌ๊ท ๊ตฌ์กฐ์ด๋ค.
change_protection_range() โ PGD ๋ ๋ฒจ ์ํ
โโ change_p4d_range() โ P4D ๋ ๋ฒจ ์ํ
โโ change_pud_range() โ PUD ๋ ๋ฒจ ์ํ (huge pud ์ฒ๋ฆฌ)
โโ change_pmd_range() โ PMD ๋ ๋ฒจ ์ํ (huge pmd ์ฒ๋ฆฌ)
โโ change_pte_range() โ ์ค์ PTE ์์
5. change_pte_range() โ PTE ๋ ๋ฒจ ์ฒ๋ฆฌ
// mm/mprotect.c:214-386
static long change_pte_range(struct mmu_gather *tlb,
struct vm_area_struct *vma, pmd_t *pmd, unsigned long addr,
unsigned long end, pgprot_t newprot, unsigned long cp_flags)
* ์ญํ : PTE ํ๋(๋๋ ๋ฐฐ์น)์ ๋ณดํธ ์์ฑ์ ๋ณ๊ฒฝ
* 3๊ฐ์ง PTE ์ํ ์ฒ๋ฆฌ:
1. pte_present(oldpte): ์กด์ฌํ๋ ํ์ด์ง โ pte_modify()๋ก ๋ณดํธ ๋ณ๊ฒฝ, uffd_wp/uffd_wp_resolve ์ฒ๋ฆฌ
2. pte_none(oldpte): ๋น PTE โ uffd_wp์ผ ๋ PTE_MARKER_UFFD_WP ๋ง์ปค ์ค์น
3. ๊ทธ ์ธ (์ค์/๋ง์ด๊ทธ๋ ์ด์
/๋๋ฐ์ด์ค): softleaf_t๋ก ํ์
๋ถ๋ฅ ํ ๋ง์ด๊ทธ๋ ์ด์
์ํธ๋ฆฌ, ๋๋ฐ์ด์ค ํ๋ผ์ด๋น ์ํธ๋ฆฌ, ๋ง์ปค ์ํธ๋ฆฌ ๊ฐ๊ฐ ์ฒ๋ฆฌ
* ๋ฐฐ์น ์ต์ ํ: mprotect_folio_pte_batch()๋ก large folio์ ์ฐ์ PTE๋ฅผ ํ๋ฒ์ ์ฒ๋ฆฌ
6. pkey_alloc / pkey_free / pkey_mprotect โ ๋ฉ๋ชจ๋ฆฌ ๋ณดํธ ํค
// mm/mprotect.c:956-1005
SYSCALL_DEFINE4(pkey_mprotect, unsigned long, start, size_t, len,
unsigned long, prot, int, pkey)
SYSCALL_DEFINE2(pkey_alloc, unsigned long, flags, unsigned long, init_val)
SYSCALL_DEFINE1(pkey_free, int, pkey)
* pkey_mprotect: pkey๋ฅผ ์ง์ ํ์ฌ mprotect ์ ์ฉ (x86 Memory Protection Keys)
* pkey_alloc: ์ ๋ณดํธ ํค ํ ๋น ํ arch_set_user_pkey_access()๋ก ๊ถํ ์ค์
* pkey_free: ๋ณดํธ ํค ํด์
ํธ์ถ ํ๋ฆ
sys_mprotect(start, len, prot)
โโ do_mprotect_pkey(start, len, prot, pkey=-1)
โโ mmap_write_lock_killable() โ mmap_lock ์ฐ๊ธฐ ์ ๊ธ
โโ vma_find() โ ๋์ VMA ํ์
โโ [for_each_vma_range] ๊ฐ VMA ๋ฐ๋ณต:
โ โโ calc_vm_prot_bits() โ PROT_* โ VM_* ๋ณํ
โ โโ map_deny_write_exec() โ MDWE ๊ฒ์ฆ
โ โโ security_file_mprotect() โ LSM ๋ณด์ ๊ฒ์ฆ
โ โโ vma->vm_ops->mprotect() โ ํ์ผ ์์คํ
์ฝ๋ฐฑ
โ โโ mprotect_fixup() โ VMA ์์
โ โโ vma_is_sealed() โ ๋ด์ธ ๊ฒ์ฌ
โ โโ vma_modify_flags() โ VMA ๋ณํฉ/๋ถํ
โ โโ vm_flags_reset_once() โ ํ๋๊ทธ ์
๋ฐ์ดํธ
โ โโ vma_set_page_prot() โ vm_page_prot ๊ฐฑ์
โ โโ change_protection() โ PTE ๋ณดํธ ๋ณ๊ฒฝ
โ โโ [Hugetlb] hugetlb_change_protection()
โ โโ [์ผ๋ฐ] change_protection_range()
โ โโ change_p4d_range() โ change_pud_range()
โ โ change_pmd_range()
โ โโ change_pte_range()
โ โโ pte_present: pte_modify + TLB flush
โ โโ pte_none: uffd-wp ๋ง์ปค ์ค์น
โ โโ swap/dev: softleaf ์ฒ๋ฆฌ
โโ tlb_finish_mmu() โ TLB ํ๋ฌ์ ์๋ฃ
์กฐ๊ฑด๋ณ ๋น๊ต
์์คํ ํธ์ถ๋ณ ๋น๊ต
| ํญ๋ชฉ | mprotect() | pkey_mprotect() | pkey_alloc() | pkey_free() |
|---|---|---|---|---|
| ์์คํ ํธ์ถ ๋ฒํธ | SYSCALL_DEFINE3 | SYSCALL_DEFINE4 | SYSCALL_DEFINE2 | SYSCALL_DEFINE1 |
| pkey ๋งค๊ฐ๋ณ์ | -1 (์์) | ์ฌ์ฉ์ ์ง์ | ๋ฐํ๊ฐ | ํด์ ๋์ |
| ๋ฉ๋ชจ๋ฆฌ ๋ณดํธ ํค | ๋ถ๊ฐ | ๊ฐ๋ฅ | ํ ๋น๋ง | ํด์ ๋ง |
| CONFIG_ARCH_HAS_PKEYS | ๋ถํ์ | ํ์ | ํ์ | ํ์ |
| ๋ด๋ถ ์ฒ๋ฆฌ | do_mprotect_pkey(start,len,prot,-1) | do_mprotect_pkey(start,len,prot,pkey) | mm_pkey_alloc + arch_set_user_pkey_access | mm_pkey_free |
PTE ๋ณดํธ ๋ณ๊ฒฝ ์กฐ๊ฑด๋ณ ๋ถ๊ธฐ
| ์กฐ๊ฑด | ์ฒ๋ฆฌ ๋ฐฉ์ | ์ฝ๋ ์์น |
|---|---|---|
| pte_present && prot_numa && pte_protnone | ๊ฑด๋๋ (์ด๋ฏธ PROT_NONE) | mprotect.c:248-249 |
| pte_present && prot_numa && !folio_can_map_prot_numa | ๋ฐฐ์น ๊ฑด๋๋ | mprotect.c:259-267 |
| pte_present && !prot_numa | pte_modify() + writable ์๋ | mprotect.c:269-299 |
| pte_none && uffd_wp && userfaultfd_wp_use_markers | PTE_MARKER_UFFD_WP ์ค์น | mprotect.c:308-318 |
| pte_none && !uffd_wp | ๊ฑด๋๋ | mprotect.c:305-306 |
| swap/migration entry | softleaf ํ์ ๋ณ ์ฒ๋ฆฌ | mprotect.c:320-379 |
| uffd_wp_resolve && pte_none marker | pte_clear() | mprotect.c:362-364 |
COW/์ฐ๊ธฐ ๊ด๋ จ ๋ถ๊ธฐ
| VMA ํ์ | ์ฐ๊ธฐ ๊ฐ๋ฅ ์กฐ๊ฑด | ์ฝ๋ ์์น |
|---|---|---|
| MAP_PRIVATE (๋น๊ณต์ ) | PageAnon && PageAnonExclusive | mprotect.c:61-77 |
| MAP_SHARED (๊ณต์ ) | pte_dirty (์ด๋ฏธ ์ฐ๊ธฐ๋จ) | mprotect.c:79-95 |
| MAP_PRIVATE + VM_LOCKED โ writable | populate_vma_page_range()๋ก COW ํธ๋ฆฌ๊ฑฐ | mprotect.c:783-786 |
| writenotify ํ์ํ ๊ณต์ ๋งคํ | pte_clean์ผ๋ก ์ฐ๊ธฐ ๋ถ๊ฐ ์ ์ง | mprotect.c:88-94 |
ํต์ฌ ํ๋ฆ: PTE ์ฐ๊ธฐ ๋ณ๊ฒฝ ์ต์ ํ
Linux 7.0์ mprotect๋ large folio์์ ์ฐ์๋ PTE๋ฅผ ๋ฐฐ์น(batching)๋ก ์ฒ๋ฆฌํ์ฌ ์ฑ๋ฅ์ ํฅ์์ํจ๋ค.
change_pte_range()
โโ mprotect_folio_pte_batch() โ large folio์์ ์ฒ๋ฆฌํ PTE ์ ๊ณ์ฐ
โ โโ folio_pte_batch_flags() โ ์ฐ์ PTE ์ค์บ
โโ modify_prot_start_ptes() โ ๋ฐฐ์น ์์ (read-modify-write ํธ๋์ญ์
)
โโ pte_modify() โ ์ ๋ณดํธ ์์ฑ ์ ์ฉ
โโ [MM_CP_TRY_CHANGE_WRITABLE]
โ โโ set_write_prot_commit_flush_ptes() โ ์ฐ๊ธฐ ๊ฐ๋ฅ ์ฌ๋ถ ๊ฒฐ์
โ โโ [๊ณต์ ] can_change_shared_pte_writable()
โ โโ [๋น๊ณต์ ] commit_anon_folio_batch()
โ โโ page_anon_exclusive_sub_batch() โ ํ์ด์ง๋ณ exclusive ๊ฒ์ฆ
โโ modify_prot_commit_ptes() โ ๋ฐฐ์น ์ปค๋ฐ + TLB flush