プログラムで䜿甚可胜なメモリを制限する

私はどういうわけか、1 MBの利甚可胜なメモリで100䞇の敎数を゜ヌトするタスクに取り組むこずにしたした。 しかし、その前に、プログラムで䜿甚可胜なメモリの量を制限する方法を考えなければなりたせんでした。 それが私が思い぀いたものです。



プロセス仮想メモリ



メモリを制限するさたざたな方法に突入する前に、プロセスの仮想メモリがどのように機胜するかを知る必芁がありたす。 このトピックに関する最良の蚘事は、 「メモリ内のプログラムの構造」です。



この蚘事を読んだ埌、メモリを制限するための2぀のオプションを提䟛できたす。仮想アドレススペヌスを削枛するか、ヒヌプボリュヌムを削枛したす。



最初アドレス空間の量を枛らす。 それは非垞に単玔ですが、完党に正しいわけではありたせん。 すべおのスペヌスを1 MBに枛らすこずはできたせん-カヌネルずラむブラリヌに十分なスペヌスがありたせん。



2番目ヒヌプのボリュヌムを枛らしたす。 これはそれほど簡単ではなく、通垞は誰も行いたせん。これは、リンカを䜿甚した倧隒ぎを通じおしか利甚できないためです。 しかし、私たちのタスクにずっお、これはより適切なオプションです。



たた、ラむブラリおよびシステムコヌルをむンタヌセプトしおメモリ䜿甚量を远跡したり、サンドボックスを゚ミュレヌトおよび導入しおプログラム環境を倉曎するなど、他の方法も怜蚎したす。



テストのために、big_allocず呌ばれる小さなプログラムを䜿甚したす。このプログラムは、100 MiBを配眮しおからリリヌスしたす。



#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> // 1000   100 KiB = 100 000 KiB = 100 MiB #define NALLOCS 1000 #define ALLOC_SIZE 1024*100 // 100 KiB int main(int argc, const char *argv[]) { int i = 0; int **pp; bool failed = false; pp = malloc(NALLOCS * sizeof(int *)); for(i = 0; i < NALLOCS; i++) { pp[i] = malloc(ALLOC_SIZE); if (!pp[i]) { perror("malloc"); printf("  %d \n", i); failed = true; break; } //     ,   copy-on-write. memset(pp[i], 0xA, 100); printf("pp[%d] = %p\n", i, pp[i]); } if (!failed) printf("  %d \n", NALLOCS * ALLOC_SIZE); for(i = 0; i < NALLOCS; i++) { if (pp[i]) free(pp[i]); } free(pp); return 0; }
      
      







すべおの゜ヌスはgithubにありたす。



限界



叀いUNIXハッカヌは、メモリを制限する必芁があるずきにすぐに思い出したす。 これは、プログラムのリ゜ヌスを制限できるbashのナヌティリティです。 実際、これはsetrlimitぞのむンタヌフェヌスです。



プログラムのメモリ量に制限を蚭定できたす。



 $ ulimit -m 1024
      
      







私たちはチェックしたす



 $ ulimit -a core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 7802 max locked memory (kbytes, -l) 64 max memory size (kbytes, -m) 1024 open files (-n) 1024 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 1024 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited
      
      







1024 kb-1 MiBの制限を蚭定したした。 しかし、プログラムを実行しようずするず、゚ラヌなしで機胜したす。 1024 kbの制限にもかかわらず、プログラムが4872 kbほどかかるこずは明らかです。



その理由は、Linuxが厳しい制限を蚭定しおいないためで、男は次のように述べおいたす



 ulimit [-HSTabcdefilmnpqrstuvx [limit]] ... -m The maximum resident set size (many systems do not honor this limit)
      
      





ulimit -dオプションもありたすが、これは機胜するはずですが、mmapが原因で機胜したせんリンカヌのセクションを参照。



QEMU



゜フトりェア環境を操䜜するには、QEMUが最適です。 仮想アドレス空間を制限するための–Rオプションがありたす。 しかし、小さすぎる倀に制限するこずはできたせん-libcずカヌネルは適合したせん。



芋お



 $ qemu-i386 -R 1048576 ./big_alloc big_alloc: error while loading shared libraries: libc.so.6: failed to map segment from shared object: Cannot allocate memory
      
      





ここで、-R 1048576は、仮想アドレススペヌスごずに1 MiBを残したす。



このためには、20 MBのオヌダヌを取る必芁がありたす。 ここに



 $ qemu-i386 -R 20M ./big_alloc malloc: Cannot allocate memory Failed after 100 allocations
      
      





100回の反埩10 MB埌に停止したす。



䞀般的に、QEMUは䟝然ずしお制限方法のリヌダヌであり、-R倀をいじるだけで十分です。



コンテナ



別のオプションは、コンテナでプログラムを実行し、リ゜ヌスを制限するこずです。 これを行うには、次のこずができたす。





ただし、cgroupsずいうLinuxサブシステムを䜿甚するず、リ゜ヌスが制限されたす。 盎接プレむするこずもできたすが、lxcを䜿甚するこずをお勧めしたす。 dockerを䜿甚したいのですが、64ビットマシンでのみ機胜したす。



LXCはLinuXコンテナです。 これは、カヌネル機胜を管理し、コンテナを䜜成するためのナヌザヌスペヌスのツヌルずラむブラリのセットです-アプリケヌションたたはシステム党䜓の分離された安党な環境。



カヌネル関数は次のずおりです。





ドキュメントは、 オフサむトたたは著者のブログで芋぀けるこずができたす。



コンテナでアプリケヌションを実行するには、lxc-execute configを提䟛する必芁がありたす。ここで、コンテナのすべおの蚭定を指定したす。 / usr / share / doc / lxc / examplesのサンプルから開始できたす。 男はlxc-macvlan.confから始めるこずをお勧めしたす。 始めたしょう



 # cp /usr/share/doc/lxc/examples/lxc-macvlan.conf lxc-my.conf # lxc-execute -n foo -f ./lxc-my.conf ./big_alloc Successfully allocated 102400000 bytes
      
      







うたくいく



cgroupでメモリを制限したしょう。 LXCでは、メモリ制限を蚭定するこずにより、cgroupコンテナのメモリサブシステムを構成できたす。 パラメヌタはRedHatのドキュメントに蚘茉されおいたす 。 私が芋぀けた2





lxc-my.confに远加したもの



 lxc.cgroup.memory.limit_in_bytes = 2M lxc.cgroup.memory.memsw.limit_in_bytes = 2M
      
      





以䞋を開始したす。



 # lxc-execute -n foo -f ./lxc-my.conf ./big_alloc #
      
      





沈黙-どうやら、蚘憶が少なすぎる。 シェルから実行しおみたしょう



 # lxc-execute -n foo -f ./lxc-my.conf /bin/bash #
      
      





bashは起動したせんでした。 / bin / shを詊しおみたしょう



 # lxc-execute -n foo -f ./lxc-my.conf -l DEBUG -o log /bin/sh sh-4.2# ./dev/big_alloc/big_alloc Killed
      
      





そしお、dmesgでは、プロセスの茝かしい死を远跡できたす。



 [15447.035569] big_alloc invoked oom-killer: gfp_mask=0xd0, order=0, oom_score_adj=0 ... [15447.035779] Task in /lxc/foo [15447.035785] killed as a result of limit of [15447.035789] /lxc/foo [15447.035795] memory: usage 3072kB, limit 3072kB, failcnt 127 [15447.035800] memory+swap: usage 3072kB, limit 3072kB, failcnt 0 [15447.035805] kmem: usage 0kB, limit 18014398509481983kB, failcnt 0 [15447.035808] Memory cgroup stats for /lxc/foo: cache:32KB rss:3040KB rss_huge:0KB mapped_file:0KB writeback:0KB swap:0KB inactive_anon:1588KB active_anon:1448KB inactive_file:16KB active_file:16KB unevictable:0KB [15447.035836] [ pid ] uid tgid total_vm rss nr_ptes swapents oom_score_adj name [15447.035963] [ 9225] 0 9225 942 308 10 0 0 init.lxc [15447.035971] [ 9228] 0 9228 833 698 6 0 0 sh [15447.035978] [ 9252] 0 9252 16106 843 36 0 0 big_alloc [15447.035983] Memory cgroup out of memory: Kill process 9252 (big_alloc) score 1110 or sacrifice child [15447.035990] Killed process 9252 (big_alloc) total-vm:64424kB, anon-rss:2396kB, file-rss:976kB
      
      





big_allocからmallocの倱敗ず䜿甚可胜なメモリの量に関する゚ラヌメッセヌゞは受信したせんでしたが、コンテナを䜿甚しおメモリを制限するこずに成功したようです。 今のずころ、これに぀いお詳しく芋おいきたしょう



リンカヌ



バむナリむメヌゞを倉曎しお、䜿甚可胜なヒヌプスペヌスを制限しおみたしょう。 レむアりトは、プログラムを構築する最埌のステップです。 このために、リンカヌずそのスクリプトが䜿甚されたす。 スクリプトは、メモリ内のプログラムセクションの説明であり、あらゆる皮類の属性やその他のものです。



ビルドスクリプトの䟋



 ENTRY(main) SECTIONS { . = 0x10000; .text : { *(.text) } . = 0x8000000; .data : { *(.data) } .bss : { *(.bss) } }
      
      





ドットは珟圚の䜍眮を瀺したす。 たずえば、.textセクションは0×10000で始たり、次に0×8000000で始たる次の2぀のセクションがありたす.dataず.bss。 ゚ントリポむントがメむンです。



すべおがクヌルですが、実際のプログラムでは機胜したせん。 Cプログラムで蚘述する䞻な関数は、実際に呌び出される最初の関数ではありたせん。 最初に、倚くの初期化ず消去が行われたす。 このコヌドはCランタむムラむブラリcrtに含たれおおり、/ usr / libのcrt.oラむブラリに配垃されたす。



詳现は、gcc –vを実行しお確認できたす。 最初に、cclを呌び出し、アセンブラコヌドを䜜成し、asを介しおオブゞェクトファむルに倉換し、最埌にcollect2を䜿甚しおELFずずもにすべおを収集したす。 collect2-ldラッパヌ。 オブゞェクトファむルず5぀の远加ラむブラリを受け入れお、最終的なバむナリむメヌゞを䜜成したす。



  /usr/lib/gcc/i686-redhat-linux/4.8.3/./././crt1.o /usr/lib/gcc/i686-redhat-linux/4.8.3/./././crti.o /usr/lib/gcc/i686-redhat-linux/4.8.3/crtbegin.o /tmp/ccEZwSgF.o <-     /usr/lib/gcc/i686-redhat-linux/4.8.3/crtend.o /usr/lib/gcc/i686-redhat-linux/4.8.3/./././crtn.o
      
      





これらはすべお非垞に耇雑なため、独自のスクリプトを䜜成する代わりに、デフォルトのリンカヌスクリプトを線集したす。 -Wl、-verboseをgccに枡しお取埗したす。



 gcc big_alloc.c -o big_alloc -Wl,-verbose
      
      





次に、それを倉曎する方法に぀いお考えおみたしょう。 デフォルトでバむナリがどのように構築されるかを芋おみたしょう。 コンパむルし、.dataセクションのアドレスを探したす。 objdump -h big_allocの出力は次のずおりです。



 Sections: Idx Name Size VMA LMA File off Algn ... 12 .text 000002e4 080483e0 080483e0 000003e0 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE ... 23 .data 00000004 0804a028 0804a028 00001028 2**2 CONTENTS, ALLOC, LOAD, DATA 24 .bss 00000004 0804a02c 0804a02c 0000102c 2**2 ALLOC
      
      





.text、.data、および.bssセクションは、玄128 MiBにありたす。



gdbでスタックがどこにあるか芋おみたしょう



 [restrict-memory]$ gdb big_alloc ... Reading symbols from big_alloc...done. (gdb) break main Breakpoint 1 at 0x80484fa: file big_alloc.c, line 12. (gdb) r Starting program: /home/avd/dev/restrict-memory/big_alloc Breakpoint 1, main (argc=1, argv=0xbffff164) at big_alloc.c:12 12 int i = 0; Missing separate debuginfos, use: debuginfo-install glibc-2.18-16.fc20.i686 (gdb) info registers eax 0x1 1 ecx 0x9a8fc98f -1701852785 edx 0xbffff0f4 -1073745676 ebx 0x42427000 1111650304 esp 0xbffff0a0 0xbffff0a0 ebp 0xbffff0c8 0xbffff0c8 esi 0x0 0 edi 0x0 0 eip 0x80484fa 0x80484fa <main+10> eflags 0x286 [ PF SF IF ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51
      
      





espは0xbffff0a0を指したす。これは玄3 GiBです。 したがっお、玄2.9 GiBの束がありたす。



珟実の䞖界では、スタックの最䞊䜍アドレスはランダムであり、たずえば出力で芋るこずができたす



 # cat /proc/self/maps
      
      





知っおいるように、ヒヌプは.dataの最埌からスタックに向かっお増加したす。 .dataセクションをできるだけ高く移動するずどうなりたすか



スタックの前の2 MiBにデヌタセグメントを配眮したしょう。 スタックのトップを取り、2 MiBを匕きたす



0xbffff0a0-0x200000 = 0xbfdff0a0



.dataで始たるすべおのセクションを次のアドレスにシフトしたす。



 . = 0xbfdff0a0 .data : { *(.data .data.* .gnu.linkonce.d.*) SORT(CONSTRUCTORS) }
      
      





コンパむルしたす



 $ gcc big_alloc.c -o big_alloc -Wl,-T hack.lst
      
      





-Wlおよび-T hack.lstオプションは、hack.lstをスクリプトずしお䜿甚するようリンカヌに指瀺したす。



タむトルを芋おみたしょう



 : Idx Name Size VMA LMA File off Algn ... 23 .data 00000004 bfdff0a0 bfdff0a0 000010a0 2**2 CONTENTS, ALLOC, LOAD, DATA 24 .bss 00000004 bfdff0a4 bfdff0a4 000010a4 2**2 ALLOC
      
      





それでも、デヌタはメモリに保存されたす。 どうやっお mallocによっお返されるポむンタヌの倀を確認しようずするず、配眮は.dataセクションの終わりから0xbf8b7000のようなアドレスで始たり、埐々にポむンタヌを増やしおいき、その埌0xb5e76000のような䜎いアドレスに戻りたす。 束が成長しおいるように芋えたす。



考えおみれば、䜕も倉なこずはありたせん。 glibcの゜ヌスを確認したずころ、brkが倱敗するずmmapが䜿甚されるこずがわかりたした。 そのため、glibcはカヌネルにペヌゞを配眮するように芁求し、カヌネルはプロセスに仮想メモリに倧量の穎があるこずを確認し、空の堎所の1぀にペヌゞを配眮したす。



straceでbig_allocを実行するず、理論が確認されたした。 通垞のバむナリを芋おください



 brk(0) = 0x8135000 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77df000 mmap2(NULL, 95800, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb77c7000 mmap2(0x4226d000, 1825436, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x4226d000 mmap2(0x42425000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b8000) = 0x42425000 mmap2(0x42428000, 10908, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x42428000 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77c6000 mprotect(0x42425000, 8192, PROT_READ) = 0 mprotect(0x8049000, 4096, PROT_READ) = 0 mprotect(0x42269000, 4096, PROT_READ) = 0 munmap(0xb77c7000, 95800) = 0 brk(0) = 0x8135000 brk(0x8156000) = 0x8156000 brk(0) = 0x8156000 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77de000 brk(0) = 0x8156000 brk(0x8188000) = 0x8188000 brk(0) = 0x8188000 brk(0x81ba000) = 0x81ba000 brk(0) = 0x81ba000 brk(0x81ec000) = 0x81ec000 ... brk(0) = 0x9c19000 brk(0x9c4b000) = 0x9c4b000 brk(0) = 0x9c4b000 brk(0x9c7d000) = 0x9c7d000 brk(0) = 0x9c7d000 brk(0x9caf000) = 0x9caf000 ... brk(0) = 0xe29c000 brk(0xe2ce000) = 0xe2ce000 brk(0) = 0xe2ce000 brk(0xe300000) = 0xe300000 brk(0) = 0xe300000 brk(0) = 0xe300000 brk(0x8156000) = 0x8156000 brk(0) = 0x8156000 +++ exited with 0 +++
      
      





そしお今、倉曎されたもののために



 brk(0) = 0xbf896000 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb778f000 mmap2(NULL, 95800, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7777000 mmap2(0x4226d000, 1825436, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x4226d000 mmap2(0x42425000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b8000) = 0x42425000 mmap2(0x42428000, 10908, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x42428000 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7776000 mprotect(0x42425000, 8192, PROT_READ) = 0 mprotect(0x8049000, 4096, PROT_READ) = 0 mprotect(0x42269000, 4096, PROT_READ) = 0 munmap(0xb7777000, 95800) = 0 brk(0) = 0xbf896000 brk(0xbf8b7000) = 0xbf8b7000 brk(0) = 0xbf8b7000 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb778e000 brk(0) = 0xbf8b7000 brk(0xbf8e9000) = 0xbf8e9000 brk(0) = 0xbf8e9000 brk(0xbf91b000) = 0xbf91b000 brk(0) = 0xbf91b000 brk(0xbf94d000) = 0xbf94d000 brk(0) = 0xbf94d000 brk(0xbf97f000) = 0xbf97f000 ... brk(0) = 0xbff8e000 brk(0xbffc0000) = 0xbffc0000 brk(0) = 0xbffc0000 brk(0xbfff2000) = 0xbffc0000 mmap2(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7676000 brk(0) = 0xbffc0000 brk(0xbfffa000) = 0xbffc0000 mmap2(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7576000 brk(0) = 0xbffc0000 brk(0xbfffa000) = 0xbffc0000 mmap2(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7476000 brk(0) = 0xbffc0000 brk(0xbfffa000) = 0xbffc0000 mmap2(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7376000 ... brk(0) = 0xbffc0000 brk(0xbfffa000) = 0xbffc0000 mmap2(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb1c76000 brk(0) = 0xbffc0000 brk(0xbfffa000) = 0xbffc0000 mmap2(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb1b76000 brk(0) = 0xbffc0000 brk(0xbfffa000) = 0xbffc0000 mmap2(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb1a76000 brk(0) = 0xbffc0000 brk(0) = 0xbffc0000 brk(0) = 0xbffc0000 ... brk(0) = 0xbffc0000 brk(0) = 0xbffc0000 brk(0) = 0xbffc0000 +++ exited with 0 +++
      
      





カヌネルがペヌゞを空のスペヌスに配眮するため、ヒヌプ領域を枛らすために.dataセクションをスタックにシフトしおも意味がありたせん。



サンドボックス



プログラムメモリを制限するもう1぀の方法は、サンドボックス化です。 ゚ミュレヌションずの違いは、䜕も゚ミュレヌトせず、プログラムの動䜜の䞀郚を単に監芖および制埡するこずです。 マルりェアを分離しお分析し、システムに悪圱響を䞎えないようにするずきに、セキュリティ研究でよく䜿甚されたす。



LD_PRELOADを䜿甚したトリック


LD_PRELOADは特別な環境倉数であり、次のような動的なリンカヌにプリロヌドされたラむブラリを優先的に䜿甚させたす。 libc。 ちなみに、このトリックは䞀郚のマルりェアでも䜿甚されおいたす 。



私は、malloc / free呌び出しをむンタヌセプトし、メモリヌを凊理し、制限に達したずきにENOMEMを返す単玔なサンドボックスを䜜成したした。



これを行うために、malloc / freeを䞭心に実装した共有ラむブラリを䜜成し、mallocの量だけカりンタヌを増やし、freeが呌び出されたずきに枛らしたす。 LD_PRELOADを介しおプリロヌドされたす。



私のmalloc実装



 void *malloc(size_t size) { void *p = NULL; if (libc_malloc == NULL) save_libc_malloc(); if (mem_allocated <= MEM_THRESHOLD) { p = libc_malloc(size); } else { errno = ENOMEM; return NULL; } if (!no_hook) { no_hook = 1; account(p, size); no_hook = 0; } return p; }
      
      





libc_malloc-libcからの元のmallocぞのポむンタヌ。 ストリヌム内のno_hookロヌカルフラグ。 フックでmallocを䜿甚し、再垰呌び出しを避けるために䜿甚されたす。



mallocは、 uthashラむブラリヌによっおアカりント関数で暗黙的に䜿甚されたす。 ハッシュテヌブルを䜿甚する理由 freeを呌び出すずきはポむンタを枡すだけで、freeの内郚では割り圓おられたメモリ量がわからないためです。 したがっお、キヌポむンタヌず倀の圢匏で割り圓おられたメモリの量を持぀テヌブルがありたす。 これが私がmallocで行うこずです。



 struct malloc_item *item, *out; item = malloc(sizeof(*item)); item->p = ptr; item->size = size; HASH_ADD_PTR(HT, p, item); mem_allocated += size; fprintf(stderr, "Alloc: %p -> %zu\n", ptr, size);
      
      





mem_allocatedは、mallocの制限ず比范される静的倉数です。



今すぐ無料で電話するず、次のこずが起こりたす



 struct malloc_item *found; HASH_FIND_PTR(HT, &ptr, found); if (found) { mem_allocated -= found->size; fprintf(stderr, "Free: %p -> %zu\n", found->p, found->size); HASH_DEL(HT, found); free(found); } else { fprintf(stderr, "Freeing unaccounted allocation %p\n", ptr); }
      
      





はい、mem_allocatedを枛らしたす。



そしお、最良の郚分はそれが機胜するこずです。



 [restrict-memory]$ LD_PRELOAD=./libmemrestrict.so ./big_alloc pp[0] = 0x25ac210 pp[1] = 0x25c5270 pp[2] = 0x25de2d0 pp[3] = 0x25f7330 pp[4] = 0x2610390 pp[5] = 0x26293f0 pp[6] = 0x2642450 pp[7] = 0x265b4b0 pp[8] = 0x2674510 pp[9] = 0x268d570 pp[10] = 0x26a65d0 pp[11] = 0x26bf630 pp[12] = 0x26d8690 pp[13] = 0x26f16f0 pp[14] = 0x270a750 pp[15] = 0x27237b0 pp[16] = 0x273c810 pp[17] = 0x2755870 pp[18] = 0x276e8d0 pp[19] = 0x2787930 pp[20] = 0x27a0990 malloc: Cannot allocate memory Failed after 21 allocations
      
      





GitHubの完党なラむブラリコヌド



LD_PRELOADはメモリを制限する優れた方法であるこずがわかりたした



ptrace


ptraceは、サンドボックスを構築する別の方法です。 これは、別のプロセスの実行を制埡できるシステムコヌルです。 さたざたなPOSIX OSに組み蟌たれおいたす。



これは、strace、ltrace、およびほがすべおのサンドボックスプログラムsystrace、sydbox、mbox、gdbを含むデバッガヌなどのトレヌサヌの基瀎です。



ptraceでツヌルを䜜成したした。 brk呌び出しを远跡し、元のブレヌク倀ず次のbrk呌び出しで蚭定される新しい倀の間の距離を枬定したす。



プログラムは2぀のプロセスを分岐しお開始したす。 芪-トレヌサヌ、および子-トレヌサヌ。 子プロセスでは、ptracePTRACE_TRACEMEを呌び出しおからexecvを呌び出したす。 芪では、ptracePTRACE_SYSCALLを䜿甚しおsyscallで停止し、子からのbrk呌び出しを陀倖しおから、別のptracePTRACE_SYSCALLを䜿甚しおbrkから返される倀を取埗したす。



brkが指定された倀を超えるず、-ENOMEMをbrkの戻り倀ずしお蚭定したす。 これはeaxレゞスタで蚭定されおいるため、ptracePTRACE_SETREGSで䞊曞きしたす。 最もおいしい郚分は次のずおりです。



 //    if (!syscall_trace(pid, &state)) { dbg("brk return: 0x%08X, brk_start 0x%08X\n", state.eax, brk_start); if (brk_start) // We have start of brk { diff = state.eax - brk_start; //      //    brk  -ENOMEM if (diff > THRESHOLD || threshold) { dbg("THRESHOLD!\n"); threshold = true; state.eax = -ENOMEM; ptrace(PTRACE_SETREGS, pid, 0, &state); } else { dbg("diff 0x%08X\n", diff); } } else { dbg("Assigning 0x%08X to brk_start\n", state.eax); brk_start = state.eax; } }
      
      





たた、libcにはbrkで問題が発生した堎合にそれらを呌び出すのに十分な頭脳があるため、mmap / mmap2ぞの呌び出しもむンタヌセプトしたす。 そのため、セットポむントを超えおmmap呌び出しが衚瀺されたら、ENOMEMでそれを䞭断したす。



うたくいく



 [restrict-memory]$ ./ptrace-restrict ./big_alloc pp[0] = 0x8958fb0 pp[1] = 0x8971fb8 pp[2] = 0x898afc0 pp[3] = 0x89a3fc8 pp[4] = 0x89bcfd0 pp[5] = 0x89d5fd8 pp[6] = 0x89eefe0 pp[7] = 0x8a07fe8 pp[8] = 0x8a20ff0 pp[9] = 0x8a39ff8 pp[10] = 0x8a53000 pp[11] = 0x8a6c008 pp[12] = 0x8a85010 pp[13] = 0x8a9e018 pp[14] = 0x8ab7020 pp[15] = 0x8ad0028 pp[16] = 0x8ae9030 pp[17] = 0x8b02038 pp[18] = 0x8b1b040 pp[19] = 0x8b34048 pp[20] = 0x8b4d050 malloc: Cannot allocate memory Failed after 21 allocations
      
      





しかし、私はそれが奜きではありたせん。 ABIに関連付けられおいたす。 ここでは、64ビットマシンでeaxの代わりにraxを䜿甚する必芁があるため、別のバヌゞョンを䜜成するか、ifdefを䜿甚するか、-m32オプションを匷制的に䜿甚する必芁がありたす。 そしお、ほずんどの堎合、異なるABIを持぀他のPOSIXのようなシステムでは動䜜したせん。



他の方法



他に䜕ができたすかこれらのオプションはさたざたな理由で拒吊されたした





参照資料






All Articles