}
 
 static int ptrace_bts_drain(struct task_struct *child,
+                           long size,
                            struct bts_struct __user *out)
 {
        int end, i;
        if (end <= 0)
                return end;
 
+       if (size < (end * sizeof(struct bts_struct)))
+               return -EIO;
+
        for (i = 0; i < end; i++, out++) {
                struct bts_struct ret;
                int retval;
 
        ds_clear(ds);
 
-       return i;
+       return end;
 }
 
 static int ptrace_bts_realloc(struct task_struct *child,
 }
 
 static int ptrace_bts_config(struct task_struct *child,
+                            long cfg_size,
                             const struct ptrace_bts_config __user *ucfg)
 {
        struct ptrace_bts_config cfg;
        int bts_size, ret = 0;
        void *ds;
 
+       if (cfg_size < sizeof(cfg))
+               return -EIO;
+
        if (copy_from_user(&cfg, ucfg, sizeof(cfg)))
                return -EFAULT;
 
+       if ((int)cfg.size < 0)
+               return -EINVAL;
+
        bts_size = 0;
        ds = (void *)child->thread.ds_area_msr;
        if (ds) {
        else
                clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
 
+       ret = sizeof(cfg);
+
 out:
        if (child->thread.debugctlmsr)
                set_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
 }
 
 static int ptrace_bts_status(struct task_struct *child,
+                            long cfg_size,
                             struct ptrace_bts_config __user *ucfg)
 {
        void *ds = (void *)child->thread.ds_area_msr;
        struct ptrace_bts_config cfg;
 
+       if (cfg_size < sizeof(cfg))
+               return -EIO;
+
        memset(&cfg, 0, sizeof(cfg));
 
        if (ds) {
 
        case PTRACE_BTS_CONFIG:
                ret = ptrace_bts_config
-                       (child, (struct ptrace_bts_config __user *)addr);
+                       (child, data, (struct ptrace_bts_config __user *)addr);
                break;
 
        case PTRACE_BTS_STATUS:
                ret = ptrace_bts_status
-                       (child, (struct ptrace_bts_config __user *)addr);
+                       (child, data, (struct ptrace_bts_config __user *)addr);
                break;
 
        case PTRACE_BTS_SIZE:
 
        case PTRACE_BTS_DRAIN:
                ret = ptrace_bts_drain
-                       (child, (struct bts_struct __user *) addr);
+                       (child, data, (struct bts_struct __user *) addr);
                break;
 
        default:
 
 
 #define PTRACE_BTS_CONFIG      40
 /* Configure branch trace recording.
-   DATA is ignored, ADDR points to a struct ptrace_bts_config.
+   ADDR points to a struct ptrace_bts_config.
+   DATA gives the size of that buffer.
    A new buffer is allocated, iff the size changes.
+   Returns the number of bytes read.
 */
 #define PTRACE_BTS_STATUS      41
-/* Return the current configuration.
-   DATA is ignored, ADDR points to a struct ptrace_bts_config
-   that will contain the result.
+/* Return the current configuration in a struct ptrace_bts_config
+   pointed to by ADDR; DATA gives the size of that buffer.
+   Returns the number of bytes written.
 */
 #define PTRACE_BTS_SIZE                42
 /* Return the number of available BTS records.
 */
 #define PTRACE_BTS_DRAIN       45
 /* Read all available BTS records and clear the buffer.
-   DATA is ignored. ADDR points to an array of struct bts_struct of
-   suitable size.
+   ADDR points to an array of struct bts_struct.
+   DATA gives the size of that buffer.
    BTS records are read from oldest to newest.
    Returns number of BTS records drained.
 */