binary進程的selinux domain初始化過程(初稿,待整理)
把一個domain與一個進程關聯分為兩種:
1)fork出來進程以後,然後通過傳遞參數的方式動態的修改新進程的domain;
2)通過exec某個binary啟動進程,該新啟動進程的domain是由其對應的binary object的context決定。
但是無論是哪種啟動方式,最終的結果就是在內核中創建一個struct cred對象,然後與之關聯到進程對應的task對象。
struct cred的定義如下,include/linux/cred.h:110
110 struct cred { 111 atomic_t usage; 112 #ifdef CONFIG_DEBUG_CREDENTIALS 113 atomic_t subscribers; /* number of processes subscribed */ 114 void *put_addr; 115 unsigned magic; 116 #define CRED_MAGIC 0x43736564 117 #define CRED_MAGIC_DEAD 0x44656144 118 #endif 119 kuid_t uid; /* real UID of the task */ 120 kgid_t gid; /* real GID of the task */ 121 kuid_t suid; /* saved UID of the task */ 122 kgid_t sgid; /* saved GID of the task */ 123 kuid_t euid; /* effective UID of the task */ 124 kgid_t egid; /* effective GID of the task */ 125 kuid_t fsuid; /* UID for VFS ops */ 126 kgid_t fsgid; /* GID for VFS ops */ 127 unsigned securebits; /* SUID-less security management */ 128 kernel_cap_t cap_inheritable; /* caps our children can inherit */ 129 kernel_cap_t cap_permitted; /* caps we‘re permitted */ 130 kernel_cap_t cap_effective; /* caps we can actually use */ 131 kernel_cap_t cap_bset; /* capability bounding set */ 132 kernel_cap_t cap_ambient; /* Ambient capability set */ 133 #ifdef CONFIG_KEYS 134 unsigned char jit_keyring; /* default keyring to attach requested 135 * keys to */ 136 struct key __rcu *session_keyring; /* keyring inherited over fork */ 137 struct key *process_keyring; /* keyring private to this process */ 138 struct key *thread_keyring; /* keyring private to this thread */ 139 struct key *request_key_auth; /* assumed request_key authority */ 140 #endif 141 #ifdef CONFIG_SECURITY 142 void *security; /* subjective LSM security */ 143 #endif 144 struct user_struct *user; /* real user ID subscription */ 145 struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */ 146 struct group_info *group_info; /* supplementary groups for euid/fsgid */ 147 struct rcu_head rcu; /* RCU deletion hook */ 148 };
而我們比較關系的與selinux相關的部分,即對struct cred對象的中的void *security成員變量的初始化。
相對而言,第一種方式相對簡單,再次不做重點介紹。重點介紹的是第二種方式,以系統調用exec作為入口,代碼如下fs/exe.c所示:
1674 /* 1675 * sys_execve() executes a new program. 1676 */ 1677 static int do_execveat_common(int fd, struct filename *filename, 1678 struct user_arg_ptr argv, 1679 struct user_arg_ptr envp, 1680 int flags) 1681 { 1682 char *pathbuf = NULL; 1683 struct linux_binprm *bprm; 1684 struct file *file; 1685 struct files_struct *displaced; 1686 int retval; ... 1716 retval = prepare_bprm_creds(bprm); ... 1730 bprm->file = file; ... 1754 retval = bprm_mm_init(bprm); ... 1766 retval = prepare_binprm(bprm); ... 1785 retval = exec_binprm(bprm);
第一步:prepare_bprm_creds,創建struct cred對象,並創建struct task_security_struct對象賦予struct cred的security成員變量,並將struct cred對象與struct linux_binprm對象關聯;
prepare_bprm_creds==> prepare_exec_creds==>prepare_creds==>selinux_cred_prepare
第二步:初始化struct linux_binprm中的file成員變量,將其對應真正的文件,用於從從file映射到inode,然後從node獲取object的security context,然後從security context變成security id;
prepare_binprm==>security_bprm_set_creds==>selinux_bprm_set_creds
第四步:exec_binprm,將新創建的struct cred對象與進程對應的task對象關聯;
exec_binprm==> search_binary_handler==>load_elf_binary==>install_exec_creds==>commit_creds
通過上述四步,完成了將一個struct cred對象關聯到一個實體的進程對應的task對象。完成對某個binary進程的selinux domain初始化。
因為exec的系統調用的caller是和新創建的進程可能屬於不同domain,其中涉及到domain的transition,在做transition的過程中,必然會涉及到權限的檢查。在上述的四個步驟中,涉及到權限檢查的函數調用包括但不限於下面兩個:
1)security_bprm_set_creds,完成struct cred的真正初始化;
security/selinux/hooks.c:2314
2314 static int selinux_bprm_set_creds(struct linux_binprm *bprm)
2315 {
2316 const struct task_security_struct *old_tsec;
2317 struct task_security_struct *new_tsec;
2318 struct inode_security_struct *isec;
2319 struct common_audit_data ad;
2320 struct inode *inode = file_inode(bprm->file);
2321 int rc;
2322
2323 /* SELinux context only depends on initial program or script and not
2324 * the script interpreter */
2325 if (bprm->cred_prepared)
2326 return 0;
2327
2328 old_tsec = current_security();
2329 new_tsec = bprm->cred->security;
2330 isec = inode_security(inode);
2331
2332 /* Default to the current task SID. */
2333 new_tsec->sid = old_tsec->sid;
2334 new_tsec->osid = old_tsec->sid;
2335
2336 /* Reset fs, key, and sock SIDs on execve. */
2337 new_tsec->create_sid = 0;
2338 new_tsec->keycreate_sid = 0;
2339 new_tsec->sockcreate_sid = 0;
2340
2341 if (old_tsec->exec_sid) {
2342 new_tsec->sid = old_tsec->exec_sid;
2343 /* Reset exec SID on execve. */
2344 new_tsec->exec_sid = 0;
2345
2346 /* Fail on NNP or nosuid if not an allowed transition. */
2347 rc = check_nnp_nosuid(bprm, old_tsec, new_tsec);
2348 if (rc)
2349 return rc;
2350 } else {
2351 /* Check for a default transition on this program. */
2352 rc = security_transition_sid(old_tsec->sid, isec->sid,
2353 SECCLASS_PROCESS, NULL,
2354 &new_tsec->sid);
2355 if (rc)
2356 return rc;
2357
2358 /*
2359 * Fallback to old SID on NNP or nosuid if not an allowed
2360 * transition.
2361 */
2362 rc = check_nnp_nosuid(bprm, old_tsec, new_tsec);
2363 if (rc)
2364 new_tsec->sid = old_tsec->sid;
2365 }
2366
2367 ad.type = LSM_AUDIT_DATA_FILE;
2368 ad.u.file = bprm->file;
2369
2370 if (new_tsec->sid == old_tsec->sid) {
2371 rc = avc_has_perm(old_tsec->sid, isec->sid,
2372 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
2373 if (rc)
2374 return rc;
2375 } else {
2376 /* Check permissions for the transition. */
2377 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
2378 SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
2379 if (rc)
2380 return rc;
2381
2382 rc = avc_has_perm(new_tsec->sid, isec->sid,
2383 SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
2384 if (rc)
2385 return rc;
2386
2387 /* Check for shared state */
2388 if (bprm->unsafe & LSM_UNSAFE_SHARE) {
2389 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
2390 SECCLASS_PROCESS, PROCESS__SHARE,
2391 NULL);
2392 if (rc)
2393 return -EPERM;
2394 }
2395
2396 /* Make sure that anyone attempting to ptrace over a task that
2397 * changes its SID has the appropriate permit */
2398 if (bprm->unsafe &
2399 (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
2400 u32 ptsid = ptrace_parent_sid(current);
2401 if (ptsid != 0) {
2402 rc = avc_has_perm(ptsid, new_tsec->sid,
2403 SECCLASS_PROCESS,
2404 PROCESS__PTRACE, NULL);
2405 if (rc)
2406 return -EPERM;
2407 }
2408 }
2409
2410 /* Clear any possibly unsafe personality bits on exec: */
2411 bprm->per_clear |= PER_CLEAR_ON_SETID;
2412 }
2413
2414 return 0;
2415 }
2)install_exec_creds,完成將一個struct cred對象關聯到一個task對象中:
fs/exec.c:1409
1409 /*
1410 * install the new credentials for this executable
1411 */
1412 void install_exec_creds(struct linux_binprm *bprm)
1413 {
1414 security_bprm_committing_creds(bprm);
1415
1416 commit_creds(bprm->cred);
1417 bprm->cred = NULL;
1418
1419 /*
1420 * Disable monitoring for regular users
1421 * when executing setuid binaries. Must
1422 * wait until new credentials are committed
1423 * by commit_creds() above
1424 */
1425 if (get_dumpable(current->mm) != SUID_DUMP_USER)
1426 perf_event_exit_task(current);
1427 /*
1428 * cred_guard_mutex must be held at least to this point to prevent
1429 * ptrace_attach() from altering our determination of the task‘s
1430 * credentials; any time after this it may be unlocked.
1431 */
1432 security_bprm_committed_creds(bprm);
1433 mutex_unlock(¤t->signal->cred_guard_mutex);
1434 }
上述兩個函數調用都會調用權限檢查:avc_has_perm,該函數的定義如下:
security/selinux/avc.c:1126
1126 /**
1127 * avc_has_perm - Check permissions and perform any appropriate auditing.
1128 * @ssid: source security identifier
1129 * @tsid: target security identifier
1130 * @tclass: target security class
1131 * @requested: requested permissions, interpreted based on @tclass
1132 * @auditdata: auxiliary audit data
1133 *
1134 * Check the AVC to determine whether the @requested permissions are granted
1135 * for the SID pair (@ssid, @tsid), interpreting the permissions
1136 * based on @tclass, and call the security server on a cache miss to obtain
1137 * a new decision and add it to the cache. Audit the granting or denial of
1138 * permissions in accordance with the policy. Return %0 if all @requested
1139 * permissions are granted, -%EACCES if any permissions are denied, or
1140 * another -errno upon other errors.
1141 */
1142 int avc_has_perm(u32 ssid, u32 tsid, u16 tclass,
1143 u32 requested, struct common_audit_data *auditdata)
1144 {
1145 struct av_decision avd;
1146 int rc, rc2;
1147
1148 rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd);
1149
1150 rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata, 0);
1151 if (rc2)
1152 return rc2;
1153 return rc;
1154 }
這個函數完成的功能即是,檢查source subject所屬的security id有沒有對target subject(object)所屬的security id擁有class參數和request參數聲明的權限。
那麽問題來了。。。。。。
那麽security id是什麽?它與selinux的配置文件XXX_context和XXX.te文件有什麽關系?
class是什麽?它和XXX_context和XXX.te文件有什麽關系?
kernel是如何決策的?決策過程和XXX_context和XXX.te文件有什麽關系?
binary進程的selinux domain初始化過程(初稿,待整理)