diff options
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r-- | security/selinux/hooks.c | 283 |
1 files changed, 118 insertions, 165 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c71bba78872f..21a592184633 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -2029,59 +2029,45 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) | |||
2029 | 2029 | ||
2030 | /* binprm security operations */ | 2030 | /* binprm security operations */ |
2031 | 2031 | ||
2032 | static int selinux_bprm_alloc_security(struct linux_binprm *bprm) | 2032 | static int selinux_bprm_set_creds(struct linux_binprm *bprm) |
2033 | { | 2033 | { |
2034 | struct bprm_security_struct *bsec; | 2034 | const struct task_security_struct *old_tsec; |
2035 | 2035 | struct task_security_struct *new_tsec; | |
2036 | bsec = kzalloc(sizeof(struct bprm_security_struct), GFP_KERNEL); | ||
2037 | if (!bsec) | ||
2038 | return -ENOMEM; | ||
2039 | |||
2040 | bsec->sid = SECINITSID_UNLABELED; | ||
2041 | bsec->set = 0; | ||
2042 | |||
2043 | bprm->security = bsec; | ||
2044 | return 0; | ||
2045 | } | ||
2046 | |||
2047 | static int selinux_bprm_set_security(struct linux_binprm *bprm) | ||
2048 | { | ||
2049 | struct task_security_struct *tsec; | ||
2050 | struct inode *inode = bprm->file->f_path.dentry->d_inode; | ||
2051 | struct inode_security_struct *isec; | 2036 | struct inode_security_struct *isec; |
2052 | struct bprm_security_struct *bsec; | ||
2053 | u32 newsid; | ||
2054 | struct avc_audit_data ad; | 2037 | struct avc_audit_data ad; |
2038 | struct inode *inode = bprm->file->f_path.dentry->d_inode; | ||
2055 | int rc; | 2039 | int rc; |
2056 | 2040 | ||
2057 | rc = secondary_ops->bprm_set_security(bprm); | 2041 | rc = secondary_ops->bprm_set_creds(bprm); |
2058 | if (rc) | 2042 | if (rc) |
2059 | return rc; | 2043 | return rc; |
2060 | 2044 | ||
2061 | bsec = bprm->security; | 2045 | /* SELinux context only depends on initial program or script and not |
2062 | 2046 | * the script interpreter */ | |
2063 | if (bsec->set) | 2047 | if (bprm->cred_prepared) |
2064 | return 0; | 2048 | return 0; |
2065 | 2049 | ||
2066 | tsec = current_security(); | 2050 | old_tsec = current_security(); |
2051 | new_tsec = bprm->cred->security; | ||
2067 | isec = inode->i_security; | 2052 | isec = inode->i_security; |
2068 | 2053 | ||
2069 | /* Default to the current task SID. */ | 2054 | /* Default to the current task SID. */ |
2070 | bsec->sid = tsec->sid; | 2055 | new_tsec->sid = old_tsec->sid; |
2056 | new_tsec->osid = old_tsec->sid; | ||
2071 | 2057 | ||
2072 | /* Reset fs, key, and sock SIDs on execve. */ | 2058 | /* Reset fs, key, and sock SIDs on execve. */ |
2073 | tsec->create_sid = 0; | 2059 | new_tsec->create_sid = 0; |
2074 | tsec->keycreate_sid = 0; | 2060 | new_tsec->keycreate_sid = 0; |
2075 | tsec->sockcreate_sid = 0; | 2061 | new_tsec->sockcreate_sid = 0; |
2076 | 2062 | ||
2077 | if (tsec->exec_sid) { | 2063 | if (old_tsec->exec_sid) { |
2078 | newsid = tsec->exec_sid; | 2064 | new_tsec->sid = old_tsec->exec_sid; |
2079 | /* Reset exec SID on execve. */ | 2065 | /* Reset exec SID on execve. */ |
2080 | tsec->exec_sid = 0; | 2066 | new_tsec->exec_sid = 0; |
2081 | } else { | 2067 | } else { |
2082 | /* Check for a default transition on this program. */ | 2068 | /* Check for a default transition on this program. */ |
2083 | rc = security_transition_sid(tsec->sid, isec->sid, | 2069 | rc = security_transition_sid(old_tsec->sid, isec->sid, |
2084 | SECCLASS_PROCESS, &newsid); | 2070 | SECCLASS_PROCESS, &new_tsec->sid); |
2085 | if (rc) | 2071 | if (rc) |
2086 | return rc; | 2072 | return rc; |
2087 | } | 2073 | } |
@@ -2090,33 +2076,63 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm) | |||
2090 | ad.u.fs.path = bprm->file->f_path; | 2076 | ad.u.fs.path = bprm->file->f_path; |
2091 | 2077 | ||
2092 | if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) | 2078 | if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) |
2093 | newsid = tsec->sid; | 2079 | new_tsec->sid = old_tsec->sid; |
2094 | 2080 | ||
2095 | if (tsec->sid == newsid) { | 2081 | if (new_tsec->sid == old_tsec->sid) { |
2096 | rc = avc_has_perm(tsec->sid, isec->sid, | 2082 | rc = avc_has_perm(old_tsec->sid, isec->sid, |
2097 | SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad); | 2083 | SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad); |
2098 | if (rc) | 2084 | if (rc) |
2099 | return rc; | 2085 | return rc; |
2100 | } else { | 2086 | } else { |
2101 | /* Check permissions for the transition. */ | 2087 | /* Check permissions for the transition. */ |
2102 | rc = avc_has_perm(tsec->sid, newsid, | 2088 | rc = avc_has_perm(old_tsec->sid, new_tsec->sid, |
2103 | SECCLASS_PROCESS, PROCESS__TRANSITION, &ad); | 2089 | SECCLASS_PROCESS, PROCESS__TRANSITION, &ad); |
2104 | if (rc) | 2090 | if (rc) |
2105 | return rc; | 2091 | return rc; |
2106 | 2092 | ||
2107 | rc = avc_has_perm(newsid, isec->sid, | 2093 | rc = avc_has_perm(new_tsec->sid, isec->sid, |
2108 | SECCLASS_FILE, FILE__ENTRYPOINT, &ad); | 2094 | SECCLASS_FILE, FILE__ENTRYPOINT, &ad); |
2109 | if (rc) | 2095 | if (rc) |
2110 | return rc; | 2096 | return rc; |
2111 | 2097 | ||
2112 | /* Clear any possibly unsafe personality bits on exec: */ | 2098 | /* Check for shared state */ |
2113 | current->personality &= ~PER_CLEAR_ON_SETID; | 2099 | if (bprm->unsafe & LSM_UNSAFE_SHARE) { |
2100 | rc = avc_has_perm(old_tsec->sid, new_tsec->sid, | ||
2101 | SECCLASS_PROCESS, PROCESS__SHARE, | ||
2102 | NULL); | ||
2103 | if (rc) | ||
2104 | return -EPERM; | ||
2105 | } | ||
2106 | |||
2107 | /* Make sure that anyone attempting to ptrace over a task that | ||
2108 | * changes its SID has the appropriate permit */ | ||
2109 | if (bprm->unsafe & | ||
2110 | (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) { | ||
2111 | struct task_struct *tracer; | ||
2112 | struct task_security_struct *sec; | ||
2113 | u32 ptsid = 0; | ||
2114 | |||
2115 | rcu_read_lock(); | ||
2116 | tracer = tracehook_tracer_task(current); | ||
2117 | if (likely(tracer != NULL)) { | ||
2118 | sec = __task_cred(tracer)->security; | ||
2119 | ptsid = sec->sid; | ||
2120 | } | ||
2121 | rcu_read_unlock(); | ||
2122 | |||
2123 | if (ptsid != 0) { | ||
2124 | rc = avc_has_perm(ptsid, new_tsec->sid, | ||
2125 | SECCLASS_PROCESS, | ||
2126 | PROCESS__PTRACE, NULL); | ||
2127 | if (rc) | ||
2128 | return -EPERM; | ||
2129 | } | ||
2130 | } | ||
2114 | 2131 | ||
2115 | /* Set the security field to the new SID. */ | 2132 | /* Clear any possibly unsafe personality bits on exec: */ |
2116 | bsec->sid = newsid; | 2133 | bprm->per_clear |= PER_CLEAR_ON_SETID; |
2117 | } | 2134 | } |
2118 | 2135 | ||
2119 | bsec->set = 1; | ||
2120 | return 0; | 2136 | return 0; |
2121 | } | 2137 | } |
2122 | 2138 | ||
@@ -2125,7 +2141,6 @@ static int selinux_bprm_check_security(struct linux_binprm *bprm) | |||
2125 | return secondary_ops->bprm_check_security(bprm); | 2141 | return secondary_ops->bprm_check_security(bprm); |
2126 | } | 2142 | } |
2127 | 2143 | ||
2128 | |||
2129 | static int selinux_bprm_secureexec(struct linux_binprm *bprm) | 2144 | static int selinux_bprm_secureexec(struct linux_binprm *bprm) |
2130 | { | 2145 | { |
2131 | const struct cred *cred = current_cred(); | 2146 | const struct cred *cred = current_cred(); |
@@ -2141,19 +2156,13 @@ static int selinux_bprm_secureexec(struct linux_binprm *bprm) | |||
2141 | the noatsecure permission is granted between | 2156 | the noatsecure permission is granted between |
2142 | the two SIDs, i.e. ahp returns 0. */ | 2157 | the two SIDs, i.e. ahp returns 0. */ |
2143 | atsecure = avc_has_perm(osid, sid, | 2158 | atsecure = avc_has_perm(osid, sid, |
2144 | SECCLASS_PROCESS, | 2159 | SECCLASS_PROCESS, |
2145 | PROCESS__NOATSECURE, NULL); | 2160 | PROCESS__NOATSECURE, NULL); |
2146 | } | 2161 | } |
2147 | 2162 | ||
2148 | return (atsecure || secondary_ops->bprm_secureexec(bprm)); | 2163 | return (atsecure || secondary_ops->bprm_secureexec(bprm)); |
2149 | } | 2164 | } |
2150 | 2165 | ||
2151 | static void selinux_bprm_free_security(struct linux_binprm *bprm) | ||
2152 | { | ||
2153 | kfree(bprm->security); | ||
2154 | bprm->security = NULL; | ||
2155 | } | ||
2156 | |||
2157 | extern struct vfsmount *selinuxfs_mount; | 2166 | extern struct vfsmount *selinuxfs_mount; |
2158 | extern struct dentry *selinux_null; | 2167 | extern struct dentry *selinux_null; |
2159 | 2168 | ||
@@ -2252,108 +2261,78 @@ static inline void flush_unauthorized_files(const struct cred *cred, | |||
2252 | spin_unlock(&files->file_lock); | 2261 | spin_unlock(&files->file_lock); |
2253 | } | 2262 | } |
2254 | 2263 | ||
2255 | static int selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) | 2264 | /* |
2265 | * Prepare a process for imminent new credential changes due to exec | ||
2266 | */ | ||
2267 | static void selinux_bprm_committing_creds(struct linux_binprm *bprm) | ||
2256 | { | 2268 | { |
2257 | struct task_security_struct *tsec; | 2269 | struct task_security_struct *new_tsec; |
2258 | struct bprm_security_struct *bsec; | 2270 | struct rlimit *rlim, *initrlim; |
2259 | struct cred *new; | 2271 | int rc, i; |
2260 | u32 sid; | ||
2261 | int rc; | ||
2262 | |||
2263 | rc = secondary_ops->bprm_apply_creds(bprm, unsafe); | ||
2264 | if (rc < 0) | ||
2265 | return rc; | ||
2266 | |||
2267 | new = prepare_creds(); | ||
2268 | if (!new) | ||
2269 | return -ENOMEM; | ||
2270 | 2272 | ||
2271 | tsec = new->security; | 2273 | secondary_ops->bprm_committing_creds(bprm); |
2272 | 2274 | ||
2273 | bsec = bprm->security; | 2275 | new_tsec = bprm->cred->security; |
2274 | sid = bsec->sid; | 2276 | if (new_tsec->sid == new_tsec->osid) |
2275 | 2277 | return; | |
2276 | tsec->osid = tsec->sid; | ||
2277 | bsec->unsafe = 0; | ||
2278 | if (tsec->sid != sid) { | ||
2279 | /* Check for shared state. If not ok, leave SID | ||
2280 | unchanged and kill. */ | ||
2281 | if (unsafe & LSM_UNSAFE_SHARE) { | ||
2282 | rc = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS, | ||
2283 | PROCESS__SHARE, NULL); | ||
2284 | if (rc) { | ||
2285 | bsec->unsafe = 1; | ||
2286 | goto out; | ||
2287 | } | ||
2288 | } | ||
2289 | 2278 | ||
2290 | /* Check for ptracing, and update the task SID if ok. | 2279 | /* Close files for which the new task SID is not authorized. */ |
2291 | Otherwise, leave SID unchanged and kill. */ | 2280 | flush_unauthorized_files(bprm->cred, current->files); |
2292 | if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) { | ||
2293 | struct task_struct *tracer; | ||
2294 | struct task_security_struct *sec; | ||
2295 | u32 ptsid = 0; | ||
2296 | 2281 | ||
2297 | rcu_read_lock(); | 2282 | /* Always clear parent death signal on SID transitions. */ |
2298 | tracer = tracehook_tracer_task(current); | 2283 | current->pdeath_signal = 0; |
2299 | if (likely(tracer != NULL)) { | ||
2300 | sec = __task_cred(tracer)->security; | ||
2301 | ptsid = sec->sid; | ||
2302 | } | ||
2303 | rcu_read_unlock(); | ||
2304 | 2284 | ||
2305 | if (ptsid != 0) { | 2285 | /* Check whether the new SID can inherit resource limits from the old |
2306 | rc = avc_has_perm(ptsid, sid, SECCLASS_PROCESS, | 2286 | * SID. If not, reset all soft limits to the lower of the current |
2307 | PROCESS__PTRACE, NULL); | 2287 | * task's hard limit and the init task's soft limit. |
2308 | if (rc) { | 2288 | * |
2309 | bsec->unsafe = 1; | 2289 | * Note that the setting of hard limits (even to lower them) can be |
2310 | goto out; | 2290 | * controlled by the setrlimit check. The inclusion of the init task's |
2311 | } | 2291 | * soft limit into the computation is to avoid resetting soft limits |
2312 | } | 2292 | * higher than the default soft limit for cases where the default is |
2293 | * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK. | ||
2294 | */ | ||
2295 | rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS, | ||
2296 | PROCESS__RLIMITINH, NULL); | ||
2297 | if (rc) { | ||
2298 | for (i = 0; i < RLIM_NLIMITS; i++) { | ||
2299 | rlim = current->signal->rlim + i; | ||
2300 | initrlim = init_task.signal->rlim + i; | ||
2301 | rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur); | ||
2313 | } | 2302 | } |
2314 | tsec->sid = sid; | 2303 | update_rlimit_cpu(rlim->rlim_cur); |
2315 | } | 2304 | } |
2316 | |||
2317 | out: | ||
2318 | commit_creds(new); | ||
2319 | return 0; | ||
2320 | } | 2305 | } |
2321 | 2306 | ||
2322 | /* | 2307 | /* |
2323 | * called after apply_creds without the task lock held | 2308 | * Clean up the process immediately after the installation of new credentials |
2309 | * due to exec | ||
2324 | */ | 2310 | */ |
2325 | static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm) | 2311 | static void selinux_bprm_committed_creds(struct linux_binprm *bprm) |
2326 | { | 2312 | { |
2327 | const struct cred *cred = current_cred(); | 2313 | const struct task_security_struct *tsec = current_security(); |
2328 | struct task_security_struct *tsec; | ||
2329 | struct rlimit *rlim, *initrlim; | ||
2330 | struct itimerval itimer; | 2314 | struct itimerval itimer; |
2331 | struct bprm_security_struct *bsec; | ||
2332 | struct sighand_struct *psig; | 2315 | struct sighand_struct *psig; |
2316 | u32 osid, sid; | ||
2333 | int rc, i; | 2317 | int rc, i; |
2334 | unsigned long flags; | 2318 | unsigned long flags; |
2335 | 2319 | ||
2336 | tsec = current_security(); | 2320 | secondary_ops->bprm_committed_creds(bprm); |
2337 | bsec = bprm->security; | ||
2338 | 2321 | ||
2339 | if (bsec->unsafe) { | 2322 | osid = tsec->osid; |
2340 | force_sig_specific(SIGKILL, current); | 2323 | sid = tsec->sid; |
2341 | return; | 2324 | |
2342 | } | 2325 | if (sid == osid) |
2343 | if (tsec->osid == tsec->sid) | ||
2344 | return; | 2326 | return; |
2345 | 2327 | ||
2346 | /* Close files for which the new task SID is not authorized. */ | 2328 | /* Check whether the new SID can inherit signal state from the old SID. |
2347 | flush_unauthorized_files(cred, current->files); | 2329 | * If not, clear itimers to avoid subsequent signal generation and |
2348 | 2330 | * flush and unblock signals. | |
2349 | /* Check whether the new SID can inherit signal state | 2331 | * |
2350 | from the old SID. If not, clear itimers to avoid | 2332 | * This must occur _after_ the task SID has been updated so that any |
2351 | subsequent signal generation and flush and unblock | 2333 | * kill done after the flush will be checked against the new SID. |
2352 | signals. This must occur _after_ the task SID has | 2334 | */ |
2353 | been updated so that any kill done after the flush | 2335 | rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL); |
2354 | will be checked against the new SID. */ | ||
2355 | rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS, | ||
2356 | PROCESS__SIGINH, NULL); | ||
2357 | if (rc) { | 2336 | if (rc) { |
2358 | memset(&itimer, 0, sizeof itimer); | 2337 | memset(&itimer, 0, sizeof itimer); |
2359 | for (i = 0; i < 3; i++) | 2338 | for (i = 0; i < 3; i++) |
@@ -2366,32 +2345,8 @@ static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm) | |||
2366 | spin_unlock_irq(¤t->sighand->siglock); | 2345 | spin_unlock_irq(¤t->sighand->siglock); |
2367 | } | 2346 | } |
2368 | 2347 | ||
2369 | /* Always clear parent death signal on SID transitions. */ | 2348 | /* Wake up the parent if it is waiting so that it can recheck |
2370 | current->pdeath_signal = 0; | 2349 | * wait permission to the new task SID. */ |
2371 | |||
2372 | /* Check whether the new SID can inherit resource limits | ||
2373 | from the old SID. If not, reset all soft limits to | ||
2374 | the lower of the current task's hard limit and the init | ||
2375 | task's soft limit. Note that the setting of hard limits | ||
2376 | (even to lower them) can be controlled by the setrlimit | ||
2377 | check. The inclusion of the init task's soft limit into | ||
2378 | the computation is to avoid resetting soft limits higher | ||
2379 | than the default soft limit for cases where the default | ||
2380 | is lower than the hard limit, e.g. RLIMIT_CORE or | ||
2381 | RLIMIT_STACK.*/ | ||
2382 | rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS, | ||
2383 | PROCESS__RLIMITINH, NULL); | ||
2384 | if (rc) { | ||
2385 | for (i = 0; i < RLIM_NLIMITS; i++) { | ||
2386 | rlim = current->signal->rlim + i; | ||
2387 | initrlim = init_task.signal->rlim+i; | ||
2388 | rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur); | ||
2389 | } | ||
2390 | update_rlimit_cpu(rlim->rlim_cur); | ||
2391 | } | ||
2392 | |||
2393 | /* Wake up the parent if it is waiting so that it can | ||
2394 | recheck wait permission to the new task SID. */ | ||
2395 | read_lock_irq(&tasklist_lock); | 2350 | read_lock_irq(&tasklist_lock); |
2396 | psig = current->parent->sighand; | 2351 | psig = current->parent->sighand; |
2397 | spin_lock_irqsave(&psig->siglock, flags); | 2352 | spin_lock_irqsave(&psig->siglock, flags); |
@@ -5556,12 +5511,10 @@ static struct security_operations selinux_ops = { | |||
5556 | .netlink_send = selinux_netlink_send, | 5511 | .netlink_send = selinux_netlink_send, |
5557 | .netlink_recv = selinux_netlink_recv, | 5512 | .netlink_recv = selinux_netlink_recv, |
5558 | 5513 | ||
5559 | .bprm_alloc_security = selinux_bprm_alloc_security, | 5514 | .bprm_set_creds = selinux_bprm_set_creds, |
5560 | .bprm_free_security = selinux_bprm_free_security, | ||
5561 | .bprm_apply_creds = selinux_bprm_apply_creds, | ||
5562 | .bprm_post_apply_creds = selinux_bprm_post_apply_creds, | ||
5563 | .bprm_set_security = selinux_bprm_set_security, | ||
5564 | .bprm_check_security = selinux_bprm_check_security, | 5515 | .bprm_check_security = selinux_bprm_check_security, |
5516 | .bprm_committing_creds = selinux_bprm_committing_creds, | ||
5517 | .bprm_committed_creds = selinux_bprm_committed_creds, | ||
5565 | .bprm_secureexec = selinux_bprm_secureexec, | 5518 | .bprm_secureexec = selinux_bprm_secureexec, |
5566 | 5519 | ||
5567 | .sb_alloc_security = selinux_sb_alloc_security, | 5520 | .sb_alloc_security = selinux_sb_alloc_security, |