mprotect(2) - wariua/manpages-ko GitHub Wiki

NAME

mprotect, pkey_mprotect - λ©”λͺ¨λ¦¬ μ˜μ—­μ— 보호 μ„€μ •ν•˜κΈ°

SYNOPSIS

#include <sys/mman.h>

int mprotect(void *addr, size_t len, int prot);

#define _GNU_SOURCE             /* feature_test_macros(7) μ°Έκ³  */
#include <sys/mman.h>

int pkey_mprotect(void *addr, size_t len, int prot, int pkey);

DESCRIPTION

mprotect()λŠ” [addr, addr+len-1] ꡬ간 μ£Όμ†Œ λ²”μœ„λ₯Ό 일뢀라도 λ‹΄κ³  μžˆλŠ” 호좜 ν”„λ‘œμ„ΈμŠ€μ˜ λ©”λͺ¨λ¦¬ νŽ˜μ΄μ§€λ“€μ— λŒ€ν•œ μ ‘κ·Ό 보호λ₯Ό λ³€κ²½ν•œλ‹€. addr이 νŽ˜μ΄μ§€ 경계에 맞게 μ •λ ¬λ˜μ–΄ μžˆμ–΄μ•Ό ν•œλ‹€.

호좜 ν”„λ‘œμ„ΈμŠ€μ—μ„œ κ·Έ 보호λ₯Ό μœ„λ°˜ν•˜λŠ” λ°©μ‹μœΌλ‘œ λ©”λͺ¨λ¦¬μ— μ ‘κ·Όν•˜λ € μ‹œλ„ν•˜λ©΄ 컀널이 κ·Έ ν”„λ‘œμ„ΈμŠ€μ— SIGSEGV μ‹œκ·Έλ„μ„ μƒμ„±ν•œλ‹€.

protλŠ” PROT_NONEμ΄κ±°λ‚˜ λ‹€μŒ λͺ©λ‘μ˜ λ‹€λ₯Έ 값듀을 λΉ„νŠΈ OR ν•œ 것이닀.

PROT_NONE
λ©”λͺ¨λ¦¬μ— μ „ν˜€ μ ‘κ·Όν•  수 μ—†λ‹€.
PROT_READ
λ©”λͺ¨λ¦¬λ₯Ό 읽을 수 μžˆλ‹€.
PROT_WRITE
λ©”λͺ¨λ¦¬λ₯Ό λ³€κ²½ν•  수 μžˆλ‹€.
PROT_EXEC
λ©”λͺ¨λ¦¬λ₯Ό μ‹€ν–‰ν•  수 μžˆλ‹€.
PROT_SEM (λ¦¬λˆ…μŠ€ 2.5.7λΆ€ν„°)
λ©”λͺ¨λ¦¬λ₯Ό μ›μž 연산에 μ“Έ 수 μžˆλ‹€. 이 ν”Œλž˜κ·ΈλŠ” futex(2) κ΅¬ν˜„μ˜ μΌλΆ€λ‘œμ„œ (FUTEX_WAIT 같은 λͺ…령에 ν•„μš”ν•œ μ›μž μ—°μ‚° μˆ˜ν–‰μ΄ κ°€λŠ₯함을 보μž₯ν•˜κΈ° μœ„ν•΄) λ„μž…λ˜μ—ˆλŠ”λ° ν˜„μž¬λŠ” μ–΄λŠ μ•„ν‚€ν…μ²˜μ—μ„œλ„ μ“°μ§€ μ•ŠλŠ”λ‹€.
PROT_SAO (λ¦¬λˆ…μŠ€ 2.6.26λΆ€ν„°)
λ©”λͺ¨λ¦¬μ— κ°•ν•œ μ ‘κ·Ό μˆœμ„œ(strong access ordering)κ°€ μžˆμ–΄μ•Ό ν•œλ‹€. 이 κΈ°λŠ₯은 PowerPC μ•„ν‚€ν…μ²˜μ— ν•œμ •λœ 것이닀. (μ•„ν‚€ν…μ²˜ λͺ…μ„Έ 2.06 λ²„μ „μ—μ„œ SAO CPU κΈ°λŠ₯을 μΆ”κ°€ν•˜λ©° POWER 7μ΄λ‚˜ PowerPC A2 λ“±μ—μ„œ μ‚¬μš© κ°€λŠ₯ν•˜λ‹€.)

μΆ”κ°€λ‘œ (λ¦¬λˆ…μŠ€ 2.6.0λΆ€ν„°) prot에 λ‹€μŒ ν”Œλž˜κ·Έλ“€ 쀑 ν•˜λ‚˜λ₯Ό μ„€μ •ν•  수 μžˆλ‹€.

PROT_GROWSUP
μœ„λ‘œ μžλΌλŠ” λ§€ν•‘μ˜ λμ κΉŒμ§€ 보호 λͺ¨λ“œλ₯Ό μ μš©ν•œλ‹€. (μŠ€νƒμ΄ μœ„λ‘œ μžλΌλŠ”, κ°€λ Ή HP-PARISC 같은 μ•„ν‚€ν…μ²˜μ—μ„œ μŠ€νƒ μ˜μ—­μ— 그런 맀핑을 λ§Œλ“ λ‹€.)
PROT_GROWSDOWN
μ•„λž˜λ‘œ μžλΌλŠ” λ§€ν•‘μ˜ μ‹œμž‘μ κΉŒμ§€ 보호 λͺ¨λ“œλ₯Ό μ μš©ν•œλ‹€. (μŠ€νƒ μ„Έκ·Έλ¨ΌνŠΈμ΄κ±°λ‚˜ MMAP_GROWSDOWN ν”Œλž˜κ·Έλ₯Ό μ„€μ •ν•΄ λ§΅ ν•œ μ„Έκ·Έλ¨ΌνŠΈμΌ 것이닀.)

mprotect()처럼 pkey_mprotect()λŠ” addrκ³Ό len으둜 μ§€μ •ν•œ νŽ˜μ΄μ§€λ“€μ˜ 보호λ₯Ό λ³€κ²½ν•œλ‹€. pkey μΈμžλŠ” κ·Έ λ©”λͺ¨λ¦¬μ— ν• λ‹Ήν•œ 보호 ν‚€(pkeys(7) μ°Έκ³ )λ₯Ό λ‚˜νƒ€λ‚Έλ‹€. 보호 ν‚€λŠ” pkey_alloc(2)으둜 ν• λ‹Ήν•΄μ„œ pkey_mprotect()μ—κ²Œ 전달해야 ν•œλ‹€. 이 μ‹œμŠ€ν…œ 호좜의 μ‚¬μš©λ‘€λŠ” pkeys(7)λ₯Ό 보라.

RETURN VALUE

성곡 μ‹œ mprotect()와 pkey_mprotect()λŠ” 0을 λ°˜ν™˜ν•œλ‹€. 였λ₯˜ μ‹œ 이 μ‹œμŠ€ν…œ ν˜ΈμΆœλ“€μ€ -1을 λ°˜ν™˜ν•˜λ©° errnoλ₯Ό 적절히 μ„€μ •ν•œλ‹€.

ERRORS

EACCES
μ§€μ •ν•œ μ ‘κ·ΌκΆŒμ„ λ©”λͺ¨λ¦¬μ— 쀄 수 μ—†λ‹€. 예λ₯Ό λ“€μ–΄ 읽기 μ „μš©μœΌλ‘œλ§Œ μ ‘κ·Όν•  수 μžˆλŠ” νŒŒμΌμ„ mmap(2) ν•˜κ³ μ„œ mprotect()μ—κ²Œ PROT_WRITE ν‘œμ‹œλ₯Ό ν•˜λΌκ³  ν•˜λŠ” κ²½μš°μ— λ°œμƒν•  수 μžˆλ‹€.
EINVAL
addr이 μœ νš¨ν•œ 포인터가 μ•„λ‹ˆκ±°λ‚˜ μ‹œμŠ€ν…œ νŽ˜μ΄μ§€ 크기의 λ°°μˆ˜κ°€ μ•„λ‹ˆλ‹€.
EINVAL
(pkey_mprotect()) pkeyκ°€ pkey_alloc(2)으둜 ν• λ‹Ήλœ 것이 μ•„λ‹ˆλ‹€.
EINVAL
prot에 PROT_GROWSUPκ³Ό PROT_GROWSDOWN을 λͺ¨λ‘ μ§€μ •ν–ˆλ‹€.
EINVAL
prot에 μœ νš¨ν•˜μ§€ μ•Šμ€ ν”Œλž˜κ·Έλ₯Ό μ§€μ •ν–ˆλ‹€.
EINVAL
(PowerPC μ•„ν‚€ν…μ²˜) prot에 PROT_SAOλ₯Ό μ§€μ •ν–ˆμ§€λ§Œ SAO ν•˜λ“œμ›¨μ–΄ κΈ°λŠ₯이 μ‚¬μš© κ°€λŠ₯ν•˜μ§€ μ•Šλ‹€.
ENOMEM
λ‚΄λΆ€ 컀널 ꡬ쑰체λ₯Ό ν• λ‹Ήν•  수 μ—†λ‹€.
ENOMEM
[addr, addr+len-1] ꡬ간 λ‚΄μ˜ μ£Όμ†Œκ°€ ν”„λ‘œμ„ΈμŠ€μ˜ μ£Όμ†Œ κ³΅κ°„μ—μ„œ μœ νš¨ν•˜μ§€ μ•Šκ±°λ‚˜, ν•œ 개 μ΄μƒμ˜ λ§΅ λ˜μ§€ μ•Šμ€ νŽ˜μ΄μ§€λ₯Ό λ‚˜νƒ€λ‚Έλ‹€. (컀널 2.4.19 μ „μ—μ„œλŠ” 이 κ²½μš°μ— 잘λͺ»ν•΄μ„œ EFAULT 였λ₯˜λ₯Ό μƒμ„±ν–ˆλ‹€.)
ENOMEM
λ©”λͺ¨λ¦¬ μ˜μ—­μ˜ 보호λ₯Ό λ³€κ²½ν•˜λ©΄ μƒμ΄ν•œ 속성(κ°€λ Ή 읽기 λ³΄ν˜Έμ™€ 읽기/μ“°κΈ° 보호)의 λ§€ν•‘ μ΄κ°œμˆ˜κ°€ ν—ˆμš© μ΅œλŒ€μΉ˜λ₯Ό μ΄ˆκ³Όν•˜κ²Œ λœλ‹€. (예λ₯Ό λ“€μ–΄ ν˜„μž¬ PROT_READ|PROT_WRITE둜 λ³΄ν˜Έν•˜λŠ” μ˜μ—­ μ€‘κ°„μ˜ μ–΄λŠ λ²”μœ„λ₯Ό PROT_READ 보호둜 λ§Œλ“€λ©΄ μ–‘μͺ½μ˜ 읽기/μ“°κΈ° λ§€ν•‘κ³Ό κ°€μš΄λ°μ˜ 읽기 μ „μš© 맀핑을 ν•©μ³μ„œ μ„Έ 개 맀핑이 생긴닀.)

VERSIONS

λ¦¬λˆ…μŠ€ 4.9μ—μ„œ pkey_mprotect()κ°€ 처음 λ“±μž₯ν–ˆλ‹€. glibc 2.27μ—μ„œ 라이브러리 지원이 μΆ”κ°€λ˜μ—ˆλ‹€.

CONFORMING TO

mprotect(): POSIX.1-2001, POSIX.1-2008, SVr4. POSIXμ—μ„œλŠ” mmap(2)을 톡해 얻은 것이 μ•„λ‹Œ λ©”λͺ¨λ¦¬ μ˜μ—­μ— 적용 μ‹œ mprotect()의 λ™μž‘ 방식이 λͺ…μ„Έλ˜μ–΄ μžˆμ§€ μ•Šλ‹€κ³  ν•œλ‹€.

pkey_mprotect()λŠ” 이식성 μ—†λŠ” λ¦¬λˆ…μŠ€ ν™•μž₯이닀.

NOTES

λ¦¬λˆ…μŠ€μ—μ„œλŠ” ν”„λ‘œμ„ΈμŠ€ μ£Όμ†Œ 곡간 λ‚΄μ˜ (컀널 vsyscall μ˜μ—­μ„ μ œμ™Έν•œ) μ–΄λŠ μ£Όμ†Œμ—λ„ mprotect() ν˜ΈμΆœμ„ 항상 ν—ˆμš©ν•œλ‹€. 특히 이λ₯Ό μ΄μš©ν•΄ 기쑴의 μ½”λ“œ 맀핑을 μ“°κΈ° κ°€λŠ₯으둜 λ°”κΏ€ 수 μžˆλ‹€.

PROT_EXEC에 PROT_READμ™€λŠ” λ‹€λ₯Έ μ–΄λ–€ 효λ ₯이 μžˆλŠ”μ§€ μ—¬λΆ€λŠ” ν”„λ‘œμ„Έμ„œ μ•„ν‚€ν…μ²˜, 컀널 버전, ν”„λ‘œμ„ΈμŠ€ μƒνƒœμ— 따라 μ •ν•΄μ§„λ‹€. ν”„λ‘œμ„ΈμŠ€ 인격 ν”Œλž˜κ·Έ(personality(2) μ°Έκ³ )에 READ_IMPLIES_EXECκ°€ 섀정돼 있으면 PROT_READλ₯Ό μ§€μ •ν•  λ•Œ PROT_EXECκ°€ μ•”λ¬΅μ μœΌλ‘œ μΆ”κ°€λœλ‹€.

일뢀 ν•˜λ“œμ›¨μ–΄ μ•„ν‚€ν…μ²˜(κ°€λ Ή i386)μ—μ„œλŠ” PROT_WRITEκ°€ PROT_READλ₯Ό ν•¨μ˜ν•œλ‹€.

POSIX.1μ—μ„œλŠ” κ΅¬ν˜„μ—μ„œ prot에 μ§€μ •λœ 것 μ΄μ™Έμ˜ 접근을 ν—ˆμš©ν•  μˆ˜λ„ 있되, μ΅œμ†Œν•œμœΌλ‘œλŠ” PROT_WRITEκ°€ μ„€μ •λœ κ²½μš°μ—λ§Œ μ“°κΈ° 접근을 ν—ˆμš©ν•  수 있고 PROT_NONE이 μ„€μ •λœ κ²½μš°μ—λŠ” μ–΄λ–€ 접근도 ν—ˆμš©ν•΄μ„  μ•ˆ λœλ‹€κ³  ν•œλ‹€.

μ‘μš©μ—μ„œ mprotect()와 pkey_mprotect()λ₯Ό μ„žμ–΄μ„œ μ‚¬μš©ν•  λ•ŒλŠ” μ£Όμ˜ν•΄μ•Ό ν•œλ‹€. x86μ—μ„œ protλ₯Ό PROT_EXEC둜 μ„€μ •ν•΄μ„œ mprotect()λ₯Ό μ“°λ©΄ μ»€λ„μ—μ„œ μ•”λ¬΅μ μœΌλ‘œ pkeyλ₯Ό ν• λ‹Ήν•΄μ„œ λ©”λͺ¨λ¦¬μ— μ„€μ •ν•  μˆ˜λ„ μžˆλ‹€. 단 pkeyκ°€ μ•žμ„œ 0μ΄μ—ˆμ„ λ•Œλ§Œ κ·Έλ ‡κ²Œ ν•œλ‹€.

ν•˜λ“œμ›¨μ–΄μ—μ„œ 보호 ν‚€λ₯Ό μ§€μ›ν•˜μ§€ μ•ŠλŠ” μ‹œμŠ€ν…œμ—μ„œλ„ pkey_mprotect()λ₯Ό μ“Έ μˆ˜λŠ” μžˆμ§€λ§Œ pkeyλ₯Ό -1둜 μ„€μ •ν•΄μ•Ό ν•œλ‹€. κ·Έλ ‡κ²Œ ν˜ΈμΆœν•  λ•Œ pkey_mprotect()의 λ™μž‘μ€ mprotect()와 λ™λ“±ν•˜λ‹€.

EXAMPLE

μ•„λž˜ ν”„λ‘œκ·Έλž¨μ€ mprotect() μ‚¬μš© 방식을 보여 μ€€λ‹€. ν”„λ‘œκ·Έλž¨μ—μ„œ λ©”λͺ¨λ¦¬ νŽ˜μ΄μ§€ 4개λ₯Ό ν• λ‹Ήν•΄μ„œ κ·Έ 쀑 μ„Έ 번째λ₯Ό 읽기 μ „μš©μœΌλ‘œ λ§Œλ“  λ‹€μŒ ν• λ‹Ή μ˜μ—­μ„ μœ„λ‘œ ν›‘μœΌλ©΄μ„œ λ°”μ΄νŠΈλ₯Ό λ³€κ²½ν•˜λŠ” 루프λ₯Ό μ‹€ν–‰ν•œλ‹€.

λ‹€μŒμ€ ν”„λ‘œκ·Έλž¨ μ‹€ν–‰ μ‹œ λ³Ό 수 μžˆμ„ 좜λ ₯ μ˜ˆμ΄λ‹€.

$ ./a.out
Start of region:        0x804c000
Got SIGSEGV at address: 0x804e000

ν”„λ‘œκ·Έλž¨ μ†ŒμŠ€

#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/mman.h>

#define handle_error(msg) \
    do { perror(msg); exit(EXIT_FAILURE); } while (0)

static char *buffer;

static void
handler(int sig, siginfo_t *si, void *unused)
{
    /* 주의: μ‹œκ·Έλ„ ν•Έλ“€λŸ¬μ—μ„œ printf()λ₯Ό ν˜ΈμΆœν•˜λŠ” 것은 μ•ˆμ „ν•˜μ§€
       μ•Šλ‹€. (λ”°λΌμ„œ μ‹€μ œ μ‚¬μš©ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ—μ„œλŠ” ν•˜μ§€ 말아야
       ν•œλ‹€.) printf()κ°€ 비동기 μ‹œκ·Έλ„ μ•ˆμ „μ΄ μ•„λ‹ˆκΈ° λ•Œλ¬Έμ΄λ‹€.
       signal-safety(7) μ°Έκ³ . κ·ΈλŸΌμ—λ„ λΆˆκ΅¬ν•˜κ³  ν•Έλ“€λŸ¬κ°€ 호좜된
       것을 κ°„λ‹¨νžˆ 보여 μ£ΌκΈ° μœ„ν•΄ 여기에 printf()λ₯Ό μ‚¬μš©ν•œλ‹€. */

    printf("Got SIGSEGV at address: 0x%lx\n",
            (long) si->si_addr);
    exit(EXIT_FAILURE);
}

int
main(int argc, char *argv[])
{
    char *p;
    int pagesize;
    struct sigaction sa;

    sa.sa_flags = SA_SIGINFO;
    sigemptyset(&sa.sa_mask);
    sa.sa_sigaction = handler;
    if (sigaction(SIGSEGV, &sa, NULL) == -1)
        handle_error("sigaction");

    pagesize = sysconf(_SC_PAGE_SIZE);
    if (pagesize == -1)
        handle_error("sysconf");

    /* νŽ˜μ΄μ§€ 경계에 맞게 μ •λ ¬λœ 버퍼 ν• λ‹Ή.
       초기 보호 방식은 PROT_READ | PROT_WRITE */

    buffer = memalign(pagesize, 4 * pagesize);
    if (buffer == NULL)
        handle_error("memalign");

    printf("Start of region:        0x%lx\n", (long) buffer);

    if (mprotect(buffer + pagesize * 2, pagesize,
                PROT_READ) == -1)
        handle_error("mprotect");

    for (p = buffer ; ; )
        *(p++) = 'a';

    printf("Loop completed\n");     /* μ ˆλŒ€ μ—¬κΈ°κΉŒμ§€ μ˜€μ§€ μ•ŠμŒ */
    exit(EXIT_SUCCESS);
}

SEE ALSO

mmap(2), sysconf(3), pkeys(7)


2019-08-02

⚠️ **GitHub.com Fallback** ⚠️