GistTree.Com
Entertainment at it's peak. The news is by your side.

Validate pointers with the msync() Linux system call

0

Main page

Creator: Nikita Ermakov a.sufficient.a. sh1r4s3

License: CC BY 4.0

Date: 14 Oct 2020

Listed right here I need to picture about easy validate the
pointer in the Linux primarily primarily based machine. Most frequently, any of us might perhaps presumably perhaps well
encounter the SIGSEGV
[1]
🙂 Nonetheless, what if I picture you that it’s likely to look at
whether or not the pointer is legit or not? There are few suggestions
to validate a pointer nevertheless for my portion this snort one is
the most efficient one. Let me introduce to you
the msync()
[2]
machine call! This methodology call is in the the Linux kernel
since 1.3.21 and after Linux 2.4.19 it conforms to the POSIX customary
[3]
.

So, with the attend of this shrimp frail-timer it turns into
likely to validate a pointer. Let’s gawk the description of
this methodology call. This methodology call became once designed to synchronize
a file with a memory design, i.e. memory mapped with
the mmap()
[4]
machine call. It will most doubtless be purposeful to invoke it sooner than
the munmap()
[4]
machine call, to synchronize the file and memory sooner than the memory
web page distributed by the kernel might perhaps presumably perhaps well be free.

Let’s choose a sight to the categorical code of
the msync() from the Linux v5.8
[5]
:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
	unsigned long pause;
	struct mm_struct *mm = recent->mm;
	struct vm_area_struct *vma;
	int unmapped_error = 0;
	int error = -EINVAL;

	birth up = untagged_addr(birth up);

	if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC))
		goto out;
	if (offset_in_page(birth up))
		goto out;
	if ((flags & MS_ASYNC) && (flags & MS_SYNC))
		goto out;
	error = -ENOMEM;
	len = (len + ~PAGE_MASK) & PAGE_MASK;
	pause = birth up + len;
	if (pause < birth up)
		goto out;
	error = 0;
	if (pause == birth up)
		goto out;

In this snippet it tests whether or not the flags, which became once passed to the
characteristic, are perfect and that birth up take care of is
aligned by the web page dimension. If one of many conditions is faux then it
will return with EINVAL
[6]
error. Subsequent, it calculates the pause of the memory chunk from
the len. Basically, it’s some distance the take care of after the final byte of
the final web page distributed for the memory jam
from birth up to birth up + len.
After that it calculates the pause take care of and performs the
traditional sanity assessments with it. It’d be price to speak that
for our applications the supreme purposeful flag would
be MS_ASYNC. This flag specifies that chance to
the msync() returns straight and an update
will most doubtless be scheduled. Now, let’s continue.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
	mmap_read_lock(mm);
	vma = find_vma(mm, birth up);
	for (;;) {
		struct file *file;
		loff_t fstart, fend;

		/Smooth birth up < pause. */
		error = -ENOMEM;
		if (!vma)
			goto out_unlock;

		if (birth up < vma->vm_start) {
			birth up = vma->vm_start;
			if (birth up >= pause)
				goto out_unlock;
			unmapped_error = -ENOMEM;
		}
		// ...
		birth up = vma->vm_end;
		if ((flags & MS_SYNC) && file &&
				(vma->vm_flags & VM_SHARED)) {
		// ...
		} else {
			if (birth up >= pause) {
				error = 0;
				goto out_unlock;
			}
			vma = vma->vm_next;
		}
	}
out_unlock:
	mmap_read_unlock(mm);
out:
	return error ? :  unmapped_error;

This snippet is a quite advanced, nevertheless there isn’t such a thing as a need to
discuss your whole branches in this code. At the birth it
locks the mm_struct and searches the first
Digital Reminiscence Remark (VMA) which might perhaps perhaps also aloof procure the birth up
take care of (birth up vm_end). In the loop it
will iterate over VMA regions till it validate that jam
from the birth up to the pause is contained in the VMA
regions. Basically, it manner that it assessments whether or not this
vary is in the distributed virtual memory jam.

With all that recordsdata we licensed bought there let’s write a characteristic that can
check whether or not the memory position is distributed by the plot or
not. Basically, in this characteristic now we procure to align the pointer take care of
by the web page dimension and advise to the msync() machine call. Here
is a straightforward implementation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
int
valid_pointer(void *p, size_t len)
{
    // Decide up web page dimension and calculate web page conceal
    size_t pagesz = sysconf(_SC_PAGESIZE);
    size_t pagemask = ~(pagesz - 1);
    // Calculate injurious take care of
    void *injurious = (void *)(((size_t)p) & pagemask);
    return msync(injurious, len, MS_ASYNC) == 0;
}

Below is an instance of the validate_pointer()
characteristic exhaust. That is it! If it’s likely you’ll presumably perhaps well decide to provide suggestions or discuss the article
it’s likely you’ll presumably perhaps well be welcome to
e mail me 🙂

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#embody 
#embody 
#embody 

// Verify the pointer
int
valid_pointer(void *p, size_t len)
{
    // Decide up web page dimension and calculate web page conceal
    size_t pagesz = sysconf(_SC_PAGESIZE);
    size_t pagemask = ~(pagesz - 1);
    // Calculate injurious take care of
    void *injurious = (void *)(((size_t)p) & pagemask);
    return msync(injurious, len, MS_ASYNC) == 0;
}

int
main()
{
    // Diagram memory
    int *p = (int *)mmap(NULL,
                         sizeof(int),
                         PROT_READ | PROT_WRITE,
                         MAP_PRIVATE | MAP_ANONYMOUS,
                         -1,
                         0);
    // Verify whether or not the mapping became once good
    if ((void *)p == MAP_FAILED)
    {
        puts("mmap failed");
        return 1;
    }
    // Verify the pointer sooner than we unmap the memory
    printf("check pointer sooner than munmap... ");
    if (valid_pointer((void *)p, sizeof(p)))
        printf("legitn");
    else
        printf("NOT legitn");
    *p = 0x00c0ffee;
    // Unmap the memory
    if (munmap((void *)p, sizeof(int)))
    {
        puts("munmap failed");
        return 1;
    }
    // Verify the pointer after we unmap the memory
    printf("check pointer after munmap... ");
    if (valid_pointer((void *)p, sizeof(*p)))
        printf("legitn");
    else
        printf("NOT legitn");
    // Kind SIGSEGV :)
    *p = 0xbaaaaaad;

    return 0;
}

References:




[1] https://man7.org/linux/man-pages/man7/stamp.7.html


[2] https://man7.org/linux/man-pages/man2/msync.2.html


[3] https://pubs.opengroup.org/onlinepubs/9699919799/capabilities/msync.html


[4] https://man7.org/linux/man-pages/man2/mmap.2.html


[5] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/mm/msync.c?h=v5.8

Read More

Leave A Reply

Your email address will not be published.