]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/ipv4/cipso_ipv4.c
[NETLINK]: Do precise netlink message allocations where possible
[linux-2.6-omap-h63xx.git] / net / ipv4 / cipso_ipv4.c
index e6ce0b3ba62a49ed8aef7ae0c6f4541a67a3d53d..6460233407c786f4138671765786d98db3bab6ae 100644 (file)
@@ -43,6 +43,7 @@
 #include <net/tcp.h>
 #include <net/netlabel.h>
 #include <net/cipso_ipv4.h>
+#include <asm/atomic.h>
 #include <asm/bug.h>
 
 struct cipso_v4_domhsh_entry {
@@ -79,7 +80,7 @@ struct cipso_v4_map_cache_entry {
        unsigned char *key;
        size_t key_len;
 
-       struct netlbl_lsm_cache lsm_data;
+       struct netlbl_lsm_cache *lsm_data;
 
        u32 activity;
        struct list_head list;
@@ -188,13 +189,14 @@ static void cipso_v4_doi_domhsh_free(struct rcu_head *entry)
  * @entry: the entry to free
  *
  * Description:
- * This function frees the memory associated with a cache entry.
+ * This function frees the memory associated with a cache entry including the
+ * LSM cache data if there are no longer any users, i.e. reference count == 0.
  *
  */
 static void cipso_v4_cache_entry_free(struct cipso_v4_map_cache_entry *entry)
 {
-       if (entry->lsm_data.free)
-               entry->lsm_data.free(entry->lsm_data.data);
+       if (entry->lsm_data)
+               netlbl_secattr_cache_free(entry->lsm_data);
        kfree(entry->key);
        kfree(entry);
 }
@@ -315,8 +317,8 @@ static int cipso_v4_cache_check(const unsigned char *key,
                    entry->key_len == key_len &&
                    memcmp(entry->key, key, key_len) == 0) {
                        entry->activity += 1;
-                       secattr->cache.free = entry->lsm_data.free;
-                       secattr->cache.data = entry->lsm_data.data;
+                       atomic_inc(&entry->lsm_data->refcount);
+                       secattr->cache = entry->lsm_data;
                        if (prev_entry == NULL) {
                                spin_unlock_bh(&cipso_v4_cache[bkt].lock);
                                return 0;
@@ -383,8 +385,8 @@ int cipso_v4_cache_add(const struct sk_buff *skb,
        memcpy(entry->key, cipso_ptr, cipso_ptr_len);
        entry->key_len = cipso_ptr_len;
        entry->hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_len);
-       entry->lsm_data.free = secattr->cache.free;
-       entry->lsm_data.data = secattr->cache.data;
+       atomic_inc(&secattr->cache->refcount);
+       entry->lsm_data = secattr->cache;
 
        bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETBITS - 1);
        spin_lock_bh(&cipso_v4_cache[bkt].lock);
@@ -474,6 +476,7 @@ doi_add_failure_rlock:
 /**
  * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine
  * @doi: the DOI value
+ * @audit_secid: the LSM secid to use in the audit message
  * @callback: the DOI cleanup/free callback
  *
  * Description:
@@ -483,7 +486,9 @@ doi_add_failure_rlock:
  * success and negative values on failure.
  *
  */
-int cipso_v4_doi_remove(u32 doi, void (*callback) (struct rcu_head * head))
+int cipso_v4_doi_remove(u32 doi,
+                       struct netlbl_audit *audit_info,
+                       void (*callback) (struct rcu_head * head))
 {
        struct cipso_v4_doi *doi_def;
        struct cipso_v4_domhsh_entry *dom_iter;
@@ -502,7 +507,8 @@ int cipso_v4_doi_remove(u32 doi, void (*callback) (struct rcu_head * head))
                spin_unlock(&cipso_v4_doi_list_lock);
                list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list)
                        if (dom_iter->valid)
-                               netlbl_domhsh_remove(dom_iter->domain);
+                               netlbl_domhsh_remove(dom_iter->domain,
+                                                    audit_info);
                cipso_v4_cache_invalidate();
                rcu_read_unlock();
 
@@ -767,13 +773,15 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def,
 {
        int cat = -1;
        u32 bitmap_len_bits = bitmap_len * 8;
-       u32 cipso_cat_size = doi_def->map.std->cat.cipso_size;
-       u32 *cipso_array = doi_def->map.std->cat.cipso;
+       u32 cipso_cat_size;
+       u32 *cipso_array;
 
        switch (doi_def->type) {
        case CIPSO_V4_MAP_PASS:
                return 0;
        case CIPSO_V4_MAP_STD:
+               cipso_cat_size = doi_def->map.std->cat.cipso_size;
+               cipso_array = doi_def->map.std->cat.cipso;
                for (;;) {
                        cat = cipso_v4_bitmap_walk(bitmap,
                                                   bitmap_len_bits,
@@ -819,19 +827,21 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
        u32 net_spot_max = 0;
        u32 host_clen_bits = host_cat_len * 8;
        u32 net_clen_bits = net_cat_len * 8;
-       u32 host_cat_size = doi_def->map.std->cat.local_size;
-       u32 *host_cat_array = doi_def->map.std->cat.local;
+       u32 host_cat_size;
+       u32 *host_cat_array;
 
        switch (doi_def->type) {
        case CIPSO_V4_MAP_PASS:
-               net_spot_max = host_cat_len - 1;
-               while (net_spot_max > 0 && host_cat[net_spot_max] == 0)
+               net_spot_max = host_cat_len;
+               while (net_spot_max > 0 && host_cat[net_spot_max - 1] == 0)
                        net_spot_max--;
                if (net_spot_max > net_cat_len)
                        return -EINVAL;
                memcpy(net_cat, host_cat, net_spot_max);
                return net_spot_max;
        case CIPSO_V4_MAP_STD:
+               host_cat_size = doi_def->map.std->cat.local_size;
+               host_cat_array = doi_def->map.std->cat.local;
                for (;;) {
                        host_spot = cipso_v4_bitmap_walk(host_cat,
                                                         host_clen_bits,
@@ -887,8 +897,8 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
        int net_spot = -1;
        u32 net_clen_bits = net_cat_len * 8;
        u32 host_clen_bits = host_cat_len * 8;
-       u32 net_cat_size = doi_def->map.std->cat.cipso_size;
-       u32 *net_cat_array = doi_def->map.std->cat.cipso;
+       u32 net_cat_size;
+       u32 *net_cat_array;
 
        switch (doi_def->type) {
        case CIPSO_V4_MAP_PASS:
@@ -897,6 +907,8 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
                memcpy(host_cat, net_cat, net_cat_len);
                return net_cat_len;
        case CIPSO_V4_MAP_STD:
+               net_cat_size = doi_def->map.std->cat.cipso_size;
+               net_cat_array = doi_def->map.std->cat.cipso;
                for (;;) {
                        net_spot = cipso_v4_bitmap_walk(net_cat,
                                                        net_clen_bits,
@@ -1295,7 +1307,8 @@ int cipso_v4_socket_setattr(const struct socket *sock,
 
        /* We can't use ip_options_get() directly because it makes a call to
         * ip_options_get_alloc() which allocates memory with GFP_KERNEL and
-        * we can't block here. */
+        * we won't always have CAP_NET_RAW even though we _always_ want to
+        * set the IPOPT_CIPSO option. */
        opt_len = (buf_len + 3) & ~3;
        opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC);
        if (opt == NULL) {
@@ -1305,11 +1318,9 @@ int cipso_v4_socket_setattr(const struct socket *sock,
        memcpy(opt->__data, buf, buf_len);
        opt->optlen = opt_len;
        opt->is_data = 1;
+       opt->cipso = sizeof(struct iphdr);
        kfree(buf);
        buf = NULL;
-       ret_val = ip_options_compile(opt, NULL);
-       if (ret_val != 0)
-               goto socket_setattr_failure;
 
        sk_inet = inet_sk(sk);
        if (sk_inet->is_icsk) {