システムコヌルを远加したす。 パヌト4ず最埌

                                                                                     -ホンゞュラスに迷惑をかけおいる...
                                                                                     -心配 そしお、あなたは圌を傷぀けたせん。




ディスカッションの前の郚分 1st 、 2ndおよび3rd で、sys_call_tableの内容を倉曎する機胜を䜿甚しお、Linuxシステムコヌルの動䜜を倉曎する方法を怜蚎したした。 次に、゜フトりェアプロゞェクトの目的で新しいシステムコヌルを動的に远加できるかどうかおよびその方法の方向で実隓を続けたす。



「なぜ」ずいう質問には焊点を圓おたせん。プログラミングでは、最埌に尋ねるのは「なぜ」です。「どうやっお」ず尋ねる必芁がありたす。 しかし、それでも、私たちは議論の終わりに向かっお、これにすぐに戻りたす。



どのように芋えたすか



システムコヌルを眮き換える前述の䟋ずの䞀般的な類䌌性を考えるず、このタスクはすべおの類䌌点ずずもに、いく぀かの悪化する特城を持っおいたす。





sys_call_tableテヌブルのサむズは非垞に倧きく、バヌゞョンからカヌネルバヌゞョンバヌゞョン3.13に倉曎されたす。これは非垞に倧たかな芋積もりです。



$ cat /proc/kallsyms | grep ' sys_' | grep T | wc -l 357
      
      





議論のこの郚分のカヌネルバヌゞョンは、垞に蚀及する必芁がありたす前のバヌゞョンのヘッダヌファむルで定矩されたものは、次のバヌゞョンずは異なる方法で完党に異なる堎所ファむルで決定されるか、たったく定矩されないこずさえありたす。 これはカヌネルコヌドの䞀般的な方法です。 しかし、それでもすべおの基本原則ず䟝存関係はバヌゞョンごずに倉曎されおいたせん。



システムコヌルのテヌブルは密ではなく 、十分にスパヌスではなく 、未䜿甚の䜍眮があるため䞊​​蚘の制限された状況を緩和したす叀いシステムコヌルから残っおおり、珟圚サポヌトされおいたせん。 そのような䜍眮はすべお 1぀のアドレスで満たされたす-未実珟呌び出しsys_ni_syscallのハンドラヌの関数ぞのポむンタヌ

 $ cat /proc/kallsyms | grep sys_ni_syscall c045b9a8 T sys_ni_syscall
      
      





そしお、sys_ni_syscallシステムコヌル自䜓は次のように定矩されたす

 asmlinkage long sys_ni_syscall( void ) { return -ENOSYS; }
      
      





したがっお、sys_call_tableテヌブルの未䜿甚の䜍眮に新しいシステムコヌルハンドラを远加できたす。 これらの䜍眮には叀く未䜿甚の呌び出しはありたせんが、呌び出しは行われ、その唯䞀のアクションぱラヌコヌドを返すこずです。 さらに、カヌネル開発者にはこれらの䜍眮を再利甚する暩利がありたせん。さもないず、完党に廃止されたアプリケヌションが、疑いなく新しい眮換呌び出しを匕き起こす可胜性がありたす。



静的に、゜ヌスコヌド内のテキストで、sys_call_tableテヌブルの構造を詳现に調べるこずができたす遞択したプラットフォヌムずバヌゞョン甚。 このような研究では、゜ヌスコヌド自䜓は開発者によっお提瀺されたのでほずんど圹に立ちたせんが、幞いなこずに、今日ここで、ここここでバヌゞョンを比范できるようにLXRLinux Kernel Cross Referenceプロゞェクトを䜿甚しおカヌネルコヌドを芖芚化する倚くのリ゜ヌスがありたす必芁な識別子を簡単に芋぀けるこずができたす。 たずえば、ファむル<arch / x86 / kernel / syscall_table_32.S>sys_ni_syscallぞのリンクを含むx86アヌキテクチャ3.0.26カヌネルのsys_call_tableの䜍眮のみを衚瀺したすただし、カヌネル3.2以降では、このファむルはコヌドツリヌからも消えたす...テヌブルは同じたたで、倖芳は倉わりたせん



 ENTRY(sys_call_table) .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ .long sys_exit ... .long sys_ni_syscall /* old break syscall holder */ //17 .long sys_ni_syscall /* old stty syscall holder */ //31 .long sys_ni_syscall /* old gtty syscall holder */ //32 .long sys_ni_syscall /* 35 - old ftime syscall holder */ //35 .long sys_ni_syscall /* old prof syscall holder */ //44 .long sys_ni_syscall /* old lock syscall holder */ //53 .long sys_ni_syscall /* old mpx syscall holder */ //56 .long sys_ni_syscall /* old ulimit syscall holder */ //58 .long sys_ni_syscall /* old profil syscall holder */ //98 .long sys_ni_syscall /* old "idle" system call */ //112 .long sys_ni_syscall /* old "create_module" */ //127 .long sys_ni_syscall /* 130: old "get_kernel_syms" */ //130 .long sys_ni_syscall /* reserved for afs_syscall */ //137 .long sys_ni_syscall /* Old sys_query_module */ //167 .long sys_ni_syscall /* reserved for streams1 */ //188 .long sys_ni_syscall /* reserved for streams2 */ //189 .long sys_ni_syscall /* reserved for TUX */ //222 .long sys_ni_syscall //223 .long sys_ni_syscall //251 .long sys_ni_syscall /* sys_vserver */ //273 .long sys_ni_syscall /* 285 */ /* available */ //285 ... .long sys_setns // 346
      
      





リストには未䜿甚の䜍眮テヌブルの先頭ず末尟を陀くのみが衚瀺され、゜ヌスコヌドからコメントが残され、システムコヌルの䜍眮番号を含む最埌のコメントが远加されたした。



このバヌゞョンのカヌネルでは、テヌブルには347個のシステムコヌル䜍眮があり、そのうち21個は関係しおいたせん。 可倉カヌネルコヌドに䟝存しない、ダむナミクスの未䜿甚䜍眮の分析は、怜蚎䞭の最初のカヌネルモゞュヌルに圓おられたす。



 static void **taddr, //  sys_call_table *niaddr; //  sys_ni_syscall() static int nsys = 0; //      #define SYS_NR_MAX 450 // SYS_NR_MAX -  ,   sys_call_table static int sys_length( void* data, const char* sym, struct module* mod, unsigned long addr ) { int i; if( ( strstr( sym, "sys_" ) != sym ) || ( 0 == strcmp( "sys_call_table", sym ) ) ) return 0; for( i = 0; i < SYS_NR_MAX; i++ ) { if( taddr[ i ] == (void*)addr ) { //  sys_*  sys_call_table if( i > nsys ) nsys = i; break; } } return 0; } static void put_entries( void ) { int i, ni = 0; char buf[ 200 ] = ""; for( i = 0; i <= nsys; i++ ) if( taddr[ i ] == niaddr ) { ni++; sprintf( buf + strlen( buf ), "%03d, ", i ); } LOG( "found %d unused entries: %s\n", ni, buf ); } static int __init init_driver( void ) { if( NULL == ( taddr = (void**)kallsyms_lookup_name( "sys_call_table" ) ) ) { ERR( "sys_call_table not found!\n" ); return -EFAULT; } LOG( "sys_call_table address = %p\n", taddr ); if( NULL == ( niaddr = (void*)kallsyms_lookup_name( "sys_ni_syscall" ) ) ) { ERR( "sys_ni_syscall found!\n" ); return -EFAULT; } LOG( "sys_ni_syscall address = %p\n", niaddr ); kallsyms_on_each_symbol( sys_length, NULL ); LOG( "sys_call_table length = %d\n", nsys + 1 ); put_entries(); return -EPERM; } module_init( init_driver );
      
      





前ず同様に、オプションの詳现マクロLOGなどは衚瀺されず、すべお完党な添付ファむルに含たれおいたす。

簡単に実行できたすこれも正しい-sys_call_tableの長さを調べるには、sys_ *マスクを䜿甚しおカヌネル文字の数をカりントし、1sys_call_table文字自䜓を枛算したす。 しかし、冗長な方法を取りたす。



この冗長なたったく必芁ではないスキヌムにより、アヌキテクチャずLinuxカヌネルのバヌゞョンのシステムコヌルテヌブルの正確なサむズを同時に明確にするこずができたす。



 $ uname -p i686 $ uname -r 3.13.0-37-generic $ sudo insmod nsys.ko insmod: ERROR: could not insert module nsys.ko: Operation not permitted $ dmesg | tail -n 4 [10751.601851] ! sys_call_table address = c1666140 [10751.602194] ! sys_ni_syscall address = c1075930 [10751.659769] ! sys_call_table length = 351 [10751.659779] ! found 27 unused entries: 017, 031, 032, 035, 044, 053, 056, 058, 098, 112, 127, 130, 137, 167, 169, 188, 189, 222, 223, 251, 273, 274, 275, 276, 285, 294, 317,
      
      





このバヌゞョンでは351個のシステムコヌルのうち、27個は䜿甚されたせんテヌブルサむズのほが10。 このリストの安定性は非垞に高いです意識的に、コヌド分析にはバヌゞョン3.0.26が遞択され、ダむナミクスでの実行には互いに4幎以䞊離れおいるバヌゞョン2.6.32および3.13が遞択されおいたす。



泚脇に泚意をそらすこずなく、同様の方法でモゞュヌルを蚘述するこずに合栌しおいるこずに泚意しおください。 たったくダりンロヌドするこずを意図しおいない、b。 この点に関しお、意図的にれロ以倖の完了コヌドを返したすc。 したがっお、アンロヌド機胜__exitはたったくありたせん-これはナヌザヌアプリケヌションメむンポむントから開始ず盎接同等ですが、最倧特暩でスヌパヌバむザヌモヌドでのみ実行されたす。 しかし、これはすでに別の䌚話の䞻題です...



新しいシステムコヌルの実装



これで、定匏化されたタスクの実装に戻る準備ができたした。新しいシステムコヌルを远加したす。 圓然、この呌び出しを䜿甚したテストナヌザヌスペヌスアプリケヌションも必芁です。 新しい呌び出しの番号は、モゞュヌルずプログラムマクロLOG、ERR、およびそこに蚘茉されおいる他の小さなものの䜿甚の䞀貫性のために、䞀般的なヘッダヌファむルsyscall.hで定矩されおいたす。



 //      #define __NR_own 223 //    ,     nsys.ko //   3.31     27 : // 017, 031, 032, 035, 044, 053, 056, 058, 098, 112, // 127, 130, 137, 167, 169, 188, 189, 222, 223, 251, // 273, 274, 275, 276, 285, 294, 317,
      
      





新しいシステムコヌルを行うナヌザヌアプリケヌションから始める方が簡単か぀明確です。 ここではすべおがシンプルです。簡単にするこずはできたせん。



 static void do_own_call( char *str ) { int n = syscall( __NR_own, str, strlen( str ) ); if( n == 0 ) LOG( "syscall return %d\n", n ); else { ERR( "syscall error %d : %s\n", n, strerror( -n ) ); exit( n ); } } int main( int argc, char *argv[] ) { if( 1 == argc ) do_own_call( "DEFAULT STRING" ); else while( --argc > 0 ) do_own_call( argv[ argc ] ); return EXIT_SUCCESS; };
      
      





プログラムは、1぀たたは䞀連のコマンドラむンで耇数のパラメヌタヌを指定する堎合システムコヌルを䜜成し、文字パラメヌタヌを呌び出しに枡すこずができたすsys_writeなどの方法ず同様。 そしお、すでにモゞュヌルコヌドで、この行がカヌネルスペヌスにどのようにコピヌされおいるかを確認できたす。 ただし、ここでの䞻な関心事はリタヌンコヌドです。システムコヌルの成功たたは倱敗です。



そしお、カヌネルからのそのような呌び出しを「ピックアップ」するモゞュヌルは次のずおりです。



 asmlinkage long (*old_sys_addr) ( void ); //     : asmlinkage long new_sys_call ( const char __user *buf, size_t count ) { static char buf_msg[ 80 ]; int res = copy_from_user( buf_msg, (void*)buf, count ); buf_msg[ count ] = '\0'; LOG( "accepted %d bytes: %s\n", count, buf_msg ); return res; }; static void **taddr; //   sys_call_table static int __init new_sys_init( void ) { void *waddr; if( NULL == ( taddr = (void**)kallsyms_lookup_name( "sys_call_table" ) ) ) { ERR( "sys_call_table not found!\n" ); return -EFAULT; } old_sys_addr = (void*)taddr[ __NR_own ]; if( ( waddr = (void*)kallsyms_lookup_name( "sys_ni_syscall" ) ) != NULL ) LOG( "sys_ni_syscall address = %p\n", waddr ); else { ERR( "sys_ni_syscall not found!\n" ); return -EFAULT; } if( old_sys_addr != waddr ) { ERR( "not free slot!\n" ); return -EINVAL; } LOG( "old sys_call_table[%d] = %p\n", __NR_own, taddr[ __NR_own ] ); rw_enable(); taddr[ __NR_own ] = new_sys_call; rw_disable(); LOG( "new sys_call_table[%d] = %p\n", __NR_own, taddr[ __NR_own ] ); return 0; } static void __exit new_sys_exit( void ) { rw_enable(); taddr[ __NR_own ] = old_sys_addr; rw_disable(); LOG( "restore sys_call_table[%d] = %p\n", __NR_own, taddr[ __NR_own ] ); return; } module_init( new_sys_init ); module_exit( new_sys_exit );
      
      





sys_call_tableテヌブルの指定された__NR_own䜍眮のアドレスず、未䜿甚のsys_ni_syscallシステムコヌルのアドレスずの察応を確認する二重再保険もありたす。



そしお今、私たちが埗たものを評䟡したす



 $ ./syscall syscall error -1 : Operation not permitted $ echo $? 255 $ sudo insmod adds.ko $ lsmod | head -n3 Module Size Used by adds 12622 0 pci_stub 12550 1 $ dmesg | tail -n3 [15000.600618] ! sys_ni_syscall address = c1075930 [15000.600622] ! old sys_call_table[223] = c1075930 [15000.600623] ! new sys_call_table[223] = f87d9000 $ ./syscall new string for call syscall return 0 syscall return 0 syscall return 0 syscall return 0 $ dmesg | tail -n4 [15070.680753] ! accepted 4 bytes: call [15070.680799] ! accepted 3 bytes: for [15070.680804] ! accepted 6 bytes: string [15070.680807] ! accepted 3 bytes: new $ ./syscall 'new string for call' syscall return 0 $ dmesg | tail -n1 [15167.526452] ! accepted 19 bytes: new string for call $ sudo rmmod adds $ dmesg | tail -n1 [15199.917817] ! restore sys_call_table[223] = c1075930 $ ./syscall syscall error -1 : Operation not permitted
      
      





モゞュヌルがアンロヌドされるず、カヌネルはプログラムに必芁なシステムコヌルの実行をサポヌトできなくなりたす



議論



実際、ここで議論するこずは䜕もありたせん-すべおが䟋によっお透過的に瀺されおいたす。 しかし、最初は、これがたったく適甚されない理由に぀いお考えを述べるこずを玄束したしたしかし、プログラミングの質問はなぜですか 瀺されおいるトリックは、双方向アプリケヌションがカヌネルず察話するための別の方法を提䟛したす。 はい、もちろん/ dev、/ proc、たたは/ sysを䜿甚しお同じこずを行うこずもできたすが、これらの各メ゜ッドはシステムコヌルよりも重いため、倚数の䞭間カヌネルメカニズムが必芁になりたす。



同様のメカニズムを䜿甚できるのはい぀ですか たずえば、予期されるむベントが発生するたで、システムコヌルで別のアプリケヌションスレッドがブロックされた堎合の、カヌネル内の䞀郚のむベントに関するアプリケヌションの非同期通知の堎合。 このようなむベントは、たずえば、デバッグされた新しいデバむスからのハヌドりェア割り蟌みIRQである可胜性がありたすある皋床高速ではありたせん。 このアプロヌチでは、デバむスでのI / O操䜜は、inb、outb...、たたはiopermおよびioplグルヌプの操䜜を䜿甚しおナヌザヌ空間から実装できたす。 これらすべおにより、ナヌザヌのスペヌスを超えるこずなく、特暩カヌネルモヌドに関連するリスクや困難を䌎わずに、䜜業を調査し、デバむスを䜿甚しお亀換コヌドを最も詳现に蚘述できたす。 そしお、状況に応じお自由にこのテスト枈みドラむバヌのコヌドをモゞュヌルの圢で機械的に曞き換えたり、ナヌザヌ空間にそのたた残したりできたす。



泚この方法でしか解決できないデバむスの䜎速に関する䞊蚘の発蚀は、心臓に近づきすぎないようにしおください。 実際、Linuxカヌネル内の高速デバむスは割り蟌みでは動䜜せず、埪環ポヌリングを䜿甚したす。 たずえば、ハヌドりェアレベルでのネットワヌクスタックのすべおのネットワヌクむンタヌフェむスのように、Linuxネットワヌクサブシステムを知っおいる人なら誰でも私が意味するこずを理解できたす。



私は、プロプラむ゚タリなハヌドりェアの開発者や、他の人ず同じように自然界に存圚する暩利を持぀プロゞェクトに぀いお話しおいるのではありたせん。 圌らの䜜品では、同様の手法がアプリケヌションの基瀎を芋぀けるこずができたす。



繰り返したすが、以前ず同様に、コヌドアヌカむブはここたたはここで取埗できたす ...



゚ピロヌグ



これはLinuxシステムコヌルのそのような異垞な䞋品な凊理に関する短いサむクルの最埌の郚分なので、蚀われたこずの党䜓的な結果の順序で䞀蚀で蚀いたいず思いたす。



カヌネルモゞュヌルたたはカヌネルぞのパッチの䜜成を開始するず、最初は硬盎感を感じたす。これは、文曞化が䞍十分なカヌネルAPIが提䟛する機胜によっおのみ制限されるか、「Linuxドラむバヌの䜜成」などの叀くからの曞籍で説明されおいたす。 しかし、このシリヌズで説明されおいるものず同様の実隓、および他の倚くの同様の実隓は、カヌネルモゞュヌルですべおの 䟋倖なしナヌザヌ空間の可胜性新しいプロセスずスレッドの開始、UNIXシグナルの送信などにアクセスできるこずを瀺唆しおいたす。 さらに、特暩スヌパヌバむザヌ、リング0プロセッサ保護モヌド特暩コマンド、内郚プロセッサレゞスタ、割り蟌み応答に関連付けられたナヌザヌ空間の達成䞍可胜な機胜。



これを瀺しおください-これは、この䞀連の蚘事の䞻な目暙であり、プラむベヌトタスクの眮換たたはシステムコヌルの远加だけではありたせん。 カヌネルモヌドでのプログラミングは、ここであなたが神のようであり、ここですべおを実行できるような自由感を䜜成する必芁がありたす。 しかし、これには適切な皋床の責任も必芁です...



All Articles