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.c114
1 files changed, 105 insertions, 9 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index c5e412a00b17..808cbdc193d3 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -56,6 +56,7 @@
56#include <linux/init.h> 56#include <linux/init.h>
57#include <linux/capability.h> 57#include <linux/capability.h>
58#include <linux/file.h> 58#include <linux/file.h>
59#include <linux/fdtable.h>
59#include <linux/string.h> 60#include <linux/string.h>
60#include <linux/seq_file.h> 61#include <linux/seq_file.h>
61#include <linux/namei.h> 62#include <linux/namei.h>
@@ -195,12 +196,32 @@ static int proc_root_link(struct inode *inode, struct path *path)
195 return result; 196 return result;
196} 197}
197 198
198#define MAY_PTRACE(task) \ 199/*
199 (task == current || \ 200 * Return zero if current may access user memory in @task, -error if not.
200 (task->parent == current && \ 201 */
201 (task->ptrace & PT_PTRACED) && \ 202static int check_mem_permission(struct task_struct *task)
202 (task_is_stopped_or_traced(task)) && \ 203{
203 security_ptrace(current,task) == 0)) 204 /*
205 * A task can always look at itself, in case it chooses
206 * to use system calls instead of load instructions.
207 */
208 if (task == current)
209 return 0;
210
211 /*
212 * If current is actively ptrace'ing, and would also be
213 * permitted to freshly attach with ptrace now, permit it.
214 */
215 if (task->parent == current && (task->ptrace & PT_PTRACED) &&
216 task_is_stopped_or_traced(task) &&
217 ptrace_may_attach(task))
218 return 0;
219
220 /*
221 * Noone else is allowed.
222 */
223 return -EPERM;
224}
204 225
205struct mm_struct *mm_for_maps(struct task_struct *task) 226struct mm_struct *mm_for_maps(struct task_struct *task)
206{ 227{
@@ -722,7 +743,7 @@ static ssize_t mem_read(struct file * file, char __user * buf,
722 if (!task) 743 if (!task)
723 goto out_no_task; 744 goto out_no_task;
724 745
725 if (!MAY_PTRACE(task) || !ptrace_may_attach(task)) 746 if (check_mem_permission(task))
726 goto out; 747 goto out;
727 748
728 ret = -ENOMEM; 749 ret = -ENOMEM;
@@ -748,7 +769,7 @@ static ssize_t mem_read(struct file * file, char __user * buf,
748 769
749 this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; 770 this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
750 retval = access_process_vm(task, src, page, this_len, 0); 771 retval = access_process_vm(task, src, page, this_len, 0);
751 if (!retval || !MAY_PTRACE(task) || !ptrace_may_attach(task)) { 772 if (!retval || check_mem_permission(task)) {
752 if (!ret) 773 if (!ret)
753 ret = -EIO; 774 ret = -EIO;
754 break; 775 break;
@@ -792,7 +813,7 @@ static ssize_t mem_write(struct file * file, const char __user *buf,
792 if (!task) 813 if (!task)
793 goto out_no_task; 814 goto out_no_task;
794 815
795 if (!MAY_PTRACE(task) || !ptrace_may_attach(task)) 816 if (check_mem_permission(task))
796 goto out; 817 goto out;
797 818
798 copied = -ENOMEM; 819 copied = -ENOMEM;
@@ -1181,6 +1202,81 @@ static const struct file_operations proc_pid_sched_operations = {
1181 1202
1182#endif 1203#endif
1183 1204
1205/*
1206 * We added or removed a vma mapping the executable. The vmas are only mapped
1207 * during exec and are not mapped with the mmap system call.
1208 * Callers must hold down_write() on the mm's mmap_sem for these
1209 */
1210void added_exe_file_vma(struct mm_struct *mm)
1211{
1212 mm->num_exe_file_vmas++;
1213}
1214
1215void removed_exe_file_vma(struct mm_struct *mm)
1216{
1217 mm->num_exe_file_vmas--;
1218 if ((mm->num_exe_file_vmas == 0) && mm->exe_file){
1219 fput(mm->exe_file);
1220 mm->exe_file = NULL;
1221 }
1222
1223}
1224
1225void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file)
1226{
1227 if (new_exe_file)
1228 get_file(new_exe_file);
1229 if (mm->exe_file)
1230 fput(mm->exe_file);
1231 mm->exe_file = new_exe_file;
1232 mm->num_exe_file_vmas = 0;
1233}
1234
1235struct file *get_mm_exe_file(struct mm_struct *mm)
1236{
1237 struct file *exe_file;
1238
1239 /* We need mmap_sem to protect against races with removal of
1240 * VM_EXECUTABLE vmas */
1241 down_read(&mm->mmap_sem);
1242 exe_file = mm->exe_file;
1243 if (exe_file)
1244 get_file(exe_file);
1245 up_read(&mm->mmap_sem);
1246 return exe_file;
1247}
1248
1249void dup_mm_exe_file(struct mm_struct *oldmm, struct mm_struct *newmm)
1250{
1251 /* It's safe to write the exe_file pointer without exe_file_lock because
1252 * this is called during fork when the task is not yet in /proc */
1253 newmm->exe_file = get_mm_exe_file(oldmm);
1254}
1255
1256static int proc_exe_link(struct inode *inode, struct path *exe_path)
1257{
1258 struct task_struct *task;
1259 struct mm_struct *mm;
1260 struct file *exe_file;
1261
1262 task = get_proc_task(inode);
1263 if (!task)
1264 return -ENOENT;
1265 mm = get_task_mm(task);
1266 put_task_struct(task);
1267 if (!mm)
1268 return -ENOENT;
1269 exe_file = get_mm_exe_file(mm);
1270 mmput(mm);
1271 if (exe_file) {
1272 *exe_path = exe_file->f_path;
1273 path_get(&exe_file->f_path);
1274 fput(exe_file);
1275 return 0;
1276 } else
1277 return -ENOENT;
1278}
1279
1184static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) 1280static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
1185{ 1281{
1186 struct inode *inode = dentry->d_inode; 1282 struct inode *inode = dentry->d_inode;