ia64/linux-2.6.18-xen.hg

annotate kernel/ptrace.c @ 798:b02a90bf5bbc

ACPI: Backport missing part for T-State MSR support

Part of below kernel commit was missed while packporting T-State
support.

commit f79f06ab9f86d7203006d2ec8992ac80df36a34e
Author: Zhao Yakui <yakui.zhao@intel.com>
Date: Thu Nov 15 17:06:36 2007 +0800

ACPI: Enable MSR (FixedHW) support for T-States

Add throttling control via MSR when T-states uses
the FixHW Control Status registers.

Signed-off-by: Zhao Yakui <yakui.zhao@intel.com>
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>

Signed-off-by: Wei Gang <gang.wei@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Mar 02 10:53:59 2009 +0000 (2009-03-02)
parents 831230e53067
children
rev   line source
ian@0 1 /*
ian@0 2 * linux/kernel/ptrace.c
ian@0 3 *
ian@0 4 * (C) Copyright 1999 Linus Torvalds
ian@0 5 *
ian@0 6 * Common interfaces for "ptrace()" which we do not want
ian@0 7 * to continually duplicate across every architecture.
ian@0 8 */
ian@0 9
ian@0 10 #include <linux/capability.h>
ian@0 11 #include <linux/module.h>
ian@0 12 #include <linux/sched.h>
ian@0 13 #include <linux/errno.h>
ian@0 14 #include <linux/mm.h>
ian@0 15 #include <linux/highmem.h>
ian@0 16 #include <linux/pagemap.h>
ian@0 17 #include <linux/smp_lock.h>
ian@0 18 #include <linux/ptrace.h>
ian@0 19 #include <linux/security.h>
ian@0 20 #include <linux/signal.h>
ian@0 21
ian@0 22 #include <asm/pgtable.h>
ian@0 23 #include <asm/uaccess.h>
ian@0 24
ian@0 25 /*
ian@0 26 * ptrace a task: make the debugger its new parent and
ian@0 27 * move it to the ptrace list.
ian@0 28 *
ian@0 29 * Must be called with the tasklist lock write-held.
ian@0 30 */
ian@0 31 void __ptrace_link(struct task_struct *child, struct task_struct *new_parent)
ian@0 32 {
ian@0 33 BUG_ON(!list_empty(&child->ptrace_list));
ian@0 34 if (child->parent == new_parent)
ian@0 35 return;
ian@0 36 list_add(&child->ptrace_list, &child->parent->ptrace_children);
ian@0 37 remove_parent(child);
ian@0 38 child->parent = new_parent;
ian@0 39 add_parent(child);
ian@0 40 }
ian@0 41
ian@0 42 /*
ian@0 43 * Turn a tracing stop into a normal stop now, since with no tracer there
ian@0 44 * would be no way to wake it up with SIGCONT or SIGKILL. If there was a
ian@0 45 * signal sent that would resume the child, but didn't because it was in
ian@0 46 * TASK_TRACED, resume it now.
ian@0 47 * Requires that irqs be disabled.
ian@0 48 */
ian@0 49 void ptrace_untrace(struct task_struct *child)
ian@0 50 {
ian@0 51 spin_lock(&child->sighand->siglock);
ian@0 52 if (child->state == TASK_TRACED) {
ian@0 53 if (child->signal->flags & SIGNAL_STOP_STOPPED) {
ian@0 54 child->state = TASK_STOPPED;
ian@0 55 } else {
ian@0 56 signal_wake_up(child, 1);
ian@0 57 }
ian@0 58 }
ian@0 59 spin_unlock(&child->sighand->siglock);
ian@0 60 }
ian@0 61
ian@0 62 /*
ian@0 63 * unptrace a task: move it back to its original parent and
ian@0 64 * remove it from the ptrace list.
ian@0 65 *
ian@0 66 * Must be called with the tasklist lock write-held.
ian@0 67 */
ian@0 68 void __ptrace_unlink(struct task_struct *child)
ian@0 69 {
ian@0 70 BUG_ON(!child->ptrace);
ian@0 71
ian@0 72 child->ptrace = 0;
ian@0 73 if (!list_empty(&child->ptrace_list)) {
ian@0 74 list_del_init(&child->ptrace_list);
ian@0 75 remove_parent(child);
ian@0 76 child->parent = child->real_parent;
ian@0 77 add_parent(child);
ian@0 78 }
ian@0 79
ian@0 80 if (child->state == TASK_TRACED)
ian@0 81 ptrace_untrace(child);
ian@0 82 }
ian@0 83
ian@0 84 /*
ian@0 85 * Check that we have indeed attached to the thing..
ian@0 86 */
ian@0 87 int ptrace_check_attach(struct task_struct *child, int kill)
ian@0 88 {
ian@0 89 int ret = -ESRCH;
ian@0 90
ian@0 91 /*
ian@0 92 * We take the read lock around doing both checks to close a
ian@0 93 * possible race where someone else was tracing our child and
ian@0 94 * detached between these two checks. After this locked check,
ian@0 95 * we are sure that this is our traced child and that can only
ian@0 96 * be changed by us so it's not changing right after this.
ian@0 97 */
ian@0 98 read_lock(&tasklist_lock);
ian@0 99 if ((child->ptrace & PT_PTRACED) && child->parent == current &&
ian@0 100 (!(child->ptrace & PT_ATTACHED) || child->real_parent != current)
ian@0 101 && child->signal != NULL) {
ian@0 102 ret = 0;
ian@0 103 spin_lock_irq(&child->sighand->siglock);
ian@0 104 if (child->state == TASK_STOPPED) {
ian@0 105 child->state = TASK_TRACED;
ian@0 106 } else if (child->state != TASK_TRACED && !kill) {
ian@0 107 ret = -ESRCH;
ian@0 108 }
ian@0 109 spin_unlock_irq(&child->sighand->siglock);
ian@0 110 }
ian@0 111 read_unlock(&tasklist_lock);
ian@0 112
ian@0 113 if (!ret && !kill) {
ian@0 114 wait_task_inactive(child);
ian@0 115 }
ian@0 116
ian@0 117 /* All systems go.. */
ian@0 118 return ret;
ian@0 119 }
ian@0 120
ian@0 121 static int may_attach(struct task_struct *task)
ian@0 122 {
ian@0 123 /* May we inspect the given task?
ian@0 124 * This check is used both for attaching with ptrace
ian@0 125 * and for allowing access to sensitive information in /proc.
ian@0 126 *
ian@0 127 * ptrace_attach denies several cases that /proc allows
ian@0 128 * because setting up the necessary parent/child relationship
ian@0 129 * or halting the specified task is impossible.
ian@0 130 */
ian@0 131 int dumpable = 0;
ian@0 132 /* Don't let security modules deny introspection */
ian@0 133 if (task == current)
ian@0 134 return 0;
ian@0 135 if (((current->uid != task->euid) ||
ian@0 136 (current->uid != task->suid) ||
ian@0 137 (current->uid != task->uid) ||
ian@0 138 (current->gid != task->egid) ||
ian@0 139 (current->gid != task->sgid) ||
ian@0 140 (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
ian@0 141 return -EPERM;
ian@0 142 smp_rmb();
ian@0 143 if (task->mm)
ian@0 144 dumpable = task->mm->dumpable;
ian@0 145 if (!dumpable && !capable(CAP_SYS_PTRACE))
ian@0 146 return -EPERM;
ian@0 147
ian@0 148 return security_ptrace(current, task);
ian@0 149 }
ian@0 150
ian@0 151 int ptrace_may_attach(struct task_struct *task)
ian@0 152 {
ian@0 153 int err;
ian@0 154 task_lock(task);
ian@0 155 err = may_attach(task);
ian@0 156 task_unlock(task);
ian@0 157 return !err;
ian@0 158 }
ian@0 159
ian@0 160 int ptrace_attach(struct task_struct *task)
ian@0 161 {
ian@0 162 int retval;
ian@0 163
ian@0 164 retval = -EPERM;
ian@0 165 if (task->pid <= 1)
ian@0 166 goto out;
ian@0 167 if (task->tgid == current->tgid)
ian@0 168 goto out;
ian@0 169
ian@0 170 repeat:
ian@0 171 /*
ian@0 172 * Nasty, nasty.
ian@0 173 *
ian@0 174 * We want to hold both the task-lock and the
ian@0 175 * tasklist_lock for writing at the same time.
ian@0 176 * But that's against the rules (tasklist_lock
ian@0 177 * is taken for reading by interrupts on other
ian@0 178 * cpu's that may have task_lock).
ian@0 179 */
ian@0 180 task_lock(task);
ian@0 181 local_irq_disable();
ian@0 182 if (!write_trylock(&tasklist_lock)) {
ian@0 183 local_irq_enable();
ian@0 184 task_unlock(task);
ian@0 185 do {
ian@0 186 cpu_relax();
ian@0 187 } while (!write_can_lock(&tasklist_lock));
ian@0 188 goto repeat;
ian@0 189 }
ian@0 190
ian@0 191 if (!task->mm)
ian@0 192 goto bad;
ian@0 193 /* the same process cannot be attached many times */
ian@0 194 if (task->ptrace & PT_PTRACED)
ian@0 195 goto bad;
ian@0 196 retval = may_attach(task);
ian@0 197 if (retval)
ian@0 198 goto bad;
ian@0 199
ian@0 200 /* Go */
ian@0 201 task->ptrace |= PT_PTRACED | ((task->real_parent != current)
ian@0 202 ? PT_ATTACHED : 0);
ian@0 203 if (capable(CAP_SYS_PTRACE))
ian@0 204 task->ptrace |= PT_PTRACE_CAP;
ian@0 205
ian@0 206 __ptrace_link(task, current);
ian@0 207
ian@0 208 force_sig_specific(SIGSTOP, task);
ian@0 209
ian@0 210 bad:
ian@0 211 write_unlock_irq(&tasklist_lock);
ian@0 212 task_unlock(task);
ian@0 213 out:
ian@0 214 return retval;
ian@0 215 }
ian@0 216
ian@0 217 static inline void __ptrace_detach(struct task_struct *child, unsigned int data)
ian@0 218 {
ian@0 219 child->exit_code = data;
ian@0 220 /* .. re-parent .. */
ian@0 221 __ptrace_unlink(child);
ian@0 222 /* .. and wake it up. */
ian@0 223 if (child->exit_state != EXIT_ZOMBIE)
ian@0 224 wake_up_process(child);
ian@0 225 }
ian@0 226
ian@0 227 int ptrace_detach(struct task_struct *child, unsigned int data)
ian@0 228 {
ian@0 229 if (!valid_signal(data))
ian@0 230 return -EIO;
ian@0 231
ian@0 232 /* Architecture-specific hardware disable .. */
ian@0 233 ptrace_disable(child);
ian@0 234
ian@0 235 write_lock_irq(&tasklist_lock);
ian@0 236 /* protect against de_thread()->release_task() */
ian@0 237 if (child->ptrace)
ian@0 238 __ptrace_detach(child, data);
ian@0 239 write_unlock_irq(&tasklist_lock);
ian@0 240
ian@0 241 return 0;
ian@0 242 }
ian@0 243
ian@0 244 /*
ian@0 245 * Access another process' address space.
ian@0 246 * Source/target buffer must be kernel space,
ian@0 247 * Do not walk the page table directly, use get_user_pages
ian@0 248 */
ian@0 249
ian@0 250 int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
ian@0 251 {
ian@0 252 struct mm_struct *mm;
ian@0 253 struct vm_area_struct *vma;
ian@0 254 struct page *page;
ian@0 255 void *old_buf = buf;
ian@0 256
ian@0 257 mm = get_task_mm(tsk);
ian@0 258 if (!mm)
ian@0 259 return 0;
ian@0 260
ian@0 261 down_read(&mm->mmap_sem);
ian@0 262 /* ignore errors, just check how much was sucessfully transfered */
ian@0 263 while (len) {
ian@0 264 int bytes, ret, offset;
ian@0 265 void *maddr;
ian@0 266
ian@0 267 ret = get_user_pages(tsk, mm, addr, 1,
ian@0 268 write, 1, &page, &vma);
ian@0 269 if (ret <= 0)
ian@0 270 break;
ian@0 271
ian@0 272 bytes = len;
ian@0 273 offset = addr & (PAGE_SIZE-1);
ian@0 274 if (bytes > PAGE_SIZE-offset)
ian@0 275 bytes = PAGE_SIZE-offset;
ian@0 276
ian@0 277 maddr = kmap(page);
ian@0 278 if (write) {
ian@0 279 copy_to_user_page(vma, page, addr,
ian@0 280 maddr + offset, buf, bytes);
ian@0 281 set_page_dirty_lock(page);
ian@0 282 } else {
ian@0 283 copy_from_user_page(vma, page, addr,
ian@0 284 buf, maddr + offset, bytes);
ian@0 285 }
ian@0 286 kunmap(page);
ian@0 287 page_cache_release(page);
ian@0 288 len -= bytes;
ian@0 289 buf += bytes;
ian@0 290 addr += bytes;
ian@0 291 }
ian@0 292 up_read(&mm->mmap_sem);
ian@0 293 mmput(mm);
ian@0 294
ian@0 295 return buf - old_buf;
ian@0 296 }
ian@0 297
ian@0 298 int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len)
ian@0 299 {
ian@0 300 int copied = 0;
ian@0 301
ian@0 302 while (len > 0) {
ian@0 303 char buf[128];
ian@0 304 int this_len, retval;
ian@0 305
ian@0 306 this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
ian@0 307 retval = access_process_vm(tsk, src, buf, this_len, 0);
ian@0 308 if (!retval) {
ian@0 309 if (copied)
ian@0 310 break;
ian@0 311 return -EIO;
ian@0 312 }
ian@0 313 if (copy_to_user(dst, buf, retval))
ian@0 314 return -EFAULT;
ian@0 315 copied += retval;
ian@0 316 src += retval;
ian@0 317 dst += retval;
ian@0 318 len -= retval;
ian@0 319 }
ian@0 320 return copied;
ian@0 321 }
ian@0 322
ian@0 323 int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len)
ian@0 324 {
ian@0 325 int copied = 0;
ian@0 326
ian@0 327 while (len > 0) {
ian@0 328 char buf[128];
ian@0 329 int this_len, retval;
ian@0 330
ian@0 331 this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
ian@0 332 if (copy_from_user(buf, src, this_len))
ian@0 333 return -EFAULT;
ian@0 334 retval = access_process_vm(tsk, dst, buf, this_len, 1);
ian@0 335 if (!retval) {
ian@0 336 if (copied)
ian@0 337 break;
ian@0 338 return -EIO;
ian@0 339 }
ian@0 340 copied += retval;
ian@0 341 src += retval;
ian@0 342 dst += retval;
ian@0 343 len -= retval;
ian@0 344 }
ian@0 345 return copied;
ian@0 346 }
ian@0 347
ian@0 348 static int ptrace_setoptions(struct task_struct *child, long data)
ian@0 349 {
ian@0 350 child->ptrace &= ~PT_TRACE_MASK;
ian@0 351
ian@0 352 if (data & PTRACE_O_TRACESYSGOOD)
ian@0 353 child->ptrace |= PT_TRACESYSGOOD;
ian@0 354
ian@0 355 if (data & PTRACE_O_TRACEFORK)
ian@0 356 child->ptrace |= PT_TRACE_FORK;
ian@0 357
ian@0 358 if (data & PTRACE_O_TRACEVFORK)
ian@0 359 child->ptrace |= PT_TRACE_VFORK;
ian@0 360
ian@0 361 if (data & PTRACE_O_TRACECLONE)
ian@0 362 child->ptrace |= PT_TRACE_CLONE;
ian@0 363
ian@0 364 if (data & PTRACE_O_TRACEEXEC)
ian@0 365 child->ptrace |= PT_TRACE_EXEC;
ian@0 366
ian@0 367 if (data & PTRACE_O_TRACEVFORKDONE)
ian@0 368 child->ptrace |= PT_TRACE_VFORK_DONE;
ian@0 369
ian@0 370 if (data & PTRACE_O_TRACEEXIT)
ian@0 371 child->ptrace |= PT_TRACE_EXIT;
ian@0 372
ian@0 373 return (data & ~PTRACE_O_MASK) ? -EINVAL : 0;
ian@0 374 }
ian@0 375
ian@0 376 static int ptrace_getsiginfo(struct task_struct *child, siginfo_t __user * data)
ian@0 377 {
ian@0 378 siginfo_t lastinfo;
ian@0 379 int error = -ESRCH;
ian@0 380
ian@0 381 read_lock(&tasklist_lock);
ian@0 382 if (likely(child->sighand != NULL)) {
ian@0 383 error = -EINVAL;
ian@0 384 spin_lock_irq(&child->sighand->siglock);
ian@0 385 if (likely(child->last_siginfo != NULL)) {
ian@0 386 lastinfo = *child->last_siginfo;
ian@0 387 error = 0;
ian@0 388 }
ian@0 389 spin_unlock_irq(&child->sighand->siglock);
ian@0 390 }
ian@0 391 read_unlock(&tasklist_lock);
ian@0 392 if (!error)
ian@0 393 return copy_siginfo_to_user(data, &lastinfo);
ian@0 394 return error;
ian@0 395 }
ian@0 396
ian@0 397 static int ptrace_setsiginfo(struct task_struct *child, siginfo_t __user * data)
ian@0 398 {
ian@0 399 siginfo_t newinfo;
ian@0 400 int error = -ESRCH;
ian@0 401
ian@0 402 if (copy_from_user(&newinfo, data, sizeof (siginfo_t)))
ian@0 403 return -EFAULT;
ian@0 404
ian@0 405 read_lock(&tasklist_lock);
ian@0 406 if (likely(child->sighand != NULL)) {
ian@0 407 error = -EINVAL;
ian@0 408 spin_lock_irq(&child->sighand->siglock);
ian@0 409 if (likely(child->last_siginfo != NULL)) {
ian@0 410 *child->last_siginfo = newinfo;
ian@0 411 error = 0;
ian@0 412 }
ian@0 413 spin_unlock_irq(&child->sighand->siglock);
ian@0 414 }
ian@0 415 read_unlock(&tasklist_lock);
ian@0 416 return error;
ian@0 417 }
ian@0 418
ian@0 419 int ptrace_request(struct task_struct *child, long request,
ian@0 420 long addr, long data)
ian@0 421 {
ian@0 422 int ret = -EIO;
ian@0 423
ian@0 424 switch (request) {
ian@0 425 #ifdef PTRACE_OLDSETOPTIONS
ian@0 426 case PTRACE_OLDSETOPTIONS:
ian@0 427 #endif
ian@0 428 case PTRACE_SETOPTIONS:
ian@0 429 ret = ptrace_setoptions(child, data);
ian@0 430 break;
ian@0 431 case PTRACE_GETEVENTMSG:
ian@0 432 ret = put_user(child->ptrace_message, (unsigned long __user *) data);
ian@0 433 break;
ian@0 434 case PTRACE_GETSIGINFO:
ian@0 435 ret = ptrace_getsiginfo(child, (siginfo_t __user *) data);
ian@0 436 break;
ian@0 437 case PTRACE_SETSIGINFO:
ian@0 438 ret = ptrace_setsiginfo(child, (siginfo_t __user *) data);
ian@0 439 break;
ian@0 440 default:
ian@0 441 break;
ian@0 442 }
ian@0 443
ian@0 444 return ret;
ian@0 445 }
ian@0 446
ian@0 447 /**
ian@0 448 * ptrace_traceme -- helper for PTRACE_TRACEME
ian@0 449 *
ian@0 450 * Performs checks and sets PT_PTRACED.
ian@0 451 * Should be used by all ptrace implementations for PTRACE_TRACEME.
ian@0 452 */
ian@0 453 int ptrace_traceme(void)
ian@0 454 {
ian@0 455 int ret = -EPERM;
ian@0 456
ian@0 457 /*
ian@0 458 * Are we already being traced?
ian@0 459 */
ian@0 460 task_lock(current);
ian@0 461 if (!(current->ptrace & PT_PTRACED)) {
ian@0 462 ret = security_ptrace(current->parent, current);
ian@0 463 /*
ian@0 464 * Set the ptrace bit in the process ptrace flags.
ian@0 465 */
ian@0 466 if (!ret)
ian@0 467 current->ptrace |= PT_PTRACED;
ian@0 468 }
ian@0 469 task_unlock(current);
ian@0 470 return ret;
ian@0 471 }
ian@0 472
ian@0 473 /**
ian@0 474 * ptrace_get_task_struct -- grab a task struct reference for ptrace
ian@0 475 * @pid: process id to grab a task_struct reference of
ian@0 476 *
ian@0 477 * This function is a helper for ptrace implementations. It checks
ian@0 478 * permissions and then grabs a task struct for use of the actual
ian@0 479 * ptrace implementation.
ian@0 480 *
ian@0 481 * Returns the task_struct for @pid or an ERR_PTR() on failure.
ian@0 482 */
ian@0 483 struct task_struct *ptrace_get_task_struct(pid_t pid)
ian@0 484 {
ian@0 485 struct task_struct *child;
ian@0 486
ian@0 487 /*
ian@0 488 * Tracing init is not allowed.
ian@0 489 */
ian@0 490 if (pid == 1)
ian@0 491 return ERR_PTR(-EPERM);
ian@0 492
ian@0 493 read_lock(&tasklist_lock);
ian@0 494 child = find_task_by_pid(pid);
ian@0 495 if (child)
ian@0 496 get_task_struct(child);
ian@0 497 read_unlock(&tasklist_lock);
ian@0 498 if (!child)
ian@0 499 return ERR_PTR(-ESRCH);
ian@0 500 return child;
ian@0 501 }
ian@0 502
ian@0 503 #ifndef __ARCH_SYS_PTRACE
ian@0 504 asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
ian@0 505 {
ian@0 506 struct task_struct *child;
ian@0 507 long ret;
ian@0 508
ian@0 509 /*
ian@0 510 * This lock_kernel fixes a subtle race with suid exec
ian@0 511 */
ian@0 512 lock_kernel();
ian@0 513 if (request == PTRACE_TRACEME) {
ian@0 514 ret = ptrace_traceme();
ian@0 515 goto out;
ian@0 516 }
ian@0 517
ian@0 518 child = ptrace_get_task_struct(pid);
ian@0 519 if (IS_ERR(child)) {
ian@0 520 ret = PTR_ERR(child);
ian@0 521 goto out;
ian@0 522 }
ian@0 523
ian@0 524 if (request == PTRACE_ATTACH) {
ian@0 525 ret = ptrace_attach(child);
ian@0 526 goto out_put_task_struct;
ian@0 527 }
ian@0 528
ian@0 529 ret = ptrace_check_attach(child, request == PTRACE_KILL);
ian@0 530 if (ret < 0)
ian@0 531 goto out_put_task_struct;
ian@0 532
ian@0 533 ret = arch_ptrace(child, request, addr, data);
ian@0 534 if (ret < 0)
ian@0 535 goto out_put_task_struct;
ian@0 536
ian@0 537 out_put_task_struct:
ian@0 538 put_task_struct(child);
ian@0 539 out:
ian@0 540 unlock_kernel();
ian@0 541 return ret;
ian@0 542 }
ian@0 543 #endif /* __ARCH_SYS_PTRACE */