ARM: tegra: Add Tegra Profiler
[linux-2.6.git] / drivers / misc / tegra-profiler / auth.c
1 /*
2  * drivers/misc/tegra-profiler/auth.c
3  *
4  * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  */
16
17 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18
19 #include <linux/module.h>
20 #include <linux/miscdevice.h>
21 #include <linux/fs.h>
22 #include <linux/wait.h>
23 #include <linux/sched.h>
24 #include <linux/uaccess.h>
25
26 #include "auth.h"
27 #include "quadd.h"
28 #include "debug.h"
29
30 #define QUADD_SECURITY_MAGIC_REQUEST    0x11112222
31 #define QUADD_SECURITY_MAGIC_RESPONSE   0x33334444
32
33 #define QUADD_TIMEOUT   1000    /* msec */
34
35 enum {
36         QUADD_SECURITY_RESPONSE_ERROR                   = 0,
37         QUADD_SECURITY_RESPONSE_DEBUG_FLAG_ON           = 1,
38         QUADD_SECURITY_RESPONSE_DEBUG_FLAG_OFF          = 2,
39         QUADD_SECURITY_RESPONSE_PACKAGE_NOT_FOUND       = 3,
40 };
41
42 enum {
43         QUADD_SECURITY_REQUEST_CMD_TEST_DEBUG_FLAG      = 1,
44         QUADD_SECURITY_RESPONSE_CMD_TEST_DEBUG_FLAG     = 2,
45 };
46
47 struct quadd_auth_data {
48         char package_name[QUADD_MAX_PACKAGE_NAME];
49
50         uid_t debug_app_uid;
51         int response_value;
52 };
53
54 static struct quadd_auth_context {
55         struct miscdevice misc_dev;
56
57         atomic_t opened;
58
59         wait_queue_head_t request_wait;
60         wait_queue_head_t response_wait;
61
62         int request_ready;
63         int response_ready;
64         struct quadd_auth_data data;
65         struct mutex lock;
66
67         unsigned int msg_id;
68
69         struct quadd_ctx *quadd_ctx;
70 } auth_ctx;
71
72 static inline void response_ready(void)
73 {
74         auth_ctx.response_ready = 1;
75         wake_up_interruptible(&auth_ctx.response_wait);
76 }
77
78 static inline void request_ready(void)
79 {
80         auth_ctx.request_ready = 1;
81         wake_up_interruptible(&auth_ctx.request_wait);
82 }
83
84 static int auth_open(struct inode *inode, struct file *file)
85 {
86         struct quadd_auth_data *data = &auth_ctx.data;
87
88         if (atomic_cmpxchg(&auth_ctx.opened, 0, 1)) {
89                 pr_err("Error: auth file is already opened\n");
90                 return -EBUSY;
91         }
92         pr_info("auth is opened\n");
93
94         auth_ctx.request_ready = 0;
95         auth_ctx.response_ready = 0;
96
97         mutex_lock(&auth_ctx.lock);
98         data->package_name[0] = '\0';
99         data->debug_app_uid = 0;
100         data->response_value = 0;
101         mutex_unlock(&auth_ctx.lock);
102
103         return 0;
104 }
105
106 static int auth_release(struct inode *inode, struct file *file)
107 {
108         pr_info("auth is released\n");
109         atomic_set(&auth_ctx.opened, 0);
110         return 0;
111 }
112
113 static ssize_t
114 auth_read(struct file *filp,
115             char __user *user_buf,
116             size_t length,
117             loff_t *offset)
118 {
119         char buf[QUADD_MAX_PACKAGE_NAME + 4 * sizeof(u32)];
120         int msg_length, err;
121         struct quadd_auth_data *data = &auth_ctx.data;
122
123         wait_event_interruptible(auth_ctx.request_wait, auth_ctx.request_ready);
124
125         mutex_lock(&auth_ctx.lock);
126
127         ((u32 *)buf)[0] = QUADD_SECURITY_MAGIC_REQUEST;
128         ((u32 *)buf)[1] = ++auth_ctx.msg_id;
129         ((u32 *)buf)[2] = QUADD_SECURITY_REQUEST_CMD_TEST_DEBUG_FLAG;
130         ((u32 *)buf)[3] = strlen(data->package_name);
131
132         strcpy(buf + 4 * sizeof(u32), data->package_name);
133         msg_length = strlen(data->package_name) + 4 * sizeof(u32);
134
135         mutex_unlock(&auth_ctx.lock);
136
137         err = copy_to_user(user_buf, buf, msg_length);
138         if (err != 0) {
139                 pr_err("Error: copy to user: %d\n", err);
140                 return err;
141         }
142
143         pr_info("auth read, msg_length: %d\n", msg_length);
144         return msg_length;
145 }
146
147 static ssize_t
148 auth_write(struct file *file,
149           const char __user *user_buf,
150           size_t count,
151           loff_t *ppos)
152 {
153         int err;
154         char buf[5 * sizeof(u32)];
155         u32 magic, response_cmd, response_value, length, uid, msg_id;
156         struct quadd_auth_data *data = &auth_ctx.data;
157
158         pr_info("auth read, count: %d\n", count);
159
160         mutex_lock(&auth_ctx.lock);
161         data->response_value = QUADD_SECURITY_RESPONSE_ERROR;
162         data->debug_app_uid = 0;
163         mutex_unlock(&auth_ctx.lock);
164
165         if (count < 5 * sizeof(u32)) {
166                 pr_err("Error count: %u\n", count);
167                 response_ready();
168                 return -E2BIG;
169         }
170
171         err = copy_from_user(buf, user_buf, 5 * sizeof(u32));
172         if (err) {
173                 pr_err("Error: copy from user: %d\n", err);
174                 response_ready();
175                 return err;
176         }
177
178         magic = ((u32 *)buf)[0];
179         if (magic != QUADD_SECURITY_MAGIC_RESPONSE) {
180                 pr_err("Error magic: %#x\n", magic);
181                 response_ready();
182                 return -EINVAL;
183         }
184
185         msg_id = ((u32 *)buf)[1];
186         if (msg_id != auth_ctx.msg_id) {
187                 pr_err("Error message id: %u\n", msg_id);
188                 response_ready();
189                 return -EINVAL;
190         }
191
192         response_cmd = ((u32 *)buf)[2];
193         response_value = ((u32 *)buf)[3];
194         length = ((u32 *)buf)[4];
195
196         switch (response_cmd) {
197         case QUADD_SECURITY_RESPONSE_CMD_TEST_DEBUG_FLAG:
198                 if (length != 4) {
199                         pr_err("Error: too long data: %u\n", length);
200                         response_ready();
201                         return -E2BIG;
202                 }
203
204                 err = get_user(uid, (u32 __user *)user_buf + 5);
205                 if (err) {
206                         pr_err("Error: copy from user: %d\n", err);
207                         response_ready();
208                         return err;
209                 }
210
211                 mutex_lock(&auth_ctx.lock);
212                 data->response_value = response_value;
213                 data->debug_app_uid = uid;
214                 mutex_unlock(&auth_ctx.lock);
215
216                 pr_info("uid: %u, response_value: %u\n",
217                         uid, response_value);
218                 break;
219
220         default:
221                 pr_err("Error: invalid response command: %u\n",
222                        response_cmd);
223                 response_ready();
224                 return -EINVAL;
225         }
226         response_ready();
227
228         return count;
229 }
230
231 static const struct file_operations auth_fops = {
232         .read           = auth_read,
233         .write          = auth_write,
234         .open           = auth_open,
235         .release        = auth_release,
236 };
237
238 int quadd_auth_check_debug_flag(const char *package_name)
239 {
240         int uid, response_value;
241         struct quadd_auth_data *data = &auth_ctx.data;
242         int pkg_name_length;
243
244         if (!package_name)
245                 return -EINVAL;
246
247         pkg_name_length = strlen(package_name);
248         if (pkg_name_length == 0 ||
249             pkg_name_length > QUADD_MAX_PACKAGE_NAME)
250                 return -EINVAL;
251
252         if (atomic_read(&auth_ctx.opened) == 0)
253                 return -EIO;
254
255         mutex_lock(&auth_ctx.lock);
256         data->debug_app_uid = 0;
257         data->response_value = 0;
258
259         strncpy(data->package_name, package_name, QUADD_MAX_PACKAGE_NAME);
260         mutex_unlock(&auth_ctx.lock);
261
262         request_ready();
263
264         wait_event_interruptible_timeout(auth_ctx.response_wait,
265                                          auth_ctx.response_ready,
266                                          msecs_to_jiffies(QUADD_TIMEOUT));
267         if (!auth_ctx.response_ready) {
268                 pr_err("Error: Tegra profiler service did not answer\n");
269                 return -ETIMEDOUT;
270         }
271
272         mutex_lock(&auth_ctx.lock);
273         uid = data->debug_app_uid;
274         response_value = data->response_value;
275         mutex_unlock(&auth_ctx.lock);
276
277         switch (response_value) {
278         case QUADD_SECURITY_RESPONSE_DEBUG_FLAG_ON:
279                 pr_info("package %s is debuggable, uid: %d\n",
280                         package_name, uid);
281                 return uid;
282
283         case QUADD_SECURITY_RESPONSE_DEBUG_FLAG_OFF:
284                 pr_info("package %s is not debuggable\n",
285                         package_name);
286                 return 0;
287
288         case QUADD_SECURITY_RESPONSE_PACKAGE_NOT_FOUND:
289                 pr_err("Error: package %s not found\n", package_name);
290                 return -ESRCH;
291
292         case QUADD_SECURITY_RESPONSE_ERROR:
293         default:
294                 pr_err("Error: invalid response\n");
295                 return -EBADMSG;
296         }
297 }
298
299 int quadd_auth_init(struct quadd_ctx *quadd_ctx)
300 {
301         int err;
302         struct miscdevice *misc_dev = &auth_ctx.misc_dev;
303
304         pr_info("auth: init\n");
305
306         misc_dev->minor = MISC_DYNAMIC_MINOR;
307         misc_dev->name = QUADD_AUTH_DEVICE_NAME;
308         misc_dev->fops = &auth_fops;
309
310         err = misc_register(misc_dev);
311         if (err < 0) {
312                 pr_err("Error: misc_register %d\n", err);
313                 return err;
314         }
315
316         init_waitqueue_head(&auth_ctx.request_wait);
317         init_waitqueue_head(&auth_ctx.response_wait);
318
319         auth_ctx.request_ready = 0;
320         auth_ctx.response_ready = 0;
321
322         atomic_set(&auth_ctx.opened, 0);
323         mutex_init(&auth_ctx.lock);
324         auth_ctx.msg_id = 0;
325
326         auth_ctx.quadd_ctx = quadd_ctx;
327         return 0;
328 }
329
330 void quadd_auth_deinit(void)
331 {
332         struct miscdevice *misc_dev = &auth_ctx.misc_dev;
333
334         pr_info("auth: deinit\n");
335         misc_deregister(misc_dev);
336 }