2 * Plan 9 style capability device implementation for the Linux Kernel
4 * Copyright 2008, 2009 Ashwin Ganti <ashwin.ganti@gmail.com>
6 * Released under the GPLv2
9 #include <linux/module.h>
10 #include <linux/moduleparam.h>
11 #include <linux/init.h>
12 #include <linux/kernel.h>
13 #include <linux/slab.h>
15 #include <linux/errno.h>
16 #include <linux/types.h>
17 #include <linux/proc_fs.h>
18 #include <linux/fcntl.h>
19 #include <linux/cdev.h>
20 #include <linux/syscalls.h>
21 #include <linux/uaccess.h>
22 #include <linux/list.h>
23 #include <linux/err.h>
25 #include <linux/string.h>
26 #include <linux/crypto.h>
27 #include <linux/highmem.h>
28 #include <linux/jiffies.h>
29 #include <linux/timex.h>
30 #include <linux/interrupt.h>
31 #include <linux/scatterlist.h>
32 #include <linux/crypto.h>
33 #include <linux/sched.h>
34 #include <linux/cred.h>
35 #include <asm/system.h>
42 #define CAP_NR_DEVS 2 /* caphash and capuse */
46 #define CAP_NODE_SIZE 20
49 #define MAX_DIGEST_SIZE 20
52 char data[CAP_NODE_SIZE];
53 struct list_head list;
57 struct cap_node *head;
64 static int cap_major = CAP_MAJOR;
66 static int cap_nr_devs = CAP_NR_DEVS;
67 static int cap_node_size = CAP_NODE_SIZE;
69 module_param(cap_major, int, S_IRUGO);
70 module_param(cap_minor, int, S_IRUGO);
71 module_param(cap_nr_devs, int, S_IRUGO);
73 MODULE_AUTHOR("Ashwin Ganti");
74 MODULE_LICENSE("GPL");
76 static struct cap_dev *cap_devices;
78 static void hexdump(unsigned char *buf, unsigned int len)
81 printk("%02x", *buf++);
85 static char *cap_hash(char *plain_text, unsigned int plain_text_size,
86 char *key, unsigned int key_size)
88 struct scatterlist sg;
90 struct crypto_hash *tfm;
91 struct hash_desc desc;
94 tfm = crypto_alloc_hash("hmac(sha1)", 0, CRYPTO_ALG_ASYNC);
97 "failed to load transform for hmac(sha1): %ld\n",
105 result = kzalloc(MAX_DIGEST_SIZE, GFP_KERNEL);
107 printk(KERN_ERR "out of memory!\n");
111 sg_set_buf(&sg, plain_text, plain_text_size);
113 ret = crypto_hash_setkey(tfm, key, key_size);
115 printk(KERN_ERR "setkey() failed ret=%d\n", ret);
121 ret = crypto_hash_digest(&desc, &sg, plain_text_size, result);
123 printk(KERN_ERR "digest () failed ret=%d\n", ret);
129 printk(KERN_DEBUG "crypto hash digest size %d\n",
130 crypto_hash_digestsize(tfm));
131 hexdump(result, MAX_DIGEST_SIZE);
134 crypto_free_hash(tfm);
138 static int cap_trim(struct cap_dev *dev)
140 struct cap_node *tmp;
141 struct list_head *pos, *q;
142 if (dev->head != NULL) {
143 list_for_each_safe(pos, q, &(dev->head->list)) {
144 tmp = list_entry(pos, struct cap_node, list);
152 static int cap_open(struct inode *inode, struct file *filp)
155 dev = container_of(inode->i_cdev, struct cap_dev, cdev);
156 filp->private_data = dev;
158 /* trim to 0 the length of the device if open was write-only */
159 if ((filp->f_flags & O_ACCMODE) == O_WRONLY) {
160 if (down_interruptible(&dev->sem))
165 /* initialise the head if it is NULL */
166 if (dev->head == NULL) {
167 dev->head = kmalloc(sizeof(struct cap_node), GFP_KERNEL);
168 INIT_LIST_HEAD(&(dev->head->list));
173 static int cap_release(struct inode *inode, struct file *filp)
178 static ssize_t cap_write(struct file *filp, const char __user *buf,
179 size_t count, loff_t *f_pos)
181 struct cap_node *node_ptr, *tmp;
182 struct list_head *pos;
183 struct cap_dev *dev = filp->private_data;
184 ssize_t retval = -ENOMEM;
186 int len, target_int, source_int, flag = 0;
187 char *user_buf, *user_buf_running, *source_user, *target_user,
188 *rand_str, *hash_str, *result;
190 if (down_interruptible(&dev->sem))
193 node_ptr = kmalloc(sizeof(struct cap_node), GFP_KERNEL);
194 user_buf = kzalloc(count, GFP_KERNEL);
196 if (copy_from_user(user_buf, buf, count)) {
202 * If the minor number is 0 ( /dev/caphash ) then simply add the
203 * hashed capability supplied by the user to the list of hashes
205 if (0 == iminor(filp->f_dentry->d_inode)) {
206 printk(KERN_INFO "Capability being written to /dev/caphash : \n");
207 hexdump(user_buf, count);
208 memcpy(node_ptr->data, user_buf, count);
209 list_add(&(node_ptr->list), &(dev->head->list));
212 * break the supplied string into tokens with @ as the
213 * delimiter If the string is "user1@user2@randomstring" we
214 * need to split it and hash 'user1@user2' using 'randomstring'
217 user_buf_running = kstrdup(user_buf, GFP_KERNEL);
218 source_user = strsep(&user_buf_running, "@");
219 target_user = strsep(&user_buf_running, "@");
220 rand_str = strsep(&user_buf_running, "@");
222 /* hash the string user1@user2 with rand_str as the key */
223 len = strlen(source_user) + strlen(target_user) + 1;
224 hash_str = kzalloc(len, GFP_KERNEL);
225 strcat(hash_str, source_user);
226 strcat(hash_str, "@");
227 strcat(hash_str, target_user);
229 printk(KERN_ALERT "the source user is %s \n", source_user);
230 printk(KERN_ALERT "the target user is %s \n", target_user);
232 result = cap_hash(hash_str, len, rand_str, strlen(rand_str));
233 if (NULL == result) {
237 memcpy(node_ptr->data, result, CAP_NODE_SIZE);
238 /* Change the process's uid if the hash is present in the
241 list_for_each(pos, &(cap_devices->head->list)) {
243 * Change the user id of the process if the hashes
248 list_entry(pos, struct cap_node,
251 target_int = (unsigned int)
252 simple_strtol(target_user, NULL, 0);
253 source_int = (unsigned int)
254 simple_strtol(source_user, NULL, 0);
258 * Check whether the process writing to capuse
259 * is actually owned by the source owner
261 if (source_int != current_uid()) {
263 "Process is not owned by the source user of the capability.\n");
268 * What all id's need to be changed here? uid,
269 * euid, fsid, savedids ?? Currently I am
270 * changing the effective user id since most of
271 * the authorisation decisions are based on it
273 new = prepare_creds();
278 new->uid = (uid_t) target_int;
279 new->euid = (uid_t) target_int;
280 retval = commit_creds(new);
285 * Remove the capability from the list and
288 tmp = list_entry(pos, struct cap_node, list);
296 * The capability is not present in the list of the
297 * hashes stored, hence return failure
300 "Invalid capabiliy written to /dev/capuse \n");
307 /* update the size */
308 if (dev->size < *f_pos)
316 static const struct file_operations cap_fops = {
317 .owner = THIS_MODULE,
320 .release = cap_release,
323 static void cap_cleanup_module(void)
326 dev_t devno = MKDEV(cap_major, cap_minor);
328 for (i = 0; i < cap_nr_devs; i++) {
329 cap_trim(cap_devices + i);
330 cdev_del(&cap_devices[i].cdev);
334 unregister_chrdev_region(devno, cap_nr_devs);
338 static void cap_setup_cdev(struct cap_dev *dev, int index)
340 int err, devno = MKDEV(cap_major, cap_minor + index);
341 cdev_init(&dev->cdev, &cap_fops);
342 dev->cdev.owner = THIS_MODULE;
343 dev->cdev.ops = &cap_fops;
344 err = cdev_add(&dev->cdev, devno, 1);
346 printk(KERN_NOTICE "Error %d adding cap%d", err, index);
349 static int cap_init_module(void)
355 dev = MKDEV(cap_major, cap_minor);
356 result = register_chrdev_region(dev, cap_nr_devs, "cap");
358 result = alloc_chrdev_region(&dev, cap_minor, cap_nr_devs,
360 cap_major = MAJOR(dev);
364 printk(KERN_WARNING "cap: can't get major %d\n",
369 cap_devices = kzalloc(cap_nr_devs * sizeof(struct cap_dev),
376 /* Initialize each device. */
377 for (i = 0; i < cap_nr_devs; i++) {
378 cap_devices[i].node_size = cap_node_size;
379 init_MUTEX(&cap_devices[i].sem);
380 cap_setup_cdev(&cap_devices[i], i);
386 cap_cleanup_module();
390 module_init(cap_init_module);
391 module_exit(cap_cleanup_module);