UBUNTU: SAUCE: apparmor4.0.0 [55/90]: prompt - add refcount to audit_node in prep or reuse and delete
BugLink: http://bugs.launchpad.net/bugs/2028253 The audit_node needs to be shared for asynchronous notifications to multiple listeners. So add a refcount to enable sharing. Signed-off-by: John Johansen <john.johansen@canonical.com> (cherry picked from https://gitlab.com/jjohansen/apparmor-kernel) Signed-off-by: Andrea Righi <andrea.righi@canonical.com> (cherry picked from commit bbebba69241db7470d5b389ae0bbb3524b02c04c https://git.launchpad.net/~apparmor-dev/ubuntu-kernel-next) Signed-off-by: Paolo Pisati <paolo.pisati@canonical.com>
This commit is contained in:
committed by
Paolo Pisati
parent
c5f3b6ece9
commit
443431be30
@@ -207,6 +207,7 @@ struct aa_audit_rule {
|
||||
};
|
||||
|
||||
/****************************** audit rules *******************************/
|
||||
|
||||
void aa_audit_rule_free(void *vrule, int lsmid)
|
||||
{
|
||||
struct aa_audit_rule *rule = vrule;
|
||||
@@ -350,7 +351,7 @@ long aa_audit_data_cmp(struct apparmor_audit_data *lhs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void aa_audit_node_free(struct aa_audit_node *node)
|
||||
static void audit_node_free(struct aa_audit_node *node)
|
||||
{
|
||||
if (!node)
|
||||
return;
|
||||
@@ -373,6 +374,13 @@ void aa_audit_node_free(struct aa_audit_node *node)
|
||||
kmem_cache_free(aa_audit_slab, node);
|
||||
}
|
||||
|
||||
void aa_audit_node_free_kref(struct kref *kref)
|
||||
{
|
||||
struct aa_audit_node *node = container_of(kref, struct aa_audit_node,
|
||||
count);
|
||||
audit_node_free(node);
|
||||
}
|
||||
|
||||
struct aa_audit_node *aa_dup_audit_data(struct apparmor_audit_data *orig,
|
||||
gfp_t gfp)
|
||||
{
|
||||
@@ -381,6 +389,7 @@ struct aa_audit_node *aa_dup_audit_data(struct apparmor_audit_data *orig,
|
||||
copy = kmem_cache_zalloc(aa_audit_slab, gfp);
|
||||
if (!copy)
|
||||
return NULL;
|
||||
kref_init(©->count);
|
||||
|
||||
copy->knotif.ad = ©->data;
|
||||
INIT_LIST_HEAD(©->list);
|
||||
@@ -457,7 +466,7 @@ struct aa_audit_node *aa_dup_audit_data(struct apparmor_audit_data *orig,
|
||||
|
||||
return copy;
|
||||
fail:
|
||||
aa_audit_node_free(copy);
|
||||
audit_node_free(copy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -473,6 +482,7 @@ __out_skip: \
|
||||
__node; \
|
||||
})
|
||||
|
||||
// increments refcount on node
|
||||
struct aa_audit_node *aa_audit_cache_find(struct aa_audit_cache *cache,
|
||||
struct apparmor_audit_data *ad)
|
||||
{
|
||||
@@ -480,6 +490,7 @@ struct aa_audit_node *aa_audit_cache_find(struct aa_audit_cache *cache,
|
||||
|
||||
rcu_read_lock();
|
||||
node = __audit_cache_find(cache, ad);
|
||||
aa_get_audit_node(node);
|
||||
rcu_read_unlock();
|
||||
|
||||
return node;
|
||||
@@ -490,9 +501,12 @@ struct aa_audit_node *aa_audit_cache_find(struct aa_audit_cache *cache,
|
||||
* @cache: the cache to insert into
|
||||
* @node: the audit node to insert into the cache
|
||||
*
|
||||
* Returns: matching node in cache OR @node if @node was inserted.
|
||||
* Returns: refcounted matching node in cache OR @node if @node was inserted.
|
||||
*
|
||||
* Increments refcount on node if successfully inserted. Assumes caller
|
||||
* already has valid ref count.
|
||||
* Increments refcount on existing node if returned
|
||||
*/
|
||||
|
||||
struct aa_audit_node *aa_audit_cache_insert(struct aa_audit_cache *cache,
|
||||
struct aa_audit_node *node)
|
||||
|
||||
@@ -507,6 +521,8 @@ struct aa_audit_node *aa_audit_cache_insert(struct aa_audit_cache *cache,
|
||||
tmp = node;
|
||||
cache->size++;
|
||||
}
|
||||
|
||||
aa_get_audit_node(tmp);
|
||||
/* else raced another insert */
|
||||
spin_unlock(&cache->lock);
|
||||
|
||||
@@ -531,7 +547,7 @@ void aa_audit_cache_destroy(struct aa_audit_cache *cache)
|
||||
|
||||
list_for_each_entry_safe(node, tmp, &cache->head, list) {
|
||||
list_del_init(&node->list);
|
||||
aa_audit_node_free(node);
|
||||
aa_put_audit_node(node);
|
||||
}
|
||||
cache->size = 0;
|
||||
}
|
||||
|
||||
+19
-18
@@ -106,6 +106,7 @@ static int check_cache(struct aa_profile *profile,
|
||||
AA_DEBUG(DEBUG_UPCALL,
|
||||
"cache hit denied, request: 0x%x by cached deny 0x%x\n",
|
||||
ad->request, hit->data.denied);
|
||||
aa_put_audit_node(hit);
|
||||
return ad->error;
|
||||
} else if (ad->request & ~hit->data.request) {
|
||||
/* asking for more perms than is cached */
|
||||
@@ -116,9 +117,12 @@ static int check_cache(struct aa_profile *profile,
|
||||
} else {
|
||||
AA_DEBUG(DEBUG_UPCALL, "cache hit");
|
||||
ad->error = 0;
|
||||
aa_put_audit_node(hit);
|
||||
/* do audit */
|
||||
return 0;
|
||||
}
|
||||
aa_put_audit_node(hit);
|
||||
hit = NULL;
|
||||
} else {
|
||||
AA_DEBUG(DEBUG_UPCALL, "cache miss");
|
||||
}
|
||||
@@ -151,34 +155,31 @@ static int check_cache(struct aa_profile *profile,
|
||||
ad->error = node->data.error;
|
||||
|
||||
if (cache_response) {
|
||||
if (hit) {
|
||||
hit:
|
||||
/* TODO: shouldn't add until after auditing it, or at
|
||||
* least having a refcount. Fix once removing entry is
|
||||
* allowed
|
||||
*/
|
||||
AA_DEBUG(DEBUG_UPCALL, "inserting cache entry requ 0x%x denied 0x%x",
|
||||
node->data.request, node->data.denied);
|
||||
hit = aa_audit_cache_insert(&profile->learning_cache,
|
||||
node);
|
||||
AA_DEBUG(DEBUG_UPCALL, "cache insert %s: name %s node %s\n",
|
||||
hit != node ? "lost race" : "",
|
||||
hit->data.name, node->data.name);
|
||||
if (hit != node) {
|
||||
AA_DEBUG(DEBUG_UPCALL, "updating existing cache entry");
|
||||
aa_audit_cache_update_ent(&profile->learning_cache,
|
||||
hit, &node->data);
|
||||
aa_put_audit_node(hit);
|
||||
} else {
|
||||
/* TODO: shouldn't add until after auditing it, or at
|
||||
* least having a refcount. Fix once removing entry is
|
||||
* allowed
|
||||
*/
|
||||
AA_DEBUG(DEBUG_UPCALL, "inserting cache entry requ 0x%x denied 0x%x",
|
||||
node->data.request, node->data.denied);
|
||||
hit = aa_audit_cache_insert(&profile->learning_cache,
|
||||
node);
|
||||
AA_DEBUG(DEBUG_UPCALL, "cache insert %s: name %s node %s\n",
|
||||
hit != node ? "lost race" : "",
|
||||
hit->data.name, node->data.name);
|
||||
if (hit != node)
|
||||
goto hit;
|
||||
|
||||
AA_DEBUG(DEBUG_UPCALL, "inserted into cache");
|
||||
/* do not free node, it is now owned by the cache */
|
||||
node = NULL;
|
||||
}
|
||||
/* now to audit */
|
||||
} /* cache_response */
|
||||
|
||||
return_to_audit:
|
||||
aa_audit_node_free(node);
|
||||
aa_put_audit_node(node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -174,6 +174,7 @@ struct apparmor_audit_data {
|
||||
};
|
||||
|
||||
struct aa_audit_node {
|
||||
struct kref count;
|
||||
struct apparmor_audit_data data;
|
||||
struct list_head list;
|
||||
struct aa_knotif knotif;
|
||||
@@ -254,10 +255,26 @@ int aa_audit_rule_match(struct lsmblob *blob, u32 field, u32 op, void *vrule,
|
||||
int lsmid);
|
||||
|
||||
|
||||
void aa_audit_node_free(struct aa_audit_node *node);
|
||||
void aa_audit_node_free_kref(struct kref *kref);
|
||||
struct aa_audit_node *aa_dup_audit_data(struct apparmor_audit_data *orig,
|
||||
gfp_t gfp);
|
||||
long aa_audit_data_cmp(struct apparmor_audit_data *lhs,
|
||||
struct apparmor_audit_data *rhs);
|
||||
|
||||
|
||||
static inline struct aa_audit_node *aa_get_audit_node(struct aa_audit_node *node)
|
||||
{
|
||||
if (node)
|
||||
kref_get(&(node->count));
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static inline void aa_put_audit_node(struct aa_audit_node *node)
|
||||
{
|
||||
if (node)
|
||||
kref_put(&node->count, aa_audit_node_free_kref);
|
||||
}
|
||||
|
||||
|
||||
#endif /* __AA_AUDIT_H */
|
||||
|
||||
@@ -91,5 +91,4 @@ static inline void aa_put_listener(struct aa_listener *listener)
|
||||
kref_put(&listener->count, aa_listener_kref);
|
||||
}
|
||||
|
||||
|
||||
#endif /* __AA_NOTIFY_H */
|
||||
|
||||
Reference in New Issue
Block a user