ドメイン遷移の解析。
今日はオブジェクトクラス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。