diff options
author | Markus Metzger <markus.t.metzger@intel.com> | 2008-01-30 07:32:03 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-01-30 07:32:03 -0500 |
commit | da35c37198132abebf877cca2ad3c6d9bcd84282 (patch) | |
tree | e0983427408996313fd32673251cdc49e5c09637 /arch/x86/kernel | |
parent | 59e87cdcd268daa85c0732e147c59e0c1bacd704 (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.c | 149 |
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 | ||
623 | static 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 | |||
683 | out: | ||
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 | |||
623 | static int ptrace_bts_config(struct task_struct *child, | 692 | static 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; | 737 | out: |
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 | |||
745 | errout: | ||
746 | child->thread.debugctlmsr &= ~ds_debugctl_mask(); | ||
747 | clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS); | ||
748 | goto out; | ||
694 | } | 749 | } |
695 | 750 | ||
696 | static int ptrace_bts_status(struct task_struct *child, | 751 | static 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 | ||