bci: some more code for testing
[pandora-kernel.git] / security / device_cgroup.c
index 236fffa..46f2397 100644 (file)
@@ -41,6 +41,7 @@ struct dev_whitelist_item {
        short type;
        short access;
        struct list_head list;
+       struct rcu_head rcu;
 };
 
 struct dev_cgroup {
@@ -133,11 +134,19 @@ static int dev_whitelist_add(struct dev_cgroup *dev_cgroup,
        }
 
        if (whcopy != NULL)
-               list_add_tail(&whcopy->list, &dev_cgroup->whitelist);
+               list_add_tail_rcu(&whcopy->list, &dev_cgroup->whitelist);
        spin_unlock(&dev_cgroup->lock);
        return 0;
 }
 
+static void whitelist_item_free(struct rcu_head *rcu)
+{
+       struct dev_whitelist_item *item;
+
+       item = container_of(rcu, struct dev_whitelist_item, rcu);
+       kfree(item);
+}
+
 /*
  * called under cgroup_lock()
  * since the list is visible to other tasks, we need the spinlock also
@@ -161,8 +170,8 @@ static void dev_whitelist_rm(struct dev_cgroup *dev_cgroup,
 remove:
                walk->access &= ~wh->access;
                if (!walk->access) {
-                       list_del(&walk->list);
-                       kfree(walk);
+                       list_del_rcu(&walk->list);
+                       call_rcu(&walk->rcu, whitelist_item_free);
                }
        }
        spin_unlock(&dev_cgroup->lock);
@@ -193,7 +202,7 @@ static struct cgroup_subsys_state *devcgroup_create(struct cgroup_subsys *ss,
                }
                wh->minor = wh->major = ~0;
                wh->type = DEV_ALL;
-               wh->access = ACC_MKNOD | ACC_READ | ACC_WRITE;
+               wh->access = ACC_MASK;
                list_add(&wh->list, &dev_cgroup->whitelist);
        } else {
                parent_dev_cgroup = cgroup_to_devcgroup(parent_cgroup);
@@ -255,11 +264,10 @@ static char type_to_char(short type)
 
 static void set_majmin(char *str, unsigned m)
 {
-       memset(str, 0, MAJMINLEN);
        if (m == ~0)
-               sprintf(str, "*");
+               strcpy(str, "*");
        else
-               snprintf(str, MAJMINLEN, "%u", m);
+               sprintf(str, "%u", m);
 }
 
 static int devcgroup_seq_read(struct cgroup *cgroup, struct cftype *cft,
@@ -269,15 +277,15 @@ static int devcgroup_seq_read(struct cgroup *cgroup, struct cftype *cft,
        struct dev_whitelist_item *wh;
        char maj[MAJMINLEN], min[MAJMINLEN], acc[ACCLEN];
 
-       spin_lock(&devcgroup->lock);
-       list_for_each_entry(wh, &devcgroup->whitelist, list) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(wh, &devcgroup->whitelist, list) {
                set_access(acc, wh->access);
                set_majmin(maj, wh->major);
                set_majmin(min, wh->minor);
                seq_printf(m, "%c %s:%s %s\n", type_to_char(wh->type),
                           maj, min, acc);
        }
-       spin_unlock(&devcgroup->lock);
+       rcu_read_unlock();
 
        return 0;
 }
@@ -351,6 +359,7 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
 {
        struct dev_cgroup *cur_devcgroup;
        const char *b;
+       char *endp;
        int retval = 0, count;
        struct dev_whitelist_item wh;
 
@@ -386,11 +395,8 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
                wh.major = ~0;
                b++;
        } else if (isdigit(*b)) {
-               wh.major = 0;
-               while (isdigit(*b)) {
-                       wh.major = wh.major*10+(*b-'0');
-                       b++;
-               }
+               wh.major = simple_strtoul(b, &endp, 10);
+               b = endp;
        } else {
                return -EINVAL;
        }
@@ -403,11 +409,8 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
                wh.minor = ~0;
                b++;
        } else if (isdigit(*b)) {
-               wh.minor = 0;
-               while (isdigit(*b)) {
-                       wh.minor = wh.minor*10+(*b-'0');
-                       b++;
-               }
+               wh.minor = simple_strtoul(b, &endp, 10);
+               b = endp;
        } else {
                return -EINVAL;
        }
@@ -505,13 +508,12 @@ int devcgroup_inode_permission(struct inode *inode, int mask)
                return 0;
        if (!S_ISBLK(inode->i_mode) && !S_ISCHR(inode->i_mode))
                return 0;
-       dev_cgroup = css_to_devcgroup(task_subsys_state(current,
-                               devices_subsys_id));
-       if (!dev_cgroup)
-               return 0;
 
-       spin_lock(&dev_cgroup->lock);
-       list_for_each_entry(wh, &dev_cgroup->whitelist, list) {
+       rcu_read_lock();
+
+       dev_cgroup = task_devcgroup(current);
+
+       list_for_each_entry_rcu(wh, &dev_cgroup->whitelist, list) {
                if (wh->type & DEV_ALL)
                        goto acc_check;
                if ((wh->type & DEV_BLOCK) && !S_ISBLK(inode->i_mode))
@@ -527,10 +529,11 @@ acc_check:
                        continue;
                if ((mask & MAY_READ) && !(wh->access & ACC_READ))
                        continue;
-               spin_unlock(&dev_cgroup->lock);
+               rcu_read_unlock();
                return 0;
        }
-       spin_unlock(&dev_cgroup->lock);
+
+       rcu_read_unlock();
 
        return -EPERM;
 }
@@ -540,12 +543,10 @@ int devcgroup_inode_mknod(int mode, dev_t dev)
        struct dev_cgroup *dev_cgroup;
        struct dev_whitelist_item *wh;
 
-       dev_cgroup = css_to_devcgroup(task_subsys_state(current,
-                               devices_subsys_id));
-       if (!dev_cgroup)
-               return 0;
+       rcu_read_lock();
+
+       dev_cgroup = task_devcgroup(current);
 
-       spin_lock(&dev_cgroup->lock);
        list_for_each_entry(wh, &dev_cgroup->whitelist, list) {
                if (wh->type & DEV_ALL)
                        goto acc_check;
@@ -560,9 +561,11 @@ int devcgroup_inode_mknod(int mode, dev_t dev)
 acc_check:
                if (!(wh->access & ACC_MKNOD))
                        continue;
-               spin_unlock(&dev_cgroup->lock);
+               rcu_read_unlock();
                return 0;
        }
-       spin_unlock(&dev_cgroup->lock);
+
+       rcu_read_unlock();
+
        return -EPERM;
 }