aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc/base.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/proc/base.c')
-rw-r--r--fs/proc/base.c126
1 files changed, 46 insertions, 80 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 9cde9edf9c4..d4548dd49b0 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -198,26 +198,6 @@ static int proc_root_link(struct dentry *dentry, struct path *path)
198 return result; 198 return result;
199} 199}
200 200
201static struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
202{
203 struct mm_struct *mm;
204 int err;
205
206 err = mutex_lock_killable(&task->signal->cred_guard_mutex);
207 if (err)
208 return ERR_PTR(err);
209
210 mm = get_task_mm(task);
211 if (mm && mm != current->mm &&
212 !ptrace_may_access(task, mode)) {
213 mmput(mm);
214 mm = ERR_PTR(-EACCES);
215 }
216 mutex_unlock(&task->signal->cred_guard_mutex);
217
218 return mm;
219}
220
221struct mm_struct *mm_for_maps(struct task_struct *task) 201struct mm_struct *mm_for_maps(struct task_struct *task)
222{ 202{
223 return mm_access(task, PTRACE_MODE_READ); 203 return mm_access(task, PTRACE_MODE_READ);
@@ -711,6 +691,13 @@ static int mem_open(struct inode* inode, struct file* file)
711 if (IS_ERR(mm)) 691 if (IS_ERR(mm))
712 return PTR_ERR(mm); 692 return PTR_ERR(mm);
713 693
694 if (mm) {
695 /* ensure this mm_struct can't be freed */
696 atomic_inc(&mm->mm_count);
697 /* but do not pin its memory */
698 mmput(mm);
699 }
700
714 /* OK to pass negative loff_t, we can catch out-of-range */ 701 /* OK to pass negative loff_t, we can catch out-of-range */
715 file->f_mode |= FMODE_UNSIGNED_OFFSET; 702 file->f_mode |= FMODE_UNSIGNED_OFFSET;
716 file->private_data = mm; 703 file->private_data = mm;
@@ -718,57 +705,13 @@ static int mem_open(struct inode* inode, struct file* file)
718 return 0; 705 return 0;
719} 706}
720 707
721static ssize_t mem_read(struct file * file, char __user * buf, 708static ssize_t mem_rw(struct file *file, char __user *buf,
722 size_t count, loff_t *ppos) 709 size_t count, loff_t *ppos, int write)
723{ 710{
724 int ret;
725 char *page;
726 unsigned long src = *ppos;
727 struct mm_struct *mm = file->private_data; 711 struct mm_struct *mm = file->private_data;
728 712 unsigned long addr = *ppos;
729 if (!mm) 713 ssize_t copied;
730 return 0;
731
732 page = (char *)__get_free_page(GFP_TEMPORARY);
733 if (!page)
734 return -ENOMEM;
735
736 ret = 0;
737
738 while (count > 0) {
739 int this_len, retval;
740
741 this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
742 retval = access_remote_vm(mm, src, page, this_len, 0);
743 if (!retval) {
744 if (!ret)
745 ret = -EIO;
746 break;
747 }
748
749 if (copy_to_user(buf, page, retval)) {
750 ret = -EFAULT;
751 break;
752 }
753
754 ret += retval;
755 src += retval;
756 buf += retval;
757 count -= retval;
758 }
759 *ppos = src;
760
761 free_page((unsigned long) page);
762 return ret;
763}
764
765static ssize_t mem_write(struct file * file, const char __user *buf,
766 size_t count, loff_t *ppos)
767{
768 int copied;
769 char *page; 714 char *page;
770 unsigned long dst = *ppos;
771 struct mm_struct *mm = file->private_data;
772 715
773 if (!mm) 716 if (!mm)
774 return 0; 717 return 0;
@@ -778,31 +721,54 @@ static ssize_t mem_write(struct file * file, const char __user *buf,
778 return -ENOMEM; 721 return -ENOMEM;
779 722
780 copied = 0; 723 copied = 0;
724 if (!atomic_inc_not_zero(&mm->mm_users))
725 goto free;
726
781 while (count > 0) { 727 while (count > 0) {
782 int this_len, retval; 728 int this_len = min_t(int, count, PAGE_SIZE);
783 729
784 this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; 730 if (write && copy_from_user(page, buf, this_len)) {
785 if (copy_from_user(page, buf, this_len)) {
786 copied = -EFAULT; 731 copied = -EFAULT;
787 break; 732 break;
788 } 733 }
789 retval = access_remote_vm(mm, dst, page, this_len, 1); 734
790 if (!retval) { 735 this_len = access_remote_vm(mm, addr, page, this_len, write);
736 if (!this_len) {
791 if (!copied) 737 if (!copied)
792 copied = -EIO; 738 copied = -EIO;
793 break; 739 break;
794 } 740 }
795 copied += retval; 741
796 buf += retval; 742 if (!write && copy_to_user(buf, page, this_len)) {
797 dst += retval; 743 copied = -EFAULT;
798 count -= retval; 744 break;
745 }
746
747 buf += this_len;
748 addr += this_len;
749 copied += this_len;
750 count -= this_len;
799 } 751 }
800 *ppos = dst; 752 *ppos = addr;
801 753
754 mmput(mm);
755free:
802 free_page((unsigned long) page); 756 free_page((unsigned long) page);
803 return copied; 757 return copied;
804} 758}
805 759
760static ssize_t mem_read(struct file *file, char __user *buf,
761 size_t count, loff_t *ppos)
762{
763 return mem_rw(file, buf, count, ppos, 0);
764}
765
766static ssize_t mem_write(struct file *file, const char __user *buf,
767 size_t count, loff_t *ppos)
768{
769 return mem_rw(file, (char __user*)buf, count, ppos, 1);
770}
771
806loff_t mem_lseek(struct file *file, loff_t offset, int orig) 772loff_t mem_lseek(struct file *file, loff_t offset, int orig)
807{ 773{
808 switch (orig) { 774 switch (orig) {
@@ -822,8 +788,8 @@ loff_t mem_lseek(struct file *file, loff_t offset, int orig)
822static int mem_release(struct inode *inode, struct file *file) 788static int mem_release(struct inode *inode, struct file *file)
823{ 789{
824 struct mm_struct *mm = file->private_data; 790 struct mm_struct *mm = file->private_data;
825 791 if (mm)
826 mmput(mm); 792 mmdrop(mm);
827 return 0; 793 return 0;
828} 794}
829 795