blob: 69efd13a5b498057137c75735fe5adc2d00ac6b5 [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;
Karthikeyan Ramasubramanian1c5707c2013-02-26 17:20:07 -070040 gid_t *group_id;
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -060041};
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;
Karthikeyan Ramasubramanian1c5707c2013-02-26 17:20:07 -0700101 int group_info_sz;
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -0600102 int ret;
103
104 if (current_euid())
105 return -EPERM;
106
107 ret = copy_from_user(&sec_rules_arg, (void *)arg,
108 sizeof(sec_rules_arg));
109 if (ret)
110 return -EFAULT;
111
112 if (sec_rules_arg.num_group_info <= 0)
113 return -EINVAL;
114
Karthikeyan Ramasubramanian1c5707c2013-02-26 17:20:07 -0700115 group_info_sz = sec_rules_arg.num_group_info * sizeof(gid_t);
116 if ((group_info_sz / sizeof(gid_t)) != sec_rules_arg.num_group_info) {
117 pr_err("%s: Integer Overflow %d * %d\n", __func__,
118 sizeof(gid_t), sec_rules_arg.num_group_info);
119 return -EINVAL;
120 }
121
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -0600122 rule = kzalloc(sizeof(struct security_rule), GFP_KERNEL);
123 if (!rule) {
124 pr_err("%s: security_rule alloc failed\n", __func__);
125 return -ENOMEM;
126 }
127
Karthikeyan Ramasubramanian1c5707c2013-02-26 17:20:07 -0700128 rule->group_id = kzalloc(group_info_sz, GFP_KERNEL);
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -0600129 if (!rule->group_id) {
130 pr_err("%s: group_id alloc failed\n", __func__);
131 kfree(rule);
132 return -ENOMEM;
133 }
134
135 rule->service_id = sec_rules_arg.service_id;
136 rule->instance_id = sec_rules_arg.instance_id;
137 rule->reserved = sec_rules_arg.reserved;
138 rule->num_group_info = sec_rules_arg.num_group_info;
139 ret = copy_from_user(rule->group_id,
140 ((void *)(arg + sizeof(sec_rules_arg))),
Karthikeyan Ramasubramanian1c5707c2013-02-26 17:20:07 -0700141 group_info_sz);
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -0600142 if (ret) {
143 kfree(rule->group_id);
144 kfree(rule);
145 return -EFAULT;
146 }
147
148 key = rule->service_id & (SEC_RULES_HASH_SZ - 1);
149 mutex_lock(&security_rules_lock);
150 if (rule->service_id == ALL_SERVICE) {
151 temp_rule = list_first_entry(&security_rules[key],
152 struct security_rule, list);
153 list_del(&temp_rule->list);
154 kfree(temp_rule->group_id);
155 kfree(temp_rule);
156 }
157 list_add_tail(&rule->list, &security_rules[key]);
158 mutex_unlock(&security_rules_lock);
159
160 if (rule->service_id == ALL_SERVICE)
161 msm_ipc_sync_default_sec_rule((void *)rule);
162 else
163 msm_ipc_sync_sec_rule(rule->service_id, rule->instance_id,
164 (void *)rule);
165
166 return 0;
167}
168EXPORT_SYMBOL(msm_ipc_config_sec_rules);
169
170/**
171 * msm_ipc_add_default_rule() - Add default security rule
172 *
173 * @return: 0 on success, < 0 on error/
174 *
175 * This function is used to ensure the basic security, if there is no
176 * security rule defined for a service. It can be overwritten by the
177 * default security rule from user-space script.
178 */
179static int msm_ipc_add_default_rule(void)
180{
181 struct security_rule *rule;
182 int key;
183
184 rule = kzalloc(sizeof(struct security_rule), GFP_KERNEL);
185 if (!rule) {
186 pr_err("%s: security_rule alloc failed\n", __func__);
187 return -ENOMEM;
188 }
189
190 rule->group_id = kzalloc(sizeof(int), GFP_KERNEL);
191 if (!rule->group_id) {
192 pr_err("%s: group_id alloc failed\n", __func__);
193 kfree(rule);
194 return -ENOMEM;
195 }
196
197 rule->service_id = ALL_SERVICE;
198 rule->instance_id = ALL_INSTANCE;
199 rule->num_group_info = 1;
200 *(rule->group_id) = AID_NET_RAW;
201 mutex_lock(&security_rules_lock);
202 key = (ALL_SERVICE & (SEC_RULES_HASH_SZ - 1));
203 list_add_tail(&rule->list, &security_rules[key]);
204 mutex_unlock(&security_rules_lock);
205 return 0;
206}
207
208/**
209 * msm_ipc_get_security_rule() - Get the security rule corresponding to a
210 * service
211 * @service_id: Service ID for which the rule has to be got.
212 * @instance_id: Instance ID for which the rule has to be got.
213 *
214 * @return: Returns the rule info on success, NULL on error.
215 *
216 * This function is used when the service comes up and gets registered with
217 * the IPC Router.
218 */
219void *msm_ipc_get_security_rule(uint32_t service_id, uint32_t instance_id)
220{
221 int key;
222 struct security_rule *rule;
223
224 key = (service_id & (SEC_RULES_HASH_SZ - 1));
225 mutex_lock(&security_rules_lock);
226 /* Return the rule for a specific <service:instance>, if found. */
227 list_for_each_entry(rule, &security_rules[key], list) {
228 if ((rule->service_id == service_id) &&
229 (rule->instance_id == instance_id)) {
230 mutex_unlock(&security_rules_lock);
231 return (void *)rule;
232 }
233 }
234
235 /* Return the rule for a specific service, if found. */
236 list_for_each_entry(rule, &security_rules[key], list) {
237 if ((rule->service_id == service_id) &&
238 (rule->instance_id == ALL_INSTANCE)) {
239 mutex_unlock(&security_rules_lock);
240 return (void *)rule;
241 }
242 }
243
244 /* Return the default rule, if no rule defined for a service. */
245 key = (ALL_SERVICE & (SEC_RULES_HASH_SZ - 1));
246 list_for_each_entry(rule, &security_rules[key], list) {
247 if ((rule->service_id == ALL_SERVICE) &&
248 (rule->instance_id == ALL_INSTANCE)) {
249 mutex_unlock(&security_rules_lock);
250 return (void *)rule;
251 }
252 }
253 return NULL;
254}
255EXPORT_SYMBOL(msm_ipc_get_security_rule);
256
257/**
258 * msm_ipc_check_send_permissions() - Check if the sendng process has
259 * permissions specified as per the rule
260 * @data: Security rule to be checked.
261 *
262 * @return: true if the process has permissions, else false.
263 *
264 * This function is used to check if the current executing process has
265 * permissions to send message to the remote entity. The security rule
266 * corresponding to the remote entity is specified by "data" parameter
267 */
268int msm_ipc_check_send_permissions(void *data)
269{
270 int i;
271 struct security_rule *rule = (struct security_rule *)data;
272
273 /* Source/Sender is Root user */
274 if (!current_euid())
275 return 1;
276
277 /* Destination has no rules defined, possibly a client. */
278 if (!rule)
279 return 1;
280
281 for (i = 0; i < rule->num_group_info; i++) {
282 if (in_egroup_p(rule->group_id[i]))
283 return 1;
284 }
285 return 0;
286}
287EXPORT_SYMBOL(msm_ipc_check_send_permissions);
288
289/**
290 * msm_ipc_router_security_init() - Initialize the security rule database
291 *
292 * @return: 0 if successful, < 0 for error.
293 */
294int msm_ipc_router_security_init(void)
295{
296 int i;
297
298 for (i = 0; i < SEC_RULES_HASH_SZ; i++)
299 INIT_LIST_HEAD(&security_rules[i]);
300
301 msm_ipc_add_default_rule();
302 return 0;
303}
304EXPORT_SYMBOL(msm_ipc_router_security_init);