blob: 756e24ec2d1a87392a45ff82b2c2bf92c55fb530 [file] [log] [blame]
Karthikeyan Ramasubramanianf7a4b6e2013-01-16 09:00:28 -07001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -06002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/module.h>
14#include <linux/types.h>
15#include <linux/net.h>
16#include <linux/socket.h>
17#include <linux/errno.h>
18#include <linux/mm.h>
19#include <linux/poll.h>
20#include <linux/fcntl.h>
21#include <linux/gfp.h>
22#include <linux/uaccess.h>
23#include <linux/kernel.h>
24#include <linux/msm_ipc.h>
25
26#include <asm/uaccess.h>
27
28#include <net/sock.h>
29#include "ipc_router.h"
30#include "msm_ipc_router_security.h"
31
Karthikeyan Ramasubramanianf7a4b6e2013-01-16 09:00:28 -070032#define IRSC_COMPLETION_TIMEOUT_MS 30000
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -060033#define SEC_RULES_HASH_SZ 32
34struct security_rule {
35 struct list_head list;
36 uint32_t service_id;
37 uint32_t instance_id;
38 unsigned reserved;
39 int num_group_info;
40 int *group_id;
41};
42
43static DEFINE_MUTEX(security_rules_lock);
44static struct list_head security_rules[SEC_RULES_HASH_SZ];
Karthikeyan Ramasubramanianf7a4b6e2013-01-16 09:00:28 -070045static DECLARE_COMPLETION(irsc_completion);
46
47/**
48 * wait_for_irsc_completion() - Wait for IPC Router Security Configuration
49 * (IRSC) to complete
50 */
51void wait_for_irsc_completion(void)
52{
53 unsigned long rem_jiffies;
54 do {
55 rem_jiffies = wait_for_completion_timeout(&irsc_completion,
56 msecs_to_jiffies(IRSC_COMPLETION_TIMEOUT_MS));
57 if (rem_jiffies)
58 return;
59 pr_err("%s: waiting for IPC Security Conf.\n", __func__);
60 } while (1);
61}
62
63/**
64 * signal_irsc_completion() - Signal the completion of IRSC
65 */
66void signal_irsc_completion(void)
67{
68 complete_all(&irsc_completion);
69}
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -060070
71/**
72 * check_permisions() - Check whether the process has permissions to
73 * create an interface handle with IPC Router
74 *
75 * @return: true if the process has permissions, else false.
76 */
77int check_permissions(void)
78{
79 int rc = 0;
80 if (!current_euid() || in_egroup_p(AID_NET_RAW))
81 rc = 1;
82 return rc;
83}
84EXPORT_SYMBOL(check_permissions);
85
86/**
87 * msm_ipc_config_sec_rules() - Add a security rule to the database
88 * @arg: Pointer to the buffer containing the rule.
89 *
90 * @return: 0 if successfully added, < 0 for error.
91 *
92 * A security rule is defined using <Service_ID: Group_ID> tuple. The rule
93 * implies that a user-space process in order to send a QMI message to
94 * service Service_ID should belong to the Linux group Group_ID.
95 */
96int msm_ipc_config_sec_rules(void *arg)
97{
98 struct config_sec_rules_args sec_rules_arg;
99 struct security_rule *rule, *temp_rule;
100 int key;
101 int ret;
102
103 if (current_euid())
104 return -EPERM;
105
106 ret = copy_from_user(&sec_rules_arg, (void *)arg,
107 sizeof(sec_rules_arg));
108 if (ret)
109 return -EFAULT;
110
111 if (sec_rules_arg.num_group_info <= 0)
112 return -EINVAL;
113
114 rule = kzalloc(sizeof(struct security_rule), GFP_KERNEL);
115 if (!rule) {
116 pr_err("%s: security_rule alloc failed\n", __func__);
117 return -ENOMEM;
118 }
119
120 rule->group_id = kzalloc((sec_rules_arg.num_group_info * sizeof(int)),
121 GFP_KERNEL);
122 if (!rule->group_id) {
123 pr_err("%s: group_id alloc failed\n", __func__);
124 kfree(rule);
125 return -ENOMEM;
126 }
127
128 rule->service_id = sec_rules_arg.service_id;
129 rule->instance_id = sec_rules_arg.instance_id;
130 rule->reserved = sec_rules_arg.reserved;
131 rule->num_group_info = sec_rules_arg.num_group_info;
132 ret = copy_from_user(rule->group_id,
133 ((void *)(arg + sizeof(sec_rules_arg))),
134 (rule->num_group_info * sizeof(uint32_t)));
135 if (ret) {
136 kfree(rule->group_id);
137 kfree(rule);
138 return -EFAULT;
139 }
140
141 key = rule->service_id & (SEC_RULES_HASH_SZ - 1);
142 mutex_lock(&security_rules_lock);
143 if (rule->service_id == ALL_SERVICE) {
144 temp_rule = list_first_entry(&security_rules[key],
145 struct security_rule, list);
146 list_del(&temp_rule->list);
147 kfree(temp_rule->group_id);
148 kfree(temp_rule);
149 }
150 list_add_tail(&rule->list, &security_rules[key]);
151 mutex_unlock(&security_rules_lock);
152
153 if (rule->service_id == ALL_SERVICE)
154 msm_ipc_sync_default_sec_rule((void *)rule);
155 else
156 msm_ipc_sync_sec_rule(rule->service_id, rule->instance_id,
157 (void *)rule);
158
159 return 0;
160}
161EXPORT_SYMBOL(msm_ipc_config_sec_rules);
162
163/**
164 * msm_ipc_add_default_rule() - Add default security rule
165 *
166 * @return: 0 on success, < 0 on error/
167 *
168 * This function is used to ensure the basic security, if there is no
169 * security rule defined for a service. It can be overwritten by the
170 * default security rule from user-space script.
171 */
172static int msm_ipc_add_default_rule(void)
173{
174 struct security_rule *rule;
175 int key;
176
177 rule = kzalloc(sizeof(struct security_rule), GFP_KERNEL);
178 if (!rule) {
179 pr_err("%s: security_rule alloc failed\n", __func__);
180 return -ENOMEM;
181 }
182
183 rule->group_id = kzalloc(sizeof(int), GFP_KERNEL);
184 if (!rule->group_id) {
185 pr_err("%s: group_id alloc failed\n", __func__);
186 kfree(rule);
187 return -ENOMEM;
188 }
189
190 rule->service_id = ALL_SERVICE;
191 rule->instance_id = ALL_INSTANCE;
192 rule->num_group_info = 1;
193 *(rule->group_id) = AID_NET_RAW;
194 mutex_lock(&security_rules_lock);
195 key = (ALL_SERVICE & (SEC_RULES_HASH_SZ - 1));
196 list_add_tail(&rule->list, &security_rules[key]);
197 mutex_unlock(&security_rules_lock);
198 return 0;
199}
200
201/**
202 * msm_ipc_get_security_rule() - Get the security rule corresponding to a
203 * service
204 * @service_id: Service ID for which the rule has to be got.
205 * @instance_id: Instance ID for which the rule has to be got.
206 *
207 * @return: Returns the rule info on success, NULL on error.
208 *
209 * This function is used when the service comes up and gets registered with
210 * the IPC Router.
211 */
212void *msm_ipc_get_security_rule(uint32_t service_id, uint32_t instance_id)
213{
214 int key;
215 struct security_rule *rule;
216
217 key = (service_id & (SEC_RULES_HASH_SZ - 1));
218 mutex_lock(&security_rules_lock);
219 /* Return the rule for a specific <service:instance>, if found. */
220 list_for_each_entry(rule, &security_rules[key], list) {
221 if ((rule->service_id == service_id) &&
222 (rule->instance_id == instance_id)) {
223 mutex_unlock(&security_rules_lock);
224 return (void *)rule;
225 }
226 }
227
228 /* Return the rule for a specific service, if found. */
229 list_for_each_entry(rule, &security_rules[key], list) {
230 if ((rule->service_id == service_id) &&
231 (rule->instance_id == ALL_INSTANCE)) {
232 mutex_unlock(&security_rules_lock);
233 return (void *)rule;
234 }
235 }
236
237 /* Return the default rule, if no rule defined for a service. */
238 key = (ALL_SERVICE & (SEC_RULES_HASH_SZ - 1));
239 list_for_each_entry(rule, &security_rules[key], list) {
240 if ((rule->service_id == ALL_SERVICE) &&
241 (rule->instance_id == ALL_INSTANCE)) {
242 mutex_unlock(&security_rules_lock);
243 return (void *)rule;
244 }
245 }
246 return NULL;
247}
248EXPORT_SYMBOL(msm_ipc_get_security_rule);
249
250/**
251 * msm_ipc_check_send_permissions() - Check if the sendng process has
252 * permissions specified as per the rule
253 * @data: Security rule to be checked.
254 *
255 * @return: true if the process has permissions, else false.
256 *
257 * This function is used to check if the current executing process has
258 * permissions to send message to the remote entity. The security rule
259 * corresponding to the remote entity is specified by "data" parameter
260 */
261int msm_ipc_check_send_permissions(void *data)
262{
263 int i;
264 struct security_rule *rule = (struct security_rule *)data;
265
266 /* Source/Sender is Root user */
267 if (!current_euid())
268 return 1;
269
270 /* Destination has no rules defined, possibly a client. */
271 if (!rule)
272 return 1;
273
274 for (i = 0; i < rule->num_group_info; i++) {
275 if (in_egroup_p(rule->group_id[i]))
276 return 1;
277 }
278 return 0;
279}
280EXPORT_SYMBOL(msm_ipc_check_send_permissions);
281
282/**
283 * msm_ipc_router_security_init() - Initialize the security rule database
284 *
285 * @return: 0 if successful, < 0 for error.
286 */
287int msm_ipc_router_security_init(void)
288{
289 int i;
290
291 for (i = 0; i < SEC_RULES_HASH_SZ; i++)
292 INIT_LIST_HEAD(&security_rules[i]);
293
294 msm_ipc_add_default_rule();
295 return 0;
296}
297EXPORT_SYMBOL(msm_ipc_router_security_init);