連載 /JavaServer Pages—@ 図 8 ctl:range のタグハンドラのソースコード (Range ・ java) package CO Ⅱ t て 01 ; import javax. servlet ・ JSP ・ tagext . * ; import j avax. servlet . 」 sp. * ; import j ava. iO . * ; public class Range extends TagSupport public void setEnd(String v) { } catch (NumberFormatException st art lnteger. parselnt(v) ; try { public void setStart (String v) { int end = 0 ; int start = 0 ; トールしたディレクトリの下の、 try { WEB—INF/cIasses/controI/Foreach. class WEB—INF/web . xml WEB-INF/t1d/contr01. tld WEB—INF/c1asses/contr01/ForeachTEI . class 84 TLD では、カスタムタグの属性の名前や型 ( クラス ) 、 いるかどうかを調べることもできます。 とともに指定されている属性の値が必要な条件を満たして をみてきました。 TagExtraInfo を使うと、カスタムタグ 前節では、 TagExtraInfo クラスを利用した変数の生成 カスタムタグの属性の検査 点が異なっています。 タグか生成する変数の情報を JSP 工ンジンに渡している ていませんが、 ForeachTEI クラスを使って ctl:foreach です。 array. jsp ファイルのコード自体は前回から変更し コード、、 array. jsp ・で、図 7 は array. jsp を表示した画面 図 6 は ctl:foreach タグを使った JSP ページのソース ジを表示した例を示します。 を利用した JSP ページのソースコードと、この JSP«— こちらも前回の医しになりますが、 ctl:foreach タグ ctl:foreach を使った JSP ページの表示 each タグの準備か整いました。 に置きます。これで、 TagExtraInfo を用いた ctl:for- end = lnteger ・ parselnt (v) ; } catch (NumberFormatException e) { public int d0StartTag ( ) throws JspException { return SKIP_BODY ; public int d0EndTag ( ) throws JspException { try { pageContext . getOut ( ) . println(" [ " + start + - } catch (IOException e) { } return EVAL_PAGE ; UNIX MAGAZINE 2003.5 く ctl :range start=" 初期値 " e Ⅱ d = " 最終値 " / > ち、 JSP ファイルに ctl:range は、 start" と、、 end" の 2 つの属性をも て、新しいカスタムタグを用意しましよう。 ます、属 1 生値の検査方法の説明と実験のための材料とし ctl:range タク トに変換するときに属性値を検査できます。 TagExtraInfo を利用すれは、 JSP ファイルをサープレッ 入れ、実行時に属性値を調べることは可能です。しかし、 理する際に呼び出されるメソッド ) に検査用のコードを もちろん、タグハンドラの setter メソッド ( 属性を処 ことはできません。 があるかどうかや、他の属匪の値との関係などを記述する 必かどうかなどを指定できますが、特定の値をとる必要 く /tag> く /attribute> く name>end く /name> く attribute> く /attribute> く name>start く /name> く attribute> く body—content>empty く /body—content> く tag¯class>control . Range く /tag—class> く name>range く /name> く t ag> 図 9 ctl:range タグの TLD の記述
連載 / IPv6 の実装ー⑩ 図 5 引数の正当性の確認 970 9 71 972 973 974 975 976 if (src = = NULL Ⅱ dst = NULL) panic("key—allocsa: NULL pointer is passed. " ) ; if (family = AF_INET6 & & ( ( (struct sockaddr *)src)->sa-family ! = AF_INET6 Ⅱ ( (struct sockaddr *)dst)->sa-family ! = AF_INET6)) { panic("key—allocsa: src/dst family is inconsistent") ; 図 6 優先して禾する SAD 工ントリの決定 982 983 984 985 986 987 988 if (key—preferred-oldsa) { saorder—state—valid = saorder_state_valid_prefer_old ; ARRAYLEN (saorder_state—valid—prefer—old) ; arrayslze } else { saorder_state—valid = saorder_state_valid_prefer_new ; ARRAYLEN (saorder-state—valid—prefer-new) ; arraYSIZe 図 7 イ銑して堋する SAD 工ントリの決定 ( 2 ) 167 168 169 170 171 172 static const u—int saorder—state—valid—prefer_old [ ] SADB_SASTATE_DYING , SADB_SASTATE_MATURE , static const u_int saorder—state—valid_prefer_new ロ SADB_SASTATE_MATURE , SADB_SASTATE_DYING , ・ SAD 工ントリの始点アドレス (src) ・ SAD 工ントリの終点アドレス (dst) ・ IP セキュリティの不鶤頁 (proto) ・ SPI 値 (spi) UNIX MAGAZINE 2003.5 valid に saorder-state-valid-prefer-old が設定され、 key-preferred-oldsa が真の場合は、 saorderstate- の値によって図 7 のいすれかの値か、設定されます。 state-valid は u-int 型の配列で、 key-preferred-oldsa 工ントリを優先して利用するかを決定します。 saorder- 工ントリの情報か史新されている途中で、どちらの SAD る時間があります。図 6 の key-preferred-oldsa は SAD れないよう、かならす新旧 2 つの SAD 工ントリが共存す す。 SAD 工ントリか更新される際、既存の通信が切断さ 向上させるために SAD 工ントリが定期的に更新されま 鍵交換プロトコルを利用している場合、セキュリティを 定したアドレス・ファミリーも同一でなけれは・なりません。 family て指定したアドレス・ファミリーと、 src/dst で指 アドレスを指定しなけれはなりません ( 970 行目 ) 。また、 key-allocsa() を呼び出す場合、かならす始点およひ終点 970 ~ 976 行目 ( 図 5 ) では引数の正当性を石忍します。 DYING 状態の SAD 工ントリが MATURE 状態のエン トリよりも優先されます。逆に、 key-preferred-oldsa が 偽であれば MATURE 状態のエントリが優先されます。 1001 LIST_FOREACH(sah, &sahtree, chain) { 1 , 001 行目から SAD 工ントリの検索を開始します。 SAD は secashead 構造体のリストとして実現されていま す。さらに、各 SAD 工ントリは、 secashead 構造体に secasvar 構造体の配列として登録されています。図 8 に SAD の構造を示します。 1 001 ~ 1 074 行目のループで、 secashead 構造体のリ ストメンバーを 1 っすっ石忍します。 1 , 006 ~ 1 , 073 行目のループでは、 982 ~ 988 行目て 1 夬 定された優先度に従って、 secasvar 構造体のリストであ る savtree のメンバーを 1 っすっ石忍します。旧い SAD 工ントリを優先するのなら sah->savtree[DYING] をさ きに、新しい SAD 工ントリを優先するのであれば sah ー > savtree[MATURE] をさきに検索します ( 図 9 ) 。 1011 if ( p て 0t0 ! = sav—>sah—>saidx. proto) 1012 continue ; 1013 if (spi ! = sav—>spi) continue ; 1014 73
連載 / 旧 v6 の実装ー⑩ 図 1 SAD 工ントリの検索 733 740 739 734 if ( (sav = key—a110csa(AF-INET6 , (caddr-t)&src—sa, IPPROTO_AH , spi) ) goto fail; (caddr-t)&dst-sa, 認証ヘッダの入力処理 684 ah6—input (mp, offp, proto) 683 int 明記していないコードは ah-input. c からの抜粋てす。 されていないかどうかを石忍します。以後ファイル名を 認証ヘッダは、入力した IP バケットか転全中で改竄 685 686 687 { struct mbuf **mp , int *offp, proto; ah6-input() は 3 つの引数をもちます。 mp は入力し た IP?NO ケットかオ褓内された mbuf へのポインタ、 offp は IP'NO ケットのうび頁アドレスから認証ヘッダの : 頁アドレ スまでのオフセットで、 proto には認証ヘッダのプロトコ ル番号である 51 か設定されます。 IP6_EXTHDR_CHECK (), off , sizeof (struct 706 (h) , IPPROTO_DONE) ; 707 ah = (struct ah * ) (mtod(m, caddr—t) + off) ; 706 ~ 707 行目で、ヘッダ処理に必喫な清幸肋ゞ連続した メモリ領域に配置されているかを石忍します。認証ヘッダ のう巨頁を示すポインタ変数 ah 経由で認証ヘッダ内部の 報にアクセスするため、認証ヘッダ全体里続したメモリ 領域に配置されていなけれはなりません。 ip6 = mt0d (m , struct ip6—hdr * ) ; 716 717 nxt = ah—>ah_nxt ; 716 行目で、 IP バケットの情報をポインタ変数 ip6 経 由て参照できるようにします。 nxt には認証ヘッダの次に 続く刻に、ツ久もしくは上位層プロトコルの番号が定 されます。 720 if (ip6-getpktaddrs(m, &src—sa' &dst-sa) ) ip6-getpktaddrs() を呼び出し、スコープ情報付きの始 点 / 終点アドレスを src-sa と dst-sa に取り出します。 SAD の検索 認証ヘッダの処理では、ます受信した認証ヘッダに対応 する SAD (Security Association Database) 工ントリ があるかを石忍します。 724 spi = ah—>ah—spi; SAD 工ントリは、 SPI (Security Parameter lndex) と受信ノードの IP アドレスの組により、ノード内で一 諸、リ、 に識別することができます。 SPI には通信している 2 者間 であらかじめ合意された値カ硬われるので、 SPI をキーに して SAD 工ントリを特定できます。 SPI の値は認証ヘッ ダに含まれています。 724 行目で、認証ヘッダに指定され ている SPI 値 (ah-spi) を取り出します。 if (ntohs (ip6->ip6—p1en) 726 730 731 } goto fail ; 721 goto fail; KAME では、バケットの始点 / 終点アドレスを参照 する際に、 IP バケットに埋め込まれている値を参照しま せん。スコーフ情報が欠けているからです。 720 行目で、 UNIX MAGAZINE 2003.5 726 ~ 731 行目は巨大ペイロード・オプションのチェ ックです。巨大ペイロード・オプションが使われている と、認証ヘッダは利用できません。巨大ペイロード・オプ ションか利用されている場合、 IP バケットのペイロード 長 (ip6-plen) は 0 に設定されています。ペイロード長が 0 であればバケットを破棄します。 733 ~ 740 行目 ( 図 1 ) で、 SAD 工ントリを検索しま す。 key-allocsa() は、引数て指定された条件に適合する SAD 工ントリを検索し、変数 sav にポインタを設定しま す。 sav は secasvar 構造体のポインタ変数です。 733 ~ 734 行目では、 IPv6 の SAD 工ントリ (AF-INET6) で、 始点アドレスと終点アドレスが入力した IP'NO ケットの始 点アドレス (srcsa) と終点アドレス (dstsa) 、 IP セキュ リティの不頁か認証ヘッダ (IPPROTO-AH) 、 SPI 値が 入力した IP バケットで指定されていた値 (spi) であるも 67
Linux の プートプロセスをみる 白崎博生 ユーザーフロセス /sbin/init の起動 1 年にわたって解説してきた Linux カーネルのプート プロセスも、今回で最後です。 今月は、ユーサープロセス /sbin/init を起重丿ける処理 について説明します。 さて、話は前回の init() の 829 行目から続きます。 します。 言のに注目し、ディスクからの言も囚み処理の説明は省略 おもにメモリ上作 ( 各種のチェックやデスクリプタの に複雑て難しい部分といえます。ただし、この連載では、 す。このため、 execve の処理はカーネルのなかでもとく ルをメモリに読み込むためのディスクアクセスも発生しま が、、がらり " と変わります。もちろん、プログラム・ファイ クリプタも再設定します。ということは、プロセスの状態 てテキストコードやスタックを入れ替え、プロセス・デス すなわち、現在のページテープルのマッピングを更新し とスタック ) を切り替えます。 ム・ファイルを読み込み、夫行コンテキスト ( プログラム システムコール execve は、引数に指定されたプログラ システムコーノレ execve 照してください ) 。 static inline int execve(const char *fi1e , char **argv , long 'int char **envp) _res; volatile ( $ 0X80 " (--res) ( 11 ) , "b" ((long)(file)), ((long) (envp))) ; 0130 : 0131 : 0829 : static char *argv—init [ 10 ] {"init", NULL,}; static char *envp—init [ 10 ] {"HOME=/" "TERM=1inux" , NULL , } ; execve ( " /sbin/init ” argv—init , envp—init) ; 829 行目の execve() は、マクロによって次のようなイ ンライン関数に展開されます ( 諞田は 2003 年 4 月号を参 UNIX MAGAZIN E 2003.5 if ( (unsigned 10 Ⅱ g ) (—-res) > = (unsigned 1 。取 g ) ( ー 125 ) ) { errno 151 待避し、システムコール番号に対応するサービスルーチン system-call() は、いくつかのレジスタをスタックに す。 タ番号 80H に対する割込みハンドラは system-call() で 割込みハンドラの実行を開始します。 Linux では、べク と、 CPU はいくつかのレジスタをスタックに待避して、 INT 80H を実行してソフトウェア割込みを発生させる ・ INT 80H を実行 ・ EDX レジスタに envp-init のアドレスをイ褓内 ・ ECX レジスタに argv-init のアドレスをイ褓内 ・ EBX レジスタに、、 /sbin/init" のアドレスを褓内 を↑褓内 ・ EAX レジスタに 11 (execve のシステムコール番号 ) このコードは、以下の処理をおこないます。 return (int) (__res) ;
連載 / Linux のプートプロセスをみる一① do-execve() を呼び出した直後のスタック 図 1 0867 : 図 2 do-execve() の引数 R ET Add 「 C7FCF000 C02E8BC0 C02E8C00 E BX ESI RET Addr EBX ECX EDX ESI EDI EBP EAX DS ES EAX EIP CS EFLAGS return retval ; dO execve() execve ( ) pt—regs envp argv filename SYS— filename ・ a rgv envp "/sbin/init' C0256633 NULL C023AC99 C023AC8E NULL 図 3 オ本 linux-binprm struct linux—binprm{ char buf [ 128 ] ; struct page *page[32] unsigned 10 Ⅱ g p ; int sh—bang ; struct file *file; int e—uid, e—gid; "HOME=/" "TERM=linux ファイルの先頭部分 ; ファイル名と引数、 環境変数の内容のコピー コピー位置のポインタ 実行ファイルの言売込み に使用 kernel—cap—t cap—inheritable, cap—permitted, cap—effective ; int argc , envc ; char *filename ; ファイル名 system -call() INT 80H init() unsigned 10 Ⅱ g loader, exec; 必要なデータをまとめて管理するためのデータ構造です。 この構造体は、 include/linux/binfmts. h で図 3 のよう に定義されています。 863 行目の open-exec() は、 filename カ甘旨すファイ ル名 (/sbin/init) のファイルを開き、構造体 file のポイ ンタを返します。 ファイルのアクセスになんらかのエラーが発生した場合 は、 open-exec() はエラー番号を返します。この値は、、ポ インタ " としてはありえないアドレス 1 なので、 865 ~ 867 行目はそれを判断してエラー番号を返します。 858 行目のキ冓造イ本 linux-binprm2 は、 execve の処理に 1 FFFFFC18H ( = ー 1000 ) 以上直です。 2 binprm は "BlNary PaRaMeter" という意未のようてす。 UNIX MAGAZINE 2003.5 0869 : 0870 : 0871 : 0872 : 0873 : 0874 : 0875 : 0876 : 0877 : 0881 : 0882 : 0883 : 0887 : bprm. p = PAGE—SIZE*32—sizeof(void * ) ; memset (bprm. page , 0 , 32*sizeof (bprm ・ page [ 0 ] ) ) ; bprm. file file; bprm. filename = filename ; bprm. sh-bang = 0 ; bprm. loader = 0 ; bprm. exec = 0 ; if ( (bprm. argc count (argv , bprm ・ p / sizeof(void * ) ) ) く 0 ) { if ( (bprm. envc count ( envp , bprm ・ p / sizeof(void * ) ) ) く 0 ) { 153
連載 /JavaServer Pages—@ 図 1 ctl:foreach のタグハンドラのソースコード (Foreach. java) package control ; import javax. servlet . jsp. tagext . * ; import Javax. servlet . jsp. * ; public class Foreach extends TagSupport value = v; public void setVa1ue (String ロ name public void setName(String v) Ⅱ u11 ; private String value ロ private String name = Ⅱ u11 ; private int index = 0 ; public int d0StartTag() throws JspException index = 0 ; = null Ⅱ if (name Ⅱ u11 Ⅱ value value . length return SKIP_BODY ; } else { pageContext . setAttribute (name , - value [index] ) ; = の { return EVAL_BODY_INCLUDE ; return EVAL_PAGE ; public int doEndTag() throws JspException { return SKIP_BODY; } else { return EVAL_BODY_AGAIN ; if ( index く value . length) { value [index] ) ; pageContext . setAttribute (name , = if (index く value. length) { index 十十 ; if (name ! = null) { public int d0AfterBody ( ) { / ( 誌面の都合上、で折り返しています。以下同様 ) 図 2 変数が含まれた JSP ファイルは TLD や TagExtraInfo を啝囲してサープレットに変換される 実行して得た出力 class ファイル④サーブレットを ③コン / ヾイ丿レ サーブレットの一・サーブレットロロ くカスタムタグ > ー - ソースコードに変換 . jsp ファイル。②サーブレットの . java ファイル ( 実行形式 ) Web ブラウザ JSPA—ジの 内容の表示 ソースコード ①変数の情報 getVariableInf0() TagExtraInf0 TLD ファイル : <variable> </variable> く /variable> く scope>NESTED く /scope> 一方、 TagExtraInfo を利用するガ去では、変数の情報 を返すメソッドを定義します。 JSP 工ンジンはこのメソッ ドを呼び出して、変数カ鯉め込まれている JSP ファイル をサープレットに変換します。図 2 はこのときの処理の 流れを示しています。 1. JSP 工ンジンは、 JSP ファイル (. jsp ファイル ) にカ 80 スタムタグか含まれていると、 TLD を調べてカスタム タグのにを取得します。さらに、 TLD のく variable 〉 タグの言当や、カスタムタグに対施つ、けられた TagEx- tralnfo クラス ( 正確には、 TagExtraInfo を継承した クラス ) から変数の報を取得します。 2. JSP 工ンジンは、これらの情報を使って JSP ファイ ルをいったんサープレットのソースコード (. java ファ イル ) に変換します。カスタムタグが生成した変数に関 する処理は、 TLD や TagExtraInfo から得た情報を UNIX MAGAZINE 2003.5
連載 / IPv6 の実装ーの SAD 工ントリの利用情報の更新 ・ SADB-EXT-LIFETIME-SOFT lfts に対応する情報をイ尉寺。 共有鍵を使ってセキュリティを確保する場合、鍵の管 理か重要です。共有多 ) セキュリティを高めるガ去として sadb 」 ifetime-allocations には認正へッタヤ暗号化へ は、以下の 2 つが一殳的です。 ッダ付きのバケットを処理した数か第求されます。すなわ ち、この SAD 工ントリを使用した認証ヘッダや暗号化 1. 同し鍵を長期間利用しない。 ヘッダの入出力が発生するたびに sadb-lifetime-alloca- 2. 同し鍵で多量窈辭長を認証 / 暗号処理しない。 tions の値か増えます。 sadb-lifetime-bytes は入出力し IP セキュリティにおいても同様の対策を講じる必要が たバケット長の合計です。 sadb-lifetime-addtime には あります。そこで、各 SAD 工ントリには一己を実現する 有寺か乂疋されます。 sadb 」 ifetime-usetime には最 ための利用情報を言当求する仕組みがあります。 SAD ェン 後に SAD 工ントリが参照された時刻カ当求されます。 トリを示す secasvar 構造体の該当部分を思い出してみま 7494 void しよう。 7495 key_sa_recordxfer(sav, m) struct secasvar *sav; 7496 keydb. h struct mbuf *m ; 7497 77 struct secasvar { 7498 { LIST_ENTRY(secasvar) chain ; 78 key-sa-recordxfer() は SAD 工ントリの利用情報を更 10 Ⅱ g created; 96 新する関数です。更新対象となる SAD 工ントリへのポイ struct sadb_lifetime *lft_ 98 C ; ンタ sav と、 sav を使って処理したバケットへのポイン struct sadb_lifetime *lft_h; 99 struct sadb_lifetime *lft 100 S ; タ m を引数にとります。 106 } ; 7510 sav—>lft—c—>sadb—lifetime—bytes + = m—>m—pkthdr . len ; lft-c に SAD 工ントリの現在の状態、 lft-h に有月限 を示す情報、 lfts に推奨有効期限を示す情幸財褓内されま sadb 」 ifetime-bytes には処理したバケット長の合計が す。 created は SAD 工ントリが作成された時刻です。 求されます。バケット長は m-pkthdr 構造体に言求さ lft-c 、 lft-h 、 lft-s は sadb 」 ifetime 構造ーをのポイン れているので、それを sadb 」 ifetime-bytes に加えます。 タです。 sadb 」 ifetime 構造体を以下に示します。 7518 sav—>lft_c—>sadb_lifetime allocations 十十 ; pfkeyv2. h sadb 」 ifetime-allocations は処理したノ、ケット数で struct sadb_lifetime { 106 u_int 16 ー t sadb_lifetime_len; 107 u_int 16 ー t sadb_lifetime_exttype; 108 sav—>lft_c—>sadb—lifetime—usetime sadb_lifetime_allocations ; u_int32_t 109 time . tv_sec; u_int64_t sadb_lifetime—bytes; 110 7541 sadb_lifetime_addtime ; u_int64_t 111 7542 } u_int64_t sadb_lifetime_ usetime; 112 113 最後に、 SAD 工ントリの使用時刻を sadbAifetime- sadb-lifetime-len には sadb 」 ifetime 構造体の大き usetime に言求します。 なお、 SAD 工ントリの有効性窈寉認は複数の条件を組 さか、故疋されます。 sadb 」 ifetime-exttype は sadb 」 ife- み合わせて判断されます。具イ勺には、以下に示す手順で time 構造体力尉寺している情報の不鶤頁を示します。以下 SAD 工ントリの状態が更新されます。 の 3 つのいすれかです。 1. MATURE 状態の SAD 工ントリ ・ SADB-EXT-LIFETIME-CURRENT lft-c に対応する情報をイ尉寺。 1.1. 時間牛 SAD 工ントリが作られてから、 lft-s の sadb 」 ife- ・ SADB-EXT-LIFETIME-HARD time-addtime で指定された時間か経過していたら、 lftA1 に対応する情報をイ尉寺。 一三ロ す。 7536 return ; 76 UNIX MAGAZINE 2003.5
連載 / Linux のプートプロセスをみる一① ( 今回の場合は sys-execve()) を呼び出します。 サービスルーチンを呼び出すまでの処理は 2003 年 3 月 号で詳しく説明したので、そちらを参照してください。 sys-execve() は、 arch/i386/kernel/process. c で定 義されています。 int sys—execve (struct pt—regs regs) 0774 : 0775 : { 0776 : 0777 : 0778 : 0779 : 0780 : 0781 : 0782 : 0783 : 0784 : 0785 : 0786 : 0787 : 0788 : 0789. int e てて or ; Char * filename ; if (IS-ERR(fi1ename)) # メモリ割当て error = ( 10 Ⅱ g ) filename; # 工ラー番号 filename = getname((char * ) regs. ebx) ; goto out ; # に失敗した ? if (error current—>ptrace putname (filename) ; out : return e てて or ; 779 行目の regs. ebx には、 152 ら復帰するとき、ソフトウェア割込みを発生した次の命令 て実装されています。そして、 CPU は割込みハンドラか Linux のシステムコールは、ソフトウェア割込みによっ 取得したメモリプロックを解放するマクロです。 786 行目の putname() は、 779 行目の getname() で 返ってきます。 execve の処理に成功すると、 do-execve() から 0 が 次の項で説明します。 783 行目で呼び出している do-execve() については、 ているのです。 リを守るために、アドレスにアクセスする前にチェックし もあります。そこで、カーネルは不正なアクセスからメモ れるため、その引数に不正なアドレスが与えられる可能陸 通常、システムコールはユーサープロセスから呼び出さ ピーします。 しいメモリプロックを割り当てて、そのなかに文字列をコ ( 言もムみアクセスの可否 ) をチェックし、有効であれは新 して、 getname() は、 regs. ebx カ甘旨すアドレスの有効生 である、、 /sbin/init" のアドレスかオ内されています。そ error = do_execve (filename , execve の 1 番目の引数 & = NPT_DTRACE ; = 0 ) # execve 処理に成功した ®s) ; (char * * ) regs ・ edx, (char * * ) regs ・ ecx, から実行を再開します。しかし、 execve システムコール の場合は、、、ちょっとしたからくり " によってまったく異 なる位置から再開します。つまり、 CPU は init() の 829 行目の次の行からではなく、新しいプログラムのエントリ ポイントから実行を始めます。このからくりについては、 あとで詳しく説明します。 そして、このとき、プロセス番号 1 のプロセスは、も はやカーネルスレッドではなく、ユーサープロセスとして 新しく生まれ変わります。 do—execve do-execve() は、コマンドライン引数や環境変数の文字 列をコピーしたり、ファイルのパーミ、、 : ノ / ョンク ) チェッ クなど、実行ファイルの形式に依存しない事前処理をおこ ないます。そして、最後に linux-binfmt の load-binary を呼び出して実行ファイルをロードします。 do-execve() か呼び出された直後のスタックの状態を 図 1 に、引数のポインタカ甘ー内容を図 2 に示します。図 に記したアドレスは、 init() の 130 ~ 131 行目の文字列と その配列か配置されたアドレスです。ただし、これらは私 がコンパイルしたカーネルでの値であり、コンパイル・オ プションの j 尺によって異なります。 変数 filename カ甘旨すアドレスは、 sys-execve() の 779 行目で getname() によって割り当てられたメモリプロッ クです。このなかには、文字列、、 / sb ⅲ / init " かオ褓内され ています。 そして、変数 argv と envp カ甘旨しているのは、 init() の 130 ~ 131 行目の argv-init と envp-init かオ各糸内され ているアドレスです。 do-execve() は、 fs/exec. c で定義されています。 0856 : 0857. 0858 : 0859 : 0860 : 0861 : 0862 : 0863 : 0864 : 0865 : 0866 : int do—execve (char *filename , Char **argv , Char **envp , struct pt—regs *regs) s t ruct 1 inux—b inprm bprm ; struct file *file; int retval; int 土 ; open—exec(filename) ; retval = PTR—ERR(fi1e) ; if (IS-ERR(fiIe) ) file UNIX MAGAZINE 2003.5
特集・プログラミング入門 なお、この処理をおこなう際に、探索文字列の末尾の文 字に対する引・算はしていません。もし探索文字列の末尾の 文字を調べているときに不一致が発生するのであれは、 の文字ではないことは明らかです。ほかの場所で不一致が 発生した場合も、探索文字列の末尾の文字を不一致の発生 した位置に移動する必要はありません。移動しなけれはな らないのは、不一致が発生した場所よりも左側にある探索 文字列内の文字だからです。このように、末尾の文字を考 慮する必要はないため、 skip 配列の言算には含まれていま せん。 不一致を検出したときは、この配列を使って、探索文字 列をどれだけ進めてよいのかを匐十ヾます。この配列に↑巒内 されている値は、探索文字列の末尾の文字を十ヾていて不 一致が発生したときにどれだけ動かしてよいかを表してい るので、実際に移動する際には、末尾から何文字目を処理 している状態なのかを考慮に入れたうえで移動する必要が あります。このために作った関数は次のようなものです。 search(char *t , char *s) int 図 9 同じ文字か複数回出現する場合 a 図 10 a 図 11 a b a b a a e a b b a e i をインクリメントした場合 b a b a a a b b 2 文字進めた場合 b a b a a a b e a e b d d e d a a a a e int i , j ; int tlen, slen; tlen = strlen(t) ; strlen(s) ; slen 1 while (i く = tlen for (j SIen if (j くの return i ; slen) 1 ; j > = 0 return ー 1 ; if (skip[(int)t[i + j]] く 十十・ else i + = skip[(int)t[i + j] & & sCj] (slen ー 1 slen ー j) この関数では、 i は文字列のインデックスとして、 j は 探索文字列のインデックスとして利用しています。ます、 i を文字列のう巨頁に設定し、探索文字列の末尾から調べる ために j を slen—l から 0 になるまでデクリメントしな がら繰り返します。ここでチェックするのは文字列の一 分と探索文字列が -- ー・致していることです。もし、探索文字 列のすべてが・一致していれは、内側のループを終えたとき UNIX MAGAZINE 2003.5 に j の値は負の数になるはすです。この場合には、一致し た文字列の地可立置を表す i の値を返します。 不一致が発生した場合にも内側のループを終了します。 このとき、 j の値は 0 以 E で、不一致が発生した文字は探 索文字列側が s[j] 、文字列側が t[i + j] となります。 こで、文字列側の不一致文字に対応する skip 配列の値が slen—j よりも小さい、つまり skip 配列に登録されてい る値を言 fr 算するために利用した文字か不一致文字よりも右 側にある場合には、たんに i をインクリメントします。そ れ以外の場合、つまり skip 配列に登録されている値を計 算するために利用した文字か不一致文字よりも左側にあれ は、その文字のところまですらすために skip 配列の値を i に加えます。 skip 配列に登録されている値を計算するために利用し た文字か不一致文字よりも右側にある場合、実際には 1 文 字より多く移動させられる場合があります。図 9 の例を見 てください。 不一致が発生している文字列の文字は a です。この探 索文字列では、 skip 「 a'] は 1 となっています。これは注 目点よりも右にある文字 a に対して引・算された値です。 の場合、さきほどのプログラムでは i をインクリメントし ているので、次の探索の様子は図 10 のようになります。 しかし、文字 a は探索文字列の注目点よりも 2 文字左 まで存在しないので、実際には 2 文字進めることができま 95
連載 / IPv6 の実装ー① のを検索します。さきはど述べたように、 SAD 工ントリ の検索に始点アドレスは必要ありません。 key-allocsa( の引数で始点アドレスを渡しているのは、旧いコードの名 残です。 56 57 58 59 60 } ; u_int16_t u_int32_t u_int32_t ( 罠 & 正データ ) ah reserve ; ah—spi; ah-seq; 743 744 749 750 if (sav—>state ! = SADB-SASTATE-MATURE & & sav->state ! = SADB-SASTATE—DYING) { got0 fail; 743 ~ 750 行目は SAD 工ントリの状態確認です。状 態には LARVAL ( 鍵交換処理中 ) 、 MATURE ( 有効 ) 、 DYING ( 推奨有測限切れ ) 、 DEAD ( 有効祺月限切れ ) の 4 不頁があります。有効な SAD 工ントリとして利用でき るのは MATURE 状態と DYING 状態だけなので、そ れ以外の場合は 749 行目でバケットを破棄します。 752 753 758 759 algo = ah—algorithm—lookup (sav¯>alg—auth) ; goto fail; if (!algo) { 認証データの長さはアルゴリズムによって異なります。 各アルゴリズムで必要な認証データの長さは、アルゴリズ ムごとに定義されている sumsiz() 関数て取得できます。 この値が 761 行目で siz にオ巒内されます。 sizl には、認 証ヘッダのアラインメントを考慮し、 4 オクテット境界に 合わせた場合の認証データの長さかオ翻タされます。 (sav—>flags & SADB-X—EXT—OLD) ? 770 sizoff 0 : 4 ; SADB-X-EXT-OLD フラグは、 RFC1826 で定義さ れた旧い形式の認証ヘッダを利用する場合に設定されま す。旧い認証ヘッダには 4 オクテットの通し番号 (ah- seq) が存在しないため、認証ヘッダ全体の長さが 4 オク テットぶん短くなります。上で引用しているのは、 RFC 2402 て規定された新しい形式の認証ヘッタてす。 if (sizl く siz) { 239 752 ~ 759 行目は、認証ヘッダの認証データ引算に利用 されたアルゴリズムの検索です。認証データの計算に利用 するアルゴリズムの不転頁は、 SAD 工ントリの alg-auth に数値でオ褓内されています。 ah-algorithm-lookup() は alg-auth の値をもとに、 ah-algorithm 構造体へのポイ ンタを返します。 ah-algorithm 構造体は認証データの計 算に必要な定数や関数の集合体です。 alg-auth で指定さ れた数値に対応するアルゴリズムがみつからなかった場合 は、 758 行目でバケットを破棄します。 ヘッダの整合性の確認 SAD 工ントリの検索が成功し、利用するアルゴリズム か判明したら、認証ヘッダの整合性を石忍します。 (*algo—>sumsiz) (sav) ; 761 SIZ SiZI 762 761 ~ 762 行目では認証データの長さを算出していま す。以下に認証ヘッダの形式を示します。 siz と sizl に は、、認証データ " の部分の長さが設定されます。 53 struct newah { ah. h 245 goto fail; 246 } アルゴリズムで規定された認証データの長さ (siz) より もバケットの構築に必要な長さ (sizl) が小さい場合には、 バケットを破棄します。通常、この条件は siz の値がオー バーフローしないかぎり成立しません。 784 if ( (ah—>ah—len くく 2 ) sizoff ! = sizl) { 790 791 } goto fail; 784 ~ 791 行目は認証ヘッダ全体の長さの石忍です 号刃 0 川じ、 証ヘッダ全体の長さは ah-len にオ内されています。 ah- len は 4 オクテット単位で、認証ヘッダの : 頁 8 オクテッ トを含みませんから、 ah 」 e11 を 4 倍した値が sizl に等し くなります。ただし、旧い形式を使っている場合は、 ah- seq の長さ ( 770 行目の sizoff) を差し引いて上交しなけ 川まなりません。 54 55 68 u_int8 u_int8_t ah ah_len nxt ; 792 796 797 if (sizl > sizeof(cksum)) { goto fail; UNIX MAGAZINE 2003.5