首页 > 系统服务 > 详细

binary进程的selinux domain初始化过程(初稿,待整理)

时间:2019-03-20 12:00:27      阅读:140      评论:0      收藏:0      [点我收藏+]
虽然在各种context文件中声明了每个subject对应的domain,可是这个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,真正初始化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 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(&current->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初始化过程(初稿,待整理)

原文:https://blog.51cto.com/2559640/2365791

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!