diff options
-rw-r--r-- | fs/proc/base.c | 9 | ||||
-rw-r--r-- | fs/proc/task_mmu.c | 6 | ||||
-rw-r--r-- | fs/proc/task_nommu.c | 2 | ||||
-rw-r--r-- | include/linux/ptrace.h | 8 | ||||
-rw-r--r-- | include/linux/security.h | 16 | ||||
-rw-r--r-- | kernel/ptrace.c | 15 | ||||
-rw-r--r-- | security/commoncap.c | 3 | ||||
-rw-r--r-- | security/dummy.c | 3 | ||||
-rw-r--r-- | security/security.c | 5 | ||||
-rw-r--r-- | security/selinux/hooks.c | 13 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 5 |
11 files changed, 55 insertions, 30 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 3b455371e7ff..58c3e6a8e15e 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -233,7 +233,7 @@ static int check_mem_permission(struct task_struct *task) | |||
233 | */ | 233 | */ |
234 | if (task->parent == current && (task->ptrace & PT_PTRACED) && | 234 | if (task->parent == current && (task->ptrace & PT_PTRACED) && |
235 | task_is_stopped_or_traced(task) && | 235 | task_is_stopped_or_traced(task) && |
236 | ptrace_may_attach(task)) | 236 | ptrace_may_access(task, PTRACE_MODE_ATTACH)) |
237 | return 0; | 237 | return 0; |
238 | 238 | ||
239 | /* | 239 | /* |
@@ -251,7 +251,8 @@ struct mm_struct *mm_for_maps(struct task_struct *task) | |||
251 | task_lock(task); | 251 | task_lock(task); |
252 | if (task->mm != mm) | 252 | if (task->mm != mm) |
253 | goto out; | 253 | goto out; |
254 | if (task->mm != current->mm && __ptrace_may_attach(task) < 0) | 254 | if (task->mm != current->mm && |
255 | __ptrace_may_access(task, PTRACE_MODE_READ) < 0) | ||
255 | goto out; | 256 | goto out; |
256 | task_unlock(task); | 257 | task_unlock(task); |
257 | return mm; | 258 | return mm; |
@@ -518,7 +519,7 @@ static int proc_fd_access_allowed(struct inode *inode) | |||
518 | */ | 519 | */ |
519 | task = get_proc_task(inode); | 520 | task = get_proc_task(inode); |
520 | if (task) { | 521 | if (task) { |
521 | allowed = ptrace_may_attach(task); | 522 | allowed = ptrace_may_access(task, PTRACE_MODE_READ); |
522 | put_task_struct(task); | 523 | put_task_struct(task); |
523 | } | 524 | } |
524 | return allowed; | 525 | return allowed; |
@@ -904,7 +905,7 @@ static ssize_t environ_read(struct file *file, char __user *buf, | |||
904 | if (!task) | 905 | if (!task) |
905 | goto out_no_task; | 906 | goto out_no_task; |
906 | 907 | ||
907 | if (!ptrace_may_attach(task)) | 908 | if (!ptrace_may_access(task, PTRACE_MODE_READ)) |
908 | goto out; | 909 | goto out; |
909 | 910 | ||
910 | ret = -ENOMEM; | 911 | ret = -ENOMEM; |
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index c492449f3b45..164bd9f9ede3 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -210,7 +210,7 @@ static int show_map(struct seq_file *m, void *v) | |||
210 | dev_t dev = 0; | 210 | dev_t dev = 0; |
211 | int len; | 211 | int len; |
212 | 212 | ||
213 | if (maps_protect && !ptrace_may_attach(task)) | 213 | if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ)) |
214 | return -EACCES; | 214 | return -EACCES; |
215 | 215 | ||
216 | if (file) { | 216 | if (file) { |
@@ -646,7 +646,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, | |||
646 | goto out; | 646 | goto out; |
647 | 647 | ||
648 | ret = -EACCES; | 648 | ret = -EACCES; |
649 | if (!ptrace_may_attach(task)) | 649 | if (!ptrace_may_access(task, PTRACE_MODE_READ)) |
650 | goto out_task; | 650 | goto out_task; |
651 | 651 | ||
652 | ret = -EINVAL; | 652 | ret = -EINVAL; |
@@ -747,7 +747,7 @@ static int show_numa_map_checked(struct seq_file *m, void *v) | |||
747 | struct proc_maps_private *priv = m->private; | 747 | struct proc_maps_private *priv = m->private; |
748 | struct task_struct *task = priv->task; | 748 | struct task_struct *task = priv->task; |
749 | 749 | ||
750 | if (maps_protect && !ptrace_may_attach(task)) | 750 | if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ)) |
751 | return -EACCES; | 751 | return -EACCES; |
752 | 752 | ||
753 | return show_numa_map(m, v); | 753 | return show_numa_map(m, v); |
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index 4b4f9cc2f186..5d84e7121df8 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c | |||
@@ -113,7 +113,7 @@ static int show_map(struct seq_file *m, void *_vml) | |||
113 | struct proc_maps_private *priv = m->private; | 113 | struct proc_maps_private *priv = m->private; |
114 | struct task_struct *task = priv->task; | 114 | struct task_struct *task = priv->task; |
115 | 115 | ||
116 | if (maps_protect && !ptrace_may_attach(task)) | 116 | if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ)) |
117 | return -EACCES; | 117 | return -EACCES; |
118 | 118 | ||
119 | return nommu_vma_show(m, vml->vma); | 119 | return nommu_vma_show(m, vml->vma); |
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index f98501ba557e..c6f5f9dd0cee 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h | |||
@@ -95,8 +95,12 @@ extern void __ptrace_link(struct task_struct *child, | |||
95 | struct task_struct *new_parent); | 95 | struct task_struct *new_parent); |
96 | extern void __ptrace_unlink(struct task_struct *child); | 96 | extern void __ptrace_unlink(struct task_struct *child); |
97 | extern void ptrace_untrace(struct task_struct *child); | 97 | extern void ptrace_untrace(struct task_struct *child); |
98 | extern int ptrace_may_attach(struct task_struct *task); | 98 | #define PTRACE_MODE_READ 1 |
99 | extern int __ptrace_may_attach(struct task_struct *task); | 99 | #define PTRACE_MODE_ATTACH 2 |
100 | /* Returns 0 on success, -errno on denial. */ | ||
101 | extern int __ptrace_may_access(struct task_struct *task, unsigned int mode); | ||
102 | /* Returns true on success, false on denial. */ | ||
103 | extern bool ptrace_may_access(struct task_struct *task, unsigned int mode); | ||
100 | 104 | ||
101 | static inline int ptrace_reparented(struct task_struct *child) | 105 | static inline int ptrace_reparented(struct task_struct *child) |
102 | { | 106 | { |
diff --git a/include/linux/security.h b/include/linux/security.h index 50737c70e78e..62bd80cb7f87 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -46,7 +46,8 @@ struct audit_krule; | |||
46 | */ | 46 | */ |
47 | extern int cap_capable(struct task_struct *tsk, int cap); | 47 | extern int cap_capable(struct task_struct *tsk, int cap); |
48 | extern int cap_settime(struct timespec *ts, struct timezone *tz); | 48 | extern int cap_settime(struct timespec *ts, struct timezone *tz); |
49 | extern int cap_ptrace(struct task_struct *parent, struct task_struct *child); | 49 | extern int cap_ptrace(struct task_struct *parent, struct task_struct *child, |
50 | unsigned int mode); | ||
50 | extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); | 51 | extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); |
51 | extern int cap_capset_check(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); | 52 | extern int cap_capset_check(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); |
52 | extern void cap_capset_set(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); | 53 | extern void cap_capset_set(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); |
@@ -1170,6 +1171,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
1170 | * attributes would be changed by the execve. | 1171 | * attributes would be changed by the execve. |
1171 | * @parent contains the task_struct structure for parent process. | 1172 | * @parent contains the task_struct structure for parent process. |
1172 | * @child contains the task_struct structure for child process. | 1173 | * @child contains the task_struct structure for child process. |
1174 | * @mode contains the PTRACE_MODE flags indicating the form of access. | ||
1173 | * Return 0 if permission is granted. | 1175 | * Return 0 if permission is granted. |
1174 | * @capget: | 1176 | * @capget: |
1175 | * Get the @effective, @inheritable, and @permitted capability sets for | 1177 | * Get the @effective, @inheritable, and @permitted capability sets for |
@@ -1295,7 +1297,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
1295 | struct security_operations { | 1297 | struct security_operations { |
1296 | char name[SECURITY_NAME_MAX + 1]; | 1298 | char name[SECURITY_NAME_MAX + 1]; |
1297 | 1299 | ||
1298 | int (*ptrace) (struct task_struct *parent, struct task_struct *child); | 1300 | int (*ptrace) (struct task_struct *parent, struct task_struct *child, |
1301 | unsigned int mode); | ||
1299 | int (*capget) (struct task_struct *target, | 1302 | int (*capget) (struct task_struct *target, |
1300 | kernel_cap_t *effective, | 1303 | kernel_cap_t *effective, |
1301 | kernel_cap_t *inheritable, kernel_cap_t *permitted); | 1304 | kernel_cap_t *inheritable, kernel_cap_t *permitted); |
@@ -1573,7 +1576,8 @@ extern struct dentry *securityfs_create_dir(const char *name, struct dentry *par | |||
1573 | extern void securityfs_remove(struct dentry *dentry); | 1576 | extern void securityfs_remove(struct dentry *dentry); |
1574 | 1577 | ||
1575 | /* Security operations */ | 1578 | /* Security operations */ |
1576 | int security_ptrace(struct task_struct *parent, struct task_struct *child); | 1579 | int security_ptrace(struct task_struct *parent, struct task_struct *child, |
1580 | unsigned int mode); | ||
1577 | int security_capget(struct task_struct *target, | 1581 | int security_capget(struct task_struct *target, |
1578 | kernel_cap_t *effective, | 1582 | kernel_cap_t *effective, |
1579 | kernel_cap_t *inheritable, | 1583 | kernel_cap_t *inheritable, |
@@ -1755,9 +1759,11 @@ static inline int security_init(void) | |||
1755 | return 0; | 1759 | return 0; |
1756 | } | 1760 | } |
1757 | 1761 | ||
1758 | static inline int security_ptrace(struct task_struct *parent, struct task_struct *child) | 1762 | static inline int security_ptrace(struct task_struct *parent, |
1763 | struct task_struct *child, | ||
1764 | unsigned int mode) | ||
1759 | { | 1765 | { |
1760 | return cap_ptrace(parent, child); | 1766 | return cap_ptrace(parent, child, mode); |
1761 | } | 1767 | } |
1762 | 1768 | ||
1763 | static inline int security_capget(struct task_struct *target, | 1769 | static inline int security_capget(struct task_struct *target, |
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 6c19e94fd0a5..e337390fce01 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -121,7 +121,7 @@ int ptrace_check_attach(struct task_struct *child, int kill) | |||
121 | return ret; | 121 | return ret; |
122 | } | 122 | } |
123 | 123 | ||
124 | int __ptrace_may_attach(struct task_struct *task) | 124 | int __ptrace_may_access(struct task_struct *task, unsigned int mode) |
125 | { | 125 | { |
126 | /* May we inspect the given task? | 126 | /* May we inspect the given task? |
127 | * This check is used both for attaching with ptrace | 127 | * This check is used both for attaching with ptrace |
@@ -148,16 +148,16 @@ int __ptrace_may_attach(struct task_struct *task) | |||
148 | if (!dumpable && !capable(CAP_SYS_PTRACE)) | 148 | if (!dumpable && !capable(CAP_SYS_PTRACE)) |
149 | return -EPERM; | 149 | return -EPERM; |
150 | 150 | ||
151 | return security_ptrace(current, task); | 151 | return security_ptrace(current, task, mode); |
152 | } | 152 | } |
153 | 153 | ||
154 | int ptrace_may_attach(struct task_struct *task) | 154 | bool ptrace_may_access(struct task_struct *task, unsigned int mode) |
155 | { | 155 | { |
156 | int err; | 156 | int err; |
157 | task_lock(task); | 157 | task_lock(task); |
158 | err = __ptrace_may_attach(task); | 158 | err = __ptrace_may_access(task, mode); |
159 | task_unlock(task); | 159 | task_unlock(task); |
160 | return !err; | 160 | return (!err ? true : false); |
161 | } | 161 | } |
162 | 162 | ||
163 | int ptrace_attach(struct task_struct *task) | 163 | int ptrace_attach(struct task_struct *task) |
@@ -195,7 +195,7 @@ repeat: | |||
195 | /* the same process cannot be attached many times */ | 195 | /* the same process cannot be attached many times */ |
196 | if (task->ptrace & PT_PTRACED) | 196 | if (task->ptrace & PT_PTRACED) |
197 | goto bad; | 197 | goto bad; |
198 | retval = __ptrace_may_attach(task); | 198 | retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH); |
199 | if (retval) | 199 | if (retval) |
200 | goto bad; | 200 | goto bad; |
201 | 201 | ||
@@ -494,7 +494,8 @@ int ptrace_traceme(void) | |||
494 | */ | 494 | */ |
495 | task_lock(current); | 495 | task_lock(current); |
496 | if (!(current->ptrace & PT_PTRACED)) { | 496 | if (!(current->ptrace & PT_PTRACED)) { |
497 | ret = security_ptrace(current->parent, current); | 497 | ret = security_ptrace(current->parent, current, |
498 | PTRACE_MODE_ATTACH); | ||
498 | /* | 499 | /* |
499 | * Set the ptrace bit in the process ptrace flags. | 500 | * Set the ptrace bit in the process ptrace flags. |
500 | */ | 501 | */ |
diff --git a/security/commoncap.c b/security/commoncap.c index 33d343308413..0b6537a3672d 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -63,7 +63,8 @@ int cap_settime(struct timespec *ts, struct timezone *tz) | |||
63 | return 0; | 63 | return 0; |
64 | } | 64 | } |
65 | 65 | ||
66 | int cap_ptrace (struct task_struct *parent, struct task_struct *child) | 66 | int cap_ptrace (struct task_struct *parent, struct task_struct *child, |
67 | unsigned int mode) | ||
67 | { | 68 | { |
68 | /* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */ | 69 | /* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */ |
69 | if (!cap_issubset(child->cap_permitted, parent->cap_permitted) && | 70 | if (!cap_issubset(child->cap_permitted, parent->cap_permitted) && |
diff --git a/security/dummy.c b/security/dummy.c index b8916883b77f..1db712d99dc7 100644 --- a/security/dummy.c +++ b/security/dummy.c | |||
@@ -30,7 +30,8 @@ | |||
30 | #include <linux/prctl.h> | 30 | #include <linux/prctl.h> |
31 | #include <linux/securebits.h> | 31 | #include <linux/securebits.h> |
32 | 32 | ||
33 | static int dummy_ptrace (struct task_struct *parent, struct task_struct *child) | 33 | static int dummy_ptrace (struct task_struct *parent, struct task_struct *child, |
34 | unsigned int mode) | ||
34 | { | 35 | { |
35 | return 0; | 36 | return 0; |
36 | } | 37 | } |
diff --git a/security/security.c b/security/security.c index 59838a99b80e..c4507ce2a5a0 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -161,9 +161,10 @@ int mod_reg_security(const char *name, struct security_operations *ops) | |||
161 | 161 | ||
162 | /* Security operations */ | 162 | /* Security operations */ |
163 | 163 | ||
164 | int security_ptrace(struct task_struct *parent, struct task_struct *child) | 164 | int security_ptrace(struct task_struct *parent, struct task_struct *child, |
165 | unsigned int mode) | ||
165 | { | 166 | { |
166 | return security_ops->ptrace(parent, child); | 167 | return security_ops->ptrace(parent, child, mode); |
167 | } | 168 | } |
168 | 169 | ||
169 | int security_capget(struct task_struct *target, | 170 | int security_capget(struct task_struct *target, |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index eca70f42e678..4be156334b22 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -1686,14 +1686,23 @@ static inline u32 file_to_av(struct file *file) | |||
1686 | 1686 | ||
1687 | /* Hook functions begin here. */ | 1687 | /* Hook functions begin here. */ |
1688 | 1688 | ||
1689 | static int selinux_ptrace(struct task_struct *parent, struct task_struct *child) | 1689 | static int selinux_ptrace(struct task_struct *parent, |
1690 | struct task_struct *child, | ||
1691 | unsigned int mode) | ||
1690 | { | 1692 | { |
1691 | int rc; | 1693 | int rc; |
1692 | 1694 | ||
1693 | rc = secondary_ops->ptrace(parent, child); | 1695 | rc = secondary_ops->ptrace(parent, child, mode); |
1694 | if (rc) | 1696 | if (rc) |
1695 | return rc; | 1697 | return rc; |
1696 | 1698 | ||
1699 | if (mode == PTRACE_MODE_READ) { | ||
1700 | struct task_security_struct *tsec = parent->security; | ||
1701 | struct task_security_struct *csec = child->security; | ||
1702 | return avc_has_perm(tsec->sid, csec->sid, | ||
1703 | SECCLASS_FILE, FILE__READ, NULL); | ||
1704 | } | ||
1705 | |||
1697 | return task_has_perm(parent, child, PROCESS__PTRACE); | 1706 | return task_has_perm(parent, child, PROCESS__PTRACE); |
1698 | } | 1707 | } |
1699 | 1708 | ||
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 4a09293efa00..3c7150b3493d 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -95,11 +95,12 @@ struct inode_smack *new_inode_smack(char *smack) | |||
95 | * | 95 | * |
96 | * Do the capability checks, and require read and write. | 96 | * Do the capability checks, and require read and write. |
97 | */ | 97 | */ |
98 | static int smack_ptrace(struct task_struct *ptp, struct task_struct *ctp) | 98 | static int smack_ptrace(struct task_struct *ptp, struct task_struct *ctp, |
99 | unsigned int mode) | ||
99 | { | 100 | { |
100 | int rc; | 101 | int rc; |
101 | 102 | ||
102 | rc = cap_ptrace(ptp, ctp); | 103 | rc = cap_ptrace(ptp, ctp, mode); |
103 | if (rc != 0) | 104 | if (rc != 0) |
104 | return rc; | 105 | return rc; |
105 | 106 | ||