Skip to content

Instantly share code, notes, and snippets.

@timo
Last active February 18, 2025 01:03
Show Gist options
  • Save timo/1d9ff134a8e962e4d7777f845bf598d8 to your computer and use it in GitHub Desktop.
Save timo/1d9ff134a8e962e4d7777f845bf598d8 to your computer and use it in GitHub Desktop.
UserfaultFD for Linux with Raku's NativeCall

UserfaultFD with #Rakulang

This Gist has a super hacky ugly implementation of a part of the UserfaultFD feature of the linux kernel (awkwardly) using raku's NativeCall. This could be much improved with a little bit of care.

Check this recording of what happens:

asciicast

you can see multiple worker threads (doods) trying to read from and write to a memory region that was initially write-protected and watched for access attempts by the UFFD thread.
The doods are stopped in their tracks when they first access some location, then the UFFD thread decides to let them continue after copying some data into the area and when they try to write to it, it just un-write-protects the page.
You can see sometimes the read and write immediately finish. That’s when the page had already been un-write-protected earlier.

⬢ [timo@toolbox moarvm]$ rakudo uffd_attempt.raku
20:01:21.451 Thd<1>(Initial thread): going to start now
20:01:22.598 Thd<4>(uffd): the api i built looks like uffdio_api.new(api => 170, features => 0, ioctls => 0)
20:01:22.600 Thd<4>(uffd): api ioctl returned 0, api is now uffdio_api.new(api => 170, features => 131071, ioctls => -9223372036854775805)
20:01:22.601 Thd<4>(uffd): features: 11111111111111111
20:01:22.601 Thd<4>(uffd): setting my own features to 1 aka 1
20:01:22.603 Thd<4>(uffd): api ioctl returned -1, api is now uffdio_api.new(api => 0, features => 0, ioctls => 0)
20:01:22.604 Thd<4>(uffd): mmap result: 30000
20:01:22.604 Thd<4>(uffd): regs prepared
20:01:22.605 Thd<4>(uffd): register ioctl returned 0, reg is now uffdio_register.new(start => 196608, len => 1048576, mode => 3, ioctls => 380)
20:01:22.607 Thd<5>(Dood 0): trying to read memory at that location: 792807 C18E7
20:01:22.611 Thd<4>(uffd): userfaultfd event:
20:01:22.612 Thd<4>(uffd): - event 0x12 - flags 0b0 - addr 0xc1000
20:01:22.613 Thd<4>(uffd): event was MISSING: do copy + write-protect
20:01:22.614 Thd<4>(uffd): UFFD_copy[dst: 0xc1000, src: 0x7f41bf000010, len: 0x1000, mode: 2]
20:01:22.618 Thd<5>(Dood 0): read: 0a 61 62 62 61 74 69 61 6c 0a 61 62 62 61 74 00
20:01:22.619 Thd<5>(Dood 0): writing buffer back to the same address ...
20:01:22.620 Thd<4>(uffd): userfaultfd event:
20:01:22.621 Thd<4>(uffd): - event 0x12 - flags 0b11 - addr 0xc1000
20:01:22.622 Thd<4>(uffd): UFFD_wprot[start: 0xc1000, len: 0x1000]
20:01:22.623 Thd<5>(Dood 0): done! sleeping now
20:01:22.941 Thd<6>(Dood 1): trying to read memory at that location: 887087 D892F
20:01:22.942 Thd<4>(uffd): userfaultfd event:
20:01:22.943 Thd<4>(uffd): - event 0x12 - flags 0b0 - addr 0xd8000
20:01:22.944 Thd<4>(uffd): event was MISSING: do copy + write-protect
20:01:22.944 Thd<4>(uffd): UFFD_copy[dst: 0xd8000, src: 0x7f41bf000010, len: 0x1000, mode: 2]
20:01:22.947 Thd<6>(Dood 1): read: 74 0a 41 62 62 65 76 69 6c 65 61 6e 0a 41 62 00
20:01:22.948 Thd<6>(Dood 1): writing buffer back to the same address ...
20:01:22.949 Thd<4>(uffd): userfaultfd event:
20:01:22.950 Thd<4>(uffd): - event 0x12 - flags 0b11 - addr 0xd8000
20:01:22.951 Thd<4>(uffd): UFFD_wprot[start: 0xd8000, len: 0x1000]
20:01:22.951 Thd<6>(Dood 1): done! sleeping now
20:01:23.274 Thd<7>(Dood 2): trying to read memory at that location: 844275 CE1F3
20:01:23.275 Thd<4>(uffd): userfaultfd event:
20:01:23.276 Thd<4>(uffd): - event 0x12 - flags 0b0 - addr 0xce000
20:01:23.277 Thd<4>(uffd): event was MISSING: do copy + write-protect
20:01:23.277 Thd<4>(uffd): UFFD_copy[dst: 0xce000, src: 0x7f41bf000010, len: 0x1000, mode: 2]
20:01:23.280 Thd<7>(Dood 2): read: 77 6f 6c 76 65 73 0a 41 61 72 65 6e 0a 41 61 00
20:01:23.280 Thd<7>(Dood 2): writing buffer back to the same address ...
20:01:23.281 Thd<4>(uffd): userfaultfd event:
20:01:23.282 Thd<4>(uffd): - event 0x12 - flags 0b11 - addr 0xce000
20:01:23.283 Thd<4>(uffd): UFFD_wprot[start: 0xce000, len: 0x1000]
20:01:23.283 Thd<7>(Dood 2): done! sleeping now
20:01:23.607 Thd<8>(Dood 3): trying to read memory at that location: 382907 5D7BB
20:01:23.608 Thd<4>(uffd): userfaultfd event:
20:01:23.609 Thd<4>(uffd): - event 0x12 - flags 0b0 - addr 0x5d000
20:01:23.609 Thd<4>(uffd): event was MISSING: do copy + write-protect
20:01:23.610 Thd<4>(uffd): UFFD_copy[dst: 0x5d000, src: 0x7f41bf000010, len: 0x1000, mode: 2]
20:01:23.612 Thd<8>(Dood 3): read: 6a 6f 75 72 73 0a 61 62 61 74 6f 6e 0a 61 62 00
20:01:23.612 Thd<8>(Dood 3): writing buffer back to the same address ...
20:01:23.613 Thd<4>(uffd): userfaultfd event:
20:01:23.614 Thd<4>(uffd): - event 0x12 - flags 0b11 - addr 0x5d000
20:01:23.614 Thd<4>(uffd): UFFD_wprot[start: 0x5d000, len: 0x1000]
20:01:23.615 Thd<8>(Dood 3): done! sleeping now
20:01:24.625 Thd<5>(Dood 0): trying to read memory at that location: 333978 5189A
20:01:24.625 Thd<4>(uffd): userfaultfd event:
20:01:24.626 Thd<4>(uffd): - event 0x12 - flags 0b0 - addr 0x51000
20:01:24.627 Thd<4>(uffd): event was MISSING: do copy + write-protect
20:01:24.627 Thd<4>(uffd): UFFD_copy[dst: 0x51000, src: 0x7f41bf000010, len: 0x1000, mode: 2]
20:01:24.628 Thd<5>(Dood 0): read: 62 61 6e 64 6f 6e 6f 0a 61 62 62 61 73 0a 61 00
20:01:24.629 Thd<5>(Dood 0): writing buffer back to the same address ...
20:01:24.629 Thd<4>(uffd): userfaultfd event:
20:01:24.629 Thd<4>(uffd): - event 0x12 - flags 0b11 - addr 0x51000
20:01:24.630 Thd<4>(uffd): UFFD_wprot[start: 0x51000, len: 0x1000]
20:01:24.630 Thd<5>(Dood 0): done! sleeping now
20:01:24.952 Thd<6>(Dood 1): trying to read memory at that location: 199610 30BBA
20:01:24.953 Thd<4>(uffd): userfaultfd event:
20:01:24.954 Thd<4>(uffd): - event 0x12 - flags 0b0 - addr 0x30000
20:01:24.954 Thd<4>(uffd): event was MISSING: do copy + write-protect
20:01:24.955 Thd<4>(uffd): UFFD_copy[dst: 0x30000, src: 0x7f41bf000010, len: 0x1000, mode: 2]
20:01:24.956 Thd<6>(Dood 1): read: 64 69 61 73 0a 61 62 64 69 63 61 62 6c 65 0a 00
20:01:24.956 Thd<6>(Dood 1): writing buffer back to the same address ...
20:01:24.957 Thd<4>(uffd): userfaultfd event:
20:01:24.957 Thd<4>(uffd): - event 0x12 - flags 0b11 - addr 0x30000
20:01:24.958 Thd<4>(uffd): UFFD_wprot[start: 0x30000, len: 0x1000]
20:01:24.958 Thd<6>(Dood 1): done! sleeping now
20:01:25.284 Thd<7>(Dood 2): trying to read memory at that location: 508346 7C1BA
20:01:25.284 Thd<4>(uffd): userfaultfd event:
20:01:25.285 Thd<4>(uffd): - event 0x12 - flags 0b0 - addr 0x7c000
20:01:25.286 Thd<4>(uffd): event was MISSING: do copy + write-protect
20:01:25.286 Thd<4>(uffd): UFFD_copy[dst: 0x7c000, src: 0x7f41bf000010, len: 0x1000, mode: 2]
20:01:25.287 Thd<7>(Dood 2): read: 62 69 79 65 0a 41 61 72 0a 41 61 72 61 0a 41 00
20:01:25.288 Thd<7>(Dood 2): writing buffer back to the same address ...
20:01:25.288 Thd<4>(uffd): userfaultfd event:
20:01:25.289 Thd<4>(uffd): - event 0x12 - flags 0b11 - addr 0x7c000
20:01:25.290 Thd<4>(uffd): UFFD_wprot[start: 0x7c000, len: 0x1000]
20:01:25.290 Thd<7>(Dood 2): done! sleeping now
20:01:25.615 Thd<8>(Dood 3): trying to read memory at that location: 697300 AA3D4
20:01:25.616 Thd<4>(uffd): userfaultfd event:
20:01:25.617 Thd<4>(uffd): - event 0x12 - flags 0b0 - addr 0xaa000
20:01:25.618 Thd<4>(uffd): event was MISSING: do copy + write-protect
20:01:25.618 Thd<4>(uffd): UFFD_copy[dst: 0xaa000, src: 0x7f41bf000010, len: 0x1000, mode: 2]
20:01:25.619 Thd<8>(Dood 3): read: 0a 61 62 61 63 75 73 65 73 0a 41 62 61 64 0a 00
20:01:25.620 Thd<8>(Dood 3): writing buffer back to the same address ...
20:01:25.620 Thd<4>(uffd): userfaultfd event:
20:01:25.620 Thd<4>(uffd): - event 0x12 - flags 0b11 - addr 0xaa000
20:01:25.621 Thd<4>(uffd): UFFD_wprot[start: 0xaa000, len: 0x1000]
20:01:25.622 Thd<8>(Dood 3): done! sleeping now
20:01:26.631 Thd<5>(Dood 0): trying to read memory at that location: 979442 EF1F2
20:01:26.632 Thd<4>(uffd): userfaultfd event:
20:01:26.633 Thd<4>(uffd): - event 0x12 - flags 0b0 - addr 0xef000
20:01:26.634 Thd<4>(uffd): event was MISSING: do copy + write-protect
20:01:26.634 Thd<4>(uffd): UFFD_copy[dst: 0xef000, src: 0x7f41bf000010, len: 0x1000, mode: 2]
20:01:26.635 Thd<5>(Dood 0): read: 64 77 6f 6c 76 65 73 0a 41 61 72 65 6e 0a 41 00
20:01:26.636 Thd<5>(Dood 0): writing buffer back to the same address ...
20:01:26.636 Thd<4>(uffd): userfaultfd event:
20:01:26.637 Thd<4>(uffd): - event 0x12 - flags 0b11 - addr 0xef000
20:01:26.637 Thd<4>(uffd): UFFD_wprot[start: 0xef000, len: 0x1000]
20:01:26.638 Thd<5>(Dood 0): done! sleeping now
20:01:26.987 Thd<6>(Dood 1): trying to read memory at that location: 453901 6ED0D
20:01:26.989 Thd<4>(uffd): userfaultfd event:
20:01:26.990 Thd<4>(uffd): - event 0x12 - flags 0b0 - addr 0x6e000
20:01:26.990 Thd<4>(uffd): event was MISSING: do copy + write-protect
20:01:26.990 Thd<4>(uffd): UFFD_copy[dst: 0x6e000, src: 0x7f41bf000010, len: 0x1000, mode: 2]
20:01:26.991 Thd<6>(Dood 1): read: 74 65 72 65 63 74 6f 6d 79 0a 61 62 64 6f 6d 00
20:01:26.992 Thd<6>(Dood 1): writing buffer back to the same address ...
20:01:26.992 Thd<4>(uffd): userfaultfd event:
20:01:26.993 Thd<4>(uffd): - event 0x12 - flags 0b11 - addr 0x6e000
20:01:26.993 Thd<4>(uffd): UFFD_wprot[start: 0x6e000, len: 0x1000]
20:01:26.994 Thd<6>(Dood 1): done! sleeping now
20:01:27.292 Thd<7>(Dood 2): trying to read memory at that location: 897065 DB029
20:01:27.293 Thd<4>(uffd): userfaultfd event:
20:01:27.294 Thd<4>(uffd): - event 0x12 - flags 0b0 - addr 0xdb000
20:01:27.294 Thd<4>(uffd): event was MISSING: do copy + write-protect
20:01:27.295 Thd<4>(uffd): UFFD_copy[dst: 0xdb000, src: 0x7f41bf000010, len: 0x1000, mode: 2]
20:01:27.296 Thd<7>(Dood 2): read: 6f 69 6e 74 0a 31 38 2d 70 6f 69 6e 74 0a 31 00
20:01:27.296 Thd<7>(Dood 2): writing buffer back to the same address ...
20:01:27.296 Thd<4>(uffd): userfaultfd event:
20:01:27.297 Thd<4>(uffd): - event 0x12 - flags 0b11 - addr 0xdb000
20:01:27.297 Thd<4>(uffd): UFFD_wprot[start: 0xdb000, len: 0x1000]
20:01:27.298 Thd<7>(Dood 2): done! sleeping now
20:01:27.623 Thd<8>(Dood 3): trying to read memory at that location: 790434 C0FA2
20:01:27.624 Thd<4>(uffd): userfaultfd event:
20:01:27.625 Thd<4>(uffd): - event 0x12 - flags 0b0 - addr 0xc0000
20:01:27.625 Thd<4>(uffd): event was MISSING: do copy + write-protect
20:01:27.625 Thd<4>(uffd): UFFD_copy[dst: 0xc0000, src: 0x7f41bf000010, len: 0x1000, mode: 2]
20:01:27.626 Thd<8>(Dood 3): read: 65 6c 73 6f 6e 0a 61 62 65 6c 74 72 65 65 0a 00
20:01:27.627 Thd<8>(Dood 3): writing buffer back to the same address ...
20:01:27.627 Thd<4>(uffd): userfaultfd event:
20:01:27.628 Thd<4>(uffd): - event 0x12 - flags 0b11 - addr 0xc0000
20:01:27.628 Thd<4>(uffd): UFFD_wprot[start: 0xc0000, len: 0x1000]
20:01:27.629 Thd<8>(Dood 3): done! sleeping now
^C
use NativeCall;
use NativeCall::Types;
use Terminal::ANSIColor;
my constant __NR_userfaultfd = 323;
sub syscall(int32 $omnomnom, int32 $foo --> int32) is native(Str) { };
sub ioctl(int32 $fd, int64 $request, OpaquePointer $thing --> int32) is native(Str) { };
class uffdio_register is repr<CStruct> is rw {
has uint64 $.start;
has uint64 $.len;
has uint64 $.mode;
has uint64 $.ioctls;
}
class uffd_zeropage is repr<CStruct> is rw {
has uint64 $.start;
has uint64 $.len;
has uint64 $.mode;
has int64 $.returnval;
method gist {
"UFFD_zeropg[dst: $.dst.fmt("0x%x"), len: $.len.fmt("0x%x")"
~ ($.mode ?? ", mode: $.mode" !! "")
~ ($.returnval ?? ", ret: $.returnval.fmt("0x%x")" !! "")
~ "]";
}
}
class uffd_copy is repr<CStruct> is rw {
has uint64 $.dst;
has uint64 $.src;
has uint64 $.len;
has uint64 $.mode;
has int64 $.returnval;
method gist {
"UFFD_copy[dst: $.dst.fmt("0x%x"), src: $.src.fmt("0x%x"), len: $.len.fmt("0x%x")"
~ ($.mode ?? ", mode: $.mode" !! "")
~ ($.returnval ?? ", ret: $.returnval.fmt("0x%x")" !! "")
~ "]";
}
}
class uffd_continue is repr<CStruct> is rw {
has uint64 $.start;
has uint64 $.len;
has uint64 $.mode;
has int64 $.returnval;
method gist {
"UFFD_copy[dst: $.dst.fmt("0x%x"), src: $.src.fmt("0x%x")]"
}
}
class uffd_writeprotect is repr<CStruct> is rw {
has uint64 $.start;
has uint64 $.len;
has uint64 $.mode;
method gist {
"UFFD_wprot[start: $.start.fmt("0x%x"), len: $.len.fmt("0x%x")"
~ ($.mode ?? ", mode: $.mode" !! "")
~ "]";
}
}
class uffdio_api is repr<CStruct> is rw {
has uint64 $.api;
has uint64 $.features;
has int64 $.ioctls;
}
class uffd_pagefault is repr<CStruct> is rw {
has uint64 $.flags;
has uint64 $.address;
has uint32 $.ptid;
has uint32 $.padding;
}
my constant UFFD_FEATURE_PAGEFAULT_FLAG_WP = (1 +< 0);
my constant UFFD_FEATURE_EVENT_FORK = (1 +< 1);
my constant UFFD_FEATURE_EVENT_REMAP = (1 +< 2);
my constant UFFD_FEATURE_EVENT_REMOVE = (1 +< 3);
my constant UFFD_FEATURE_MISSING_HUGETLBFS = (1 +< 4);
my constant UFFD_FEATURE_MISSING_SHMEM = (1 +< 5);
my constant UFFD_FEATURE_EVENT_UNMAP = (1 +< 6);
my constant UFFD_FEATURE_SIGBUS = (1 +< 7);
my constant UFFD_FEATURE_THREAD_ID = (1 +< 8);
my constant UFFD_FEATURE_MINOR_HUGETLBFS = (1 +< 9);
my constant UFFD_FEATURE_MINOR_SHMEM = (1 <+ 10);
my constant UFFD_FEATURE_EXACT_ADDRESS = (1 <+ 11);
my constant UFFD_FEATURE_WP_HUGETLBFS_SHMEM = (1 <+ 12);
my constant UFFD_FEATURE_WP_UNPOPULATED = (1 <+ 13);
my constant UFFD_FEATURE_POISON = (1 <+ 14);
my constant UFFD_FEATURE_WP_ASYNC = (1 <+ 15);
my constant UFFD_FEATURE_MOVE = (1 <+ 16);
my constant UFFD_EVENT_PAGEFAULT = 0x12;
my constant UFFD_EVENT_FORK = 0x13;
my constant UFFD_EVENT_REMAP = 0x14;
my constant UFFD_EVENT_REMOVE = 0x15;
my constant UFFD_EVENT_UNMAP = 0x16;
my constant _UFFDIO_REGISTER = 0x00;
my constant _UFFDIO_UNREGISTER = 0x01;
my constant _UFFDIO_WAKE = 0x02;
my constant _UFFDIO_COPY = 0x03;
my constant _UFFDIO_ZEROPAGE = 0x04;
my constant _UFFDIO_MOVE = 0x05;
my constant _UFFDIO_WRITEPROTECT = 0x06;
my constant _UFFDIO_CONTINUE = 0x07;
my constant _UFFDIO_POISON = 0x08;
my constant _UFFDIO_API = 0x3F;
my constant UFFDIO_REGISTER_MODE_MISSING = 1 +< 0;
my constant UFFDIO_REGISTER_MODE_WP = 1 +< 1;
my constant UFFDIO_REGISTER_MODE_MINOR = 1 +< 2;
my constant UFFDIO_COPY_MODE_DONTWAKE = 1 +< 0;
my constant UFFDIO_COPY_MODE_WP = 1 +< 1;
my constant UFFDIO = 0xAA;
my constant UFFDIO_API = 0xc018aa3f;
my constant UFFDIO_ZEROPAGE = 0xc020aa04;
my constant UFFDIO_CONTINUE = 0xc020aa07;
my constant UFFDIO_COPY = 0xc028aa03;
my constant UFFDIO_WAKE = 0x8010aa02;
my constant UFFDIO_WRITEPROTECT = 0xc018aa06;
my constant UFFDIO_REGISTER = 0xc020aa00;
class uffd_msg is repr<CStruct> is rw {
has uint8 $.event;
has uint8 $.reserved1;
has uint16 $.reserved2;
has uint32 $.reserved3;
# needs to be a union if we want more than just this kind
HAS uffd_pagefault $.event_pagefault;
}
sub c_read(int32 $fd, buf8 $buf, uint64 $len --> int32) is native(Str) is symbol("read") { }
sub mmap(int64 $addr, int64 $len, int32 $prot, int32 $flags, int32 $fd, int64 $offs --> int64) is native(Str) { }
sub memset(int64 $addr, int32 $c, int64 $len --> int64) is native(Str) { }
sub memcpy(buf8 $tgt, int64 $src_addr, int64 $len --> int64) is native(Str) { }
sub rmemcpy(int64 $tgt_addr, buf8 $src, int64 $len --> int64) is native(Str) is symbol("memcpy") { }
# my @colors = (^255).combinations(3).roll(*).map({ .join(",") });
my @colors = ((16, 32 ...^ 256) X (16, 32 ...^ 256) X (16, 32 ...^ 256)).grep({ .sum >= 400 && .minmax.elems > 216 }).map({ .join(",") }).pick(*);
# $*OUT.put(colored($_, $_)) for @colors;
sub say(*@text) {
my $ts = (
colored(.hour.fmt("%02d"), "128,128,128"),
colored(.minute.fmt("%02d"), "196,196,196"),
colored(.whole-second.fmt("%02d"), "200,200,200") ~ "."
~ colored((.second - .whole-second).fmt("%3.3f").substr(2), "255,255,255")).join(":")
given DateTime.now;
$*OUT.put($ts ~ " " ~ colored($*THREAD.Str.subst("Thread", "Thd") ~ ": " ~ @text>>.gist.join(""), @colors[$*THREAD.id]));
}
say "going to start now";
my $uffdt = Thread.start(:name<uffd>, sub {
try {
my int32 $uffd = syscall(__NR_userfaultfd, 0);
my $mmapped_size = 0x100000;
my buf8 $buf .= allocate(4096);
my CArray[uint8] $copysrc .= new("/usr/share/dict/words".IO.slurp(:bin));
sub pump() {
my int64 $rcnt = c_read($uffd, $buf, 32);
# say $buf.head($rcnt);
say "userfaultfd event:";
say " - event ", $buf.read-uint8(0).fmt("0x%02x"),
" - flags ", (my uint64 $flags = $buf.read-uint64(8)).fmt("0b%b"),
" - addr ", (my uint64 $addr = $buf.read-uint64(16)).fmt("0x%x");
# we're not getting thread IDs ;(
#" - ptid ", $buf.read-uint32(24).fmt("0x%x");
if $flags == 0 {
say "event was MISSING: do copy + write-protect";
my uffd_copy $cpy .= new(:dst($addr), :src(nativecast(OpaquePointer, $copysrc)), :len(4096), :mode(UFFDIO_COPY_MODE_WP));
say $cpy;
say "ioctl result: $_" andthen say $cpy if ioctl($uffd, UFFDIO_COPY, nativecast(OpaquePointer, $cpy));
}
elsif $flags == 0b11 {
#say "reacting with zeropage";
#my uffd_zeropage $zp .= new(:start($addr), :len(4096), :mode(0));
#say $zp.raku;
#say "ioctl result: ", ioctl($uffd, UFFDIO_ZEROPAGE, nativecast(OpaquePointer, $zp));
#say $zp.raku;
#if $zp.returnval == -17 {
# say "event was WP: remove writeprotect";
my uffd_writeprotect $wp .= new(:start($addr), :len(4096), :mode(0));
say $wp;
say "ioctl result: $_" if ioctl($uffd, UFFDIO_WRITEPROTECT, nativecast(OpaquePointer, $wp));
#say $wp.raku;
#}
}
else {
say "don't know what to do with these flags?";
}
}
if $uffd == 0 {
say "couldn't create userfaultfd (do you need to set /proc/sys/vm/unprivileged_userfaultfd to 1?)";
exit(1);
}
my uffdio_api $api .= new(:api(0xAA), :features(0));
say "the api i built looks like $api.raku()";
my $ioctlresult = ioctl($uffd, 3222841919, nativecast(OpaquePointer, $api));
say "api ioctl returned $ioctlresult, api is now $api.raku()";
say "features: ", $api.features.base(2);
$api.features = UFFD_FEATURE_PAGEFAULT_FLAG_WP +| UFFD_FEATURE_WP_UNPOPULATED;
say "setting my own features to $api.features() aka $api.features().base(2)";
$ioctlresult = ioctl($uffd, 3222841919, nativecast(OpaquePointer, $api));
say "api ioctl returned $ioctlresult, api is now $api.raku()";
say "mmap result: ", (my $baseaddr = mmap(0x30000, $mmapped_size, 0x1 +| 0x2, 0x02 +| 0x20, 0, 0)).base(16);
#my @maps = "/proc/self/maps".IO.lines.>>.words>>.[0]>>.split("-")>>.parse-base(16);
#.fmt("%10x", "-").say for @maps;
#my uffdio_register @regs = uffdio_register.new(:mode(1)) xx +@maps;
#for @maps Z @regs -> ($m, $r) {
# $r.start = $m[0];
# $r.len = $m[1];
#}
my @regs = uffdio_register.new(:start($baseaddr), :len($mmapped_size), :mode(UFFDIO_REGISTER_MODE_WP +| UFFDIO_REGISTER_MODE_MISSING));
say "regs prepared";
for @regs {
$ioctlresult = ioctl($uffd, UFFDIO_REGISTER, nativecast(OpaquePointer, $_));
say "register ioctl returned $ioctlresult, reg is now ", $_;
}
for ^4 -> $dood {
Thread.start(:name("Dood $dood"), sub {
sleep $dood / 3;
loop {
my int64 $targetaddr = $baseaddr + ($mmapped_size - 0x1000).rand.Int;
say "trying to read memory at that location: ", $targetaddr, " ", $targetaddr.base(16);
my buf8 $tb .= allocate(0x10);
memcpy($tb, $targetaddr, 0x0f);
say "read: ", $tb.list.fmt("%02x", " ");
@$tb = (^255).pick xx $tb.elems;
say "writing buffer back to the same address ...";
rmemcpy($targetaddr, $tb, 0x10);
say "done! sleeping now";
sleep 2;
}
});
}
pump() while True;
CATCH {
.say;
}
}
});
$uffdt.finish;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment