source: trunk/src/samhain_kmem.c @ 346

Last change on this file since 346 was 346, checked in by katerina, 10 years ago

Fixes for ticket #254: kernel check not working on Ubuntu 8.04 x86_64

File size: 15.3 KB
Line 
1/* Most of this code is ripped from the Linux kernel:
2 *
3 *  linux/drivers/char/mem.c
4 *
5 *  Copyright (C) 1991, 1992  Linus Torvalds
6 *
7 *  Added devfs support.
8 *    Jan-11-1998, C. Scott Ananian <cananian@alumni.princeton.edu>
9 *  Shared /dev/zero mmaping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com>
10 */
11
12#include "config.h"
13
14#undef _
15#define _(string) string
16
17#include <linux/version.h>
18#include <linux/module.h>
19#include <linux/kernel.h>
20#include <linux/proc_fs.h>
21#include <linux/string.h>
22#include <linux/vmalloc.h>
23#include <linux/mm.h>
24#include <linux/miscdevice.h>
25#include <linux/slab.h>
26#include <linux/vmalloc.h>
27#include <linux/mman.h>
28#include <linux/random.h>
29#include <linux/init.h>
30#include <linux/raw.h>
31#include <linux/tty.h>
32#include <linux/capability.h>
33#include <linux/ptrace.h>
34#include <linux/device.h>
35#include <linux/highmem.h>
36#include <linux/crash_dump.h>
37#include <linux/backing-dev.h>
38#include <linux/bootmem.h>
39#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22)
40#include <linux/splice.h>
41#endif
42#include <linux/pfn.h>
43
44#include <asm/uaccess.h>
45#include <asm/io.h>
46#include <asm/pgtable.h>
47
48#ifdef CONFIG_IA64
49# include <linux/efi.h>
50#endif
51
52MODULE_LICENSE("GPL");
53MODULE_DESCRIPTION("samhain_kmem Kernel Module");
54MODULE_AUTHOR("Rainer Wichmann");
55
56static int debug = 0;
57#ifdef MODULE_PARM
58MODULE_PARM (debug, "i");
59#else
60module_param(debug, int, 0444);
61#endif
62
63#ifdef MODULE_PARM_DESC
64MODULE_PARM_DESC(debug, "Set to a non-zero value for debugging.");
65#endif
66
67/* struct task_struct
68 */
69#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
70#define TASK_EUID euid
71#else
72#define TASK_EUID cred->euid
73#endif
74
75static struct proc_dir_entry *proc_entry;
76
77/*
78 * Architectures vary in how they handle caching for addresses
79 * outside of main memory.
80 *
81 */
82static inline int uncached_access(struct file *file, unsigned long addr)
83{
84#if defined(__i386__) && !defined(__arch_um__)
85  /*
86   * On the PPro and successors, the MTRRs are used to set
87   * memory types for physical addresses outside main memory,
88   * so blindly setting PCD or PWT on those pages is wrong.
89   * For Pentiums and earlier, the surround logic should disable
90   * caching for the high addresses through the KEN pin, but
91   * we maintain the tradition of paranoia in this code.
92   */
93  if (file->f_flags & O_SYNC)
94    return 1;
95  return !( test_bit(X86_FEATURE_MTRR, (const void *) boot_cpu_data.x86_capability) ||
96            test_bit(X86_FEATURE_K6_MTRR, (const void *) boot_cpu_data.x86_capability) ||
97            test_bit(X86_FEATURE_CYRIX_ARR, (const void *) boot_cpu_data.x86_capability) ||
98            test_bit(X86_FEATURE_CENTAUR_MCR, (const void *) boot_cpu_data.x86_capability) )
99    && addr >= __pa(high_memory);
100#elif defined(__x86_64__) && !defined(__arch_um__)
101  /*
102   * This is broken because it can generate memory type aliases,
103   * which can cause cache corruptions
104   * But it is only available for root and we have to be bug-to-bug
105   * compatible with i386.
106   */
107  if (file->f_flags & O_SYNC)
108    return 1;
109  /* same behaviour as i386. PAT always set to cached and MTRRs control the
110     caching behaviour.
111     Hopefully a full PAT implementation will fix that soon. */     
112  return 0;
113#elif defined(CONFIG_IA64)
114  /*
115   * On ia64, we ignore O_SYNC because we cannot tolerate
116   * memory attribute aliases.
117   */
118  return !(efi_mem_attributes(addr) & EFI_MEMORY_WB);
119#elif defined(CONFIG_MIPS)
120  {
121    extern int __uncached_access(struct file *file,
122                                 unsigned long addr);
123   
124    return __uncached_access(file, addr);
125  }
126#else
127  /*
128   * Accessing memory above the top the kernel knows about
129   * or through a file pointer
130   * that was marked O_SYNC will be done non-cached.
131   */
132  if (file->f_flags & O_SYNC)
133    return 1;
134  return addr >= __pa(high_memory);
135#endif
136}
137
138#ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE
139static inline int valid_phys_addr_range(unsigned long addr, size_t count)
140{
141  if (addr + count > __pa(high_memory))
142    return 0;
143 
144  return 1;
145}
146
147static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
148{
149  return 1;
150}
151#endif
152
153
154/* #ifndef __HAVE_PHYS_MEM_ACCESS_PROT */
155static pgprot_t my_phys_mem_access_prot(struct file *file, unsigned long pfn,
156                                     unsigned long size, pgprot_t vma_prot)
157{
158#ifdef pgprot_noncached
159  unsigned long offset = pfn << PAGE_SHIFT;
160 
161  if (uncached_access(file, offset))
162    return pgprot_noncached(vma_prot);
163#else
164#error pgtable
165#endif
166  return vma_prot;
167}
168/* #endif */
169
170
171#ifndef CONFIG_MMU
172static unsigned long get_unmapped_area_mem(struct file *file,
173                                           unsigned long addr,
174                                           unsigned long len,
175                                           unsigned long pgoff,
176                                           unsigned long flags)
177{
178  if (!valid_mmap_phys_addr_range(pgoff, len))
179    return (unsigned long) -EINVAL;
180  return pgoff << PAGE_SHIFT;
181}
182
183/* can't do an in-place private mapping if there's no MMU */
184static inline int private_mapping_ok(struct vm_area_struct *vma)
185{
186  return vma->vm_flags & VM_MAYSHARE;
187}
188#else
189#define get_unmapped_area_mem   NULL
190
191static inline int private_mapping_ok(struct vm_area_struct *vma)
192{
193  return 1;
194}
195#endif
196
197static int mmap_mem(struct file * file, struct vm_area_struct * vma)
198{
199  size_t size = vma->vm_end - vma->vm_start;
200 
201  if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))
202    return -EINVAL;
203 
204  if (!private_mapping_ok(vma))
205    return -ENOSYS;
206 
207  vma->vm_page_prot = my_phys_mem_access_prot(file, vma->vm_pgoff,
208                                              size,
209                                              vma->vm_page_prot);
210 
211  /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */
212  if (remap_pfn_range(vma,
213                      vma->vm_start,
214                      vma->vm_pgoff,
215                      size,
216                      vma->vm_page_prot))
217    return -EAGAIN;
218  return 0;
219}
220
221static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
222{
223  unsigned long pfn;
224 
225  /* Turn a kernel-virtual address into a physical page frame */
226  pfn = __pa((u64)vma->vm_pgoff << PAGE_SHIFT) >> PAGE_SHIFT;
227 
228  /*
229   * RED-PEN: on some architectures there is more mapped memory
230   * than available in mem_map which pfn_valid checks
231   * for. Perhaps should add a new macro here.
232   *
233   * RED-PEN: vmalloc is not supported right now.
234   */
235  if (!pfn_valid(pfn))
236    return -EIO;
237 
238  vma->vm_pgoff = pfn;
239  return mmap_mem(file, vma);
240}
241
242static int my_permission(struct inode *inode, int op)
243{
244  /*
245   * only root (uid 0) may read from it
246   */
247  if (debug)
248    {
249      printk(KERN_INFO "samhain_kmem: permission op = %d, current->euid = %d\n", 
250             op, (int)current->TASK_EUID );
251    }
252
253  if ((op & 4) != 0 && (op & 2) == 0 && current->TASK_EUID == 0)
254    {
255      if (debug)
256        {
257          printk(KERN_INFO "samhain_kmem: access granted\n" );
258        }
259      return 0;
260    }
261 
262  /*
263   * If it's anything else, access is denied
264   */
265  if ((op & 2) != 0)
266    {
267      printk(KERN_INFO "/proc/kmem: access denied, "
268             "permission op = %d, current->euid = %d\n", 
269             op, (int)current->TASK_EUID );
270    }
271  else if (debug)
272    {
273      printk(KERN_INFO "samhain_kmem: access denied\n" );
274    }
275  return -EACCES;
276}
277
278static struct inode_operations Inode_Ops_Kmem = {
279  .permission = my_permission,  /* check for permissions */
280};
281
282static int open_kmem(struct inode * inode, struct file * filp)
283{
284  int ret = capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
285
286  if (debug)
287    {
288      printk(KERN_INFO "samhain_kmem: open_kmem retval = %d\n", ret);
289    }
290
291  if (ret == 0)
292    try_module_get(THIS_MODULE);
293
294  if (debug)
295    {
296      printk(KERN_INFO "samhain_kmem: open_kmem return\n");
297    }
298
299  return ret;
300}
301
302static int close_kmem(struct inode *inode, struct file *file)
303{
304  if (debug)
305    {
306      printk(KERN_INFO "samhain_kmem: close_kmem enter\n");
307    }
308
309  module_put(THIS_MODULE);
310
311  if (debug)
312    {
313      printk(KERN_INFO "samhain_kmem: close_kmem return\n");
314    }
315
316  return 0;             /* success */
317}
318
319/*********************************************************************
320 *
321 *   >>>  Required info from System.map: vmlist_lock, vmlist  <<<
322 */
323static rwlock_t * sh_vmlist_lock_ptr = (rwlock_t *) SH_VMLIST_LOCK;
324
325static struct vm_struct * sh_vmlist   = (struct vm_struct *) SH_VMLIST;
326/*
327 *
328 *********************************************************************/
329
330static long my_vread(char *buf, char *addr, unsigned long count)
331{
332        struct vm_struct *tmp;
333        char *vaddr, *buf_start = buf;
334        unsigned long n;
335
336        /* Don't allow overflow */
337        if ((unsigned long) addr + count < count)
338                count = -(unsigned long) addr;
339
340        read_lock(sh_vmlist_lock_ptr);
341        for (tmp = sh_vmlist; tmp; tmp = tmp->next) {
342                vaddr = (char *) tmp->addr;
343                if (addr >= vaddr + tmp->size - PAGE_SIZE)
344                        continue;
345                while (addr < vaddr) {
346                        if (count == 0)
347                                goto finished;
348                        *buf = '\0';
349                        buf++;
350                        addr++;
351                        count--;
352                }
353                n = vaddr + tmp->size - PAGE_SIZE - addr;
354                do {
355                        if (count == 0)
356                                goto finished;
357                        *buf = *addr;
358                        buf++;
359                        addr++;
360                        count--;
361                } while (--n > 0);
362        }
363finished:
364        read_unlock(sh_vmlist_lock_ptr);
365        if (debug)
366          {
367            printk(KERN_INFO "samhain_kmem:  start %lu\n", (unsigned long) buf_start);
368            printk(KERN_INFO "samhain_kmem:  end   %lu\n", (unsigned long) buf);
369            printk(KERN_INFO "samhain_kmem:  size  %lu\n", (unsigned long) (buf - buf_start));
370          }
371        return buf - buf_start;
372}
373
374static ssize_t read_kmem(struct file *file, char __user *buf, 
375                         size_t count, loff_t *ppos)
376{
377  unsigned long p = *ppos;
378  ssize_t low_count, read, sz;
379  char * kbuf; /* k-addr because vread() takes vmlist_lock rwlock */
380 
381  if (debug) {
382    printk(KERN_INFO "samhain_kmem: read_kmem entry\n");
383    printk(KERN_INFO "samhain_kmem:  p    %lu\n", (unsigned long) p);
384    printk(KERN_INFO "samhain_kmem:  high %lu\n", (unsigned long) high_memory);
385  }
386 
387  read = 0;
388  if (p < (unsigned long) high_memory) {
389    low_count = count;
390
391    if (debug) {
392      printk(KERN_INFO "samhain_kmem:  low_count(1)  %ld\n", (long) low_count);
393    }
394
395    if (count > (unsigned long) high_memory - p)
396      low_count = (unsigned long) high_memory - p;
397   
398    if (debug) {
399      printk(KERN_INFO "samhain_kmem:  low_count(2)  %ld\n", (long) low_count);
400    }
401
402#ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED
403    /* we don't have page 0 mapped on sparc and m68k.. */
404    if (p < PAGE_SIZE && low_count > 0) {
405      size_t tmp = PAGE_SIZE - p;
406      if (tmp > low_count) tmp = low_count;
407      if (clear_user(buf, tmp))
408        {
409          if (debug) {
410            printk(KERN_INFO "samhain_kmem: Bad address, line %d\n", __LINE__);
411          }
412          return -EFAULT;
413        }
414      buf += tmp;
415      p += tmp;
416      read += tmp;
417      low_count -= tmp;
418      count -= tmp;
419    }
420#endif
421
422    if (debug) {
423      printk(KERN_INFO "samhain_kmem:  low_count(3)  %ld\n", (long) low_count);
424    }
425
426    while (low_count > 0) {
427      /*
428       * Handle first page in case it's not aligned
429       */
430      if (-p & (PAGE_SIZE - 1))
431        sz = -p & (PAGE_SIZE - 1);
432      else
433        sz = PAGE_SIZE;
434     
435      sz = min_t(unsigned long, sz, low_count);
436     
437      /*
438       * On ia64 if a page has been mapped somewhere as
439       * uncached, then it must also be accessed uncached
440       * by the kernel or data corruption may occur
441       */
442      kbuf = xlate_dev_kmem_ptr((char *)p);
443     
444      if (copy_to_user(buf, kbuf, sz))
445        {
446          if (debug) {
447            printk(KERN_INFO "samhain_kmem: Bad address, line %d\n", __LINE__);
448            printk(KERN_INFO "samhain_kmem:  size %ld\n", (long) sz);
449            printk(KERN_INFO "samhain_kmem:  kbuf %p\n", kbuf);
450            printk(KERN_INFO "samhain_kmem:  buf  %p\n", buf);
451            printk(KERN_INFO "samhain_kmem:  high %lu\n", (unsigned long) high_memory);
452          }
453          return -EFAULT;
454        }
455      buf += sz;
456      p += sz;
457      read += sz;
458      low_count -= sz;
459      count -= sz;
460      if (debug) {
461        printk(KERN_INFO "samhain_kmem:  low_count(4)  %ld\n", (long) low_count);
462      }
463    }
464  }
465
466  if (debug) {
467    printk(KERN_INFO "samhain_kmem: read_kmem mid\n");
468    printk(KERN_INFO "samhain_kmem:  count  %lu\n", (unsigned long) count);
469  }
470
471  if (count > 0) {
472    kbuf = (char *)__get_free_page(GFP_KERNEL);
473    if (!kbuf)
474      {
475        if (debug) {
476          printk(KERN_INFO "samhain_kmem: out of memory\n");
477        }
478        return -ENOMEM;
479      }
480    while (count > 0) {
481      int len = count;
482     
483      if (len > PAGE_SIZE)
484        len = PAGE_SIZE;
485      len = my_vread(kbuf, (char *)p, len);
486      if (!len)
487        break;
488      if (copy_to_user(buf, kbuf, len)) {
489        if (debug) {
490          printk(KERN_INFO "samhain_kmem: Bad address, line %d\n", __LINE__);
491          printk(KERN_INFO "samhain_kmem:  size %ld\n", (long) len);
492          printk(KERN_INFO "samhain_kmem:  kbuf %p\n", kbuf);
493          printk(KERN_INFO "samhain_kmem:  buf  %p\n", buf);
494          printk(KERN_INFO "samhain_kmem:  high %lu\n", (unsigned long) high_memory);
495        }
496        free_page((unsigned long)kbuf);
497        return -EFAULT;
498      }
499      count -= len;
500      buf += len;
501      read += len;
502      p += len;
503    }
504    free_page((unsigned long)kbuf);
505  }
506  *ppos = p;
507  if (debug) {
508    printk(KERN_INFO "samhain_kmem: read_kmem end\n");
509    printk(KERN_INFO "samhain_kmem:  read  %ld\n", (long) read);
510  }
511  return read;
512}
513
514
515static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
516{
517  loff_t ret;
518 
519#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
520  mutex_lock(&file->f_dentry->d_inode->i_mutex);
521#else
522  mutex_lock(&file->f_path.dentry->d_inode->i_mutex);
523#endif
524
525  switch (orig) {
526  case 0:
527    file->f_pos = offset;
528    ret = file->f_pos;
529    force_successful_syscall_return();
530    break;
531  case 1:
532    file->f_pos += offset;
533    ret = file->f_pos;
534    force_successful_syscall_return();
535    break;
536  default:
537    if (debug) {
538      printk(KERN_INFO "samhain_kmem: invalid input %d\n", orig);
539    }
540    ret = -EINVAL;
541  }
542#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
543  mutex_unlock(&file->f_dentry->d_inode->i_mutex);
544#else
545  mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
546#endif
547  return ret;
548}
549
550static const struct file_operations File_Ops_Kmem = {
551  .llseek            = memory_lseek,
552  .read              = read_kmem,
553  .mmap              = mmap_kmem,
554  .open              = open_kmem,
555  .release           = close_kmem,
556  .get_unmapped_area = get_unmapped_area_mem,
557};
558
559
560/* Init function called on module entry
561 */
562static int my_module_init( void )
563{
564  int ret = 0;
565
566  proc_entry = create_proc_entry( "kmem", 0400, NULL ); 
567
568  if (proc_entry == NULL) {
569   
570    ret = -ENOMEM;
571   
572    printk(KERN_INFO "samhain_kmem: Couldn't create proc entry\n");
573   
574  } else {
575   
576/* 2.6.30 */
577#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
578    proc_entry->owner     = THIS_MODULE;
579#endif
580    proc_entry->proc_iops = &Inode_Ops_Kmem;
581    proc_entry->proc_fops = &File_Ops_Kmem;
582   
583    proc_entry->uid       = 0;
584    proc_entry->gid       = 0;
585    proc_entry->mode      = S_IFREG | S_IRUSR;
586   
587    if (debug) {
588      printk(KERN_INFO "samhain_kmem: module is now loaded.\n");
589    }
590  }
591
592  return ret;
593}
594
595/* Cleanup function called on module exit */
596
597static void my_module_cleanup( void )
598{
599  remove_proc_entry("kmem", NULL);
600
601  if (debug) {
602    printk(KERN_INFO "samhain_kmem: module is now unloaded.\n");
603  }
604  return;
605}
606
607
608
609/* Declare entry and exit functions */
610
611module_init( my_module_init );
612
613module_exit( my_module_cleanup );
Note: See TracBrowser for help on using the repository browser.