source: trunk/src/samhain_kmem.c@ 446

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

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

File size: 15.3 KB
RevLine 
[279]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
[286]17#include <linux/version.h>
[279]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>
[286]39#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22)
[279]40#include <linux/splice.h>
[286]41#endif
[279]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
[346]325static struct vm_struct * sh_vmlist = (struct vm_struct *) SH_VMLIST;
[279]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;
[286]518
519#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
520 mutex_lock(&file->f_dentry->d_inode->i_mutex);
521#else
[279]522 mutex_lock(&file->f_path.dentry->d_inode->i_mutex);
[286]523#endif
524
[279]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 }
[286]542#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
543 mutex_unlock(&file->f_dentry->d_inode->i_mutex);
544#else
[279]545 mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
[286]546#endif
[279]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.