proc: maps protection
[deliverable/linux.git] / fs / proc / base.c
index 989af5e55d1bec761b8a2604d6e8528713d7d8da..17f7a7ee6c5e14aa00e2b9b8a999a8cfa89d21d9 100644 (file)
@@ -64,6 +64,7 @@
 #include <linux/smp_lock.h>
 #include <linux/rcupdate.h>
 #include <linux/kallsyms.h>
+#include <linux/module.h>
 #include <linux/mount.h>
 #include <linux/security.h>
 #include <linux/ptrace.h>
@@ -123,6 +124,9 @@ struct pid_entry {
                NULL, &proc_info_file_operations,       \
                { .proc_read = &proc_##OTYPE } )
 
+int maps_protect;
+EXPORT_SYMBOL(maps_protect);
+
 static struct fs_struct *get_fs_struct(struct task_struct *task)
 {
        struct fs_struct *fs;
@@ -715,6 +719,40 @@ static const struct file_operations proc_oom_adjust_operations = {
        .write          = oom_adjust_write,
 };
 
+static ssize_t clear_refs_write(struct file *file, const char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       struct task_struct *task;
+       char buffer[PROC_NUMBUF], *end;
+       struct mm_struct *mm;
+
+       memset(buffer, 0, sizeof(buffer));
+       if (count > sizeof(buffer) - 1)
+               count = sizeof(buffer) - 1;
+       if (copy_from_user(buffer, buf, count))
+               return -EFAULT;
+       if (!simple_strtol(buffer, &end, 0))
+               return -EINVAL;
+       if (*end == '\n')
+               end++;
+       task = get_proc_task(file->f_path.dentry->d_inode);
+       if (!task)
+               return -ESRCH;
+       mm = get_task_mm(task);
+       if (mm) {
+               clear_refs_smap(mm);
+               mmput(mm);
+       }
+       put_task_struct(task);
+       if (end - buffer == 0)
+               return -EIO;
+       return end - buffer;
+}
+
+static struct file_operations proc_clear_refs_operations = {
+       .write          = clear_refs_write,
+};
+
 #ifdef CONFIG_AUDITSYSCALL
 #define TMPBUFLEN 21
 static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
@@ -1413,11 +1451,29 @@ static const struct file_operations proc_fd_operations = {
        .readdir        = proc_readfd,
 };
 
+/*
+ * /proc/pid/fd needs a special permission handler so that a process can still
+ * access /proc/self/fd after it has executed a setuid().
+ */
+static int proc_fd_permission(struct inode *inode, int mask,
+                               struct nameidata *nd)
+{
+       int rv;
+
+       rv = generic_permission(inode, mask, NULL);
+       if (rv == 0)
+               return 0;
+       if (task_pid(current) == proc_pid(inode))
+               rv = 0;
+       return rv;
+}
+
 /*
  * proc directories can do almost nothing..
  */
 static const struct inode_operations proc_fd_inode_operations = {
        .lookup         = proc_lookupfd,
+       .permission     = proc_fd_permission,
        .setattr        = proc_setattr,
 };
 
@@ -1851,6 +1907,7 @@ static struct pid_entry tgid_base_stuff[] = {
        REG("mounts",     S_IRUGO, mounts),
        REG("mountstats", S_IRUSR, mountstats),
 #ifdef CONFIG_MMU
+       REG("clear_refs", S_IWUSR, clear_refs),
        REG("smaps",      S_IRUGO, smaps),
 #endif
 #ifdef CONFIG_SECURITY
@@ -2132,6 +2189,7 @@ static struct pid_entry tid_base_stuff[] = {
        LNK("exe",       exe),
        REG("mounts",    S_IRUGO, mounts),
 #ifdef CONFIG_MMU
+       REG("clear_refs", S_IWUSR, clear_refs),
        REG("smaps",     S_IRUGO, smaps),
 #endif
 #ifdef CONFIG_SECURITY
This page took 0.028438 seconds and 5 git commands to generate.