Blame view

kernel/linux-imx6_3.14.28/lib/test_user_copy.c 3.05 KB
6b13f685e   김민수   BSP 최초 추가
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
  /*
   * Kernel module for testing copy_to/from_user infrastructure.
   *
   * Copyright 2013 Google Inc. All Rights Reserved
   *
   * Authors:
   *      Kees Cook       <keescook@chromium.org>
   *
   * This software is licensed under the terms of the GNU General Public
   * License version 2, as published by the Free Software Foundation, and
   * may be copied, distributed, and modified under those terms.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   */
  
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  
  #include <linux/mman.h>
  #include <linux/module.h>
  #include <linux/sched.h>
  #include <linux/slab.h>
  #include <linux/uaccess.h>
  #include <linux/vmalloc.h>
  
  #define test(condition, msg)		\
  ({					\
  	int cond = (condition);		\
  	if (cond)			\
  		pr_warn("%s
  ", msg);	\
  	cond;				\
  })
  
  static int __init test_user_copy_init(void)
  {
  	int ret = 0;
  	char *kmem;
  	char __user *usermem;
  	char *bad_usermem;
  	unsigned long user_addr;
  	unsigned long value = 0x5A;
  
  	kmem = kmalloc(PAGE_SIZE * 2, GFP_KERNEL);
  	if (!kmem)
  		return -ENOMEM;
  
  	user_addr = vm_mmap(NULL, 0, PAGE_SIZE * 2,
  			    PROT_READ | PROT_WRITE | PROT_EXEC,
  			    MAP_ANONYMOUS | MAP_PRIVATE, 0);
  	if (user_addr >= (unsigned long)(TASK_SIZE)) {
  		pr_warn("Failed to allocate user memory
  ");
  		kfree(kmem);
  		return -ENOMEM;
  	}
  
  	usermem = (char __user *)user_addr;
  	bad_usermem = (char *)user_addr;
  
  	/* Legitimate usage: none of these should fail. */
  	ret |= test(copy_from_user(kmem, usermem, PAGE_SIZE),
  		    "legitimate copy_from_user failed");
  	ret |= test(copy_to_user(usermem, kmem, PAGE_SIZE),
  		    "legitimate copy_to_user failed");
  	ret |= test(get_user(value, (unsigned long __user *)usermem),
  		    "legitimate get_user failed");
  	ret |= test(put_user(value, (unsigned long __user *)usermem),
  		    "legitimate put_user failed");
  
  	/* Invalid usage: none of these should succeed. */
  	ret |= test(!copy_from_user(kmem, (char __user *)(kmem + PAGE_SIZE),
  				    PAGE_SIZE),
  		    "illegal all-kernel copy_from_user passed");
  	ret |= test(!copy_from_user(bad_usermem, (char __user *)kmem,
  				    PAGE_SIZE),
  		    "illegal reversed copy_from_user passed");
  	ret |= test(!copy_to_user((char __user *)kmem, kmem + PAGE_SIZE,
  				  PAGE_SIZE),
  		    "illegal all-kernel copy_to_user passed");
  	ret |= test(!copy_to_user((char __user *)kmem, bad_usermem,
  				  PAGE_SIZE),
  		    "illegal reversed copy_to_user passed");
  	ret |= test(!get_user(value, (unsigned long __user *)kmem),
  		    "illegal get_user passed");
  	ret |= test(!put_user(value, (unsigned long __user *)kmem),
  		    "illegal put_user passed");
  
  	vm_munmap(user_addr, PAGE_SIZE * 2);
  	kfree(kmem);
  
  	if (ret == 0) {
  		pr_info("tests passed.
  ");
  		return 0;
  	}
  
  	return -EINVAL;
  }
  
  module_init(test_user_copy_init);
  
  static void __exit test_user_copy_exit(void)
  {
  	pr_info("unloaded.
  ");
  }
  
  module_exit(test_user_copy_exit);
  
  MODULE_AUTHOR("Kees Cook <keescook@chromium.org>");
  MODULE_LICENSE("GPL");