ドメイン遷移の解析。

今日はオブジェクトクラスprocess関連の解析。
これに先立って,ドメインがどんなふうにSELinuxに割り当てられるか解析しておく必要があった。

ドメイン遷移の仕組み

ドメイン遷移は, do_execv(execシステムコールの本体)の中で起こる。

  • do_execvの動作の概要。

プログラムをロードし,現在のプロセスを,上書きする。
新しいプロセスの生成でないことに注意。
なので,タスク構造体の情報は受け継がれる。
例えば,ファイルディスクリプタ,シグナル状態(シグナルハンドラなど)などが受け継がれる。

● fs/exec.c
まず,ずらずらと。

1134 int do_execve(char * filename,
1135         char __user *__user *argv,
1136         char __user *__user *envp,
1137         struct pt_regs * regs)
1138 {
…
1183         retval = prepare_binprm(bprm);
→
924 int prepare_binprm(struct linux_binprm *bprm)
925 {
…
962         /* fill in binprm security blob */
963         retval = security_bprm_set(bprm);

security_bprm_setから, SELinuxのソースに飛ぶ。
ここでドメイン遷移の計算が行われる。
飛ぶ先は以下。

1494 static int selinux_bprm_set_security(struct linux_binprm *bprm)
1495 {
1496         struct task_security_struct *tsec;
1497         struct inode *inode = bprm->file->f_dentry->d_inode;
1498         struct inode_security_struct *isec;
1499         struct bprm_security_struct *bsec; 
1500         u32 newsid;
1501         struct avc_audit_data ad;
…
1508         bsec = bprm->security; ★1
…
1513         tsec = current->security;
…
1516         /* Default to the current task SID. */
1517         bsec->sid = tsec->sid; ★2
…
1519         /* Reset create SID on execve. */
1520         tsec->create_sid = 0;
1521 
1522         if (tsec->exec_sid) {
1523                 newsid = tsec->exec_sid;
1524                 /* Reset exec SID on execve. */
1525                 tsec->exec_sid = 0;
1526         } else {
1527                 /* Check for a default transition on this program. */
1528                 rc = security_transition_sid(tsec->sid, isec->sid,
1529                                              SECCLASS_PROCESS, &newsid);★3
…
1540 
1541         if (tsec->sid == newsid) {
1542                 rc = avc_has_perm(tsec->sid, isec->sid,
1543                                   SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
1544                 if (rc)
1545                         return rc;
1546         } else {
1547                 /* Check permissions for the transition. */
1548                 rc = avc_has_perm(tsec->sid, newsid,
1549                                   SECCLASS_PROCESS, PROCESS__TRANSITION, &ad); ★4
…
1562                 bsec->sid = newsid;★5

ドメインの遷移の情報は,★1のnewsidに一旦格納されることに注意。あとでこの値がタスク構造体にセットされる。
★2:ここでデフォルトのドメインの値がセット。ドメイン遷移が無い時は,ドメインはそのままという振る舞い。
★3:ここでポリシのドメイン遷移のルールを調べる。tsec->sidは遷移元,isec->sidはエントリポイント。で,遷移先がnewsidに格納。
★4:tsec->sid→newsidの遷移が許可されているかチェック(つまりallow tsec->sid newsid:process transitionが記述されているかチェック)
★5:newsidをbsec->sidに格納。

  • どこでドメインがプロセスにセットされる?

さて,計算されたドメイン遷移の情報はbsec->sid(do_execvのbprm変数->sid)に格納されただけ。まだタスク構造体にセットされてない。
どこでタスク構造体(task_struct)にセットされるのだろう?

do_execvの中
…
1200         retval = search_binary_handler(bprm,regs);
ここから,下に飛ぶ。
fs/exec.c
1036 int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
…
1081         set_fs(USER_DS);
1082         retval = -ENOENT;
1083         for (try=0; try<2; try++) {
1084                 read_lock(&binfmt_lock);
1085                 for (fmt = formats ; fmt ; fmt = fmt->next) {
1086                         int (*fn)(struct linux_binprm *, struct pt_regs *) = fmt->load_binary; ★6
…
1092                         retval = fn(bprm, regs);★7

fnにfmt->load_binaryがセット。load_binaryは下のように,load_elf_binaryを指している。

●fs/binfmt_elf.c
 81 static struct linux_binfmt elf_format = {
 82                 .module         = THIS_MODULE,
 83                 .load_binary    = load_elf_binary,

で,★7にて,load_elf_binaryが実行される。load_elf_binaryの本体は以下。

fs/binfmt_elf.c
511 static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
…
952         compute_creds(bprm);

さて,compute_credsは以下。

fs/exec.c
990 void compute_creds(struct linux_binprm *bprm)
991 {
992         int unsafe;
…
999         unsafe = unsafe_exec(current);
1000         security_bprm_apply_creds(bprm, unsafe);
…

security_bprm_apply_credsにて、ついに以下のSELinuxの関数が呼ばれる。

selinux/hooks.c
1685 static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
…
1686 {
1687         struct task_security_struct *tsec;
1688         struct bprm_security_struct *bsec;
1689         u32 sid;
1690         int rc;
1691 
1692         secondary_ops->bprm_apply_creds(bprm, unsafe);
1693 
1694         tsec = current->security;
1695 
1696         bsec = bprm->security;★8
1697         sid = bsec->sid;
1698 
1699         tsec->osid = tsec->sid;
1700         bsec->unsafe = 0;
1701         if (tsec->sid != sid) {
1702                 /* Check for shared state.  If not ok, leave SID
1703                    unchanged and kill. */
1704                 if (unsafe & LSM_UNSAFE_SHARE) {
1705                         rc = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
1706                                         PROCESS__SHARE, NULL);
1707                         if (rc) {
1708                                 bsec->unsafe = 1;
1709                                 return;
1710                         }
1711                 }
1712 
1713                 /* Check for ptracing, and update the task SID if ok.
1714                    Otherwise, leave SID unchanged and kill. */
1715                 if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
1716                         rc = avc_has_perm(tsec->ptrace_sid, sid,
1717                                           SECCLASS_PROCESS, PROCESS__PTRACE,
1718                                           NULL);
1719                         if (rc) {
1720                                 bsec->unsafe = 1;
1721                                 return;
1722                         }
1723                 }
1724                 tsec->sid = sid;★9

★8は,さっき★5で計算したドメイン遷移後のドメイン
これが,★9にて,タスク構造体にセットされる。
やっと,遷移後のドメイン情報がプロセスにセットされた。長かった…
色んなところに飛ぶので,grepでは解析が厳しい。ありがとうlxr