把一个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_CREDENTIALS113 atomic_t subscribers; /* number of processes subscribed */114 voID *put_addr;115 unsigned magic;116 #define CRED_MAGIC 0x43736564117 #define CRED_MAGIC_DEAD 0x44656144118 #endif119 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_KEYS134 unsigned char jit_keyring; /* default keyring to attach requested135 * 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 #endif141 #ifdef CONfig_Security142 voID *security; /* subjective LSM security */143 #endif144 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,真正初始化struct cred,将其所有成员变量都对应到正确的值;
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 not2324 * 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 allowed2360 * Transition.2361 */2362 rc = check_nnp_nosuID(bprm,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,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,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,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 that2397 * 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,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 executable1411 */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 users1421 * when executing setuID binarIEs. Must1422 * wait until new credentials are committed1423 * by commit_creds() above1424 */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 prevent1429 * ptrace_attach() from altering our determination of the task‘s1430 * 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 IDentifIEr1129 * @tsID: target security IDentifIEr1130 * @tclass: target security class1131 * @requested: requested permissions,interpreted based on @tclass1132 * @auditdata: auxiliary audit data1133 *1134 * Check the AVC to determine whether the @requested permissions are granted1135 * for the SID pair (@ssID,@tsID),interpreting the permissions1136 * based on @tclass,and call the security server on a cache miss to obtain1137 * a new decision and add it to the cache. Audit the granting or denial of1138 * permissions in accordance with the policy. Return %0 if all @requested1139 * permissions are granted,-%EACCES if any permissions are denIEd,or1140 * 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,&avd);1149 1150 rc2 = avc_audit(ssID,&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初始化过程(初稿,待整理)全部内容,希望文章能够帮你解决binary进程的selinux domain初始化过程(初稿,待整理)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)