diff options
-rw-r--r-- | security/selinux/hooks.c | 71 | ||||
-rw-r--r-- | security/selinux/include/objsec.h | 1 |
2 files changed, 47 insertions, 25 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 973e31eb1097..9d002f8484a3 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -161,7 +161,7 @@ static int task_alloc_security(struct task_struct *task) | |||
161 | if (!tsec) | 161 | if (!tsec) |
162 | return -ENOMEM; | 162 | return -ENOMEM; |
163 | 163 | ||
164 | tsec->osid = tsec->sid = tsec->ptrace_sid = SECINITSID_UNLABELED; | 164 | tsec->osid = tsec->sid = SECINITSID_UNLABELED; |
165 | task->security = tsec; | 165 | task->security = tsec; |
166 | 166 | ||
167 | return 0; | 167 | return 0; |
@@ -1671,19 +1671,13 @@ static inline u32 file_to_av(struct file *file) | |||
1671 | 1671 | ||
1672 | static int selinux_ptrace(struct task_struct *parent, struct task_struct *child) | 1672 | static int selinux_ptrace(struct task_struct *parent, struct task_struct *child) |
1673 | { | 1673 | { |
1674 | struct task_security_struct *psec = parent->security; | ||
1675 | struct task_security_struct *csec = child->security; | ||
1676 | int rc; | 1674 | int rc; |
1677 | 1675 | ||
1678 | rc = secondary_ops->ptrace(parent,child); | 1676 | rc = secondary_ops->ptrace(parent,child); |
1679 | if (rc) | 1677 | if (rc) |
1680 | return rc; | 1678 | return rc; |
1681 | 1679 | ||
1682 | rc = task_has_perm(parent, child, PROCESS__PTRACE); | 1680 | return task_has_perm(parent, child, PROCESS__PTRACE); |
1683 | /* Save the SID of the tracing process for later use in apply_creds. */ | ||
1684 | if (!(child->ptrace & PT_PTRACED) && !rc) | ||
1685 | csec->ptrace_sid = psec->sid; | ||
1686 | return rc; | ||
1687 | } | 1681 | } |
1688 | 1682 | ||
1689 | static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, | 1683 | static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, |
@@ -1905,6 +1899,22 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) | |||
1905 | return __vm_enough_memory(mm, pages, cap_sys_admin); | 1899 | return __vm_enough_memory(mm, pages, cap_sys_admin); |
1906 | } | 1900 | } |
1907 | 1901 | ||
1902 | /** | ||
1903 | * task_tracer_task - return the task that is tracing the given task | ||
1904 | * @task: task to consider | ||
1905 | * | ||
1906 | * Returns NULL if noone is tracing @task, or the &struct task_struct | ||
1907 | * pointer to its tracer. | ||
1908 | * | ||
1909 | * Must be called under rcu_read_lock(). | ||
1910 | */ | ||
1911 | static struct task_struct *task_tracer_task(struct task_struct *task) | ||
1912 | { | ||
1913 | if (task->ptrace & PT_PTRACED) | ||
1914 | return rcu_dereference(task->parent); | ||
1915 | return NULL; | ||
1916 | } | ||
1917 | |||
1908 | /* binprm security operations */ | 1918 | /* binprm security operations */ |
1909 | 1919 | ||
1910 | static int selinux_bprm_alloc_security(struct linux_binprm *bprm) | 1920 | static int selinux_bprm_alloc_security(struct linux_binprm *bprm) |
@@ -2151,12 +2161,25 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) | |||
2151 | /* Check for ptracing, and update the task SID if ok. | 2161 | /* Check for ptracing, and update the task SID if ok. |
2152 | Otherwise, leave SID unchanged and kill. */ | 2162 | Otherwise, leave SID unchanged and kill. */ |
2153 | if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) { | 2163 | if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) { |
2154 | rc = avc_has_perm(tsec->ptrace_sid, sid, | 2164 | struct task_struct *tracer; |
2155 | SECCLASS_PROCESS, PROCESS__PTRACE, | 2165 | struct task_security_struct *sec; |
2156 | NULL); | 2166 | u32 ptsid = 0; |
2157 | if (rc) { | 2167 | |
2158 | bsec->unsafe = 1; | 2168 | rcu_read_lock(); |
2159 | return; | 2169 | tracer = task_tracer_task(current); |
2170 | if (likely(tracer != NULL)) { | ||
2171 | sec = tracer->security; | ||
2172 | ptsid = sec->sid; | ||
2173 | } | ||
2174 | rcu_read_unlock(); | ||
2175 | |||
2176 | if (ptsid != 0) { | ||
2177 | rc = avc_has_perm(ptsid, sid, SECCLASS_PROCESS, | ||
2178 | PROCESS__PTRACE, NULL); | ||
2179 | if (rc) { | ||
2180 | bsec->unsafe = 1; | ||
2181 | return; | ||
2182 | } | ||
2160 | } | 2183 | } |
2161 | } | 2184 | } |
2162 | tsec->sid = sid; | 2185 | tsec->sid = sid; |
@@ -3112,11 +3135,6 @@ static int selinux_task_alloc_security(struct task_struct *tsk) | |||
3112 | tsec2->keycreate_sid = tsec1->keycreate_sid; | 3135 | tsec2->keycreate_sid = tsec1->keycreate_sid; |
3113 | tsec2->sockcreate_sid = tsec1->sockcreate_sid; | 3136 | tsec2->sockcreate_sid = tsec1->sockcreate_sid; |
3114 | 3137 | ||
3115 | /* Retain ptracer SID across fork, if any. | ||
3116 | This will be reset by the ptrace hook upon any | ||
3117 | subsequent ptrace_attach operations. */ | ||
3118 | tsec2->ptrace_sid = tsec1->ptrace_sid; | ||
3119 | |||
3120 | return 0; | 3138 | return 0; |
3121 | } | 3139 | } |
3122 | 3140 | ||
@@ -5080,6 +5098,7 @@ static int selinux_setprocattr(struct task_struct *p, | |||
5080 | char *name, void *value, size_t size) | 5098 | char *name, void *value, size_t size) |
5081 | { | 5099 | { |
5082 | struct task_security_struct *tsec; | 5100 | struct task_security_struct *tsec; |
5101 | struct task_struct *tracer; | ||
5083 | u32 sid = 0; | 5102 | u32 sid = 0; |
5084 | int error; | 5103 | int error; |
5085 | char *str = value; | 5104 | char *str = value; |
@@ -5168,18 +5187,24 @@ static int selinux_setprocattr(struct task_struct *p, | |||
5168 | /* Check for ptracing, and update the task SID if ok. | 5187 | /* Check for ptracing, and update the task SID if ok. |
5169 | Otherwise, leave SID unchanged and fail. */ | 5188 | Otherwise, leave SID unchanged and fail. */ |
5170 | task_lock(p); | 5189 | task_lock(p); |
5171 | if (p->ptrace & PT_PTRACED) { | 5190 | rcu_read_lock(); |
5172 | error = avc_has_perm_noaudit(tsec->ptrace_sid, sid, | 5191 | tracer = task_tracer_task(p); |
5192 | if (tracer != NULL) { | ||
5193 | struct task_security_struct *ptsec = tracer->security; | ||
5194 | u32 ptsid = ptsec->sid; | ||
5195 | rcu_read_unlock(); | ||
5196 | error = avc_has_perm_noaudit(ptsid, sid, | ||
5173 | SECCLASS_PROCESS, | 5197 | SECCLASS_PROCESS, |
5174 | PROCESS__PTRACE, 0, &avd); | 5198 | PROCESS__PTRACE, 0, &avd); |
5175 | if (!error) | 5199 | if (!error) |
5176 | tsec->sid = sid; | 5200 | tsec->sid = sid; |
5177 | task_unlock(p); | 5201 | task_unlock(p); |
5178 | avc_audit(tsec->ptrace_sid, sid, SECCLASS_PROCESS, | 5202 | avc_audit(ptsid, sid, SECCLASS_PROCESS, |
5179 | PROCESS__PTRACE, &avd, error, NULL); | 5203 | PROCESS__PTRACE, &avd, error, NULL); |
5180 | if (error) | 5204 | if (error) |
5181 | return error; | 5205 | return error; |
5182 | } else { | 5206 | } else { |
5207 | rcu_read_unlock(); | ||
5183 | tsec->sid = sid; | 5208 | tsec->sid = sid; |
5184 | task_unlock(p); | 5209 | task_unlock(p); |
5185 | } | 5210 | } |
@@ -5653,5 +5678,3 @@ int selinux_disable(void) | |||
5653 | return 0; | 5678 | return 0; |
5654 | } | 5679 | } |
5655 | #endif | 5680 | #endif |
5656 | |||
5657 | |||
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 020a8754b809..957b10d0f76f 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
@@ -34,7 +34,6 @@ struct task_security_struct { | |||
34 | u32 create_sid; /* fscreate SID */ | 34 | u32 create_sid; /* fscreate SID */ |
35 | u32 keycreate_sid; /* keycreate SID */ | 35 | u32 keycreate_sid; /* keycreate SID */ |
36 | u32 sockcreate_sid; /* fscreate SID */ | 36 | u32 sockcreate_sid; /* fscreate SID */ |
37 | u32 ptrace_sid; /* SID of ptrace parent */ | ||
38 | }; | 37 | }; |
39 | 38 | ||
40 | struct inode_security_struct { | 39 | struct inode_security_struct { |