Skip to content

Commit

Permalink
cipso,calipso: resolve a number of problems with the DOI refcounts
Browse files Browse the repository at this point in the history
The current CIPSO and CALIPSO refcounting scheme for the DOI
definitions is a bit flawed in that we:

1. Don't correctly match gets/puts in netlbl_cipsov4_list().
2. Decrement the refcount on each attempt to remove the DOI from the
   DOI list, only removing it from the list once the refcount drops
   to zero.

This patch fixes these problems by adding the missing "puts" to
netlbl_cipsov4_list() and introduces a more conventional, i.e.
not-buggy, refcounting mechanism to the DOI definitions.  Upon the
addition of a DOI to the DOI list, it is initialized with a refcount
of one, removing a DOI from the list removes it from the list and
drops the refcount by one; "gets" and "puts" behave as expected with
respect to refcounts, increasing and decreasing the DOI's refcount by
one.

Fixes: b1edeb1 ("netlabel: Replace protocol/NetLabel linking with refrerence counts")
Fixes: d7cce01 ("netlabel: Add support for removing a CALIPSO DOI.")
Reported-by: syzbot+9ec037722d2603a9f52e@syzkaller.appspotmail.com
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
pcmoore authored and davem330 committed Mar 4, 2021
1 parent 67eb211 commit ad5d07f
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 19 deletions.
11 changes: 1 addition & 10 deletions net/ipv4/cipso_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -519,16 +519,10 @@ int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info)
ret_val = -ENOENT;
goto doi_remove_return;
}
if (!refcount_dec_and_test(&doi_def->refcount)) {
spin_unlock(&cipso_v4_doi_list_lock);
ret_val = -EBUSY;
goto doi_remove_return;
}
list_del_rcu(&doi_def->list);
spin_unlock(&cipso_v4_doi_list_lock);

cipso_v4_cache_invalidate();
call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
cipso_v4_doi_putdef(doi_def);
ret_val = 0;

doi_remove_return:
Expand Down Expand Up @@ -585,9 +579,6 @@ void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def)

if (!refcount_dec_and_test(&doi_def->refcount))
return;
spin_lock(&cipso_v4_doi_list_lock);
list_del_rcu(&doi_def->list);
spin_unlock(&cipso_v4_doi_list_lock);

cipso_v4_cache_invalidate();
call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
Expand Down
14 changes: 5 additions & 9 deletions net/ipv6/calipso.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ struct calipso_map_cache_entry {

static struct calipso_map_cache_bkt *calipso_cache;

static void calipso_cache_invalidate(void);
static void calipso_doi_putdef(struct calipso_doi *doi_def);

/* Label Mapping Cache Functions
*/

Expand Down Expand Up @@ -444,15 +447,10 @@ static int calipso_doi_remove(u32 doi, struct netlbl_audit *audit_info)
ret_val = -ENOENT;
goto doi_remove_return;
}
if (!refcount_dec_and_test(&doi_def->refcount)) {
spin_unlock(&calipso_doi_list_lock);
ret_val = -EBUSY;
goto doi_remove_return;
}
list_del_rcu(&doi_def->list);
spin_unlock(&calipso_doi_list_lock);

call_rcu(&doi_def->rcu, calipso_doi_free_rcu);
calipso_doi_putdef(doi_def);
ret_val = 0;

doi_remove_return:
Expand Down Expand Up @@ -508,10 +506,8 @@ static void calipso_doi_putdef(struct calipso_doi *doi_def)

if (!refcount_dec_and_test(&doi_def->refcount))
return;
spin_lock(&calipso_doi_list_lock);
list_del_rcu(&doi_def->list);
spin_unlock(&calipso_doi_list_lock);

calipso_cache_invalidate();
call_rcu(&doi_def->rcu, calipso_doi_free_rcu);
}

Expand Down
3 changes: 3 additions & 0 deletions net/netlabel/netlabel_cipso_v4.c
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,7 @@ static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)

break;
}
cipso_v4_doi_putdef(doi_def);
rcu_read_unlock();

genlmsg_end(ans_skb, data);
Expand All @@ -583,12 +584,14 @@ static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)
list_retry:
/* XXX - this limit is a guesstimate */
if (nlsze_mult < 4) {
cipso_v4_doi_putdef(doi_def);
rcu_read_unlock();
kfree_skb(ans_skb);
nlsze_mult *= 2;
goto list_start;
}
list_failure_lock:
cipso_v4_doi_putdef(doi_def);
rcu_read_unlock();
list_failure:
kfree_skb(ans_skb);
Expand Down

0 comments on commit ad5d07f

Please sign in to comment.