From 714e85be3557222bc25f69c252326207c900a7db Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 20:51:49 -0800 Subject: [IPV6]: Assorted trivial endianness annotations. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/cipso_ipv4.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net/ipv4/cipso_ipv4.c') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 6460233407c..c3a61ebbade 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -966,7 +966,7 @@ static int cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def, buf[0] = IPOPT_CIPSO; buf[1] = CIPSO_V4_HDR_LEN + len; - *(u32 *)&buf[2] = htonl(doi_def->doi); + *(__be32 *)&buf[2] = htonl(doi_def->doi); return 0; } @@ -1140,7 +1140,7 @@ int cipso_v4_validate(unsigned char **option) } rcu_read_lock(); - doi_def = cipso_v4_doi_getdef(ntohl(*((u32 *)&opt[2]))); + doi_def = cipso_v4_doi_getdef(ntohl(*((__be32 *)&opt[2]))); if (doi_def == NULL) { err_offset = 2; goto validate_return_locked; @@ -1370,7 +1370,7 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) if (ret_val == 0) return ret_val; - doi = ntohl(*(u32 *)&cipso_ptr[2]); + doi = ntohl(*(__be32 *)&cipso_ptr[2]); rcu_read_lock(); doi_def = cipso_v4_doi_getdef(doi); if (doi_def == NULL) { @@ -1436,7 +1436,7 @@ int cipso_v4_skbuff_getattr(const struct sk_buff *skb, if (cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr) == 0) return 0; - doi = ntohl(*(u32 *)&cipso_ptr[2]); + doi = ntohl(*(__be32 *)&cipso_ptr[2]); rcu_read_lock(); doi_def = cipso_v4_doi_getdef(doi); if (doi_def == NULL) -- cgit v1.2.3 From fac5d7315126f4b6745a8565c3a875617e02f8b8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 17 Nov 2006 11:14:16 -0200 Subject: [NETLABEL]: Use kmemdup in cipso_ipv4.c Code diff stats: [acme@newtoy net-2.6.20]$ codiff /tmp/cipso_ipv4.o.before /tmp/cipso_ipv4.o.after /pub/scm/linux/kernel/git/acme/net-2.6.20/net/ipv4/cipso_ipv4.c: cipso_v4_cache_add | -46 1 function changed, 46 bytes removed [acme@newtoy net-2.6.20]$ Signed-off-by: Arnaldo Carvalho de Melo --- net/ipv4/cipso_ipv4.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net/ipv4/cipso_ipv4.c') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index c3a61ebbade..095038ad72a 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -377,12 +377,11 @@ int cipso_v4_cache_add(const struct sk_buff *skb, entry = kzalloc(sizeof(*entry), GFP_ATOMIC); if (entry == NULL) return -ENOMEM; - entry->key = kmalloc(cipso_ptr_len, GFP_ATOMIC); + entry->key = kmemdup(cipso_ptr, cipso_ptr_len, GFP_ATOMIC); if (entry->key == NULL) { ret_val = -ENOMEM; goto cache_add_failure; } - 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); atomic_inc(&secattr->cache->refcount); -- cgit v1.2.3 From 701a90bad99b8081a824cca52c178c8fc8f46bb2 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 17 Nov 2006 17:38:46 -0500 Subject: NetLabel: make netlbl_lsm_secattr struct easier/quicker to understand The existing netlbl_lsm_secattr struct required the LSM to check all of the fields to determine if any security attributes were present resulting in a lot of work in the common case of no attributes. This patch adds a 'flags' field which is used to indicate which attributes are present in the structure; this should allow the LSM to do a quick comparison to determine if the structure holds any security attributes. Example: if (netlbl_lsm_secattr->flags) /* security attributes present */ else /* NO security attributes present */ Signed-off-by: Paul Moore Signed-off-by: James Morris --- net/ipv4/cipso_ipv4.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'net/ipv4/cipso_ipv4.c') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 095038ad72a..f0a0785047f 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -319,6 +319,7 @@ static int cipso_v4_cache_check(const unsigned char *key, entry->activity += 1; atomic_inc(&entry->lsm_data->refcount); secattr->cache = entry->lsm_data; + secattr->flags |= NETLBL_SECATTR_CACHE; if (prev_entry == NULL) { spin_unlock_bh(&cipso_v4_cache[bkt].lock); return 0; @@ -991,12 +992,15 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def, unsigned char **buffer, u32 *buffer_len) { - int ret_val = -EPERM; + int ret_val; unsigned char *buf = NULL; u32 buf_len; u32 level; - if (secattr->mls_cat) { + if ((secattr->flags & NETLBL_SECATTR_MLS_LVL) == 0) + return -EPERM; + + if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { buf = kzalloc(CIPSO_V4_HDR_LEN + 4 + CIPSO_V4_TAG1_CAT_LEN, GFP_ATOMIC); if (buf == NULL) @@ -1013,10 +1017,10 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def, /* This will send packets using the "optimized" format when * possibile as specified in section 3.4.2.6 of the * CIPSO draft. */ - if (cipso_v4_rbm_optfmt && (ret_val > 0 && ret_val < 10)) - ret_val = 10; - - buf_len = 4 + ret_val; + if (cipso_v4_rbm_optfmt && ret_val > 0 && ret_val <= 10) + buf_len = 14; + else + buf_len = 4 + ret_val; } else { buf = kzalloc(CIPSO_V4_HDR_LEN + 4, GFP_ATOMIC); if (buf == NULL) @@ -1070,7 +1074,7 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def, if (ret_val != 0) return ret_val; secattr->mls_lvl = level; - secattr->mls_lvl_vld = 1; + secattr->flags |= NETLBL_SECATTR_MLS_LVL; if (tag_len > 4) { switch (doi_def->type) { @@ -1094,8 +1098,10 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def, if (ret_val < 0) { kfree(secattr->mls_cat); return ret_val; + } else if (ret_val > 0) { + secattr->mls_cat_len = ret_val; + secattr->flags |= NETLBL_SECATTR_MLS_CAT; } - secattr->mls_cat_len = ret_val; } return 0; -- cgit v1.2.3 From 05e00cbf5036929355020dab4837b637203a0742 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 17 Nov 2006 17:38:47 -0500 Subject: NetLabel: check for a CIPSOv4 option before we do call into the CIPSOv4 layer Right now the NetLabel code always jumps into the CIPSOv4 layer to determine if a CIPSO IP option is present. However, we can do this check directly in the NetLabel code by making use of the CIPSO_V4_OPTEXIST() macro which should save us a function call in the common case of not having a CIPSOv4 option present. Signed-off-by: Paul Moore Signed-off-by: James Morris --- net/ipv4/cipso_ipv4.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'net/ipv4/cipso_ipv4.c') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index f0a0785047f..fb5d913f581 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -1435,8 +1435,6 @@ int cipso_v4_skbuff_getattr(const struct sk_buff *skb, u32 doi; struct cipso_v4_doi *doi_def; - if (!CIPSO_V4_OPTEXIST(skb)) - return -ENOMSG; cipso_ptr = CIPSO_V4_OPTPTR(skb); if (cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr) == 0) return 0; -- cgit v1.2.3 From 6ce61a7c2678800cfe59a5f4a41ce8f785b9d355 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 17 Nov 2006 17:38:48 -0500 Subject: NetLabel: add tag verification when adding new CIPSOv4 DOI definitions Currently the CIPSOv4 engine does not do any sort of checking when a new DOI definition is added. The tags are still verified but only as a side effect of normal NetLabel operation (packet processing, socket labeling, etc.) which would cause application errors due to the faulty configuration. This patch adds tag checking when new DOI definition are added allowing us to catch these configuration problems when they happen. Signed-off-by: Paul Moore Signed-off-by: James Morris --- net/ipv4/cipso_ipv4.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'net/ipv4/cipso_ipv4.c') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index fb5d913f581..23a968f754b 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -447,8 +447,22 @@ static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi) */ int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) { + u32 iter; + if (doi_def == NULL || doi_def->doi == CIPSO_V4_DOI_UNKNOWN) return -EINVAL; + for (iter = 0; iter < CIPSO_V4_TAG_MAXCNT; iter++) { + switch (doi_def->tags[iter]) { + case CIPSO_V4_TAG_RBITMAP: + break; + case CIPSO_V4_TAG_INVALID: + if (iter == 0) + return -EINVAL; + break; + default: + return -EINVAL; + } + } doi_def->valid = 1; INIT_RCU_HEAD(&doi_def->rcu); -- cgit v1.2.3 From 91b1ed0afdbffbda88c472ef72af37e19b7876fb Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 17 Nov 2006 17:38:49 -0500 Subject: NetLabel: fixup the handling of CIPSOv4 tags to allow for multiple tag types While the original CIPSOv4 code had provisions for multiple tag types the implementation was not as great as it could be, pushing a lot of non-tag specific processing into the tag specific code blocks. This patch fixes that issue making it easier to support multiple tag types in the future. Signed-off-by: Paul Moore Signed-off-by: James Morris --- net/ipv4/cipso_ipv4.c | 113 +++++++++++++++++++++++--------------------------- 1 file changed, 53 insertions(+), 60 deletions(-) (limited to 'net/ipv4/cipso_ipv4.c') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 23a968f754b..a056278ad62 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -958,35 +958,28 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, * Protocol Handling Functions */ +#define CIPSO_V4_OPT_LEN_MAX 40 #define CIPSO_V4_HDR_LEN 6 /** * cipso_v4_gentag_hdr - Generate a CIPSO option header * @doi_def: the DOI definition - * @len: the total tag length in bytes + * @len: the total tag length in bytes, not including this header * @buf: the CIPSO option buffer * * Description: - * Write a CIPSO header into the beginning of @buffer. Return zero on success, - * negative values on failure. + * Write a CIPSO header into the beginning of @buffer. * */ -static int cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def, - u32 len, - unsigned char *buf) +static void cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def, + unsigned char *buf, + u32 len) { - if (CIPSO_V4_HDR_LEN + len > 40) - return -ENOSPC; - buf[0] = IPOPT_CIPSO; buf[1] = CIPSO_V4_HDR_LEN + len; *(__be32 *)&buf[2] = htonl(doi_def->doi); - - return 0; } -#define CIPSO_V4_TAG1_CAT_LEN 30 - /** * cipso_v4_gentag_rbm - Generate a CIPSO restricted bitmap tag (type #1) * @doi_def: the DOI definition @@ -997,71 +990,50 @@ static int cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def, * Description: * Generate a CIPSO option using the restricted bitmap tag, tag type #1. The * actual buffer length may be larger than the indicated size due to - * translation between host and network category bitmaps. Returns zero on - * success, negative values on failure. + * translation between host and network category bitmaps. Returns the size of + * the tag on success, negative values on failure. * */ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def, const struct netlbl_lsm_secattr *secattr, - unsigned char **buffer, - u32 *buffer_len) + unsigned char *buffer, + u32 buffer_len) { int ret_val; - unsigned char *buf = NULL; - u32 buf_len; + u32 tag_len; u32 level; if ((secattr->flags & NETLBL_SECATTR_MLS_LVL) == 0) return -EPERM; - if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { - buf = kzalloc(CIPSO_V4_HDR_LEN + 4 + CIPSO_V4_TAG1_CAT_LEN, - GFP_ATOMIC); - if (buf == NULL) - return -ENOMEM; + ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); + if (ret_val != 0) + return ret_val; + if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { ret_val = cipso_v4_map_cat_rbm_hton(doi_def, secattr->mls_cat, secattr->mls_cat_len, - &buf[CIPSO_V4_HDR_LEN + 4], - CIPSO_V4_TAG1_CAT_LEN); + &buffer[4], + buffer_len - 4); if (ret_val < 0) - goto gentag_failure; + return ret_val; /* This will send packets using the "optimized" format when * possibile as specified in section 3.4.2.6 of the * CIPSO draft. */ if (cipso_v4_rbm_optfmt && ret_val > 0 && ret_val <= 10) - buf_len = 14; + tag_len = 14; else - buf_len = 4 + ret_val; - } else { - buf = kzalloc(CIPSO_V4_HDR_LEN + 4, GFP_ATOMIC); - if (buf == NULL) - return -ENOMEM; - buf_len = 4; - } - - ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); - if (ret_val != 0) - goto gentag_failure; - - ret_val = cipso_v4_gentag_hdr(doi_def, buf_len, buf); - if (ret_val != 0) - goto gentag_failure; - - buf[CIPSO_V4_HDR_LEN] = 0x01; - buf[CIPSO_V4_HDR_LEN + 1] = buf_len; - buf[CIPSO_V4_HDR_LEN + 3] = level; + tag_len = 4 + ret_val; + } else + tag_len = 4; - *buffer = buf; - *buffer_len = CIPSO_V4_HDR_LEN + buf_len; + buffer[0] = 0x01; + buffer[1] = tag_len; + buffer[3] = level; - return 0; - -gentag_failure: - kfree(buf); - return ret_val; + return tag_len; } /** @@ -1284,7 +1256,7 @@ int cipso_v4_socket_setattr(const struct socket *sock, { int ret_val = -EPERM; u32 iter; - unsigned char *buf = NULL; + unsigned char *buf; u32 buf_len = 0; u32 opt_len; struct ip_options *opt = NULL; @@ -1300,17 +1272,28 @@ int cipso_v4_socket_setattr(const struct socket *sock, if (sk == NULL) return 0; + /* We allocate the maximum CIPSO option size here so we are probably + * being a little wasteful, but it makes our life _much_ easier later + * on and after all we are only talking about 40 bytes. */ + buf_len = CIPSO_V4_OPT_LEN_MAX; + buf = kmalloc(buf_len, GFP_ATOMIC); + if (buf == NULL) { + ret_val = -ENOMEM; + goto socket_setattr_failure; + } + /* XXX - This code assumes only one tag per CIPSO option which isn't * really a good assumption to make but since we only support the MAC * tags right now it is a safe assumption. */ iter = 0; do { + memset(buf, 0, buf_len); switch (doi_def->tags[iter]) { case CIPSO_V4_TAG_RBITMAP: ret_val = cipso_v4_gentag_rbm(doi_def, - secattr, - &buf, - &buf_len); + secattr, + &buf[CIPSO_V4_HDR_LEN], + buf_len - CIPSO_V4_HDR_LEN); break; default: ret_val = -EPERM; @@ -1318,11 +1301,13 @@ int cipso_v4_socket_setattr(const struct socket *sock, } iter++; - } while (ret_val != 0 && + } while (ret_val < 0 && iter < CIPSO_V4_TAG_MAXCNT && doi_def->tags[iter] != CIPSO_V4_TAG_INVALID); - if (ret_val != 0) + if (ret_val < 0) goto socket_setattr_failure; + cipso_v4_gentag_hdr(doi_def, buf, ret_val); + buf_len = CIPSO_V4_HDR_LEN + ret_val; /* 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 @@ -1396,6 +1381,10 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) rcu_read_unlock(); return -ENOMSG; } + + /* XXX - This code assumes only one tag per CIPSO option which isn't + * really a good assumption to make but since we only support the MAC + * tags right now it is a safe assumption. */ switch (cipso_ptr[6]) { case CIPSO_V4_TAG_RBITMAP: ret_val = cipso_v4_parsetag_rbm(doi_def, @@ -1458,6 +1447,10 @@ int cipso_v4_skbuff_getattr(const struct sk_buff *skb, doi_def = cipso_v4_doi_getdef(doi); if (doi_def == NULL) goto skbuff_getattr_return; + + /* XXX - This code assumes only one tag per CIPSO option which isn't + * really a good assumption to make but since we only support the MAC + * tags right now it is a safe assumption. */ switch (cipso_ptr[6]) { case CIPSO_V4_TAG_RBITMAP: ret_val = cipso_v4_parsetag_rbm(doi_def, -- cgit v1.2.3 From 9fade4bf8eed3db2fd1306968da4d51bc611aca3 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 17 Nov 2006 17:38:50 -0500 Subject: NetLabel: return the correct error for translated CIPSOv4 tags The CIPSOv4 translated tag #1 mapping does not always return the correct error code if the desired mapping does not exist; instead of returning -EPERM it returns -ENOSPC indicating that the buffer is not large enough to hold the translated value. This was caused by failing to check a specific error condition. This patch fixes this so that unknown mappings return -EPERM which is consistent with the rest of the related CIPSOv4 code. Signed-off-by: Paul Moore Signed-off-by: James Morris --- net/ipv4/cipso_ipv4.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net/ipv4/cipso_ipv4.c') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index a056278ad62..c305de6fa20 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -867,6 +867,8 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def, return -EPERM; net_spot = host_cat_array[host_spot]; + if (net_spot >= CIPSO_V4_INV_CAT) + return -EPERM; if (net_spot >= net_clen_bits) return -ENOSPC; cipso_v4_bitmap_setbit(net_cat, net_spot, 1); @@ -935,6 +937,8 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, return -EPERM; host_spot = net_cat_array[net_spot]; + if (host_spot >= CIPSO_V4_INV_CAT) + return -EPERM; if (host_spot >= host_clen_bits) return -ENOSPC; cipso_v4_bitmap_setbit(host_cat, host_spot, 1); -- cgit v1.2.3 From 9bb5fd2b05cb4dba229e225536faa59eaadd837d Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 17 Nov 2006 17:38:52 -0500 Subject: NetLabel: use cipso_v4_doi_search() for local CIPSOv4 functions The cipso_v4_doi_search() function behaves the same as cipso_v4_doi_getdef() but is a local, static function so use it whenever possibile in the CIPSOv4 code base. Signed-of-by: Paul Moore Signed-off-by: James Morris --- net/ipv4/cipso_ipv4.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net/ipv4/cipso_ipv4.c') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index c305de6fa20..a60af830407 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -1135,7 +1135,7 @@ int cipso_v4_validate(unsigned char **option) } rcu_read_lock(); - doi_def = cipso_v4_doi_getdef(ntohl(*((__be32 *)&opt[2]))); + doi_def = cipso_v4_doi_search(ntohl(*((u32 *)&opt[2]))); if (doi_def == NULL) { err_offset = 2; goto validate_return_locked; @@ -1380,7 +1380,7 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) doi = ntohl(*(__be32 *)&cipso_ptr[2]); rcu_read_lock(); - doi_def = cipso_v4_doi_getdef(doi); + doi_def = cipso_v4_doi_search(doi); if (doi_def == NULL) { rcu_read_unlock(); return -ENOMSG; @@ -1448,7 +1448,7 @@ int cipso_v4_skbuff_getattr(const struct sk_buff *skb, doi = ntohl(*(__be32 *)&cipso_ptr[2]); rcu_read_lock(); - doi_def = cipso_v4_doi_getdef(doi); + doi_def = cipso_v4_doi_search(doi); if (doi_def == NULL) goto skbuff_getattr_return; -- cgit v1.2.3 From 66625984ca94552f75836596e0e83f3e5594bd58 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 20 Nov 2006 18:08:37 -0800 Subject: [CIPSO]: Missing annotation in cipso_ipv4 update. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- net/ipv4/cipso_ipv4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/ipv4/cipso_ipv4.c') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index a60af830407..f3957cfaed4 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -1135,7 +1135,7 @@ int cipso_v4_validate(unsigned char **option) } rcu_read_lock(); - doi_def = cipso_v4_doi_search(ntohl(*((u32 *)&opt[2]))); + doi_def = cipso_v4_doi_search(ntohl(*((__be32 *)&opt[2]))); if (doi_def == NULL) { err_offset = 2; goto validate_return_locked; -- cgit v1.2.3 From 02752760359db6b00a3ffb1acfc13ef8d9eb1e3f Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 29 Nov 2006 13:18:18 -0500 Subject: NetLabel: convert to an extensibile/sparse category bitmap The original NetLabel category bitmap was a straight char bitmap which worked fine for the initial release as it only supported 240 bits due to limitations in the CIPSO restricted bitmap tag (tag type 0x01). This patch converts that straight char bitmap into an extensibile/sparse bitmap in order to lay the foundation for other CIPSO tag types and protocols. This patch also has a nice side effect in that all of the security attributes passed by NetLabel into the LSM are now in a format which is in the host's native byte/bit ordering which makes the LSM specific code much simpler; look at the changes in security/selinux/ss/ebitmap.c as an example. Signed-off-by: Paul Moore Signed-off-by: James Morris --- net/ipv4/cipso_ipv4.c | 168 +++++++++++++++++++++----------------------------- 1 file changed, 69 insertions(+), 99 deletions(-) (limited to 'net/ipv4/cipso_ipv4.c') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index f3957cfaed4..08144f8fc91 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -819,8 +819,7 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def, /** * cipso_v4_map_cat_rbm_hton - Perform a category mapping from host to network * @doi_def: the DOI definition - * @host_cat: the category bitmap in host format - * @host_cat_len: the length of the host's category bitmap in bytes + * @secattr: the security attributes * @net_cat: the zero'd out category bitmap in network/CIPSO format * @net_cat_len: the length of the CIPSO bitmap in bytes * @@ -831,61 +830,51 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def, * */ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def, - const unsigned char *host_cat, - u32 host_cat_len, + const struct netlbl_lsm_secattr *secattr, unsigned char *net_cat, u32 net_cat_len) { int host_spot = -1; - u32 net_spot; + u32 net_spot = CIPSO_V4_INV_CAT; 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; - u32 *host_cat_array; + u32 host_cat_size = 0; + u32 *host_cat_array = NULL; - switch (doi_def->type) { - case CIPSO_V4_MAP_PASS: - 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: + if (doi_def->type == 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, - host_spot + 1, - 1); - if (host_spot < 0) - break; + } + + for (;;) { + host_spot = netlbl_secattr_catmap_walk(secattr->mls_cat, + host_spot + 1); + if (host_spot < 0) + break; + + switch (doi_def->type) { + case CIPSO_V4_MAP_PASS: + net_spot = host_spot; + break; + case CIPSO_V4_MAP_STD: if (host_spot >= host_cat_size) return -EPERM; - net_spot = host_cat_array[host_spot]; if (net_spot >= CIPSO_V4_INV_CAT) return -EPERM; - if (net_spot >= net_clen_bits) - return -ENOSPC; - cipso_v4_bitmap_setbit(net_cat, net_spot, 1); - - if (net_spot > net_spot_max) - net_spot_max = net_spot; + break; } + if (net_spot >= net_clen_bits) + return -ENOSPC; + cipso_v4_bitmap_setbit(net_cat, net_spot, 1); - if (host_spot == -2) - return -EFAULT; - - if (++net_spot_max % 8) - return net_spot_max / 8 + 1; - return net_spot_max / 8; + if (net_spot > net_spot_max) + net_spot_max = net_spot; } - return -EINVAL; + if (++net_spot_max % 8) + return net_spot_max / 8 + 1; + return net_spot_max / 8; } /** @@ -893,66 +882,59 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def, * @doi_def: the DOI definition * @net_cat: the category bitmap in network/CIPSO format * @net_cat_len: the length of the CIPSO bitmap in bytes - * @host_cat: the zero'd out category bitmap in host format - * @host_cat_len: the length of the host's category bitmap in bytes + * @secattr: the security attributes * * Description: * Perform a label mapping to translate a CIPSO bitmap to the correct local - * MLS category bitmap using the given DOI definition. Returns the minimum - * size in bytes of the host bitmap on success, negative values otherwise. + * MLS category bitmap using the given DOI definition. Returns zero on + * success, negative values on failure. * */ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, const unsigned char *net_cat, u32 net_cat_len, - unsigned char *host_cat, - u32 host_cat_len) + struct netlbl_lsm_secattr *secattr) { - u32 host_spot; - u32 host_spot_max = 0; + int ret_val; int net_spot = -1; + u32 host_spot = CIPSO_V4_INV_CAT; u32 net_clen_bits = net_cat_len * 8; - u32 host_clen_bits = host_cat_len * 8; - u32 net_cat_size; - u32 *net_cat_array; + u32 net_cat_size = 0; + u32 *net_cat_array = NULL; - switch (doi_def->type) { - case CIPSO_V4_MAP_PASS: - if (net_cat_len > host_cat_len) - return -EINVAL; - memcpy(host_cat, net_cat, net_cat_len); - return net_cat_len; - case CIPSO_V4_MAP_STD: + if (doi_def->type == 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, - net_spot + 1, - 1); - if (net_spot < 0) - break; - if (net_spot >= net_cat_size || - net_cat_array[net_spot] >= CIPSO_V4_INV_CAT) - return -EPERM; + } + for (;;) { + net_spot = cipso_v4_bitmap_walk(net_cat, + net_clen_bits, + net_spot + 1, + 1); + if (net_spot < 0) { + if (net_spot == -2) + return -EFAULT; + return 0; + } + + switch (doi_def->type) { + case CIPSO_V4_MAP_PASS: + host_spot = net_spot; + break; + case CIPSO_V4_MAP_STD: + if (net_spot >= net_cat_size) + return -EPERM; host_spot = net_cat_array[net_spot]; if (host_spot >= CIPSO_V4_INV_CAT) return -EPERM; - if (host_spot >= host_clen_bits) - return -ENOSPC; - cipso_v4_bitmap_setbit(host_cat, host_spot, 1); - - if (host_spot > host_spot_max) - host_spot_max = host_spot; + break; } - - if (net_spot == -2) - return -EFAULT; - - if (++host_spot_max % 8) - return host_spot_max / 8 + 1; - return host_spot_max / 8; + ret_val = netlbl_secattr_catmap_setbit(secattr->mls_cat, + host_spot, + GFP_ATOMIC); + if (ret_val != 0) + return ret_val; } return -EINVAL; @@ -1016,8 +998,7 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def, if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { ret_val = cipso_v4_map_cat_rbm_hton(doi_def, - secattr->mls_cat, - secattr->mls_cat_len, + secattr, &buffer[4], buffer_len - 4); if (ret_val < 0) @@ -1067,31 +1048,20 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def, secattr->flags |= NETLBL_SECATTR_MLS_LVL; if (tag_len > 4) { - switch (doi_def->type) { - case CIPSO_V4_MAP_PASS: - secattr->mls_cat_len = tag_len - 4; - break; - case CIPSO_V4_MAP_STD: - secattr->mls_cat_len = - doi_def->map.std->cat.local_size; - break; - } - secattr->mls_cat = kzalloc(secattr->mls_cat_len, GFP_ATOMIC); + secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); if (secattr->mls_cat == NULL) return -ENOMEM; ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def, &tag[4], tag_len - 4, - secattr->mls_cat, - secattr->mls_cat_len); - if (ret_val < 0) { - kfree(secattr->mls_cat); + secattr); + if (ret_val != 0) { + netlbl_secattr_catmap_free(secattr->mls_cat); return ret_val; - } else if (ret_val > 0) { - secattr->mls_cat_len = ret_val; - secattr->flags |= NETLBL_SECATTR_MLS_CAT; } + + secattr->flags |= NETLBL_SECATTR_MLS_CAT; } return 0; -- cgit v1.2.3 From 654bbc2a2b87185630d05b79cc0db0e9364bb7e0 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 29 Nov 2006 13:18:19 -0500 Subject: NetLabel: add the enumerated tag to the CIPSOv4 protocol Add support for the enumerated tag (tag type #2) to the CIPSOv4 protocol. The enumerated tag allows for 15 categories to be specified in a CIPSO option, where each category is an unsigned 16 bit field with a maximum value of 65534. See Documentation/netlabel/draft-ietf-cipso-ipsecurity-01.txt for more details. Signed-off-by: Paul Moore Signed-off-by: James Morris --- net/ipv4/cipso_ipv4.c | 233 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) (limited to 'net/ipv4/cipso_ipv4.c') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 08144f8fc91..70858dccaca 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -459,6 +459,10 @@ int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) if (iter == 0) return -EINVAL; break; + case CIPSO_V4_TAG_ENUM: + if (doi_def->type != CIPSO_V4_MAP_PASS) + return -EINVAL; + break; default: return -EINVAL; } @@ -940,6 +944,107 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, return -EINVAL; } +/** + * cipso_v4_map_cat_enum_valid - Checks to see if the categories are valid + * @doi_def: the DOI definition + * @enumcat: category list + * @enumcat_len: length of the category list in bytes + * + * Description: + * Checks the given categories against the given DOI definition and returns a + * negative value if any of the categories do not have a valid mapping and a + * zero value if all of the categories are valid. + * + */ +static int cipso_v4_map_cat_enum_valid(const struct cipso_v4_doi *doi_def, + const unsigned char *enumcat, + u32 enumcat_len) +{ + u16 cat; + int cat_prev = -1; + u32 iter; + + if (doi_def->type != CIPSO_V4_MAP_PASS || enumcat_len & 0x01) + return -EFAULT; + + for (iter = 0; iter < enumcat_len; iter += 2) { + cat = ntohs(*((__be16 *)&enumcat[iter])); + if (cat <= cat_prev) + return -EFAULT; + cat_prev = cat; + } + + return 0; +} + +/** + * cipso_v4_map_cat_enum_hton - Perform a category mapping from host to network + * @doi_def: the DOI definition + * @secattr: the security attributes + * @net_cat: the zero'd out category list in network/CIPSO format + * @net_cat_len: the length of the CIPSO category list in bytes + * + * Description: + * Perform a label mapping to translate a local MLS category bitmap to the + * correct CIPSO category list using the given DOI definition. Returns the + * size in bytes of the network category bitmap on success, negative values + * otherwise. + * + */ +static int cipso_v4_map_cat_enum_hton(const struct cipso_v4_doi *doi_def, + const struct netlbl_lsm_secattr *secattr, + unsigned char *net_cat, + u32 net_cat_len) +{ + int cat = -1; + u32 cat_iter = 0; + + for (;;) { + cat = netlbl_secattr_catmap_walk(secattr->mls_cat, cat + 1); + if (cat < 0) + break; + if ((cat_iter + 2) > net_cat_len) + return -ENOSPC; + + *((__be16 *)&net_cat[cat_iter]) = htons(cat); + cat_iter += 2; + } + + return cat_iter; +} + +/** + * cipso_v4_map_cat_enum_ntoh - Perform a category mapping from network to host + * @doi_def: the DOI definition + * @net_cat: the category list in network/CIPSO format + * @net_cat_len: the length of the CIPSO bitmap in bytes + * @secattr: the security attributes + * + * Description: + * Perform a label mapping to translate a CIPSO category list to the correct + * local MLS category bitmap using the given DOI definition. Returns zero on + * success, negative values on failure. + * + */ +static int cipso_v4_map_cat_enum_ntoh(const struct cipso_v4_doi *doi_def, + const unsigned char *net_cat, + u32 net_cat_len, + struct netlbl_lsm_secattr *secattr) +{ + int ret_val; + u32 iter; + + for (iter = 0; iter < net_cat_len; iter += 2) { + ret_val = netlbl_secattr_catmap_setbit(secattr->mls_cat, + ntohs(*((__be16 *)&net_cat[iter])), + GFP_ATOMIC); + if (ret_val != 0) + return ret_val; + } + + return 0; +} + /* * Protocol Handling Functions */ @@ -1067,6 +1172,99 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def, return 0; } +/** + * cipso_v4_gentag_enum - Generate a CIPSO enumerated tag (type #2) + * @doi_def: the DOI definition + * @secattr: the security attributes + * @buffer: the option buffer + * @buffer_len: length of buffer in bytes + * + * Description: + * Generate a CIPSO option using the enumerated tag, tag type #2. Returns the + * size of the tag on success, negative values on failure. + * + */ +static int cipso_v4_gentag_enum(const struct cipso_v4_doi *doi_def, + const struct netlbl_lsm_secattr *secattr, + unsigned char *buffer, + u32 buffer_len) +{ + int ret_val; + u32 tag_len; + u32 level; + + if (!(secattr->flags & NETLBL_SECATTR_MLS_LVL)) + return -EPERM; + + ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); + if (ret_val != 0) + return ret_val; + + if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { + ret_val = cipso_v4_map_cat_enum_hton(doi_def, + secattr, + &buffer[4], + buffer_len - 4); + if (ret_val < 0) + return ret_val; + + tag_len = 4 + ret_val; + } else + tag_len = 4; + + buffer[0] = 0x02; + buffer[1] = tag_len; + buffer[3] = level; + + return tag_len; +} + +/** + * cipso_v4_parsetag_enum - Parse a CIPSO enumerated tag + * @doi_def: the DOI definition + * @tag: the CIPSO tag + * @secattr: the security attributes + * + * Description: + * Parse a CIPSO enumerated tag (tag type #2) and return the security + * attributes in @secattr. Return zero on success, negatives values on + * failure. + * + */ +static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def, + const unsigned char *tag, + struct netlbl_lsm_secattr *secattr) +{ + int ret_val; + u8 tag_len = tag[1]; + u32 level; + + ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level); + if (ret_val != 0) + return ret_val; + secattr->mls_lvl = level; + secattr->flags |= NETLBL_SECATTR_MLS_LVL; + + if (tag_len > 4) { + secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); + if (secattr->mls_cat == NULL) + return -ENOMEM; + + ret_val = cipso_v4_map_cat_enum_ntoh(doi_def, + &tag[4], + tag_len - 4, + secattr); + if (ret_val != 0) { + netlbl_secattr_catmap_free(secattr->mls_cat); + return ret_val; + } + + secattr->flags |= NETLBL_SECATTR_MLS_CAT; + } + + return 0; +} + /** * cipso_v4_validate - Validate a CIPSO option * @option: the start of the option, on error it is set to point to the error @@ -1156,6 +1354,25 @@ int cipso_v4_validate(unsigned char **option) } } break; + case CIPSO_V4_TAG_ENUM: + if (tag_len < 4) { + err_offset = opt_iter + 1; + goto validate_return_locked; + } + + if (cipso_v4_map_lvl_valid(doi_def, + tag[3]) < 0) { + err_offset = opt_iter + 3; + goto validate_return_locked; + } + if (tag_len > 4 && + cipso_v4_map_cat_enum_valid(doi_def, + &tag[4], + tag_len - 4) < 0) { + err_offset = opt_iter + 4; + goto validate_return_locked; + } + break; default: err_offset = opt_iter; goto validate_return_locked; @@ -1269,6 +1486,12 @@ int cipso_v4_socket_setattr(const struct socket *sock, &buf[CIPSO_V4_HDR_LEN], buf_len - CIPSO_V4_HDR_LEN); break; + case CIPSO_V4_TAG_ENUM: + ret_val = cipso_v4_gentag_enum(doi_def, + secattr, + &buf[CIPSO_V4_HDR_LEN], + buf_len - CIPSO_V4_HDR_LEN); + break; default: ret_val = -EPERM; goto socket_setattr_failure; @@ -1365,6 +1588,11 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) &cipso_ptr[6], secattr); break; + case CIPSO_V4_TAG_ENUM: + ret_val = cipso_v4_parsetag_enum(doi_def, + &cipso_ptr[6], + secattr); + break; } rcu_read_unlock(); @@ -1431,6 +1659,11 @@ int cipso_v4_skbuff_getattr(const struct sk_buff *skb, &cipso_ptr[6], secattr); break; + case CIPSO_V4_TAG_ENUM: + ret_val = cipso_v4_parsetag_enum(doi_def, + &cipso_ptr[6], + secattr); + break; } skbuff_getattr_return: -- cgit v1.2.3 From 484b366932be0b73a22c74a82748ca10a721643e Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 29 Nov 2006 13:18:20 -0500 Subject: NetLabel: add the ranged tag to the CIPSOv4 protocol Add support for the ranged tag (tag type #5) to the CIPSOv4 protocol. The ranged tag allows for seven, or eight if zero is the lowest category, category ranges to be specified in a CIPSO option. Each range is specified by two unsigned 16 bit fields, each with a maximum value of 65534. The two values specify the start and end of the category range; if the start of the category range is zero then it is omitted. See Documentation/netlabel/draft-ietf-cipso-ipsecurity-01.txt for more details. Signed-off-by: Paul Moore Signed-off-by: James Morris --- net/ipv4/cipso_ipv4.c | 268 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 268 insertions(+) (limited to 'net/ipv4/cipso_ipv4.c') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 70858dccaca..60aafb4a8ad 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -455,6 +455,10 @@ int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) switch (doi_def->tags[iter]) { case CIPSO_V4_TAG_RBITMAP: break; + case CIPSO_V4_TAG_RANGE: + if (doi_def->type != CIPSO_V4_MAP_PASS) + return -EINVAL; + break; case CIPSO_V4_TAG_INVALID: if (iter == 0) return -EINVAL; @@ -1045,6 +1049,148 @@ static int cipso_v4_map_cat_enum_ntoh(const struct cipso_v4_doi *doi_def, return 0; } +/** + * cipso_v4_map_cat_rng_valid - Checks to see if the categories are valid + * @doi_def: the DOI definition + * @rngcat: category list + * @rngcat_len: length of the category list in bytes + * + * Description: + * Checks the given categories against the given DOI definition and returns a + * negative value if any of the categories do not have a valid mapping and a + * zero value if all of the categories are valid. + * + */ +static int cipso_v4_map_cat_rng_valid(const struct cipso_v4_doi *doi_def, + const unsigned char *rngcat, + u32 rngcat_len) +{ + u16 cat_high; + u16 cat_low; + u32 cat_prev = CIPSO_V4_MAX_REM_CATS + 1; + u32 iter; + + if (doi_def->type != CIPSO_V4_MAP_PASS || rngcat_len & 0x01) + return -EFAULT; + + for (iter = 0; iter < rngcat_len; iter += 4) { + cat_high = ntohs(*((__be16 *)&rngcat[iter])); + if ((iter + 4) <= rngcat_len) + cat_low = ntohs(*((__be16 *)&rngcat[iter + 2])); + else + cat_low = 0; + + if (cat_high > cat_prev) + return -EFAULT; + + cat_prev = cat_low; + } + + return 0; +} + +/** + * cipso_v4_map_cat_rng_hton - Perform a category mapping from host to network + * @doi_def: the DOI definition + * @secattr: the security attributes + * @net_cat: the zero'd out category list in network/CIPSO format + * @net_cat_len: the length of the CIPSO category list in bytes + * + * Description: + * Perform a label mapping to translate a local MLS category bitmap to the + * correct CIPSO category list using the given DOI definition. Returns the + * size in bytes of the network category bitmap on success, negative values + * otherwise. + * + */ +static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def, + const struct netlbl_lsm_secattr *secattr, + unsigned char *net_cat, + u32 net_cat_len) +{ + /* The constant '16' is not random, it is the maximum number of + * high/low category range pairs as permitted by the CIPSO draft based + * on a maximum IPv4 header length of 60 bytes - the BUG_ON() assertion + * does a sanity check to make sure we don't overflow the array. */ + int iter = -1; + u16 array[16]; + u32 array_cnt = 0; + u32 cat_size = 0; + + BUG_ON(net_cat_len > 30); + + for (;;) { + iter = netlbl_secattr_catmap_walk(secattr->mls_cat, iter + 1); + if (iter < 0) + break; + cat_size += (iter == 0 ? 0 : sizeof(u16)); + if (cat_size > net_cat_len) + return -ENOSPC; + array[array_cnt++] = iter; + + iter = netlbl_secattr_catmap_walk_rng(secattr->mls_cat, iter); + if (iter < 0) + return -EFAULT; + cat_size += sizeof(u16); + if (cat_size > net_cat_len) + return -ENOSPC; + array[array_cnt++] = iter; + } + + for (iter = 0; array_cnt > 0;) { + *((__be16 *)&net_cat[iter]) = htons(array[--array_cnt]); + iter += 2; + array_cnt--; + if (array[array_cnt] != 0) { + *((__be16 *)&net_cat[iter]) = htons(array[array_cnt]); + iter += 2; + } + } + + return cat_size; +} + +/** + * cipso_v4_map_cat_rng_ntoh - Perform a category mapping from network to host + * @doi_def: the DOI definition + * @net_cat: the category list in network/CIPSO format + * @net_cat_len: the length of the CIPSO bitmap in bytes + * @secattr: the security attributes + * + * Description: + * Perform a label mapping to translate a CIPSO category list to the correct + * local MLS category bitmap using the given DOI definition. Returns zero on + * success, negative values on failure. + * + */ +static int cipso_v4_map_cat_rng_ntoh(const struct cipso_v4_doi *doi_def, + const unsigned char *net_cat, + u32 net_cat_len, + struct netlbl_lsm_secattr *secattr) +{ + int ret_val; + u32 net_iter; + u16 cat_low; + u16 cat_high; + + for(net_iter = 0; net_iter < net_cat_len; net_iter += 4) { + cat_high = ntohs(*((__be16 *)&net_cat[net_iter])); + if ((net_iter + 4) <= net_cat_len) + cat_low = ntohs(*((__be16 *)&net_cat[net_iter + 2])); + else + cat_low = 0; + + ret_val = netlbl_secattr_catmap_setrng(secattr->mls_cat, + cat_low, + cat_high, + GFP_ATOMIC); + if (ret_val != 0) + return ret_val; + } + + return 0; +} + /* * Protocol Handling Functions */ @@ -1265,6 +1411,98 @@ static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def, return 0; } +/** + * cipso_v4_gentag_rng - Generate a CIPSO ranged tag (type #5) + * @doi_def: the DOI definition + * @secattr: the security attributes + * @buffer: the option buffer + * @buffer_len: length of buffer in bytes + * + * Description: + * Generate a CIPSO option using the ranged tag, tag type #5. Returns the + * size of the tag on success, negative values on failure. + * + */ +static int cipso_v4_gentag_rng(const struct cipso_v4_doi *doi_def, + const struct netlbl_lsm_secattr *secattr, + unsigned char *buffer, + u32 buffer_len) +{ + int ret_val; + u32 tag_len; + u32 level; + + if (!(secattr->flags & NETLBL_SECATTR_MLS_LVL)) + return -EPERM; + + ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); + if (ret_val != 0) + return ret_val; + + if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { + ret_val = cipso_v4_map_cat_rng_hton(doi_def, + secattr, + &buffer[4], + buffer_len - 4); + if (ret_val < 0) + return ret_val; + + tag_len = 4 + ret_val; + } else + tag_len = 4; + + buffer[0] = 0x05; + buffer[1] = tag_len; + buffer[3] = level; + + return tag_len; +} + +/** + * cipso_v4_parsetag_rng - Parse a CIPSO ranged tag + * @doi_def: the DOI definition + * @tag: the CIPSO tag + * @secattr: the security attributes + * + * Description: + * Parse a CIPSO ranged tag (tag type #5) and return the security attributes + * in @secattr. Return zero on success, negatives values on failure. + * + */ +static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def, + const unsigned char *tag, + struct netlbl_lsm_secattr *secattr) +{ + int ret_val; + u8 tag_len = tag[1]; + u32 level; + + ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level); + if (ret_val != 0) + return ret_val; + secattr->mls_lvl = level; + secattr->flags |= NETLBL_SECATTR_MLS_LVL; + + if (tag_len > 4) { + secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); + if (secattr->mls_cat == NULL) + return -ENOMEM; + + ret_val = cipso_v4_map_cat_rng_ntoh(doi_def, + &tag[4], + tag_len - 4, + secattr); + if (ret_val != 0) { + netlbl_secattr_catmap_free(secattr->mls_cat); + return ret_val; + } + + secattr->flags |= NETLBL_SECATTR_MLS_CAT; + } + + return 0; +} + /** * cipso_v4_validate - Validate a CIPSO option * @option: the start of the option, on error it is set to point to the error @@ -1373,6 +1611,25 @@ int cipso_v4_validate(unsigned char **option) goto validate_return_locked; } break; + case CIPSO_V4_TAG_RANGE: + if (tag_len < 4) { + err_offset = opt_iter + 1; + goto validate_return_locked; + } + + if (cipso_v4_map_lvl_valid(doi_def, + tag[3]) < 0) { + err_offset = opt_iter + 3; + goto validate_return_locked; + } + if (tag_len > 4 && + cipso_v4_map_cat_rng_valid(doi_def, + &tag[4], + tag_len - 4) < 0) { + err_offset = opt_iter + 4; + goto validate_return_locked; + } + break; default: err_offset = opt_iter; goto validate_return_locked; @@ -1492,6 +1749,12 @@ int cipso_v4_socket_setattr(const struct socket *sock, &buf[CIPSO_V4_HDR_LEN], buf_len - CIPSO_V4_HDR_LEN); break; + case CIPSO_V4_TAG_RANGE: + ret_val = cipso_v4_gentag_rng(doi_def, + secattr, + &buf[CIPSO_V4_HDR_LEN], + buf_len - CIPSO_V4_HDR_LEN); + break; default: ret_val = -EPERM; goto socket_setattr_failure; @@ -1593,6 +1856,11 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) &cipso_ptr[6], secattr); break; + case CIPSO_V4_TAG_RANGE: + ret_val = cipso_v4_parsetag_rng(doi_def, + &cipso_ptr[6], + secattr); + break; } rcu_read_unlock(); -- cgit v1.2.3