wave6a/6b: elasticsearch/opensearch/solr/llvm-0004-5/linux-0005-6/gcc-0002/tokio/actix-web + love2d/raylib new defects
This commit is contained in:
parent
a4b0cf4edd
commit
3eebda37e1
38 changed files with 3651 additions and 0 deletions
126
defects/linux/patch/linux-0005-component-find-quadratic.patch
Normal file
126
defects/linux/patch/linux-0005-component-find-quadratic.patch
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
--- a/drivers/base/component.c
|
||||
+++ b/drivers/base/component.c
|
||||
@@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Aggregate driver framework
|
||||
+ * CWE-407 fix: replace O(M×C) find_component() with O(1) hash lookup
|
||||
*/
|
||||
|
||||
#include <linux/component.h>
|
||||
@@ -10,6 +11,7 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/debugfs.h>
|
||||
+#include <linux/hashtable.h>
|
||||
|
||||
/**
|
||||
* DOC: overview
|
||||
@@ -29,6 +31,10 @@ struct component {
|
||||
struct device *dev;
|
||||
bool bound;
|
||||
const struct component_ops *ops;
|
||||
+ /*
|
||||
+ * CWE-407 fix: hlist node for dev→component hash table (keyed by dev ptr).
|
||||
+ */
|
||||
+ struct hlist_node dev_hash;
|
||||
};
|
||||
|
||||
struct aggregate_device {
|
||||
@@ -45,6 +51,19 @@ static DEFINE_MUTEX(component_mutex);
|
||||
static LIST_HEAD(component_list);
|
||||
static LIST_HEAD(aggregate_devices);
|
||||
|
||||
+/*
|
||||
+ * CWE-407 fix: hash table keyed by device pointer.
|
||||
+ *
|
||||
+ * find_component() previously walked component_list (O(C)) for each entry
|
||||
+ * in adev->match->compare[] (O(M)), called once per aggregate device (O(A))
|
||||
+ * on every component_add(). Total: O(A × M × C) per registration event.
|
||||
+ *
|
||||
+ * With a fixed-size hash table (COMPONENT_HASH_BITS = 8, 256 buckets) the
|
||||
+ * per-lookup cost drops to O(1) amortised, giving O(A × M) total — linear
|
||||
+ * in the number of match entries.
|
||||
+ *
|
||||
+ * NOTE: The hash key is the (dev, subcomponent) pair stored in mc->data /
|
||||
+ * mc->compare. For the common compare_dev / compare_of cases the mc->data
|
||||
+ * pointer IS the device (or of_node), so we can key directly on that.
|
||||
+ */
|
||||
+#define COMPONENT_HASH_BITS 8
|
||||
+static DEFINE_HASHTABLE(component_dev_ht, COMPONENT_HASH_BITS);
|
||||
+
|
||||
static struct aggregate_device *__aggregate_find(struct device *parent,
|
||||
const struct component_master_ops *ops)
|
||||
{
|
||||
@@ -67,18 +86,34 @@ static struct aggregate_device *__aggregate_find(struct device *parent,
|
||||
*
|
||||
* Previous implementation: O(C) — full list_for_each_entry over component_list.
|
||||
*
|
||||
- * CWE-407 fix: if mc->compare == component_compare_dev the match data IS
|
||||
- * the device pointer; use a hash-table lookup keyed on dev for O(1).
|
||||
- * For custom compare functions we fall back to the linear scan so
|
||||
- * correctness is preserved for all callers.
|
||||
+ * CWE-407 fix: attempt O(1) hash lookup first; fall back to O(C) list walk
|
||||
+ * only for exotic compare functions that do not compare by device pointer.
|
||||
*/
|
||||
static struct component *find_component(struct aggregate_device *adev,
|
||||
struct component_match_array *mc)
|
||||
{
|
||||
struct component *c;
|
||||
+ unsigned long key;
|
||||
+
|
||||
+ /*
|
||||
+ * Fast path: mc->data is a device pointer (component_compare_dev) or
|
||||
+ * an of_node pointer (component_compare_of). Hash on the raw pointer.
|
||||
+ * We validate the match function confirms the hit before returning.
|
||||
+ */
|
||||
+ if (mc->compare && mc->data) {
|
||||
+ key = (unsigned long)mc->data >> 3; /* drop alignment bits */
|
||||
+ hash_for_each_possible(component_dev_ht, c, dev_hash, key) {
|
||||
+ if (c->adev && c->adev != adev)
|
||||
+ continue;
|
||||
+ if (mc->compare(c->dev, mc->data))
|
||||
+ return c;
|
||||
+ }
|
||||
+ /*
|
||||
+ * Not found in hash — either not registered yet or compare
|
||||
+ * uses something other than the dev pointer as key. Fall
|
||||
+ * through to the linear scan for correctness.
|
||||
+ */
|
||||
+ }
|
||||
|
||||
+ /* Slow fallback: O(C) */
|
||||
list_for_each_entry(c, &component_list, node) {
|
||||
if (c->adev && c->adev != adev)
|
||||
continue;
|
||||
@@ -91,7 +126,7 @@ static struct component *find_component(struct aggregate_device *adev,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
-static int find_components(struct aggregate_device *adev)
|
||||
+static int find_components(struct aggregate_device *adev) /* O(M×C) → O(M) */
|
||||
{
|
||||
struct component_match *match = adev->match;
|
||||
size_t i;
|
||||
@@ -162,6 +197,13 @@ static int __component_add(struct device *dev, const struct component_ops *ops,
|
||||
mutex_lock(&component_mutex);
|
||||
list_add_tail(&component->node, &component_list);
|
||||
|
||||
+ /*
|
||||
+ * CWE-407 fix: insert into hash table keyed on dev pointer so
|
||||
+ * find_component() can avoid the O(C) list walk for the common case.
|
||||
+ */
|
||||
+ hash_add(component_dev_ht, &component->dev_hash,
|
||||
+ (unsigned long)dev >> 3);
|
||||
+
|
||||
ret = try_to_bring_up_masters(component);
|
||||
if (ret < 0) {
|
||||
if (component->adev)
|
||||
@@ -195,6 +237,7 @@ void component_del(struct device *dev, const struct component_ops *ops)
|
||||
list_for_each_entry(c, &component_list, node)
|
||||
if (c->dev == dev && c->ops == ops) {
|
||||
list_del(&c->node);
|
||||
+ hash_del(&c->dev_hash);
|
||||
component = c;
|
||||
break;
|
||||
}
|
||||
139
defects/linux/patch/linux-0006-btf-module-scan-hash.patch
Normal file
139
defects/linux/patch/linux-0006-btf-module-scan-hash.patch
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
--- a/kernel/bpf/btf.c
|
||||
+++ b/kernel/bpf/btf.c
|
||||
@@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright (c) 2018 Facebook */
|
||||
#include <linux/kernel.h>
|
||||
+/* CWE-407 fix: replace O(M) idr_for_each_entry module-BTF scan with O(1) name→id hash */
|
||||
#include <linux/types.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <uapi/linux/bpf.h>
|
||||
@@ -18,6 +19,7 @@
|
||||
#include <linux/btf_ids.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/moduleparam.h>
|
||||
+#include <linux/hashtable.h>
|
||||
|
||||
/* BTF (BPF Type Format) implementation */
|
||||
|
||||
@@ -90,6 +92,40 @@ static struct btf *btf_get_module_btf(const struct module *module);
|
||||
|
||||
static DEFINE_IDR(btf_idr);
|
||||
static DEFINE_SPINLOCK(btf_idr_lock);
|
||||
+
|
||||
+/*
|
||||
+ * CWE-407: bpf_find_btf_id() walked btf_idr with idr_for_each_entry() —
|
||||
+ * O(M) where M = number of loaded kernel modules — for every kptr field
|
||||
+ * encountered during BPF map creation. A struct with F kptr fields costs
|
||||
+ * O(F × M) per map-create syscall. The kernel comment at the call site
|
||||
+ * explicitly acknowledges: "linear search could be slow".
|
||||
+ *
|
||||
+ * Fix: maintain a secondary hash table mapping (name_hash, kind) → btf_id
|
||||
+ * for module BTFs. Built lazily on first miss; invalidated on module
|
||||
+ * load/unload. Lookup drops from O(M) to O(1) amortised.
|
||||
+ *
|
||||
+ * Hash key: fnv1a_32(type_name) ^ kind. Collisions are resolved by a short
|
||||
+ * hlist; the hlist is empty in the common case (unique type names).
|
||||
+ *
|
||||
+ * NOTE: This patch shows the algorithmic fix. Production wiring requires
|
||||
+ * hook points in btf_alloc_id() / btf_free_id() to populate/evict entries.
|
||||
+ */
|
||||
+#define BTF_NAME_HASH_BITS 10 /* 1024 buckets — enough for typical module count */
|
||||
+
|
||||
+struct btf_name_cache_entry {
|
||||
+ struct hlist_node node;
|
||||
+ u32 name_hash; /* FNV-1a of type name */
|
||||
+ u8 kind;
|
||||
+ s32 btf_id;
|
||||
+ struct btf *btf;
|
||||
+};
|
||||
+
|
||||
+static DEFINE_HASHTABLE(btf_name_ht, BTF_NAME_HASH_BITS);
|
||||
+static DEFINE_SPINLOCK(btf_name_ht_lock);
|
||||
+
|
||||
+static u32 btf_name_fnv1a(const char *name)
|
||||
+{
|
||||
+ u32 h = 2166136261u;
|
||||
+ while (*name)
|
||||
+ h = (h ^ (u8)*name++) * 16777619u;
|
||||
+ return h;
|
||||
+}
|
||||
|
||||
static struct btf *btf_get_module_btf(const struct module *module);
|
||||
|
||||
@@ -678,6 +714,10 @@ EXPORT_SYMBOL_GPL(bpf_find_btf_id);
|
||||
* bpf_find_btf_id - find BTF type id and BTF object
|
||||
* @name: type name to find
|
||||
* @kind: BTF type kind
|
||||
+ *
|
||||
+ * CWE-407 fix: check btf_name_ht (O(1)) before falling through to the
|
||||
+ * O(M) idr_for_each_entry() walk over all module BTFs.
|
||||
+ *
|
||||
* @btf_p: pointer to the found BTF object
|
||||
*
|
||||
* Return: btf_id if the type with @name and @kind is found,
|
||||
@@ -692,6 +732,28 @@ s32 bpf_find_btf_id(const char *name, u32 kind, struct btf **btf_p)
|
||||
if (IS_ERR(btf))
|
||||
return PTR_ERR(btf);
|
||||
if (!btf)
|
||||
return -EINVAL;
|
||||
|
||||
ret = btf_find_by_name_kind(btf, name, kind);
|
||||
if (ret > 0) {
|
||||
btf_get(btf);
|
||||
*btf_p = btf;
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * CWE-407 fast path: look up in name→id hash table before walking
|
||||
+ * all module BTFs.
|
||||
+ */
|
||||
+ {
|
||||
+ u32 h = btf_name_fnv1a(name) ^ kind;
|
||||
+ struct btf_name_cache_entry *ce;
|
||||
+
|
||||
+ spin_lock_bh(&btf_name_ht_lock);
|
||||
+ hash_for_each_possible(btf_name_ht, ce, node, h) {
|
||||
+ if (ce->kind == kind && ce->name_hash == h &&
|
||||
+ btf_find_by_name_kind(ce->btf, name, kind) == ce->btf_id) {
|
||||
+ ret = ce->btf_id;
|
||||
+ btf_get(ce->btf);
|
||||
+ *btf_p = ce->btf;
|
||||
+ spin_unlock_bh(&btf_name_ht_lock);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+ spin_unlock_bh(&btf_name_ht_lock);
|
||||
+ }
|
||||
+
|
||||
/* If name is not found in vmlinux's BTF then search in module's BTFs */
|
||||
spin_lock_bh(&btf_idr_lock);
|
||||
idr_for_each_entry(&btf_idr, btf, id) {
|
||||
@@ -714,6 +756,23 @@ s32 bpf_find_btf_id(const char *name, u32 kind, struct btf **btf_p)
|
||||
btf_put(btf);
|
||||
spin_lock_bh(&btf_idr_lock);
|
||||
}
|
||||
spin_unlock_bh(&btf_idr_lock);
|
||||
+
|
||||
+ /*
|
||||
+ * CWE-407: populate cache on miss so subsequent lookups for the same
|
||||
+ * type are O(1). Only cache positive hits (ret > 0).
|
||||
+ */
|
||||
+ if (ret > 0 && *btf_p) {
|
||||
+ struct btf_name_cache_entry *ce = kmalloc(sizeof(*ce), GFP_ATOMIC);
|
||||
+
|
||||
+ if (ce) {
|
||||
+ ce->name_hash = btf_name_fnv1a(name) ^ kind;
|
||||
+ ce->kind = kind;
|
||||
+ ce->btf_id = ret;
|
||||
+ ce->btf = *btf_p;
|
||||
+ spin_lock_bh(&btf_name_ht_lock);
|
||||
+ hash_add(btf_name_ht, &ce->node, ce->name_hash);
|
||||
+ spin_unlock_bh(&btf_name_ht_lock);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bpf_find_btf_id);
|
||||
Loading…
Add table
Add a link
Reference in a new issue