• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012-2017 ARM Limited. All rights reserved.
3  *
4  * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5  * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
6  *
7  * A copy of the licence is included with the program, and can also be obtained from Free Software
8  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
9  */
10 
11 #include <linux/init.h>
12 #include <linux/module.h>
13 #include <linux/fs.h>
14 #include <linux/slab.h>
15 #include <linux/cdev.h>
16 #include <linux/device.h>
17 #include <linux/uaccess.h>
18 #include "umplock_ioctl.h"
19 #include <linux/sched.h>
20 
21 #define MAX_ITEMS 1024
22 #define MAX_PIDS 128
23 
24 typedef struct lock_cmd_priv {
25 	uint32_t msg[128];    /*ioctl args*/
26 	u32 pid;              /*process id*/
27 } _lock_cmd_priv;
28 
29 typedef struct lock_ref {
30 	int ref_count;
31 	u32 pid;
32 	u32 down_count;
33 } _lock_ref;
34 
35 typedef struct umplock_item {
36 	u32 secure_id;
37 	u32 id_ref_count;
38 	u32 owner;
39 	_lock_access_usage usage;
40 	_lock_ref references[MAX_PIDS];
41 	struct semaphore item_lock;
42 } umplock_item;
43 
44 typedef struct umplock_device_private {
45 	struct mutex item_list_lock;
46 	atomic_t sessions;
47 	umplock_item items[MAX_ITEMS];
48 	u32 pids[MAX_PIDS];
49 } umplock_device_private;
50 
51 struct umplock_device {
52 	struct cdev cdev;
53 	struct class *umplock_class;
54 };
55 
56 static struct umplock_device umplock_device;
57 static umplock_device_private device;
58 static dev_t umplock_dev;
59 static char umplock_dev_name[] = "umplock";
60 
61 int umplock_debug_level = 0;
62 module_param(umplock_debug_level, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); /* rw-rw-r-- */
63 MODULE_PARM_DESC(umplock_debug_level, "set umplock_debug_level to print debug messages");
64 
65 #define PDEBUG(level, fmt, args...) do { if ((level) <= umplock_debug_level) printk(KERN_DEBUG "umplock: " fmt, ##args); } while (0)
66 #define PERROR(fmt, args...) do { printk(KERN_ERR "umplock: " fmt, ##args); } while (0)
67 
umplock_find_item(u32 secure_id)68 int umplock_find_item(u32 secure_id)
69 {
70 	int i;
71 	for (i = 0; i < MAX_ITEMS; i++) {
72 		if (device.items[i].secure_id == secure_id) {
73 			return i;
74 		}
75 	}
76 
77 	return -1;
78 }
79 
umplock_find_item_by_pid(_lock_cmd_priv * lock_cmd,int * item_slot,int * ref_slot)80 static int umplock_find_item_by_pid(_lock_cmd_priv *lock_cmd, int *item_slot, int *ref_slot)
81 {
82 	_lock_item_s *lock_item;
83 	int i, j;
84 
85 	lock_item = (_lock_item_s *)&lock_cmd->msg;
86 
87 	i = umplock_find_item(lock_item->secure_id);
88 
89 	if (i < 0) {
90 		return -1;
91 	}
92 
93 	for (j = 0; j < MAX_PIDS; j++) {
94 		if (device.items[i].references[j].pid == lock_cmd->pid) {
95 			*item_slot = i;
96 			*ref_slot = j;
97 			return 0;
98 		}
99 	}
100 	return -1 ;
101 }
102 
umplock_find_client_valid(u32 pid)103 static int umplock_find_client_valid(u32 pid)
104 {
105 	int i;
106 
107 	if (pid == 0) {
108 		return -1;
109 	}
110 
111 	for (i = 0; i < MAX_PIDS; i++) {
112 		if (device.pids[i] == pid) {
113 			return i;
114 		}
115 	}
116 
117 	return -1;
118 }
119 
do_umplock_create_locked(_lock_cmd_priv * lock_cmd)120 static int do_umplock_create_locked(_lock_cmd_priv *lock_cmd)
121 {
122 	int i_index, ref_index;
123 	int ret;
124 	_lock_item_s *lock_item = (_lock_item_s *)&lock_cmd->msg;
125 
126 	i_index = ref_index = -1;
127 
128 	ret = umplock_find_client_valid(lock_cmd->pid);
129 	if (ret < 0) {
130 		/*lock request from an invalid client pid, do nothing*/
131 		return -EINVAL;
132 	}
133 
134 	ret = umplock_find_item_by_pid(lock_cmd, &i_index, &ref_index);
135 	if (ret >= 0) {
136 	} else if ((i_index = umplock_find_item(lock_item->secure_id)) >= 0) {
137 		for (ref_index = 0; ref_index < MAX_PIDS; ref_index++) {
138 			if (device.items[i_index].references[ref_index].pid == 0) {
139 				break;
140 			}
141 		}
142 		if (ref_index < MAX_PIDS) {
143 			device.items[i_index].references[ref_index].pid = lock_cmd->pid;
144 			device.items[i_index].references[ref_index].ref_count = 0;
145 			device.items[i_index].references[ref_index].down_count = 0;
146 		} else {
147 			PERROR("whoops, item ran out of available reference slots\n");
148 			return -EINVAL;
149 
150 		}
151 	} else {
152 		i_index = umplock_find_item(0);
153 
154 		if (i_index >= 0) {
155 			device.items[i_index].secure_id = lock_item->secure_id;
156 			device.items[i_index].id_ref_count = 0;
157 			device.items[i_index].usage = lock_item->usage;
158 			device.items[i_index].references[0].pid = lock_cmd->pid;
159 			device.items[i_index].references[0].ref_count = 0;
160 			device.items[i_index].references[0].down_count = 0;
161 			sema_init(&device.items[i_index].item_lock, 1);
162 		} else {
163 			PERROR("whoops, ran out of available slots\n");
164 			return -EINVAL;
165 		}
166 	}
167 
168 	return 0;
169 }
170 /** IOCTLs **/
171 
do_umplock_create(_lock_cmd_priv * lock_cmd)172 static int do_umplock_create(_lock_cmd_priv *lock_cmd)
173 {
174 	return 0;
175 }
176 
do_umplock_process(_lock_cmd_priv * lock_cmd)177 static int do_umplock_process(_lock_cmd_priv *lock_cmd)
178 {
179 	int ret, i_index, ref_index;
180 	_lock_item_s *lock_item = (_lock_item_s *)&lock_cmd->msg;
181 
182 	mutex_lock(&device.item_list_lock);
183 
184 	if (0 == lock_item->secure_id) {
185 		PERROR("IOCTL_UMPLOCK_PROCESS called with secure_id is 0, pid: %d\n", lock_cmd->pid);
186 		mutex_unlock(&device.item_list_lock);
187 		return -EINVAL;
188 	}
189 
190 	ret = do_umplock_create_locked(lock_cmd);
191 	if (ret < 0) {
192 		mutex_unlock(&device.item_list_lock);
193 		return -EINVAL;
194 	}
195 
196 	ret = umplock_find_item_by_pid(lock_cmd, &i_index, &ref_index);
197 	if (ret < 0) {
198 		/*fail to find a item*/
199 		PERROR("IOCTL_UMPLOCK_PROCESS called with invalid parameter, pid: %d\n", lock_cmd->pid);
200 		mutex_unlock(&device.item_list_lock);
201 		return -EINVAL;
202 	}
203 	device.items[i_index].references[ref_index].ref_count++;
204 	device.items[i_index].id_ref_count++;
205 	PDEBUG(1, "try to lock, pid: %d, secure_id: 0x%x, ref_count: %d\n", lock_cmd->pid, lock_item->secure_id, device.items[i_index].references[ref_index].ref_count);
206 
207 	if (lock_cmd->pid == device.items[i_index].owner) {
208 		PDEBUG(1, "already own the lock, pid: %d, secure_id: 0x%x, ref_count: %d\n", lock_cmd->pid, lock_item->secure_id, device.items[i_index].references[ref_index].ref_count);
209 		mutex_unlock(&device.item_list_lock);
210 		return 0;
211 	}
212 
213 	device.items[i_index].references[ref_index].down_count++;
214 	mutex_unlock(&device.item_list_lock);
215 	if (down_interruptible(&device.items[i_index].item_lock)) {
216 		/*wait up without hold the umplock. restore previous state and return*/
217 		mutex_lock(&device.item_list_lock);
218 		device.items[i_index].references[ref_index].ref_count--;
219 		device.items[i_index].id_ref_count--;
220 		device.items[i_index].references[ref_index].down_count--;
221 		if (0 == device.items[i_index].references[ref_index].ref_count) {
222 			device.items[i_index].references[ref_index].pid = 0;
223 			if (0 == device.items[i_index].id_ref_count) {
224 				PDEBUG(1, "release item, pid: %d, secure_id: 0x%x\n", lock_cmd->pid, lock_item->secure_id);
225 				device.items[i_index].secure_id = 0;
226 			}
227 		}
228 
229 		PERROR("failed lock, pid: %d, secure_id: 0x%x, ref_count: %d\n", lock_cmd->pid, lock_item->secure_id, device.items[i_index].references[ref_index].ref_count);
230 
231 		mutex_unlock(&device.item_list_lock);
232 		return -ERESTARTSYS;
233 	}
234 
235 	mutex_lock(&device.item_list_lock);
236 	PDEBUG(1, "got lock, pid: %d, secure_id: 0x%x, ref_count: %d\n", lock_cmd->pid, lock_item->secure_id, device.items[i_index].references[ref_index].ref_count);
237 	device.items[i_index].owner = lock_cmd->pid;
238 	mutex_unlock(&device.item_list_lock);
239 
240 	return 0;
241 }
242 
do_umplock_release(_lock_cmd_priv * lock_cmd)243 static int do_umplock_release(_lock_cmd_priv *lock_cmd)
244 {
245 	int ret, i_index, ref_index, call_up;
246 	_lock_item_s *lock_item = (_lock_item_s *)&lock_cmd->msg;
247 
248 	mutex_lock(&device.item_list_lock);
249 
250 	if (0 == lock_item->secure_id) {
251 		PERROR("IOCTL_UMPLOCK_RELEASE called with secure_id is 0, pid: %d\n", lock_cmd->pid);
252 		mutex_unlock(&device.item_list_lock);
253 		return -EINVAL;
254 	}
255 
256 	ret = umplock_find_client_valid(lock_cmd->pid);
257 	if (ret < 0) {
258 		/*lock request from an invalid client pid, do nothing*/
259 		mutex_unlock(&device.item_list_lock);
260 		return -EPERM;
261 	}
262 
263 	i_index = ref_index = -1;
264 
265 	ret = umplock_find_item_by_pid(lock_cmd, &i_index, &ref_index);
266 	if (ret < 0) {
267 		/*fail to find item*/
268 		PERROR("IOCTL_UMPLOCK_RELEASE called with invalid parameter pid: %d, secid: 0x%x\n", lock_cmd->pid, lock_item->secure_id);
269 		mutex_unlock(&device.item_list_lock);
270 		return -EINVAL;
271 	}
272 
273 	/* if the lock is not owned by this process */
274 	if (lock_cmd->pid != device.items[i_index].owner) {
275 		mutex_unlock(&device.item_list_lock);
276 		return -EPERM;
277 	}
278 
279 	/* if the ref_count is 0, that means nothing to unlock, just return */
280 	if (0 == device.items[i_index].references[ref_index].ref_count) {
281 		mutex_unlock(&device.item_list_lock);
282 		return 0;
283 	}
284 
285 	device.items[i_index].references[ref_index].ref_count--;
286 	device.items[i_index].id_ref_count--;
287 	PDEBUG(1, "unlock, pid: %d, secure_id: 0x%x, ref_count: %d\n", lock_cmd->pid, lock_item->secure_id, device.items[i_index].references[ref_index].ref_count);
288 
289 	call_up = 0;
290 	if (device.items[i_index].references[ref_index].down_count > 1) {
291 		call_up = 1;
292 		device.items[i_index].references[ref_index].down_count--;
293 	}
294 	if (0 == device.items[i_index].references[ref_index].ref_count) {
295 		device.items[i_index].references[ref_index].pid = 0;
296 		if (0 == device.items[i_index].id_ref_count) {
297 			PDEBUG(1, "release item, pid: %d, secure_id: 0x%x\n", lock_cmd->pid, lock_item->secure_id);
298 			device.items[i_index].secure_id = 0;
299 		}
300 		device.items[i_index].owner = 0;
301 		call_up = 1;
302 	}
303 	if (call_up) {
304 		PDEBUG(1, "call up, pid: %d, secure_id: 0x%x\n", lock_cmd->pid, lock_item->secure_id);
305 		up(&device.items[i_index].item_lock);
306 	}
307 	mutex_unlock(&device.item_list_lock);
308 
309 	return 0;
310 }
311 
do_umplock_zap(void)312 static int do_umplock_zap(void)
313 {
314 	int i;
315 
316 	PDEBUG(1, "ZAP ALL ENTRIES!\n");
317 
318 	mutex_lock(&device.item_list_lock);
319 
320 	for (i = 0; i < MAX_ITEMS; i++) {
321 		device.items[i].secure_id = 0;
322 		memset(&device.items[i].references, 0, sizeof(_lock_ref) * MAX_PIDS);
323 		sema_init(&device.items[i].item_lock, 1);
324 	}
325 
326 	for (i = 0; i < MAX_PIDS; i++) {
327 		device.pids[i] = 0;
328 	}
329 	mutex_unlock(&device.item_list_lock);
330 
331 	return 0;
332 }
333 
do_umplock_dump(void)334 static int do_umplock_dump(void)
335 {
336 	int i, j;
337 
338 	mutex_lock(&device.item_list_lock);
339 	PERROR("dump all the items begin\n");
340 	for (i = 0; i < MAX_ITEMS; i++) {
341 		for (j = 0; j < MAX_PIDS; j++) {
342 			if (device.items[i].secure_id != 0 && device.items[i].references[j].pid != 0) {
343 				PERROR("item[%d]->secure_id=0x%x, owner=%d\t reference[%d].ref_count=%d.pid=%d\n",
344 				       i,
345 				       device.items[i].secure_id,
346 				       device.items[i].owner,
347 				       j,
348 				       device.items[i].references[j].ref_count,
349 				       device.items[i].references[j].pid);
350 			}
351 		}
352 	}
353 	PERROR("dump all the items end\n");
354 	mutex_unlock(&device.item_list_lock);
355 
356 	return 0;
357 }
358 
do_umplock_client_add(_lock_cmd_priv * lock_cmd)359 int do_umplock_client_add(_lock_cmd_priv *lock_cmd)
360 {
361 	int i;
362 	mutex_lock(&device.item_list_lock);
363 	for (i = 0; i < MAX_PIDS; i++) {
364 		if (device.pids[i] == lock_cmd->pid) {
365 			mutex_unlock(&device.item_list_lock);
366 			return 0;
367 		}
368 	}
369 	for (i = 0; i < MAX_PIDS; i++) {
370 		if (device.pids[i] == 0) {
371 			device.pids[i] = lock_cmd->pid;
372 			break;
373 		}
374 	}
375 	mutex_unlock(&device.item_list_lock);
376 	if (i == MAX_PIDS) {
377 		PERROR("Oops, Run out of client slots\n ");
378 		return -EINVAL;
379 	}
380 	return 0;
381 }
382 
do_umplock_client_delete(_lock_cmd_priv * lock_cmd)383 int do_umplock_client_delete(_lock_cmd_priv *lock_cmd)
384 {
385 	int p_index = -1, i_index = -1, ref_index = -1;
386 	int ret;
387 	_lock_item_s *lock_item;
388 	lock_item = (_lock_item_s *)&lock_cmd->msg;
389 
390 	mutex_lock(&device.item_list_lock);
391 	p_index = umplock_find_client_valid(lock_cmd->pid);
392 	/*lock item pid is not valid.*/
393 	if (p_index < 0) {
394 		mutex_unlock(&device.item_list_lock);
395 		return 0;
396 	}
397 
398 	/*walk through umplock item list and release reference attached to this client*/
399 	for (i_index = 0; i_index < MAX_ITEMS; i_index++) {
400 		lock_item->secure_id = device.items[i_index].secure_id;
401 
402 		/*find the item index and reference slot for the lock_item*/
403 		ret = umplock_find_item_by_pid(lock_cmd, &i_index, &ref_index);
404 
405 		if (ret < 0) {
406 			/*client has no reference on this umplock item, skip*/
407 			continue;
408 		}
409 		while (device.items[i_index].references[ref_index].ref_count) {
410 			/*release references on this client*/
411 
412 			PDEBUG(1, "delete client, pid: %d, ref_count: %d\n", lock_cmd->pid, device.items[i_index].references[ref_index].ref_count);
413 
414 			mutex_unlock(&device.item_list_lock);
415 			do_umplock_release(lock_cmd);
416 			mutex_lock(&device.item_list_lock);
417 		}
418 	}
419 
420 	/*remove the pid from umplock valid pid list*/
421 	device.pids[p_index] = 0;
422 	mutex_unlock(&device.item_list_lock);
423 
424 	return 0;
425 }
426 
umplock_driver_ioctl(struct file * f,unsigned int cmd,unsigned long arg)427 static long umplock_driver_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
428 {
429 	int ret;
430 	uint32_t size = _IOC_SIZE(cmd);
431 	_lock_cmd_priv lock_cmd ;
432 
433 	if (_IOC_TYPE(cmd) != LOCK_IOCTL_GROUP) {
434 		return -ENOTTY;
435 	}
436 
437 	if (_IOC_NR(cmd) >= LOCK_IOCTL_MAX_CMDS) {
438 		return -ENOTTY;
439 	}
440 
441 	switch (cmd) {
442 	case LOCK_IOCTL_CREATE:
443 		if (size != sizeof(_lock_item_s)) {
444 			return -ENOTTY;
445 		}
446 
447 		if (copy_from_user(&lock_cmd.msg, (void __user *)arg, size)) {
448 			return -EFAULT;
449 		}
450 		lock_cmd.pid = (u32)current->tgid;
451 		ret = do_umplock_create(&lock_cmd);
452 		if (ret) {
453 			return ret;
454 		}
455 		return 0;
456 
457 	case LOCK_IOCTL_PROCESS:
458 		if (size != sizeof(_lock_item_s)) {
459 			return -ENOTTY;
460 		}
461 
462 		if (copy_from_user(&lock_cmd.msg, (void __user *)arg, size)) {
463 			return -EFAULT;
464 		}
465 		lock_cmd.pid = (u32)current->tgid;
466 		return do_umplock_process(&lock_cmd);
467 
468 	case LOCK_IOCTL_RELEASE:
469 		if (size != sizeof(_lock_item_s)) {
470 			return -ENOTTY;
471 		}
472 
473 		if (copy_from_user(&lock_cmd.msg, (void __user *)arg, size)) {
474 			return -EFAULT;
475 		}
476 		lock_cmd.pid = (u32)current->tgid;
477 		ret = do_umplock_release(&lock_cmd);
478 		if (ret) {
479 			return ret;
480 		}
481 		return 0;
482 
483 	case LOCK_IOCTL_ZAP:
484 		do_umplock_zap();
485 		return 0;
486 
487 	case LOCK_IOCTL_DUMP:
488 		do_umplock_dump();
489 		return 0;
490 	}
491 
492 	return -ENOIOCTLCMD;
493 }
494 
umplock_driver_open(struct inode * inode,struct file * filp)495 static int umplock_driver_open(struct inode *inode, struct file *filp)
496 {
497 	_lock_cmd_priv lock_cmd;
498 
499 	atomic_inc(&device.sessions);
500 	PDEBUG(1, "OPEN SESSION (%i references)\n", atomic_read(&device.sessions));
501 
502 	lock_cmd.pid = (u32)current->tgid;
503 	do_umplock_client_add(&lock_cmd);
504 
505 	return 0;
506 }
507 
umplock_driver_release(struct inode * inode,struct file * filp)508 static int umplock_driver_release(struct inode *inode, struct file *filp)
509 {
510 	int sessions = 0;
511 	_lock_cmd_priv lock_cmd;
512 
513 	lock_cmd.pid = (u32)current->tgid;
514 	do_umplock_client_delete(&lock_cmd);
515 
516 	mutex_lock(&device.item_list_lock);
517 	atomic_dec(&device.sessions);
518 	sessions = atomic_read(&device.sessions);
519 	PDEBUG(1, "CLOSE SESSION (%i references)\n", sessions);
520 	mutex_unlock(&device.item_list_lock);
521 	if (sessions == 0) {
522 		do_umplock_zap();
523 	}
524 
525 	return 0;
526 }
527 
528 static struct file_operations umplock_fops = {
529 	.owner   = THIS_MODULE,
530 	.open    = umplock_driver_open,
531 	.release = umplock_driver_release,
532 	.unlocked_ioctl = umplock_driver_ioctl,
533 };
534 
umplock_device_initialize(void)535 int umplock_device_initialize(void)
536 {
537 	int err;
538 
539 	err = alloc_chrdev_region(&umplock_dev, 0, 1, umplock_dev_name);
540 
541 	if (0 == err) {
542 		memset(&umplock_device, 0, sizeof(umplock_device));
543 		cdev_init(&umplock_device.cdev, &umplock_fops);
544 		umplock_device.cdev.owner = THIS_MODULE;
545 		umplock_device.cdev.ops = &umplock_fops;
546 
547 		err = cdev_add(&umplock_device.cdev, umplock_dev, 1);
548 		if (0 == err) {
549 			umplock_device.umplock_class = class_create(THIS_MODULE, umplock_dev_name);
550 			if (IS_ERR(umplock_device.umplock_class)) {
551 				err = PTR_ERR(umplock_device.umplock_class);
552 			} else {
553 				struct device *mdev;
554 				mdev = device_create(umplock_device.umplock_class, NULL, umplock_dev, NULL, umplock_dev_name);
555 				if (!IS_ERR(mdev)) {
556 					return 0; /* all ok */
557 				}
558 
559 				err = PTR_ERR(mdev);
560 				class_destroy(umplock_device.umplock_class);
561 			}
562 			cdev_del(&umplock_device.cdev);
563 		}
564 
565 		unregister_chrdev_region(umplock_dev, 1);
566 	} else {
567 		PERROR("alloc chardev region failed\n");
568 	}
569 
570 	return err;
571 }
572 
umplock_device_terminate(void)573 void umplock_device_terminate(void)
574 {
575 	device_destroy(umplock_device.umplock_class, umplock_dev);
576 	class_destroy(umplock_device.umplock_class);
577 
578 	cdev_del(&umplock_device.cdev);
579 	unregister_chrdev_region(umplock_dev, 1);
580 }
581 
umplock_initialize_module(void)582 static int __init umplock_initialize_module(void)
583 {
584 	PDEBUG(1, "Inserting UMP lock device driver. Compiled: %s, time: %s\n", __DATE__, __TIME__);
585 
586 	mutex_init(&device.item_list_lock);
587 	if (umplock_device_initialize() != 0) {
588 		PERROR("UMP lock device driver init failed\n");
589 		return -ENOTTY;
590 	}
591 	memset(&device.items, 0, sizeof(umplock_item) * MAX_ITEMS);
592 	memset(&device.pids, 0, sizeof(u32) * MAX_PIDS);
593 	atomic_set(&device.sessions, 0);
594 
595 	PDEBUG(1, "UMP lock device driver loaded\n");
596 
597 	return 0;
598 }
599 
umplock_cleanup_module(void)600 static void __exit umplock_cleanup_module(void)
601 {
602 	PDEBUG(1, "unloading UMP lock module\n");
603 
604 	memset(&device.items, 0, sizeof(umplock_item) * MAX_ITEMS);
605 	memset(&device.pids, 0, sizeof(u32) * MAX_PIDS);
606 	umplock_device_terminate();
607 	mutex_destroy(&device.item_list_lock);
608 
609 	PDEBUG(1, "UMP lock module unloaded\n");
610 }
611 
612 module_init(umplock_initialize_module);
613 module_exit(umplock_cleanup_module);
614 
615 
616 MODULE_LICENSE("GPL");
617 MODULE_AUTHOR("ARM Ltd.");
618 MODULE_DESCRIPTION("ARM UMP locker");
619