Back to home page

LXR

 
 

    


0001 /*
0002  * Kernel module for testing copy_to/from_user infrastructure.
0003  *
0004  * Copyright 2013 Google Inc. All Rights Reserved
0005  *
0006  * Authors:
0007  *      Kees Cook       <keescook@chromium.org>
0008  *
0009  * This software is licensed under the terms of the GNU General Public
0010  * License version 2, as published by the Free Software Foundation, and
0011  * may be copied, distributed, and modified under those terms.
0012  *
0013  * This program is distributed in the hope that it will be useful,
0014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0016  * GNU General Public License for more details.
0017  */
0018 
0019 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0020 
0021 #include <linux/mman.h>
0022 #include <linux/module.h>
0023 #include <linux/sched.h>
0024 #include <linux/slab.h>
0025 #include <linux/uaccess.h>
0026 #include <linux/vmalloc.h>
0027 
0028 #define test(condition, msg)        \
0029 ({                  \
0030     int cond = (condition);     \
0031     if (cond)           \
0032         pr_warn("%s\n", msg);   \
0033     cond;               \
0034 })
0035 
0036 static int __init test_user_copy_init(void)
0037 {
0038     int ret = 0;
0039     char *kmem;
0040     char __user *usermem;
0041     char *bad_usermem;
0042     unsigned long user_addr;
0043     unsigned long value = 0x5A;
0044 
0045     kmem = kmalloc(PAGE_SIZE * 2, GFP_KERNEL);
0046     if (!kmem)
0047         return -ENOMEM;
0048 
0049     user_addr = vm_mmap(NULL, 0, PAGE_SIZE * 2,
0050                 PROT_READ | PROT_WRITE | PROT_EXEC,
0051                 MAP_ANONYMOUS | MAP_PRIVATE, 0);
0052     if (user_addr >= (unsigned long)(TASK_SIZE)) {
0053         pr_warn("Failed to allocate user memory\n");
0054         kfree(kmem);
0055         return -ENOMEM;
0056     }
0057 
0058     usermem = (char __user *)user_addr;
0059     bad_usermem = (char *)user_addr;
0060 
0061     /* Legitimate usage: none of these should fail. */
0062     ret |= test(copy_from_user(kmem, usermem, PAGE_SIZE),
0063             "legitimate copy_from_user failed");
0064     ret |= test(copy_to_user(usermem, kmem, PAGE_SIZE),
0065             "legitimate copy_to_user failed");
0066     ret |= test(get_user(value, (unsigned long __user *)usermem),
0067             "legitimate get_user failed");
0068     ret |= test(put_user(value, (unsigned long __user *)usermem),
0069             "legitimate put_user failed");
0070 
0071     /* Invalid usage: none of these should succeed. */
0072     ret |= test(!copy_from_user(kmem, (char __user *)(kmem + PAGE_SIZE),
0073                     PAGE_SIZE),
0074             "illegal all-kernel copy_from_user passed");
0075     ret |= test(!copy_from_user(bad_usermem, (char __user *)kmem,
0076                     PAGE_SIZE),
0077             "illegal reversed copy_from_user passed");
0078     ret |= test(!copy_to_user((char __user *)kmem, kmem + PAGE_SIZE,
0079                   PAGE_SIZE),
0080             "illegal all-kernel copy_to_user passed");
0081     ret |= test(!copy_to_user((char __user *)kmem, bad_usermem,
0082                   PAGE_SIZE),
0083             "illegal reversed copy_to_user passed");
0084     ret |= test(!get_user(value, (unsigned long __user *)kmem),
0085             "illegal get_user passed");
0086     ret |= test(!put_user(value, (unsigned long __user *)kmem),
0087             "illegal put_user passed");
0088 
0089     vm_munmap(user_addr, PAGE_SIZE * 2);
0090     kfree(kmem);
0091 
0092     if (ret == 0) {
0093         pr_info("tests passed.\n");
0094         return 0;
0095     }
0096 
0097     return -EINVAL;
0098 }
0099 
0100 module_init(test_user_copy_init);
0101 
0102 static void __exit test_user_copy_exit(void)
0103 {
0104     pr_info("unloaded.\n");
0105 }
0106 
0107 module_exit(test_user_copy_exit);
0108 
0109 MODULE_AUTHOR("Kees Cook <keescook@chromium.org>");
0110 MODULE_LICENSE("GPL");