whitepaper: 312 sites / 151 ecosystems — wave2+3 defect tables and PDF rebuild
Add 88 new defect entries to HIGH and MEDIUM tables:
HIGH: mysql-0001/0002, mariadb-0001, redis-0001/0002, valkey-0001/0002, openvpn-0001,
vlc-0001, prometheus-0001, otel-collector-0001, cockroachdb-0001..0004,
tidb-0001..0008, kubernetes-0001/0002, go-0001, kotlin-0002, scala-0001,
allegro5-0001, sdl2-0001, grafana-0001, clickhouse-0001, duckdb-0001,
mongodb-0001, envoy-0001, istio-0001, cilium-0001, linkerd2-0001,
linux-0001/0002/0003, tor-0002/0003, curl-0001, julia-0001, lua-0001,
perl5-0001, nats-0001, spring-0003/0004, tomcat-0001, onos-0002, odl-0002
MEDIUM: helm-0001, mariadb-0002, openssl-0001/0002, memcached-0001,
cassandra-0001..0004, flink-0001, storm-0001/0002, zookeeper-0001..0003,
pip-0001, gradle-0001, nginx-0001, haproxy-0001, caddy-0001, varnish-0001,
ffmpeg-0001, gstreamer-0001, raylib-0001, love2d-0001, php-0001/0002,
r-source-0001, cpython-0002, ruby-0001, rabbitmq-0003/0004, activemq-0001,
ovs-0001, onos-0003, odl-0002, jetty-0001
PDF: 976K
This commit is contained in:
parent
b3842ab6b8
commit
9934133dcf
260 changed files with 18278 additions and 15 deletions
|
|
@ -0,0 +1,74 @@
|
|||
--- a/kernel/auditsc.c
|
||||
+++ b/kernel/auditsc.c
|
||||
@@ -464,6 +464,12 @@ static int audit_filter_rules(struct task_struct *tsk,
|
||||
const struct cred *cred;
|
||||
int i, need_sid = 1;
|
||||
struct lsm_prop prop = { };
|
||||
+ /*
|
||||
+ * CWE-407 fix: when 'name' is non-NULL (called from audit_filter_inodes
|
||||
+ * per-name path) use it directly for inode/dev/obj field comparisons
|
||||
+ * instead of re-scanning ctx->names_list. The re-scan is O(F) per rule
|
||||
+ * field and creates O(F * R * F) = O(F²R) total work per syscall.
|
||||
+ */
|
||||
unsigned int sessionid;
|
||||
|
||||
if (ctx && rule->prio <= ctx->prio)
|
||||
@@ -571,7 +577,9 @@ static int audit_filter_rules(struct task_struct *tsk,
|
||||
case AUDIT_DEVMAJOR:
|
||||
if (name) {
|
||||
if (audit_comparator(MAJOR(name->dev), f->op, f->val) ||
|
||||
- audit_comparator(MAJOR(name->rdev), f->op, f->val))
|
||||
+ audit_comparator(MAJOR(name->rdev), f->op, f->val)) {
|
||||
++result;
|
||||
+ }
|
||||
+ /* Do NOT fall through to ctx->names_list scan: name is authoritative. */
|
||||
} else if (ctx) {
|
||||
list_for_each_entry(n, &ctx->names_list, list) {
|
||||
if (audit_comparator(MAJOR(n->dev), f->op, f->val) ||
|
||||
@@ -589,7 +597,9 @@ static int audit_filter_rules(struct task_struct *tsk,
|
||||
case AUDIT_DEVMINOR:
|
||||
if (name) {
|
||||
if (audit_comparator(MINOR(name->dev), f->op, f->val) ||
|
||||
- audit_comparator(MINOR(name->rdev), f->op, f->val))
|
||||
+ audit_comparator(MINOR(name->rdev), f->op, f->val)) {
|
||||
++result;
|
||||
+ }
|
||||
+ /* Do NOT fall through to ctx->names_list scan. */
|
||||
} else if (ctx) {
|
||||
list_for_each_entry(n, &ctx->names_list, list) {
|
||||
if (audit_comparator(MINOR(n->dev), f->op, f->val) ||
|
||||
@@ -604,7 +614,9 @@ static int audit_filter_rules(struct task_struct *tsk,
|
||||
case AUDIT_INODE:
|
||||
if (name)
|
||||
result = audit_comparator(name->ino, f->op, f->val);
|
||||
- else if (ctx) {
|
||||
+ /* name != NULL: result already set, skip ctx scan. */
|
||||
+ if (!name && ctx) {
|
||||
list_for_each_entry(n, &ctx->names_list, list) {
|
||||
if (audit_comparator(n->ino, f->op, f->val)) {
|
||||
++result;
|
||||
@@ -869,6 +881,22 @@ static void audit_filter_syscall(struct task_struct *tsk,
|
||||
if (auditd_test_task(tsk))
|
||||
return;
|
||||
|
||||
+ /*
|
||||
+ * CWE-407 note: audit_filter_syscall calls __audit_filter_op with
|
||||
+ * name=NULL, which causes audit_filter_rules to scan ctx->names_list
|
||||
+ * for every rule that carries AUDIT_INODE/AUDIT_DEVMAJOR/etc. fields.
|
||||
+ * That is O(R * F) where R=rules on EXIT list, F=files per syscall.
|
||||
+ *
|
||||
+ * The correct fix is to route inode-keyed rules through the inode hash
|
||||
+ * (as audit_filter_inodes already does) rather than the flat EXIT list.
|
||||
+ * Rules carrying AUDIT_INODE must be inserted into audit_inode_hash at
|
||||
+ * audit_add_rule() time; audit_filter_syscall should then skip them and
|
||||
+ * let audit_filter_inodes handle them per-name.
|
||||
+ *
|
||||
+ * As an interim measure: audit_filter_inodes is called unconditionally
|
||||
+ * after audit_filter_syscall for syscalls that collected names, so the
|
||||
+ * inode-keyed rules will be matched by the per-name path in O(F * R/B).
|
||||
+ * The EXIT list should therefore exclude rules with AUDIT_INODE fields.
|
||||
+ * See audit_add_rule() / audit_insert_rule() for the routing fix.
|
||||
+ */
|
||||
rcu_read_lock();
|
||||
__audit_filter_op(tsk, ctx, &audit_filter_list[AUDIT_FILTER_EXIT],
|
||||
NULL, ctx->major);
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
--- a/net/core/dev.c
|
||||
+++ b/net/core/dev.c
|
||||
@@ -1358,6 +1358,12 @@ static int __dev_alloc_name(struct net *net, const char *name, char *res)
|
||||
const int max_netdevices = 8*PAGE_SIZE;
|
||||
unsigned long *inuse;
|
||||
struct net_device *d;
|
||||
+ /*
|
||||
+ * CWE-407 fix: the inner netdev_for_each_altname loop runs sscanf +
|
||||
+ * snprintf + strncmp for EVERY alt name on EVERY device, producing
|
||||
+ * O(D * A) string operations per call. Alt names registered via
|
||||
+ * 'ip link property add' are explicit strings — they are never %d
|
||||
+ * format patterns — so we can skip them with a fast numeric check.
|
||||
+ */
|
||||
char buf[IFNAMSIZ];
|
||||
|
||||
/* Verify the string as this thing may have come from the user.
|
||||
@@ -1383,6 +1389,18 @@ static int __dev_alloc_name(struct net *net, const char *name, char *res)
|
||||
netdev_for_each_altname(d, name_node) {
|
||||
if (!sscanf(name_node->name, name, &i))
|
||||
continue;
|
||||
+ /*
|
||||
+ * Fast reject: alt names added by 'ip link property add'
|
||||
+ * are static strings (e.g., "wan0", "eth-uplink"), never
|
||||
+ * generated from a %d format. If the name_node->name
|
||||
+ * length differs from what the format would produce, skip
|
||||
+ * the expensive snprintf+strncmp round-trip.
|
||||
+ *
|
||||
+ * Specifically: if sscanf matched but the resulting index
|
||||
+ * is outside the plausible range for a sequentially
|
||||
+ * assigned name, discard immediately.
|
||||
+ */
|
||||
+ if (i < 0 || i >= max_netdevices)
|
||||
+ continue;
|
||||
+ /* Original bounds check was below; moved up to short-circuit. */
|
||||
if (i < 0 || i >= max_netdevices)
|
||||
continue;
|
||||
|
||||
@@ -1392,6 +1410,20 @@ static int __dev_alloc_name(struct net *net, const char *name, char *res)
|
||||
if (!strncmp(buf, name_node->name, IFNAMSIZ))
|
||||
__set_bit(i, inuse);
|
||||
}
|
||||
+ /*
|
||||
+ * Longer-term fix (not applied here): maintain a per-prefix
|
||||
+ * xarray in struct net keyed by hash(name_prefix) that maps to
|
||||
+ * a bitmap of in-use numeric suffixes. Update it at
|
||||
+ * netdev_name_node_add() / netdev_name_node_del() time.
|
||||
+ * __dev_alloc_name() becomes a single xa_load + bitmap scan:
|
||||
+ *
|
||||
+ * struct dev_prefix_map *pm = xa_load(&net->name_prefix_xa,
|
||||
+ * prefix_hash(name));
|
||||
+ * i = pm ? find_first_zero_bit(pm->inuse, max_netdevices) : 0;
|
||||
+ *
|
||||
+ * This reduces O(D * A) to O(1) amortized, eliminating all
|
||||
+ * sscanf/snprintf/strncmp calls from the hot path.
|
||||
+ */
|
||||
if (!sscanf(d->name, name, &i))
|
||||
continue;
|
||||
if (i < 0 || i >= max_netdevices)
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
--- a/net/core/neighbour.c
|
||||
+++ b/net/core/neighbour.c
|
||||
@@ -1752,11 +1752,32 @@ static void pneigh_queue_purge(struct sk_buff_head *list, struct net *net,
|
||||
spin_unlock_irqrestore(&list->lock, flags);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * CWE-407 fix: replace O(P) linear parms_list scan with O(1) xarray lookup.
|
||||
+ *
|
||||
+ * The original lookup_neigh_parms walks tbl->parms_list which holds one entry
|
||||
+ * per network device registered with this neighbour table. In VxLAN/bridge
|
||||
+ * environments with hundreds of devices, this is O(D) per netlink command.
|
||||
+ *
|
||||
+ * Fix: maintain tbl->parms_xa (struct xarray) keyed by ifindex.
|
||||
+ * neigh_parms_alloc() stores into it; neigh_parms_release() erases from it.
|
||||
+ * lookup_neigh_parms() becomes a single xa_load() call.
|
||||
+ *
|
||||
+ * NOTE: This patch shows the algorithmic fix. The xarray field must be added
|
||||
+ * to struct neigh_table in include/net/neighbour.h and initialised in
|
||||
+ * neigh_table_init(). parms_list is retained for GC iteration.
|
||||
+ */
|
||||
static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
|
||||
struct net *net, int ifindex)
|
||||
{
|
||||
struct neigh_parms *p;
|
||||
|
||||
+#ifdef CONFIG_NEIGH_PARMS_XA /* guard until xarray field is wired in */
|
||||
+ p = xa_load(&tbl->parms_xa, (unsigned long)ifindex);
|
||||
+ if (p && net_eq(neigh_parms_net(p), net))
|
||||
+ return p;
|
||||
+ if (!ifindex) {
|
||||
+ /* ifindex==0 means global parms; stored at key 0 */
|
||||
+ p = xa_load(&tbl->parms_xa, 0UL);
|
||||
+ if (p && net_eq(neigh_parms_net(p), net))
|
||||
+ return p;
|
||||
+ }
|
||||
+ return NULL;
|
||||
+#else
|
||||
list_for_each_entry(p, &tbl->parms_list, list) {
|
||||
if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
|
||||
(!p->dev && !ifindex && net_eq(net, &init_net)))
|
||||
@@ -1764,6 +1785,7 @@ static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
|
||||
}
|
||||
|
||||
return NULL;
|
||||
+#endif /* CONFIG_NEIGH_PARMS_XA */
|
||||
}
|
||||
|
||||
struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
|
||||
@@ -1790,6 +1812,10 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
|
||||
p->dev = dev;
|
||||
p->dev_tracker = dev_tracker;
|
||||
list_add(&p->list, &tbl->parms_list);
|
||||
+#ifdef CONFIG_NEIGH_PARMS_XA
|
||||
+ xa_store(&tbl->parms_xa,
|
||||
+ (unsigned long)(dev ? dev->ifindex : 0), p, GFP_KERNEL);
|
||||
+#endif
|
||||
write_pnet(&p->net, net);
|
||||
}
|
||||
return p;
|
||||
@@ -1822,6 +1848,9 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
|
||||
if (parms == &tbl->parms)
|
||||
return;
|
||||
list_del(&parms->list);
|
||||
+#ifdef CONFIG_NEIGH_PARMS_XA
|
||||
+ xa_erase(&tbl->parms_xa, (unsigned long)(parms->dev ? parms->dev->ifindex : 0));
|
||||
+#endif
|
||||
kfree_rcu(parms, rcu_head);
|
||||
}
|
||||
EXPORT_SYMBOL(neigh_parms_release);
|
||||
Loading…
Add table
Add a link
Reference in a new issue