Thomas Graf wrote:
> * [EMAIL PROTECTED] <[EMAIL PROTECTED]> 2006-09-21 12:57
>
>>At the suggestion of Thomas Graf, rewrite NetLabel's use of Netlink attributes
>>to better follow the common Netlink attribute usage.
>>
>>Signed-off-by: Paul Moore <[EMAIL PROTECTED]>
>>---
>> net/netlabel/netlabel_cipso_v4.c | 593
>> +++++++++++++++++++++++++-------------
>> net/netlabel/netlabel_cipso_v4.h | 235 +++++----------
>> net/netlabel/netlabel_mgmt.c | 531 +++++++++++++++++-----------------
>> net/netlabel/netlabel_mgmt.h | 213 ++++---------
>> net/netlabel/netlabel_unlabeled.c | 77 ++--
>> net/netlabel/netlabel_unlabeled.h | 41 +-
>> 6 files changed, 875 insertions(+), 815 deletions(-)
>>
>> {snip}
>>
>>@@ -128,28 +156,44 @@ static int netlbl_cipsov4_add_std(u32 do
>> }
>> doi_def->type = CIPSO_V4_MAP_STD;
>>
>>- for (iter = 0; iter < num_tags; iter++) {
>>- if (msg_len < NETLBL_LEN_U8)
>>- goto add_std_failure;
>>- doi_def->tags[iter] = netlbl_getinc_u8(&msg, &msg_len);
>>- switch (doi_def->tags[iter]) {
>>- case CIPSO_V4_TAG_RBITMAP:
>>- break;
>>- default:
>>- goto add_std_failure;
>>+ nla_for_each_attr(nla_a,
>>+ nla_data(info->attrs[NLBL_CIPSOV4_A_TAGLST]),
>>+ nla_len(info->attrs[NLBL_CIPSOV4_A_TAGLST]),
>>+ nla_a_rem)
>
>
> You can use nla_for_each_nested() here.
Huh, look at that, guess I didn't scroll down far enough in the header
file :) Thanks.
>>+ if (nla_a->nla_type == NLBL_CIPSOV4_A_TAG) {
>>+ if (iter > CIPSO_V4_TAG_MAXCNT)
>>+ goto add_std_failure;
>>+ doi_def->tags[iter++] = nla_get_u8(nla_a);
>> }
>
>
> Perfectly validated against generic policy yet flexible, I
> like this a lot.
>
>
>
>>+ nla_for_each_attr(nla_a,
>>+ nla_data(info->attrs[NLBL_CIPSOV4_A_MLSLVLLST]),
>>+ nla_len(info->attrs[NLBL_CIPSOV4_A_MLSLVLLST]),
>>+ nla_a_rem)
>
>
> Could use nla_for_each_nested() here as well.
>
>
>>+ if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSLVL) {
>>+ nla_for_each_attr(nla_b,
>>+ nla_data(nla_a),
>>+ nla_len(nla_a),
>>+ nla_b_rem)
>
>
> ... and again :-)
>
>
>>+ switch (nla_b->nla_type) {
>>+ case NLBL_CIPSOV4_A_MLSLVLLOC:
>>+ if (nla_get_u32(nla_b) >=
>
>
> Attributes on this level are not yet validated.
>
Yes, you're right, same problem with the _MLSCAT attribute. Thanks.
>>+ doi_def->map.std->lvl.local_size)
>>+ doi_def->map.std->lvl.local_size =
>>+ nla_get_u32(nla_b) + 1;
>>+ break;
>>+ case NLBL_CIPSOV4_A_MLSLVLREM:
>>+ if (nla_get_u32(nla_b) >=
>>+ doi_def->map.std->lvl.cipso_size)
>>+ doi_def->map.std->lvl.cipso_size =
>>+ nla_get_u32(nla_b) + 1;
>>+ break;
>>+ }
>>+ }
>>@@ -168,68 +209,96 @@ static int netlbl_cipsov4_add_std(u32 do
>> ret_val = -ENOMEM;
>> goto add_std_failure;
>> }
>>+ nla_for_each_attr(nla_a,
>>+ nla_data(info->attrs[NLBL_CIPSOV4_A_MLSLVLLST]),
>>+ nla_len(info->attrs[NLBL_CIPSOV4_A_MLSLVLLST]),
>>+ nla_a_rem)
>
>
>>+ if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSLVL) {
>>+ nla_b = nla_find_nested(nla_a,
>>+ NLBL_CIPSOV4_A_MLSLVLLOC);
>>+ nla_c = nla_find_nested(nla_a,
>>+ NLBL_CIPSOV4_A_MLSLVLREM);
>
>
> Maybe find better names for nla_a and nla_b, would enhance readability
>
Fair enough.
>>+ if (nla_b == NULL || nla_c == NULL)
>>+ goto add_std_failure;
>>+ doi_def->map.std->lvl.local[nla_get_u32(nla_b)] =
>>+ nla_get_u32(nla_c);
>>+ doi_def->map.std->lvl.cipso[nla_get_u32(nla_c)] =
>>+ nla_get_u32(nla_b);
>>+ }
>>
>>- num_cats = netlbl_getinc_u32(&msg, &msg_len);
>>- doi_def->map.std->cat.local_size = netlbl_getinc_u32(&msg, &msg_len);
>>- if (doi_def->map.std->cat.local_size > CIPSO_V4_MAX_LOC_CATS)
>>- goto add_std_failure;
>>- doi_def->map.std->cat.local = kcalloc(doi_def->map.std->cat.local_size,
>>+ if (info->attrs[NLBL_CIPSOV4_A_MLSCATLST]) {
>>+ if (nla_validate(
>>+ nla_data(info->attrs[NLBL_CIPSOV4_A_MLSCATLST]),
>>+ nla_len(info->attrs[NLBL_CIPSOV4_A_MLSCATLST]),
>>+ NLBL_CIPSOV4_A_MAX,
>>+ netlbl_cipsov4_genl_policy) != 0)
>
> We might want to add nla_validate_nested() to the interface as this seems
> to become a common usage.
Easy enough. I'll make that a separate patch in the next patchset.
>>@@ -276,21 +345,20 @@ static int netlbl_cipsov4_add_pass(u32 d
>> }
>> doi_def->type = CIPSO_V4_MAP_PASS;
>>
>>- for (iter = 0; iter < num_tags; iter++) {
>>- if (msg_len < NETLBL_LEN_U8)
>>- goto add_pass_failure;
>>- doi_def->tags[iter] = netlbl_getinc_u8(&msg, &msg_len);
>>- switch (doi_def->tags[iter]) {
>>- case CIPSO_V4_TAG_RBITMAP:
>>- break;
>>- default:
>>- goto add_pass_failure;
>>+ nla_for_each_attr(nla,
>>+ nla_data(info->attrs[NLBL_CIPSOV4_A_TAGLST]),
>>+ nla_len(info->attrs[NLBL_CIPSOV4_A_TAGLST]),
>>+ nla_rem)
>>+ if (nla->nla_type == NLBL_CIPSOV4_A_TAG) {
>>+ if (iter > CIPSO_V4_TAG_MAXCNT)
>>+ goto add_pass_failure;
>>+ doi_def->tags[iter++] = nla_get_u8(nla);
>> }
>
> This is duplicated code, put this into netlbl_cipsov4_get_tags()?
>
There is actually a little bit more than that too, I see your point.
I'll make a netlbl_cipsov4_add_common().
>>@@ -353,84 +408,237 @@ add_return:
>> * @info: the Generic NETLINK info block
>> *
>> * Description:
>>- * Process a user generated LIST message and respond accordingly. Returns
>>- * zero on success and negative values on error.
>>+ * Process a user generated LIST message and respond accordingly. While the
>>+ * response message generated by the kernel is straightforward, determining
>>+ * before hand the size of the buffer to allocate is not (we have to generate
>>+ * the message to know the size). In order to keep this function sane what
>>we
>>+ * do is allocate a buffer of NLMSG_GOODSIZE and try to fit the response in
>>+ * that size, if we fail then we restart with a larger buffer and try again.
>>+ * We continue in this manner until we hit a limit of failed attempts then we
>>+ * give up and just send an error message. Returns zero on success and
>>+ * negative values on error.
>> *
>> */
>> static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)
>> {
>>- int ret_val = -EINVAL;
>>+ int ret_val;
>>+ struct sk_buff *ans_skb = NULL;
>>+ u32 nlsze_mult = 1;
>>+ void *data;
>> u32 doi;
>>- struct nlattr *msg = netlbl_netlink_payload_data(skb);
>>- struct sk_buff *ans_skb;
>>+ struct nlattr *nla_a;
>>+ struct nlattr *nla_b;
>>+ struct cipso_v4_doi *doi_def;
>>+ u32 iter;
>>
>>- if (netlbl_netlink_payload_len(skb) != NETLBL_LEN_U32)
>>+ if (!info->attrs[NLBL_CIPSOV4_A_DOI]) {
>>+ ret_val = -EINVAL;
>> goto list_failure;
>>+ }
>>
>>- doi = nla_get_u32(msg);
>>- ans_skb = cipso_v4_doi_dump(doi, NLMSG_SPACE(GENL_HDRLEN));
>>+list_start:
>>+ ans_skb = nlmsg_new(NLMSG_GOODSIZE * nlsze_mult, GFP_KERNEL);
>> if (ans_skb == NULL) {
>> ret_val = -ENOMEM;
>> goto list_failure;
>> }
>>- netlbl_netlink_hdr_push(ans_skb,
>>- info->snd_pid,
>>- 0,
>>- netlbl_cipsov4_gnl_family.id,
>>- NLBL_CIPSOV4_C_LIST);
>>+ data = netlbl_netlink_hdr_put(ans_skb,
>>+ info->snd_pid,
>>+ info->snd_seq,
>>+ netlbl_cipsov4_gnl_family.id,
>>+ 0,
>>+ NLBL_CIPSOV4_C_LIST);
>>+ if (data == NULL) {
>>+ ret_val = -ENOMEM;
>>+ goto list_failure;
>>+ }
>>+
>>+ doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
>>+
>>+ rcu_read_lock();
>>+ doi_def = cipso_v4_doi_getdef(doi);
>>+ if (doi_def == NULL) {
>>+ ret_val = -EINVAL;
>>+ goto list_failure;
>>+ }
>>+
>>+ ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type);
>>+ if (ret_val != 0)
>>+ goto list_failure_lock;
>>+
>>+ nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_TAGLST);
>>+ if (nla_a == NULL) {
>>+ ret_val = -ENOMEM;
>>+ goto list_failure_lock;
>>+ }
>>+ for (iter = 0;
>>+ iter < CIPSO_V4_TAG_MAXCNT &&
>>+ doi_def->tags[iter] != CIPSO_V4_TAG_INVALID;
>>+ iter++) {
>>+ ret_val = nla_put_u8(ans_skb,
>>+ NLBL_CIPSOV4_A_TAG,
>>+ doi_def->tags[iter]);
>>+ if (ret_val != 0)
>>+ goto list_failure_lock;
>>+ }
>>+ nla_nest_end(ans_skb, nla_a);
>>
>>- ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid);
>>+ switch (doi_def->type) {
>>+ case CIPSO_V4_MAP_STD:
>>+ nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST);
>>+ if (nla_a == NULL) {
>>+ ret_val = -ENOMEM;
>>+ goto list_failure_lock;
>>+ }
>>+ for (iter = 0;
>>+ iter < doi_def->map.std->lvl.local_size;
>>+ iter++) {
>>+ if (doi_def->map.std->lvl.local[iter] ==
>>+ CIPSO_V4_INV_LVL)
>>+ continue;
>
>
> Can you estimate the number of entries being dumped here and in the cat
> list below?
>
It's too hard to come up with a reasonable estimate without going
through the entire list before hand, which in previous messages (might
of been off-list) you pointed out as a bad thing. If you would prefer I
can go back to doing it that way?
>>+
>>+ nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVL);
>>+ if (nla_b == NULL) {
>>+ ret_val = -ENOMEM;
>>+ goto list_retry;
>>+ }
>>+ ret_val = nla_put_u32(ans_skb,
>>+ NLBL_CIPSOV4_A_MLSLVLLOC,
>>+ iter);
>>+ if (ret_val != 0)
>>+ goto list_retry;
>>+ ret_val = nla_put_u32(ans_skb,
>>+ NLBL_CIPSOV4_A_MLSLVLREM,
>>+ doi_def->map.std->lvl.local[iter]);
>>+ if (ret_val != 0)
>>+ goto list_retry;
>>+ nla_nest_end(ans_skb, nla_b);
>>+ }
>>+ nla_nest_end(ans_skb, nla_a);
>>+
>>+ nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCATLST);
>>+ if (nla_a == NULL) {
>>+ ret_val = -ENOMEM;
>>+ goto list_retry;
>>+ }
>>+ for (iter = 0;
>>+ iter < doi_def->map.std->cat.local_size;
>>+ iter++) {
>>+ if (doi_def->map.std->cat.local[iter] ==
>>+ CIPSO_V4_INV_CAT)
>>+ continue;
>>+
>>+ nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCAT);
>>+ if (nla_b == NULL) {
>>+ ret_val = -ENOMEM;
>>+ goto list_retry;
>>+ }
>>+ ret_val = nla_put_u32(ans_skb,
>>+ NLBL_CIPSOV4_A_MLSCATLOC,
>>+ iter);
>>+ if (ret_val != 0)
>>+ goto list_retry;
>>+ ret_val = nla_put_u32(ans_skb,
>>+ NLBL_CIPSOV4_A_MLSCATREM,
>>+ doi_def->map.std->cat.local[iter]);
>>+ if (ret_val != 0)
>>+ goto list_retry;
>>+ nla_nest_end(ans_skb, nla_b);
>>+ }
>>+ nla_nest_end(ans_skb, nla_a);
>>+
>>+ break;
>>+ }
>>+ rcu_read_unlock();
>
> What I meant in the previous posting is to put genlmsg_end() in here
> like the rest of the code to be clear and symmetric.
Okay, I put it there because it was a common trend in the code, i.e. end
the message then do a write, I thought I would combine them. I'll split
it back out.
> The rest of the code has simliar issues, nevertheless this looks
> really great. Everything is extendable and relatively easy to
> maintain. This should definitely go into 2.6.19. Good work.
Thanks for your patience as I got the hang of the genetlink stuff. I'll
make the changes you suggested and get a new version out soon.
--
paul moore
linux security @ hp
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html