カーネルとスタックとプロセス

スタックの役割

  • システムコール中にプロセスのスレッドは、ユーザースタックとカーネルスタックを持っている
    • システムコール実行が終わるまで、ユーザースタックは変化しない(シグナルハンドラは例外)
  • スタックにはスレッドが必要とする、関数やレジスタの状態などの実行情報が格納されている

Linuxカーネルでは、コンテキストの保存領域としてthread_info構造体とカーネルスタックを併用します。 この二つはプロセス毎に割り当てられており、プロセス生成時に作成されます。
Linuxのしくみを学ぶ – プロセス管理とスケジューリング より引用

カーネルと割り込み処理

  • カーネルはシステムコールのほかにデバイスからの割り込みにも対応する
    • デバイスからの割り込みに対し、割り込みサービスルーチンが登録されるが、重い処理が必要な際は割り込みスレッドにスケジューリングされる
    • 割り込みが到着してから処理されるまでの時間を割り込みレイテンシという
  • 割り込みには割り込み優先レベル(interrupt priority level: IPL)というアクティブな割り込みサービスルーチンの優先度を表すものがある
  • エラーの IPL は非常に高い、シリアル I/O についてもバッファオーバーフローを避けるためにクロックよりも高い IPL となっている

 Linuxカーネルはアプリケーションが動作するための基本環境を提供します。
(中略)
Linuxカーネルはこれらの便利な機能を提供しますが、処理を依頼されて初めて動作するイベント駆動型のプログラムです。アプリケーションからのシステムコールによる要求、ハードウェアからの割り込みによる要求を受けて、初めてその要求に対応する処理を行います。Linuxカーネルが能動的に動作することはありません。
0.1 Linuxカーネルとは – Linux Kernel Documents Wiki – Linux Kernel Documents – OSDN より引用

カーネルとプロセス

  • プロセスは fork() システムコールにて作成される

プロセス生成の方法・目的
fork: ウェブサーバーなどで同時にリクエストを受け付ける場合などに、プログラムの処理を複数のプロセスに分ける
execve: シェルから各種プログラムをたちあげるときなどに、プロセスを生成する

fork 関数のふるまい
子プロセスのメモリ領域を確保して親プロセスのメモリをコピー
fork 関数は親プロセスと子プロセスで戻り値が異なり、その値に応じたソースコードを、それぞれのプロセスで実行していく

execve 関数のふるまい
現在のプロセスのメモリに、引数で指定された実行ファイルのデータを上書きする
コンピュータシステムとプロセスの概要 – ゴミ箱 より

  • プロセスの構成要素は以下のようなもの
    • メモリアドレス空間
    • ファイルディスクリプタ
    • スレッドスタック
    • レジスタ
  • fork() は Copy On Write でパフォーマンスを向上できる
    • 前のアドレス空間の内容を全てコピーするのではなく、参照手段だけを用意し、変更が加わるタイミングでコピーを作る
  • プロセスはカーネルによってマルチタスクに実行される
  • プロセスは一つ以上のスレッドを持つ
    • スレッドはプロセス空間やファイルディスクリプタを共有する
    • スレッドはスタック、レジスタ、プログラムカウンタから構成される実行コンテキスト
    • マルチスレッドにすると、ひとつのプロセスが複数の CPU にまたがって並列実行可能
  • プロセスは以下の task_struct 構造体に対応する
struct task_struct {
    #...
    /* -1 unrunnable, 0 runnable, >0 stopped: */
    volatile long           state;

    /*
     * This begins the randomizable portion of task_struct. Only
     * scheduling-critical items should be added above here.
     */
    randomized_struct_fields_start

    void                *stack;
    atomic_t            usage;
    /* Per task flags (PF_*), defined further below: */
    unsigned int            flags;
    unsigned int            ptrace;

    #...

    int             on_rq;

    int             prio;
    int             static_prio;
    int             normal_prio;
    unsigned int            rt_priority;

    const struct sched_class    *sched_class;
    struct sched_entity     se;
    struct sched_rt_entity      rt;
    #...
    struct sched_dl_entity      dl;

    #...

    /*
     * Pointers to the (original) parent process, youngest child, younger sibling,
     * older sibling, respectively.  (p->father can be replaced with
     * p->real_parent->pid)
     */

    /* Real parent process: */
    struct task_struct __rcu    *real_parent;

    /* Recipient of SIGCHLD, wait4() reports: */
    struct task_struct __rcu    *parent;

    /*
     * Children/sibling form the list of natural children:
     */
    struct list_head        children;
    struct list_head        sibling;
    struct task_struct      *group_leader;

    /*
     * 'ptraced' is the list of tasks this task is using ptrace() on.
     *
     * This includes both natural children and PTRACE_ATTACH targets.
     * 'ptrace_entry' is this task's link on the p->parent->ptraced list.
     */
    struct list_head        ptraced;
    struct list_head        ptrace_entry;

    /* PID/PID hash table linkage. */
    struct pid_link         pids[PIDTYPE_MAX];
    struct list_head        thread_group;
    struct list_head        thread_node;

    struct completion       *vfork_done;

    /* CLONE_CHILD_SETTID: */
    int __user          *set_child_tid;

    /* CLONE_CHILD_CLEARTID: */
    int __user          *clear_child_tid;

    u64             utime;
    u64             stime;

    #...
}
  • プロセスは以下のようなライフサイクルを持つ
    • マルチスレッド下では スレッドがスケジューリングされるような実装が追加される
                          <= (プリエンプション/タイムクォンタムを使い切る)
プロセス作成 --> [アイドル状態] => [実行可能] => [処理中] => [ゾンビ状態]
                      ^                      |
                      |------[スリープ]<-------|  (I/O など: ブロック)
  • プロセス環境は、アドレス空間内のデータとカーネルコンテキストから構成される
  • カーネルコンテキストは ps コマンドで解析できる
      - プロセスのプロパティと統計情報から構成される
  • ユーザーアドレス空間には実行可能ファイル、ライブラリ、ヒープからなるプロセスセグメントが含まれている

演習

システムコール、プロセスとtask_struct構造体 より引用

★問題(101) システム・コールとライブラリ関数の相違点
システム・コールとライブラリ関数の相違点を述べなさい。

WIP

★問題(102) chdir()システムコールの引数と結果
このシステム・コールを処理する関数がカーネルの中でどのように定義されて いるか、その概略(引数と結果の宣言)を示しなさい。関数の内容は空でよい。 マクロを利用しても利用しなくてもどちらでもよい。

WIP

★問題(103) Ready状態のプロセス
オペレーティング・システムでは、「一般に」プロセスは、 実行待ち(Ready)、実行中(Running)、 待機中(Waiting、Blocked)という3つの 状態を持つ。Linux において、プロセスが Ready 状態であることを 示すために、task struct のフィールド state に、何という値を設定しているか。

WIP

★問題(104) pidとppid

WIP

★問題(105) getuid()システム・コール
getuid() システム・コールを実装の概略を、今日の授業の範囲内で答えなさい。 利用する重要な変数、マクロ、構造体を列挙しなさい。そして、どのようにポ インタをたどっていくかを示しなさい。概略を記述するためには、簡易的なC 言語、日本語、または、英語を使いなさい。

WIP

参考資料

自分は最初は「バッファオーバーフローぐらい知ってるぞ」などと調子づいていたのですが、それを実現するための鮮やかな手際、環境変数を利用したスマートな攻撃方法、はたまたシェルコードの説明やシェルコードを自作する方法まで載っていて、自分の知らなかった情報が詰まっていてすごく面白かったです。「root権限で動くprocessに脆弱性があるとすごく危険」という事実も、知識としては知っていたものの、実際に「脆弱性を突いてrootでshellを立ち上げるコード」を目にすることで「実感」を持つことが出来るようになりました
「HACKING」や「Linuxカーネル2.6解読室」など、最近の「買って良かった技術書」について – Nao Minami’s Blog より引用

面白そう。読んでみたい。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください