aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel
diff options
context:
space:
mode:
authorMarkus Metzger <markus.t.metzger@intel.com>2008-01-30 07:32:03 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:32:03 -0500
commitda35c37198132abebf877cca2ad3c6d9bcd84282 (patch)
treee0983427408996313fd32673251cdc49e5c09637 /arch/x86/kernel
parent59e87cdcd268daa85c0732e147c59e0c1bacd704 (diff)
x86, ptrace: rlimit BTS buffer allocation
Check the rlimit of the tracing task for total and locked memory when allocating the BTS buffer. Signed-off-by: Markus Metzger <markus.t.metzger@intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r--arch/x86/kernel/ptrace.c149
1 files changed, 103 insertions, 46 deletions
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 3e34b14e8846..88ed1e74cee9 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -620,12 +620,80 @@ static int ptrace_bts_drain(struct task_struct *child,
620 return i; 620 return i;
621} 621}
622 622
623static int ptrace_bts_realloc(struct task_struct *child,
624 int size, int reduce_size)
625{
626 unsigned long rlim, vm;
627 int ret, old_size;
628
629 if (size < 0)
630 return -EINVAL;
631
632 old_size = ds_get_bts_size((void *)child->thread.ds_area_msr);
633 if (old_size < 0)
634 return old_size;
635
636 ret = ds_free((void **)&child->thread.ds_area_msr);
637 if (ret < 0)
638 goto out;
639
640 size >>= PAGE_SHIFT;
641 old_size >>= PAGE_SHIFT;
642
643 current->mm->total_vm -= old_size;
644 current->mm->locked_vm -= old_size;
645
646 if (size == 0)
647 goto out;
648
649 rlim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT;
650 vm = current->mm->total_vm + size;
651 if (rlim < vm) {
652 ret = -ENOMEM;
653
654 if (!reduce_size)
655 goto out;
656
657 size = rlim - current->mm->total_vm;
658 if (size <= 0)
659 goto out;
660 }
661
662 rlim = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
663 vm = current->mm->locked_vm + size;
664 if (rlim < vm) {
665 ret = -ENOMEM;
666
667 if (!reduce_size)
668 goto out;
669
670 size = rlim - current->mm->locked_vm;
671 if (size <= 0)
672 goto out;
673 }
674
675 ret = ds_allocate((void **)&child->thread.ds_area_msr,
676 size << PAGE_SHIFT);
677 if (ret < 0)
678 goto out;
679
680 current->mm->total_vm += size;
681 current->mm->locked_vm += size;
682
683out:
684 if (child->thread.ds_area_msr)
685 set_tsk_thread_flag(child, TIF_DS_AREA_MSR);
686 else
687 clear_tsk_thread_flag(child, TIF_DS_AREA_MSR);
688
689 return ret;
690}
691
623static int ptrace_bts_config(struct task_struct *child, 692static int ptrace_bts_config(struct task_struct *child,
624 const struct ptrace_bts_config __user *ucfg) 693 const struct ptrace_bts_config __user *ucfg)
625{ 694{
626 struct ptrace_bts_config cfg; 695 struct ptrace_bts_config cfg;
627 unsigned long debugctl_mask; 696 int bts_size, ret = 0;
628 int bts_size, ret;
629 void *ds; 697 void *ds;
630 698
631 if (copy_from_user(&cfg, ucfg, sizeof(cfg))) 699 if (copy_from_user(&cfg, ucfg, sizeof(cfg)))
@@ -638,59 +706,46 @@ static int ptrace_bts_config(struct task_struct *child,
638 if (bts_size < 0) 706 if (bts_size < 0)
639 return bts_size; 707 return bts_size;
640 } 708 }
709 cfg.size = PAGE_ALIGN(cfg.size);
641 710
642 if (bts_size != cfg.size) { 711 if (bts_size != cfg.size) {
643 ret = ds_free((void **)&child->thread.ds_area_msr); 712 ret = ptrace_bts_realloc(child, cfg.size,
713 cfg.flags & PTRACE_BTS_O_CUT_SIZE);
644 if (ret < 0) 714 if (ret < 0)
645 return ret; 715 goto errout;
646 716
647 if (cfg.size > 0)
648 ret = ds_allocate((void **)&child->thread.ds_area_msr,
649 cfg.size);
650 ds = (void *)child->thread.ds_area_msr; 717 ds = (void *)child->thread.ds_area_msr;
651 if (ds)
652 set_tsk_thread_flag(child, TIF_DS_AREA_MSR);
653 else
654 clear_tsk_thread_flag(child, TIF_DS_AREA_MSR);
655
656 if (ret < 0)
657 return ret;
658
659 bts_size = ds_get_bts_size(ds);
660 if (bts_size <= 0)
661 return bts_size;
662 } 718 }
663 719
664 if (ds) { 720 if (cfg.flags & PTRACE_BTS_O_SIGNAL)
665 if (cfg.flags & PTRACE_BTS_O_SIGNAL) { 721 ret = ds_set_overflow(ds, DS_O_SIGNAL);
666 ret = ds_set_overflow(ds, DS_O_SIGNAL); 722 else
667 } else { 723 ret = ds_set_overflow(ds, DS_O_WRAP);
668 ret = ds_set_overflow(ds, DS_O_WRAP); 724 if (ret < 0)
669 } 725 goto errout;
670 if (ret < 0)
671 return ret;
672 }
673
674 debugctl_mask = ds_debugctl_mask();
675 if (ds && (cfg.flags & PTRACE_BTS_O_TRACE)) {
676 child->thread.debugctlmsr |= debugctl_mask;
677 set_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
678 } else {
679 /* there is no way for us to check whether we 'own'
680 * the respective bits in the DEBUGCTL MSR, we're
681 * about to clear */
682 child->thread.debugctlmsr &= ~debugctl_mask;
683 726
684 if (!child->thread.debugctlmsr) 727 if (cfg.flags & PTRACE_BTS_O_TRACE)
685 clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR); 728 child->thread.debugctlmsr |= ds_debugctl_mask();
686 } 729 else
730 child->thread.debugctlmsr &= ~ds_debugctl_mask();
687 731
688 if (ds && (cfg.flags & PTRACE_BTS_O_SCHED)) 732 if (cfg.flags & PTRACE_BTS_O_SCHED)
689 set_tsk_thread_flag(child, TIF_BTS_TRACE_TS); 733 set_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
690 else 734 else
691 clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS); 735 clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
692 736
693 return 0; 737out:
738 if (child->thread.debugctlmsr)
739 set_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
740 else
741 clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
742
743 return ret;
744
745errout:
746 child->thread.debugctlmsr &= ~ds_debugctl_mask();
747 clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
748 goto out;
694} 749}
695 750
696static int ptrace_bts_status(struct task_struct *child, 751static int ptrace_bts_status(struct task_struct *child,
@@ -726,7 +781,7 @@ void ptrace_bts_take_timestamp(struct task_struct *tsk,
726{ 781{
727 struct bts_struct rec = { 782 struct bts_struct rec = {
728 .qualifier = qualifier, 783 .qualifier = qualifier,
729 .variant.jiffies = jiffies 784 .variant.jiffies = jiffies_64
730 }; 785 };
731 786
732 ptrace_bts_write_record(tsk, &rec); 787 ptrace_bts_write_record(tsk, &rec);
@@ -743,10 +798,12 @@ void ptrace_disable(struct task_struct *child)
743#ifdef TIF_SYSCALL_EMU 798#ifdef TIF_SYSCALL_EMU
744 clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); 799 clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
745#endif 800#endif
746 ptrace_bts_config(child, /* options = */ 0);
747 if (child->thread.ds_area_msr) { 801 if (child->thread.ds_area_msr) {
748 ds_free((void **)&child->thread.ds_area_msr); 802 ptrace_bts_realloc(child, 0, 0);
749 clear_tsk_thread_flag(child, TIF_DS_AREA_MSR); 803 child->thread.debugctlmsr &= ~ds_debugctl_mask();
804 if (!child->thread.debugctlmsr)
805 clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
806 clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
750 } 807 }
751} 808}
752 809