๏ปฟ# process_vm_readv/writev ๐Ÿ‘ฅ

๊ด€๋ จ ์†Œ์Šค: mm/process_vm_access.c, include/linux/uio.h, include/linux/mm_types.h

๊ฐœ์š” (Overview)

process_vm_readv๊ณผ process_vm_writev๋Š” ํ”„๋กœ์„ธ์Šค ๊ฐ„ ๋ฉ”๋ชจ๋ฆฌ ์ง์ ‘ ์ ‘๊ทผ์„ ์œ„ํ•œ ์‹œ์Šคํ…œ ํ˜ธ์ถœ์ž…๋‹ˆ๋‹ค. ๊ธฐ์กด์˜ ptrace(PTRACE_PEEKDATA)๋‚˜ ํŒŒ์ดํ”„/์†Œ์ผ“์„ ํ†ตํ•œ ๊ฐ„์ ‘ ์ „์†ก๊ณผ ๋‹ฌ๋ฆฌ, ์ปค๋„์ด ๋‘ ํ”„๋กœ์„ธ์Šค์˜ ๊ฐ€์ƒ ์ฃผ์†Œ ๊ณต๊ฐ„์— ์ง์ ‘ ์ ‘๊ทผํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ƒ๋Œ€๋ฐฉ ํ”„๋กœ์„ธ์Šค์˜ ๊ฐ€์ƒ ์ฃผ์†Œ๋ฅผ ํ•˜๋‚˜์˜ ์‹œ์Šคํ…œ ํ˜ธ์ถœ๋กœ ์—ฌ๋Ÿฌ ๋ฒˆ ์ฝ๊ฑฐ๋‚˜ ์“ธ ์ˆ˜ ์žˆ์–ด ์„ฑ๋Šฅ๊ณผ ํŽธ์˜์„ฑ์ด ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค.

์‹œ์Šคํ…œ ํ˜ธ์ถœ์€ ์‚ฌ์šฉ์ž ์ œ๊ณต iovec ๋ฐฐ์—ด์„ ํ†ตํ•ด ๋กœ์ปฌ๊ณผ ์›๊ฒฉ ์ฃผ์†Œ ์˜์—ญ์„ ์ง€์ •ํ•˜๋ฉฐ, ์ปค๋„ ๋‚ด๋ถ€์—์„œ pin_user_pages_remote()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์›๊ฒฉ ํ”„๋กœ์„ธ์Šค์˜ ํŽ˜์ด์ง€๋ฅผ ๊ณ ์ •(pinning)ํ•œ ํ›„ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์—์„œ mm_access()๋ฅผ ํ†ตํ•ด ๋Œ€์ƒ ํ”„๋กœ์„ธ์Šค์˜ mm_struct์— ์ ‘๊ทผ ๊ถŒํ•œ์„ ์–ป์–ด์•ผ ํ•˜๋ฉฐ, PTRACE_MODE_ATTACH_REALCREDS ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

/* mm/process_vm_access.c โ€” ์‹œ์Šคํ…œ ํ˜ธ์ถœ ์ •์˜ (๋ผ์ธ 292-305) */
SYSCALL_DEFINE6(process_vm_readv, pid_t, pid, const struct iovec __user *, lvec,
		unsigned long, liovcnt, const struct iovec __user *, rvec,
		unsigned long, riovcnt,	unsigned long, flags)
{
	return process_vm_rw(pid, lvec, liovcnt, rvec, riovcnt, flags, 0);
}

SYSCALL_DEFINE6(process_vm_writev, pid_t, pid,
		const struct iovec __user *, lvec,
		unsigned long, liovcnt, const struct iovec __user *, rvec,
		unsigned long, riovcnt,	unsigned long, flags)
{
	return process_vm_rw(pid, lvec, liovcnt, rvec, riovcnt, flags, 1);
}

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

# ๋Œ€์ƒ ํ”„๋กœ์„ธ์Šค์˜ ๋ฉ”๋ชจ๋ฆฌ ๋งคํ•‘ ํ™•์ธ
cat /proc/<pid>/maps

# process_vm_readv/writev ์‹œ์Šคํ…œ ํ˜ธ์ถœ ์ถ”์ 
strace -e process_vm_readv,process_vm_writev <command>

# ํ˜„์žฌ ํ”„๋กœ์„ธ์Šค์˜ RSS ํ™•์ธ
cat /proc/self/status | grep VmRSS

# ์ปค๋„ ๋กœ๊ทธ์—์„œ ๊ด€๋ จ fault ๋ฉ”์‹œ์ง€ ํ™•์ธ
dmesg | grep -i "fault\|page"

# ์‹œ์Šคํ…œ ํ˜ธ์ถœ ํ†ต๊ณ„ ํ™•์ธ
cat /proc/self/syscall

# ๋Œ€์ƒ ํ”„๋กœ์„ธ์Šค์˜ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ๋ชจ๋‹ˆํ„ฐ๋ง
top -p <pid>

# iovec ๊ตฌ์กฐ์ฒด ํ™•์ธ (๋””๋ฒ„๊น…์šฉ)
strace -v -e process_vm_readv <command>

# ์ปค๋„ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ํ†ต๊ณ„
cat /proc/meminfo | grep -E "MemTotal|MemFree|MemAvailable"

# ํ”„๋กœ์„ธ์Šค์˜ ์—ด๋ฆฐ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ ํ™•์ธ
ls -la /proc/<pid>/fd

# ๋Œ€์ƒ ํ”„๋กœ์„ธ์Šค์˜ mm_struct ์ฃผ์†Œ ํ™•์ธ (crash ๋„๊ตฌ ์‚ฌ์šฉ ์‹œ)
crash> task_struct.mm <pid>

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

struct iov_iter โ€” I/O ๋ฒกํ„ฐ ๋ฐ˜๋ณต์ž

๋‹ค์–‘ํ•œ ์œ ํ˜•์˜ ๋ฒกํ„ฐ(iov, kvec, bvec ๋“ฑ)๋ฅผ ์ถ”์ƒํ™”ํ•˜์—ฌ ํ†ต์ผ๋œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. process_vm_access.c์—์„œ๋Š” ๋กœ์ปฌ๊ณผ ์›๊ฒฉ ์ฃผ์†Œ ์˜์—ญ์„ ์ˆœํšŒํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

/* include/linux/uio.h:43-83 */
struct iov_iter {
	u8 iter_type;          /* ๋ฐ˜๋ณต์ž ์œ ํ˜• (ITER_IOVEC ๋“ฑ) */
	bool nofault;          /* ํดํŠธ ์—†์ด ์ฒ˜๋ฆฌํ• ์ง€ ์—ฌ๋ถ€ */
	bool data_source;      /* ๋ฐ์ดํ„ฐ ์†Œ์Šค ๋ฐฉํ–ฅ (์ฝ๊ธฐ/์“ฐ๊ธฐ) */
	size_t iov_offset;     /* ํ˜„์žฌ ๋ฒกํ„ฐ ๋‚ด ์˜คํ”„์…‹ */
	union {
		struct iovec __ubuf_iovec;
		struct {
			union {
				const struct iovec *__iov;  /* iovec ๋ฐฐ์—ด ํฌ์ธํ„ฐ */
				const struct kvec *kvec;
				const struct bio_vec *bvec;
				const struct folio_queue *folioq;
				struct xarray *xarray;
				void __user *ubuf;
			};
			size_t count;             /* ๋‚จ์€ ๋ฐ”์ดํŠธ ์ˆ˜ */
		};
	};
	union {
		unsigned long nr_segs;           /* ์„ธ๊ทธ๋จผํŠธ ์ˆ˜ */
		u8 folioq_slot;
		loff_t xarray_start;
	};
};

struct mm_struct โ€” ํ”„๋กœ์„ธ์Šค ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊ตฌ์กฐ์ฒด

ํ”„๋กœ์„ธ์Šค์˜ ๊ฐ€์ƒ ์ฃผ์†Œ ๊ณต๊ฐ„, ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”, VMA ๋ชฉ๋ก ๋“ฑ์„ ๊ด€๋ฆฌํ•˜๋Š” ํ•ต์‹ฌ ๊ตฌ์กฐ์ฒด์ž…๋‹ˆ๋‹ค. process_vm_rw_core()์—์„œ mm_access()๋ฅผ ํ†ตํ•ด ํš๋“ํ•ฉ๋‹ˆ๋‹ค.

/* include/linux/mm_types.h:1123-1240 (์ผ๋ถ€) */
struct mm_struct {
	struct {
		struct {
			atomic_t mm_count;           /* mm_struct ์ฐธ์กฐ ์นด์šดํŠธ */
		} ____cacheline_aligned_in_smp;

		struct maple_tree mm_mt;         /* VMA ์ €์žฅ (maple tree) */
		unsigned long mmap_base;         /* mmap ์˜์—ญ ๊ธฐ์ค€ ์ฃผ์†Œ */
		unsigned long mmap_legacy_base;   /* ์•„๋ž˜์ชฝ ์„ฑ์žฅ mmap ๊ธฐ์ค€ ์ฃผ์†Œ */
		unsigned long task_size;         /* ์‚ฌ์šฉ์ž ์ฃผ์†Œ ๊ณต๊ฐ„ ํฌ๊ธฐ */
		pgd_t *pgd;                      /* ํŽ˜์ด์ง€ ๊ธ€๋กœ๋ฒŒ ๋””๋ ‰ํ† ๋ฆฌ */

		atomic_t mm_users;               /* ์‚ฌ์šฉ์ž ์ˆ˜ (mmget/mmput) */
		int map_count;                   /* VMA ๊ฐœ์ˆ˜ */

		spinlock_t page_table_lock;      /* ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ๋ณดํ˜ธ */
		struct rw_semaphore mmap_lock;   /* mmap ๋ณดํ˜ธ (์ฝ๊ธฐ/์“ฐ๊ธฐ ์ž ๊ธˆ) */

		unsigned long total_vm;          /* ์ด ๋งคํ•‘๋œ ํŽ˜์ด์ง€ ์ˆ˜ */
		unsigned long locked_vm;         /* ๊ณ ์ •๋œ ํŽ˜์ด์ง€ ์ˆ˜ */
		atomic64_t pinned_vm;            /* ์˜๊ตฌ ๊ณ ์ • ํŽ˜์ด์ง€ ์ˆ˜ */
	};
	/* ... */
};

struct task_struct โ€” ํƒœ์Šคํฌ ๊ตฌ์กฐ์ฒด (๋ฐœ์ทŒ)

process_vm_rw_core()์—์„œ find_get_task_by_vpid()๋ฅผ ํ†ตํ•ด ๋Œ€์ƒ ํ”„๋กœ์„ธ์Šค์˜ task_struct๋ฅผ ํš๋“ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด mm_struct์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

/* include/linux/sched.h:952-959 */
struct sched_info		sched_info;

struct list_head		tasks;
struct plist_node		pushable_tasks;
struct rb_node			pushable_dl_tasks;

struct mm_struct		*mm;
struct mm_struct		*active_mm;

struct iovec โ€” ์‚ฌ์šฉ์ž ๊ณต๊ฐ„ I/O ๋ฒกํ„ฐ

์‚ฌ์šฉ์ž ๊ณต๊ฐ„์—์„œ process_vm_readv/writev์— ์ „๋‹ฌ๋˜๋Š” ์ฃผ์†Œ-๊ธธ์ด ์Œ์ž…๋‹ˆ๋‹ค.

/* include/uapi/linux/uio.h */
struct iovec {
	void __user *iov_base;    /* ์‹œ์ž‘ ์ฃผ์†Œ */
	size_t iov_len;           /* ๊ธธ์ด (๋ฐ”์ดํŠธ) */
};

PVM_MAX_* ๋งคํฌ๋กœ โ€” ๋‚ด๋ถ€ ์ œํ•œ๊ฐ’

/* mm/process_vm_access.c:56-59 */
#define PVM_MAX_KMALLOC_PAGES 2
#define PVM_MAX_USER_PAGES (PVM_MAX_KMALLOC_PAGES * PAGE_SIZE / sizeof(struct page *))

/* mm/process_vm_access.c:136 */
#define PVM_MAX_PP_ARRAY_COUNT 16
์ž๋ฃŒ๊ตฌ์กฐ ๊ด€๊ณ„๋„

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

1. SYSCALL_DEFINE6(process_vm_readv/writev) โ€” ์‹œ์Šคํ…œ ํ˜ธ์ถœ ์ง„์ž…์ 

process_vm_rw()๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  vm_write ํ”Œ๋ž˜๊ทธ๋กœ ์ฝ๊ธฐ(0) ๋˜๋Š” ์“ฐ๊ธฐ(1)๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

  • ์ž…๋ ฅ: pid, lvec(๋กœ์ปฌ), liovcnt, rvec(์›๊ฒฉ), riovcnt, flags
  • ๋ฐ˜ํ™˜: ์ „์†ก๋œ ๋ฐ”์ดํŠธ ์ˆ˜ ๋˜๋Š” ์˜ค๋ฅ˜ ์ฝ”๋“œ
  • ์กฐ๊ฑด ๋ถ„๊ธฐ: flags != 0์ด๋ฉด -EINVAL ๋ฐ˜ํ™˜
  • 2. process_vm_rw() โ€” iovec ๊ฒ€์ฆ ๋ฐ ์ฝ”์–ด ํ˜ธ์ถœ

    ์‚ฌ์šฉ์ž ์ œ๊ณต iovec ๋ฐฐ์—ด์„ ์ปค๋„ ๊ณต๊ฐ„์œผ๋กœ ๊ฐ€์ ธ์˜ค๊ณ  import_iovec()๋กœ iov_iter๋ฅผ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

    /* mm/process_vm_access.c:254-290 */
    static ssize_t process_vm_rw(pid_t pid,
    			     const struct iovec __user *lvec,
    			     unsigned long liovcnt,
    			     const struct iovec __user *rvec,
    			     unsigned long riovcnt,
    			     unsigned long flags, int vm_write)
    {
    	/* ... */
    	int dir = vm_write ? ITER_SOURCE : ITER_DEST;
    
    	if (flags != 0)
    		return -EINVAL;
    
    	/* ๋กœ์ปฌ iovec์„ iov_iter๋กœ ๋ณ€ํ™˜ */
    	rc = import_iovec(dir, lvec, liovcnt, UIO_FASTIOV, &iov_l, &iter);
    	if (rc < 0)
    		return rc;
    	if (!iov_iter_count(&iter))
    		goto free_iov_l;
    
    	/* ์›๊ฒฉ iovec์„ ์ปค๋„ ๊ณต๊ฐ„์œผ๋กœ ๋ณต์‚ฌ */
    	iov_r = iovec_from_user(rvec, riovcnt, UIO_FASTIOV, iovstack_r,
    				in_compat_syscall());
    	if (IS_ERR(iov_r)) {
    		rc = PTR_ERR(iov_r);
    		goto free_iov_l;
    	}
    
    	rc = process_vm_rw_core(pid, &iter, iov_r, riovcnt, flags, vm_write);
    	/* ... */
    }
  • ์กฐ๊ฑด ๋ถ„๊ธฐ:
  • - flags != 0: -EINVAL ๋ฐ˜ํ™˜ (ํ˜„์žฌ ๋ฏธ์‚ฌ์šฉ)

    - iov_iter_count(&iter) == 0: ๋ฐ”๋กœ ๋ฐ˜ํ™˜

    - import_iovec() ์‹คํŒจ: ์˜ค๋ฅ˜ ์ฝ”๋“œ ๋ฐ˜ํ™˜

    3. process_vm_rw_core() โ€” ์ฝ”์–ด ์ฒ˜๋ฆฌ ๋ฃจํ‹ด

    ๋Œ€์ƒ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ฐพ๊ณ , mm_struct์— ์ ‘๊ทผํ•œ ํ›„, ๋ชจ๋“  ์›๊ฒฉ ๋ฒกํ„ฐ์— ๋Œ€ํ•ด process_vm_rw_single_vec()์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

    /* mm/process_vm_access.c:151-238 (์ผ๋ถ€) */
    static ssize_t process_vm_rw_core(pid_t pid, struct iov_iter *iter,
    				  const struct iovec *rvec,
    				  unsigned long riovcnt,
    				  unsigned long flags, int vm_write)
    {
    	struct task_struct *task;
    	struct page *pp_stack[PVM_MAX_PP_ARRAY_COUNT];
    	struct page **process_pages = pp_stack;
    	struct mm_struct *mm;
    	/* ... */
    
    	/* ๋Œ€์ƒ ํ”„๋กœ์„ธ์Šค ์ฐพ๊ธฐ */
    	task = find_get_task_by_vpid(pid);
    	if (!task) {
    		rc = -ESRCH;
    		goto free_proc_pages;
    	}
    
    	/* mm_struct ์ ‘๊ทผ ๊ถŒํ•œ ํš๋“ */
    	mm = mm_access(task, PTRACE_MODE_ATTACH_REALCREDS);
    	if (IS_ERR(mm)) {
    		rc = PTR_ERR(mm);
    		if (rc == -EACCES)
    			rc = -EPERM;  /* EACCES๋ฅผ EPERM์œผ๋กœ ๋ณ€ํ™˜ */
    		goto put_task_struct;
    	}
    
    	/* ๊ฐ ์›๊ฒฉ ๋ฒกํ„ฐ์— ๋Œ€ํ•ด ์ฒ˜๋ฆฌ */
    	for (i = 0; i < riovcnt && iov_iter_count(iter) && !rc; i++)
    		rc = process_vm_rw_single_vec(
    			(unsigned long)rvec[i].iov_base, rvec[i].iov_len,
    			iter, process_pages, mm, task, vm_write);
    
    	/* ์ „์†ก๋œ ๋ฐ”์ดํŠธ ์ˆ˜ ๊ณ„์‚ฐ */
    	total_len -= iov_iter_count(iter);
    	if (total_len)
    		rc = total_len;
    
    	mmput(mm);
    put_task_struct:
    	put_task_struct(task);
    free_proc_pages:
    	if (process_pages != pp_stack)
    		kfree(process_pages);
    	return rc;
    }
  • ์กฐ๊ฑด ๋ถ„๊ธฐ:
  • - find_get_task_by_vpid() ์‹คํŒจ: -ESRCH

    - mm_access() ์‹คํŒจ: -EACCES โ†’ -EPERM ๋ณ€ํ™˜

    - nr_pages == 0: ๋ฐ”๋กœ ๋ฐ˜ํ™˜

    4. process_vm_rw_single_vec() โ€” ๋‹จ์ผ ๋ฒกํ„ฐ ์ฒ˜๋ฆฌ

    ํ•˜๋‚˜์˜ ์›๊ฒฉ ๋ฒกํ„ฐ์— ๋Œ€ํ•ด ํŽ˜์ด์ง€๋ฅผ ๊ณ ์ •(pinning)ํ•˜๊ณ  ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค. pin_user_pages_remote()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์›๊ฒฉ ํ”„๋กœ์„ธ์Šค์˜ ํŽ˜์ด์ง€๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ๊ณ ์ •ํ•ฉ๋‹ˆ๋‹ค.

    /* mm/process_vm_access.c:73-132 (์ผ๋ถ€) */
    static int process_vm_rw_single_vec(unsigned long addr,
    				    unsigned long len,
    				    struct iov_iter *iter,
    				    struct page **process_pages,
    				    struct mm_struct *mm,
    				    struct task_struct *task,
    				    int vm_write)
    {
    	unsigned long pa = addr & PAGE_MASK;
    	unsigned long start_offset = addr - pa;
    	/* ... */
    
    	if (vm_write)
    		flags |= FOLL_WRITE;
    
    	while (!rc && nr_pages && iov_iter_count(iter)) {
    		int pinned_pages = min_t(unsigned long, nr_pages, PVM_MAX_USER_PAGES);
    
    		/* ์›๊ฒฉ ํ”„๋กœ์„ธ์Šค์˜ ํŽ˜์ด์ง€ ๊ณ ์ • */
    		mmap_read_lock(mm);
    		pinned_pages = pin_user_pages_remote(mm, pa, pinned_pages,
    						     flags, process_pages,
    						     &locked);
    		if (locked)
    			mmap_read_unlock(mm);
    		if (pinned_pages <= 0)
    			return -EFAULT;
    
    		/* ํŽ˜์ด์ง€ ๋ณต์‚ฌ */
    		rc = process_vm_rw_pages(process_pages,
    					 start_offset, bytes, iter,
    					 vm_write);
    
    		/* ์“ฐ๊ธฐ ์‹œ ํŽ˜์ด์ง€ ๋”๋Ÿฌ์šด ํ”Œ๋ž˜๊ทธ ์„ค์ • */
    		unpin_user_pages_dirty_lock(process_pages, pinned_pages,
    					    vm_write);
    	}
    
    	return rc;
    }
  • ์กฐ๊ฑด ๋ถ„๊ธฐ:
  • - vm_write == 1: FOLL_WRITE ํ”Œ๋ž˜๊ทธ ์ถ”๊ฐ€

    - pinned_pages <= 0: -EFAULT

    - locked == 1: mmap_read_unlock() ํ˜ธ์ถœ

    5. process_vm_rw_pages() โ€” ์‹ค์ œ ํŽ˜์ด์ง€ ๋ณต์‚ฌ

    ๊ณ ์ •๋œ ํŽ˜์ด์ง€๋“ค์˜ ๋‚ด์šฉ์„ copy_page_to_iter() ๋˜๋Š” copy_page_from_iter()๋ฅผ ํ†ตํ•ด ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค.

    /* mm/process_vm_access.c:27-53 */
    static int process_vm_rw_pages(struct page **pages,
    			       unsigned offset,
    			       size_t len,
    			       struct iov_iter *iter,
    			       int vm_write)
    {
    	while (len && iov_iter_count(iter)) {
    		struct page *page = *pages++;
    		size_t copy = PAGE_SIZE - offset;
    		size_t copied;
    
    		if (copy > len)
    			copy = len;
    
    		if (vm_write)
    			copied = copy_page_from_iter(page, offset, copy, iter);
    		else
    			copied = copy_page_to_iter(page, offset, copy, iter);
    
    		len -= copied;
    		if (copied < copy && iov_iter_count(iter))
    			return -EFAULT;
    		offset = 0;
    	}
    	return 0;
    }
  • ์กฐ๊ฑด ๋ถ„๊ธฐ:
  • - vm_write == 1: copy_page_from_iter() (์›๊ฒฉ โ†’ ๋กœ์ปฌ)

    - vm_write == 0: copy_page_to_iter() (๋กœ์ปฌ โ†’ ์›๊ฒฉ)

    - copied < copy: -EFAULT


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

    ํ˜ธ์ถœ ํ๋ฆ„ ๋‹ค์ด์–ด๊ทธ๋žจ
    process_vm_readv / process_vm_writev
    โ”‚
    โ””โ”€โ”€ process_vm_rw()
    โ”‚
    โ”œโ”€โ”€ import_iovec()          โ† ๋กœ์ปฌ iovec โ†’ iov_iter ๋ณ€ํ™˜
    โ”œโ”€โ”€ iovec_from_user()       โ† ์›๊ฒฉ iovec์„ ์ปค๋„ ๊ณต๊ฐ„์œผ๋กœ ๋ณต์‚ฌ
    โ”‚
    โ””โ”€โ”€ process_vm_rw_core()
    โ”‚
    โ”œโ”€โ”€ find_get_task_by_vpid()  โ† ๋Œ€์ƒ ํ”„๋กœ์„ธ์Šค ์ฐพ๊ธฐ
    โ”œโ”€โ”€ mm_access()              โ† mm_struct ์ ‘๊ทผ ๊ถŒํ•œ ํš๋“
    โ”‚
    โ””โ”€โ”€ process_vm_rw_single_vec()  โ† ๊ฐ ์›๊ฒฉ ๋ฒกํ„ฐ๋ณ„ ๋ฐ˜๋ณต
    โ”‚
    โ”œโ”€โ”€ pin_user_pages_remote()  โ† ์›๊ฒฉ ํŽ˜์ด์ง€ ๊ณ ์ •
    โ”œโ”€โ”€ process_vm_rw_pages()    โ† ์‹ค์ œ ๋ฐ์ดํ„ฐ ๋ณต์‚ฌ
    โ”‚   โ”œโ”€โ”€ copy_page_to_iter()      (์ฝ๊ธฐ)
    โ”‚   โ””โ”€โ”€ copy_page_from_iter()    (์“ฐ๊ธฐ)
    โ””โ”€โ”€ unpin_user_pages_dirty_lock() โ† ํŽ˜์ด์ง€ ๊ณ ์ • ํ•ด์ œ

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

    ํ•ญ๋ชฉprocess_vm_readvprocess_vm_writev
    **๋ฐฉํ–ฅ**์›๊ฒฉ โ†’ ๋กœ์ปฌ๋กœ์ปฌ โ†’ ์›๊ฒฉ
    **vm_write**01
    **FOLL_WRITE**๋ฏธ์„ค์ •์„ค์ •
    ** iov_iter ๋ฐฉํ–ฅ**ITER_DESTITER_SOURCE
    **ํŽ˜์ด์ง€ ๋”๋Ÿฌ์›€**์„ค์ • ์•ˆ ํ•จunpin ์‹œ ๋”๋Ÿฌ์šด ํ”Œ๋ž˜๊ทธ ์„ค์ •
    **EACCES ์ฒ˜๋ฆฌ**EACCES โ†’ EPERM ๋ณ€ํ™˜EACCES โ†’ EPERM ๋ณ€ํ™˜
    ํ•ญ๋ชฉprocess_vm_readv/writevptrace(PTRACE_PEEKDATA)ํŒŒ์ดํ”„
    **๋™์‹œ ์ ‘๊ทผ**๋‹จ์ผ ์‹œ์Šคํ…œ ํ˜ธ์ถœ๋กœ ๋‹ค์ˆ˜ ๋ฒกํ„ฐ ์ฒ˜๋ฆฌ1ํšŒ ํ˜ธ์ถœ๋‹น 1 ์›Œ๋“œ์–‘๋ฐฉํ–ฅ ๊ฐ€๋Šฅ
    **์„ฑ๋Šฅ**๋†’์Œ (ํŽ˜์ด์ง€ ๊ณ ์ • ํ›„ ๋ณต์‚ฌ)๋‚ฎ์Œ (์ปจํ…์ŠคํŠธ ์Šค์œ„์น˜ ๋ฐ˜๋ณต)์ค‘๊ฐ„
    **๊ถŒํ•œ**PTRACE_MODE_ATTACH_REALCREDSPTRACE_MODE_ATTACH๋‘ ํ”„๋กœ์„ธ์Šค๊ฐ„ ํŒŒ์ดํ”„ ํ•„์š”
    **๋Œ€์ƒ ํ”„๋กœ์„ธ์Šค**PID๋กœ ์ง€์ •PID๋กœ ์ง€์ •ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ ํ•„์š”
    ์กฐ๊ฑด๊ฒฐ๊ณผ
    `flags != 0``-EINVAL` ๋ฐ˜ํ™˜
    `find_get_task_by_vpid()` ์‹คํŒจ`-ESRCH` ๋ฐ˜ํ™˜
    `mm_access()` ์‹คํŒจ ์‹œ `-EACCES``-EPERM`์œผ๋กœ ๋ณ€ํ™˜
    `pin_user_pages_remote() <= 0``-EFAULT` ๋ฐ˜ํ™˜
    `nr_pages == 0`๋ฐ”๋กœ 0 ๋ฐ˜ํ™˜
    `iov_iter_count(&iter) == 0`๋ฐ”๋กœ ๋ฐ˜ํ™˜

    ์ผ์ƒ ๋น„์œ 

    process_vm_readv/writev๋Š” ๋‘ ์ด์›ƒ์ง‘ ์‚ฌ์ด์— ์ง์ ‘ ํ†ต๋กœ๋ฅผ ๋šซ๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด ๋ฐฉ๋ฒ•(ํŒŒ์ดํ”„/์†Œ์ผ“)์€ ์šฐ์ฒด๊ตญ(์ปค๋„)์„ ํ†ตํ•ด ํŽธ์ง€๋ฅผ ์ฃผ๊ณ ๋ฐ›๋Š” ๋ฐฉ์‹์ด๋ผ๋ฉด, ์ด ์‹œ์Šคํ…œ ํ˜ธ์ถœ์€ ์ด์›ƒ์ง‘ ๋ฌธ์„ ์—ด๊ณ  ์ƒ๋Œ€๋ฐฉ ์„ ๋ฐ˜์—์„œ ์ง์ ‘ ๋ฌผ๊ฑด์„ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ๋„ฃ์–ด๋‘๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ๋‹จ, ๋ณด์•ˆ(๊ถŒํ•œ ๊ฒ€์‚ฌ)์ด ํ•„์š”ํ•˜๋ฉฐ, ํ•œ ๋ฒˆ์— ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋Š” ๋ฌผ๊ฑด์˜ ์–‘(ํŽ˜์ด์ง€ ์ˆ˜)์— ์ œํ•œ์ด ์žˆ์Šต๋‹ˆ๋‹ค.


    ๊ด€๋ จ ๋ฌธ์„œ

  • ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊ฐœ์š”
  • Buddy Allocator
  • VMA / mmap
  • GUP (Get User Pages)