1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2023 Huawei Device Co., Ltd.
4 */
5
6 #include <linux/code_sign.h>
7 #include <linux/compat.h>
8 #include <linux/file.h>
9 #include <linux/miscdevice.h>
10 #include <linux/mm.h>
11 #include <linux/mman.h>
12 #include <linux/mm_types.h>
13
14 #include "code_sign_ext.h"
15 #include "xpm_log.h"
16 #include "xpm_misc_device.h"
17 #include "xpm_report.h"
18
19 #define XPM_SET_REGION _IOW('x', 0x01, struct xpm_config)
20 #define XPM_SET_OWNERID _IOW('x', 0x02, struct xpm_config)
21
xpm_set_region(struct xpm_config * config)22 static int xpm_set_region(struct xpm_config *config)
23 {
24 uint64_t addr;
25 struct mm_struct *mm = current->mm;
26
27 if (!mm)
28 return -EINVAL;
29
30 if ((mm->xpm_region.addr_start != 0) ||
31 (mm->xpm_region.addr_end != 0)) {
32 xpm_log_info("xpm region has been set");
33 return 0;
34 }
35
36 addr = get_unmapped_area(NULL, config->region_addr,
37 config->region_length, 0, 0);
38 if (IS_ERR_VALUE(addr) || (ULLONG_MAX - addr < config->region_length)) {
39 xpm_log_error("xpm get unmmaped area failed");
40 return -EINVAL;
41 }
42
43 if (mmap_write_lock_killable(mm))
44 return -EINTR;
45
46 mm->xpm_region.addr_start = addr;
47 mm->xpm_region.addr_end = addr + config->region_length;
48 mmap_write_unlock(mm);
49
50 return 0;
51 }
52
xpm_set_ownerid(struct xpm_config * config)53 static int xpm_set_ownerid(struct xpm_config *config)
54 {
55 struct mm_struct *mm = current->mm;
56
57 if (!mm)
58 return -EINVAL;
59
60 if (config->id_type >= PROCESS_OWNERID_MAX) {
61 xpm_log_error("input ownerid type is invalid");
62 return -EINVAL;
63 }
64
65 #ifndef CONFIG_SECURITY_XPM_DEBUG
66 if ((mm->pcs_info.id_type == PROCESS_OWNERID_APP) ||
67 mm->pcs_info.id_type == PROCESS_OWNERID_DEBUG) {
68 xpm_log_info("process ownerid has been set");
69 return 0;
70 }
71 #endif
72
73 if (config->ownerid[MAX_OWNERID_LEN - 1] != '\0') {
74 xpm_log_error("input ownerid string is invalid");
75 return -EINVAL;
76 }
77
78 if (mmap_write_lock_killable(mm))
79 return -EINTR;
80
81 code_sign_set_ownerid(&mm->pcs_info, config->id_type,
82 config->ownerid, strlen(config->ownerid));
83 mmap_write_unlock(mm);
84
85 return 0;
86 }
87
xpm_ioctl(struct file * file,unsigned int cmd,unsigned long arg)88 static long xpm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
89 {
90 int ret;
91 struct xpm_config config = {0};
92
93 if (unlikely(copy_from_user(&config, u64_to_user_ptr((uint64_t)arg),
94 sizeof(struct xpm_config))))
95 return -EFAULT;
96
97 switch (cmd) {
98 case XPM_SET_REGION:
99 ret = xpm_set_region(&config);
100 break;
101 case XPM_SET_OWNERID:
102 ret = xpm_set_ownerid(&config);
103 break;
104 default:
105 xpm_log_error("xpm ioctl cmd error, cmd = %d", cmd);
106 ret = -EINVAL;
107 break;
108 }
109
110 return ret;
111 }
112
113 #ifdef CONFIG_COMPAT
xpm_compat_ioctl(struct file * file,unsigned int cmd,unsigned long arg)114 static long xpm_compat_ioctl(struct file *file, unsigned int cmd,
115 unsigned long arg)
116 {
117 return 0;
118 }
119 #endif
120
xpm_open(struct inode * inode,struct file * file)121 static int xpm_open(struct inode *inode, struct file *file)
122 {
123 return 0;
124 }
125
xpm_release(struct inode * inode,struct file * file)126 static int xpm_release(struct inode *inode, struct file *file)
127 {
128 return 0;
129 }
130
131 static const struct file_operations xpm_fops = {
132 .owner = THIS_MODULE,
133 .open = xpm_open,
134 .release = xpm_release,
135 .unlocked_ioctl = xpm_ioctl,
136 #ifdef CONFIG_COMPAT
137 .compat_ioctl = xpm_compat_ioctl,
138 #endif
139 };
140
141 static struct miscdevice xpm_misc = {
142 .minor = MISC_DYNAMIC_MINOR,
143 .name = "xpm",
144 .fops = &xpm_fops,
145 };
146
xpm_register_misc_device(void)147 int xpm_register_misc_device(void)
148 {
149 return misc_register(&xpm_misc);
150 }
151
xpm_deregister_misc_device(void)152 void xpm_deregister_misc_device(void)
153 {
154 misc_deregister(&xpm_misc);
155 }
156