Commit 91b1ed0a authored by Paul Moore's avatar Paul Moore Committed by David S. Miller

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: default avatarPaul Moore <paul.moore@hp.com>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent 6ce61a7c
...@@ -958,35 +958,28 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, ...@@ -958,35 +958,28 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
* Protocol Handling Functions * Protocol Handling Functions
*/ */
#define CIPSO_V4_OPT_LEN_MAX 40
#define CIPSO_V4_HDR_LEN 6 #define CIPSO_V4_HDR_LEN 6
/** /**
* cipso_v4_gentag_hdr - Generate a CIPSO option header * cipso_v4_gentag_hdr - Generate a CIPSO option header
* @doi_def: the DOI definition * @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 * @buf: the CIPSO option buffer
* *
* Description: * Description:
* Write a CIPSO header into the beginning of @buffer. Return zero on success, * Write a CIPSO header into the beginning of @buffer.
* negative values on failure.
* *
*/ */
static int cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def, static void cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def,
u32 len, unsigned char *buf,
unsigned char *buf) u32 len)
{ {
if (CIPSO_V4_HDR_LEN + len > 40)
return -ENOSPC;
buf[0] = IPOPT_CIPSO; buf[0] = IPOPT_CIPSO;
buf[1] = CIPSO_V4_HDR_LEN + len; buf[1] = CIPSO_V4_HDR_LEN + len;
*(__be32 *)&buf[2] = htonl(doi_def->doi); *(__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) * cipso_v4_gentag_rbm - Generate a CIPSO restricted bitmap tag (type #1)
* @doi_def: the DOI definition * @doi_def: the DOI definition
...@@ -997,71 +990,50 @@ static int cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def, ...@@ -997,71 +990,50 @@ static int cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def,
* Description: * Description:
* Generate a CIPSO option using the restricted bitmap tag, tag type #1. The * 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 * actual buffer length may be larger than the indicated size due to
* translation between host and network category bitmaps. Returns zero on * translation between host and network category bitmaps. Returns the size of
* success, negative values on failure. * the tag on success, negative values on failure.
* *
*/ */
static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def, static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def,
const struct netlbl_lsm_secattr *secattr, const struct netlbl_lsm_secattr *secattr,
unsigned char **buffer, unsigned char *buffer,
u32 *buffer_len) u32 buffer_len)
{ {
int ret_val; int ret_val;
unsigned char *buf = NULL; u32 tag_len;
u32 buf_len;
u32 level; u32 level;
if ((secattr->flags & NETLBL_SECATTR_MLS_LVL) == 0) if ((secattr->flags & NETLBL_SECATTR_MLS_LVL) == 0)
return -EPERM; return -EPERM;
if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level);
buf = kzalloc(CIPSO_V4_HDR_LEN + 4 + CIPSO_V4_TAG1_CAT_LEN, if (ret_val != 0)
GFP_ATOMIC); return ret_val;
if (buf == NULL)
return -ENOMEM;
if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
ret_val = cipso_v4_map_cat_rbm_hton(doi_def, ret_val = cipso_v4_map_cat_rbm_hton(doi_def,
secattr->mls_cat, secattr->mls_cat,
secattr->mls_cat_len, secattr->mls_cat_len,
&buf[CIPSO_V4_HDR_LEN + 4], &buffer[4],
CIPSO_V4_TAG1_CAT_LEN); buffer_len - 4);
if (ret_val < 0) if (ret_val < 0)
goto gentag_failure; return ret_val;
/* This will send packets using the "optimized" format when /* This will send packets using the "optimized" format when
* possibile as specified in section 3.4.2.6 of the * possibile as specified in section 3.4.2.6 of the
* CIPSO draft. */ * CIPSO draft. */
if (cipso_v4_rbm_optfmt && ret_val > 0 && ret_val <= 10) if (cipso_v4_rbm_optfmt && ret_val > 0 && ret_val <= 10)
buf_len = 14; tag_len = 14;
else else
buf_len = 4 + ret_val; tag_len = 4 + ret_val;
} else { } else
buf = kzalloc(CIPSO_V4_HDR_LEN + 4, GFP_ATOMIC); tag_len = 4;
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;
*buffer = buf; buffer[0] = 0x01;
*buffer_len = CIPSO_V4_HDR_LEN + buf_len; buffer[1] = tag_len;
buffer[3] = level;
return 0; return tag_len;
gentag_failure:
kfree(buf);
return ret_val;
} }
/** /**
...@@ -1284,7 +1256,7 @@ int cipso_v4_socket_setattr(const struct socket *sock, ...@@ -1284,7 +1256,7 @@ int cipso_v4_socket_setattr(const struct socket *sock,
{ {
int ret_val = -EPERM; int ret_val = -EPERM;
u32 iter; u32 iter;
unsigned char *buf = NULL; unsigned char *buf;
u32 buf_len = 0; u32 buf_len = 0;
u32 opt_len; u32 opt_len;
struct ip_options *opt = NULL; struct ip_options *opt = NULL;
...@@ -1300,17 +1272,28 @@ int cipso_v4_socket_setattr(const struct socket *sock, ...@@ -1300,17 +1272,28 @@ int cipso_v4_socket_setattr(const struct socket *sock,
if (sk == NULL) if (sk == NULL)
return 0; 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 /* 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 * really a good assumption to make but since we only support the MAC
* tags right now it is a safe assumption. */ * tags right now it is a safe assumption. */
iter = 0; iter = 0;
do { do {
memset(buf, 0, buf_len);
switch (doi_def->tags[iter]) { switch (doi_def->tags[iter]) {
case CIPSO_V4_TAG_RBITMAP: case CIPSO_V4_TAG_RBITMAP:
ret_val = cipso_v4_gentag_rbm(doi_def, ret_val = cipso_v4_gentag_rbm(doi_def,
secattr, secattr,
&buf, &buf[CIPSO_V4_HDR_LEN],
&buf_len); buf_len - CIPSO_V4_HDR_LEN);
break; break;
default: default:
ret_val = -EPERM; ret_val = -EPERM;
...@@ -1318,11 +1301,13 @@ int cipso_v4_socket_setattr(const struct socket *sock, ...@@ -1318,11 +1301,13 @@ int cipso_v4_socket_setattr(const struct socket *sock,
} }
iter++; iter++;
} while (ret_val != 0 && } while (ret_val < 0 &&
iter < CIPSO_V4_TAG_MAXCNT && iter < CIPSO_V4_TAG_MAXCNT &&
doi_def->tags[iter] != CIPSO_V4_TAG_INVALID); doi_def->tags[iter] != CIPSO_V4_TAG_INVALID);
if (ret_val != 0) if (ret_val < 0)
goto socket_setattr_failure; 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 /* 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 * 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) ...@@ -1396,6 +1381,10 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
rcu_read_unlock(); rcu_read_unlock();
return -ENOMSG; 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]) { switch (cipso_ptr[6]) {
case CIPSO_V4_TAG_RBITMAP: case CIPSO_V4_TAG_RBITMAP:
ret_val = cipso_v4_parsetag_rbm(doi_def, ret_val = cipso_v4_parsetag_rbm(doi_def,
...@@ -1458,6 +1447,10 @@ int cipso_v4_skbuff_getattr(const struct sk_buff *skb, ...@@ -1458,6 +1447,10 @@ int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
doi_def = cipso_v4_doi_getdef(doi); doi_def = cipso_v4_doi_getdef(doi);
if (doi_def == NULL) if (doi_def == NULL)
goto skbuff_getattr_return; 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]) { switch (cipso_ptr[6]) {
case CIPSO_V4_TAG_RBITMAP: case CIPSO_V4_TAG_RBITMAP:
ret_val = cipso_v4_parsetag_rbm(doi_def, ret_val = cipso_v4_parsetag_rbm(doi_def,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment