*/
        if (task->parent == current && (task->ptrace & PT_PTRACED) &&
            task_is_stopped_or_traced(task) &&
-           ptrace_may_attach(task))
+           ptrace_may_access(task, PTRACE_MODE_ATTACH))
                return 0;
 
        /*
        task_lock(task);
        if (task->mm != mm)
                goto out;
-       if (task->mm != current->mm && __ptrace_may_attach(task) < 0)
+       if (task->mm != current->mm &&
+           __ptrace_may_access(task, PTRACE_MODE_READ) < 0)
                goto out;
        task_unlock(task);
        return mm;
         */
        task = get_proc_task(inode);
        if (task) {
-               allowed = ptrace_may_attach(task);
+               allowed = ptrace_may_access(task, PTRACE_MODE_READ);
                put_task_struct(task);
        }
        return allowed;
        if (!task)
                goto out_no_task;
 
-       if (!ptrace_may_attach(task))
+       if (!ptrace_may_access(task, PTRACE_MODE_READ))
                goto out;
 
        ret = -ENOMEM;
 
        dev_t dev = 0;
        int len;
 
-       if (maps_protect && !ptrace_may_attach(task))
+       if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ))
                return -EACCES;
 
        if (file) {
                goto out;
 
        ret = -EACCES;
-       if (!ptrace_may_attach(task))
+       if (!ptrace_may_access(task, PTRACE_MODE_READ))
                goto out_task;
 
        ret = -EINVAL;
        struct proc_maps_private *priv = m->private;
        struct task_struct *task = priv->task;
 
-       if (maps_protect && !ptrace_may_attach(task))
+       if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ))
                return -EACCES;
 
        return show_numa_map(m, v);
 
        struct proc_maps_private *priv = m->private;
        struct task_struct *task = priv->task;
 
-       if (maps_protect && !ptrace_may_attach(task))
+       if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ))
                return -EACCES;
 
        return nommu_vma_show(m, vml->vma);
 
                          struct task_struct *new_parent);
 extern void __ptrace_unlink(struct task_struct *child);
 extern void ptrace_untrace(struct task_struct *child);
-extern int ptrace_may_attach(struct task_struct *task);
-extern int __ptrace_may_attach(struct task_struct *task);
+#define PTRACE_MODE_READ   1
+#define PTRACE_MODE_ATTACH 2
+/* Returns 0 on success, -errno on denial. */
+extern int __ptrace_may_access(struct task_struct *task, unsigned int mode);
+/* Returns true on success, false on denial. */
+extern bool ptrace_may_access(struct task_struct *task, unsigned int mode);
 
 static inline int ptrace_reparented(struct task_struct *child)
 {
 
  */
 extern int cap_capable(struct task_struct *tsk, int cap);
 extern int cap_settime(struct timespec *ts, struct timezone *tz);
-extern int cap_ptrace(struct task_struct *parent, struct task_struct *child);
+extern int cap_ptrace(struct task_struct *parent, struct task_struct *child,
+                     unsigned int mode);
 extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
 extern int cap_capset_check(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
 extern void cap_capset_set(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
  *     attributes would be changed by the execve.
  *     @parent contains the task_struct structure for parent process.
  *     @child contains the task_struct structure for child process.
+ *     @mode contains the PTRACE_MODE flags indicating the form of access.
  *     Return 0 if permission is granted.
  * @capget:
  *     Get the @effective, @inheritable, and @permitted capability sets for
 struct security_operations {
        char name[SECURITY_NAME_MAX + 1];
 
-       int (*ptrace) (struct task_struct *parent, struct task_struct *child);
+       int (*ptrace) (struct task_struct *parent, struct task_struct *child,
+                      unsigned int mode);
        int (*capget) (struct task_struct *target,
                       kernel_cap_t *effective,
                       kernel_cap_t *inheritable, kernel_cap_t *permitted);
 extern void securityfs_remove(struct dentry *dentry);
 
 /* Security operations */
-int security_ptrace(struct task_struct *parent, struct task_struct *child);
+int security_ptrace(struct task_struct *parent, struct task_struct *child,
+                   unsigned int mode);
 int security_capget(struct task_struct *target,
                    kernel_cap_t *effective,
                    kernel_cap_t *inheritable,
        return 0;
 }
 
-static inline int security_ptrace(struct task_struct *parent, struct task_struct *child)
+static inline int security_ptrace(struct task_struct *parent,
+                                 struct task_struct *child,
+                                 unsigned int mode)
 {
-       return cap_ptrace(parent, child);
+       return cap_ptrace(parent, child, mode);
 }
 
 static inline int security_capget(struct task_struct *target,
 
        return ret;
 }
 
-int __ptrace_may_attach(struct task_struct *task)
+int __ptrace_may_access(struct task_struct *task, unsigned int mode)
 {
        /* May we inspect the given task?
         * This check is used both for attaching with ptrace
        if (!dumpable && !capable(CAP_SYS_PTRACE))
                return -EPERM;
 
-       return security_ptrace(current, task);
+       return security_ptrace(current, task, mode);
 }
 
-int ptrace_may_attach(struct task_struct *task)
+bool ptrace_may_access(struct task_struct *task, unsigned int mode)
 {
        int err;
        task_lock(task);
-       err = __ptrace_may_attach(task);
+       err = __ptrace_may_access(task, mode);
        task_unlock(task);
-       return !err;
+       return (!err ? true : false);
 }
 
 int ptrace_attach(struct task_struct *task)
        /* the same process cannot be attached many times */
        if (task->ptrace & PT_PTRACED)
                goto bad;
-       retval = __ptrace_may_attach(task);
+       retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH);
        if (retval)
                goto bad;
 
         */
        task_lock(current);
        if (!(current->ptrace & PT_PTRACED)) {
-               ret = security_ptrace(current->parent, current);
+               ret = security_ptrace(current->parent, current,
+                                     PTRACE_MODE_ATTACH);
                /*
                 * Set the ptrace bit in the process ptrace flags.
                 */
 
        return 0;
 }
 
-int cap_ptrace (struct task_struct *parent, struct task_struct *child)
+int cap_ptrace (struct task_struct *parent, struct task_struct *child,
+               unsigned int mode)
 {
        /* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */
        if (!cap_issubset(child->cap_permitted, parent->cap_permitted) &&
 
 #include <linux/prctl.h>
 #include <linux/securebits.h>
 
-static int dummy_ptrace (struct task_struct *parent, struct task_struct *child)
+static int dummy_ptrace (struct task_struct *parent, struct task_struct *child,
+                        unsigned int mode)
 {
        return 0;
 }
 
 
 /* Security operations */
 
-int security_ptrace(struct task_struct *parent, struct task_struct *child)
+int security_ptrace(struct task_struct *parent, struct task_struct *child,
+                   unsigned int mode)
 {
-       return security_ops->ptrace(parent, child);
+       return security_ops->ptrace(parent, child, mode);
 }
 
 int security_capget(struct task_struct *target,
 
 
 /* Hook functions begin here. */
 
-static int selinux_ptrace(struct task_struct *parent, struct task_struct *child)
+static int selinux_ptrace(struct task_struct *parent,
+                         struct task_struct *child,
+                         unsigned int mode)
 {
        int rc;
 
-       rc = secondary_ops->ptrace(parent, child);
+       rc = secondary_ops->ptrace(parent, child, mode);
        if (rc)
                return rc;
 
+       if (mode == PTRACE_MODE_READ) {
+               struct task_security_struct *tsec = parent->security;
+               struct task_security_struct *csec = child->security;
+               return avc_has_perm(tsec->sid, csec->sid,
+                                   SECCLASS_FILE, FILE__READ, NULL);
+       }
+
        return task_has_perm(parent, child, PROCESS__PTRACE);
 }
 
 
  *
  * Do the capability checks, and require read and write.
  */
-static int smack_ptrace(struct task_struct *ptp, struct task_struct *ctp)
+static int smack_ptrace(struct task_struct *ptp, struct task_struct *ctp,
+                       unsigned int mode)
 {
        int rc;
 
-       rc = cap_ptrace(ptp, ctp);
+       rc = cap_ptrace(ptp, ctp, mode);
        if (rc != 0)
                return rc;