1. 程式人生 > >binary進程的selinux domain初始化過程(初稿,待整理)

binary進程的selinux domain初始化過程(初稿,待整理)

nsa search har ctu bit 初始 back person when

雖然在各種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初始化過程(初稿,待整理)