~ubuntu-branches/ubuntu/wily/linux-ti-omap4/wily

« back to all changes in this revision

Viewing changes to kernel/ptrace.c

  • Committer: Package Import Robot
  • Author(s): Paolo Pisati, Paolo Pisati, Ubuntu: 3.5.0-25.38
  • Date: 2013-02-20 22:03:31 UTC
  • mfrom: (74.1.1 quantal-proposed)
  • Revision ID: package-import@ubuntu.com-20130220220331-0ea4l33x3cr61nch
Tags: 3.5.0-220.28
* Release Tracking Bug
  - LP: #1130311

[ Paolo Pisati ]

* rebased on Ubuntu-3.5.0-25.38

[ Ubuntu: 3.5.0-25.38 ]

* Release Tracking Bug
  - LP: #1129472
* ptrace: introduce signal_wake_up_state() and ptrace_signal_wake_up()
  - LP: #1119885, #1129192
  - CVE-2013-0871
* ptrace: ensure arch_ptrace/ptrace_request can never race with SIGKILL
  - LP: #1119885, #1129192
  - CVE-2013-0871
* wake_up_process() should be never used to wakeup a TASK_STOPPED/TRACED
  task
  - LP: #1119885, #1129192
  - CVE-2013-0871

Show diffs side-by-side

added added

removed removed

Lines of Context:
117
117
         * TASK_KILLABLE sleeps.
118
118
         */
119
119
        if (child->jobctl & JOBCTL_STOP_PENDING || task_is_traced(child))
120
 
                signal_wake_up(child, task_is_traced(child));
 
120
                ptrace_signal_wake_up(child, true);
121
121
 
122
122
        spin_unlock(&child->sighand->siglock);
123
123
}
124
124
 
 
125
/* Ensure that nothing can wake it up, even SIGKILL */
 
126
static bool ptrace_freeze_traced(struct task_struct *task)
 
127
{
 
128
        bool ret = false;
 
129
 
 
130
        /* Lockless, nobody but us can set this flag */
 
131
        if (task->jobctl & JOBCTL_LISTENING)
 
132
                return ret;
 
133
 
 
134
        spin_lock_irq(&task->sighand->siglock);
 
135
        if (task_is_traced(task) && !__fatal_signal_pending(task)) {
 
136
                task->state = __TASK_TRACED;
 
137
                ret = true;
 
138
        }
 
139
        spin_unlock_irq(&task->sighand->siglock);
 
140
 
 
141
        return ret;
 
142
}
 
143
 
 
144
static void ptrace_unfreeze_traced(struct task_struct *task)
 
145
{
 
146
        if (task->state != __TASK_TRACED)
 
147
                return;
 
148
 
 
149
        WARN_ON(!task->ptrace || task->parent != current);
 
150
 
 
151
        spin_lock_irq(&task->sighand->siglock);
 
152
        if (__fatal_signal_pending(task))
 
153
                wake_up_state(task, __TASK_TRACED);
 
154
        else
 
155
                task->state = TASK_TRACED;
 
156
        spin_unlock_irq(&task->sighand->siglock);
 
157
}
 
158
 
125
159
/**
126
160
 * ptrace_check_attach - check whether ptracee is ready for ptrace operation
127
161
 * @child: ptracee to check for
151
185
         * be changed by us so it's not changing right after this.
152
186
         */
153
187
        read_lock(&tasklist_lock);
154
 
        if ((child->ptrace & PT_PTRACED) && child->parent == current) {
 
188
        if (child->ptrace && child->parent == current) {
 
189
                WARN_ON(child->state == __TASK_TRACED);
155
190
                /*
156
191
                 * child->sighand can't be NULL, release_task()
157
192
                 * does ptrace_unlink() before __exit_signal().
158
193
                 */
159
 
                spin_lock_irq(&child->sighand->siglock);
160
 
                WARN_ON_ONCE(task_is_stopped(child));
161
 
                if (ignore_state || (task_is_traced(child) &&
162
 
                                     !(child->jobctl & JOBCTL_LISTENING)))
 
194
                if (ignore_state || ptrace_freeze_traced(child))
163
195
                        ret = 0;
164
 
                spin_unlock_irq(&child->sighand->siglock);
165
196
        }
166
197
        read_unlock(&tasklist_lock);
167
198
 
168
 
        if (!ret && !ignore_state)
169
 
                ret = wait_task_inactive(child, TASK_TRACED) ? 0 : -ESRCH;
 
199
        if (!ret && !ignore_state) {
 
200
                if (!wait_task_inactive(child, __TASK_TRACED)) {
 
201
                        /*
 
202
                         * This can only happen if may_ptrace_stop() fails and
 
203
                         * ptrace_stop() changes ->state back to TASK_RUNNING,
 
204
                         * so we should not worry about leaking __TASK_TRACED.
 
205
                         */
 
206
                        WARN_ON(child->state == __TASK_TRACED);
 
207
                        ret = -ESRCH;
 
208
                }
 
209
        }
170
210
 
171
 
        /* All systems go.. */
172
211
        return ret;
173
212
}
174
213
 
310
349
         */
311
350
        if (task_is_stopped(task) &&
312
351
            task_set_jobctl_pending(task, JOBCTL_TRAP_STOP | JOBCTL_TRAPPING))
313
 
                signal_wake_up(task, 1);
 
352
                signal_wake_up_state(task, __TASK_STOPPED);
314
353
 
315
354
        spin_unlock(&task->sighand->siglock);
316
355
 
727
766
                 * tracee into STOP.
728
767
                 */
729
768
                if (likely(task_set_jobctl_pending(child, JOBCTL_TRAP_STOP)))
730
 
                        signal_wake_up(child, child->jobctl & JOBCTL_LISTENING);
 
769
                        ptrace_signal_wake_up(child, child->jobctl & JOBCTL_LISTENING);
731
770
 
732
771
                unlock_task_sighand(child, &flags);
733
772
                ret = 0;
753
792
                         * start of this trap and now.  Trigger re-trap.
754
793
                         */
755
794
                        if (child->jobctl & JOBCTL_TRAP_NOTIFY)
756
 
                                signal_wake_up(child, true);
 
795
                                ptrace_signal_wake_up(child, true);
757
796
                        ret = 0;
758
797
                }
759
798
                unlock_task_sighand(child, &flags);
890
929
                goto out_put_task_struct;
891
930
 
892
931
        ret = arch_ptrace(child, request, addr, data);
 
932
        if (ret || request != PTRACE_DETACH)
 
933
                ptrace_unfreeze_traced(child);
893
934
 
894
935
 out_put_task_struct:
895
936
        put_task_struct(child);
1029
1070
 
1030
1071
        ret = ptrace_check_attach(child, request == PTRACE_KILL ||
1031
1072
                                  request == PTRACE_INTERRUPT);
1032
 
        if (!ret)
 
1073
        if (!ret) {
1033
1074
                ret = compat_arch_ptrace(child, request, addr, data);
 
1075
                if (ret || request != PTRACE_DETACH)
 
1076
                        ptrace_unfreeze_traced(child);
 
1077
        }
1034
1078
 
1035
1079
 out_put_task_struct:
1036
1080
        put_task_struct(child);