Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package inspektor-gadget for
openSUSE:Factory checked in at 2026-08-28 19:52:51
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/inspektor-gadget (Old)
and /work/SRC/openSUSE:Factory/.inspektor-gadget.new.1265 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "inspektor-gadget"
Fri Aug 28 19:52:51 2026 rev:37 rq:1374283 version:0.55.1
Changes:
--------
--- /work/SRC/openSUSE:Factory/inspektor-gadget/inspektor-gadget.changes
2026-08-04 21:38:54.829598689 +0200
+++
/work/SRC/openSUSE:Factory/.inspektor-gadget.new.1265/inspektor-gadget.changes
2026-08-28 19:55:20.748677860 +0200
@@ -1,0 +2,17 @@
+Fri Aug 28 08:06:23 UTC 2026 - Johannes Kastl
<[email protected]>
+
+- Update to version 0.55.1:
+ * Bugfixes
+ - [BACKPORT] Various fixes in #5763:
+ - ELF/uprobe resource exhaustion: crafted binaries from
+ untrusted containers could exhaust memory or CPU in the
+ privileged process. Symbol parsing now uses a bounded
+ streaming iterator, USDT notes are capped at 10,000, and
+ debuginfod files are size-checked before parsing.
+ - runc / container hook: the fanotify listener now only
+ accepts exec events from root, validates container IDs
+ against runc's format (blocking log injection and path
+ traversal), and consumes one event per read(), fixing queue
+ overflows and lost container events.
+
+-------------------------------------------------------------------
Old:
----
inspektor-gadget-0.55.0.obscpio
New:
----
inspektor-gadget-0.55.1.obscpio
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ inspektor-gadget.spec ++++++
--- /var/tmp/diff_new_pack.aJtS0g/_old 2026-08-28 19:55:22.219729291 +0200
+++ /var/tmp/diff_new_pack.aJtS0g/_new 2026-08-28 19:55:22.220729326 +0200
@@ -17,7 +17,7 @@
Name: inspektor-gadget
-Version: 0.55.0
+Version: 0.55.1
Release: 0
Summary: A eBPF tool and systems inspection framework
License: Apache-2.0
++++++ _service ++++++
--- /var/tmp/diff_new_pack.aJtS0g/_old 2026-08-28 19:55:22.293731878 +0200
+++ /var/tmp/diff_new_pack.aJtS0g/_new 2026-08-28 19:55:22.304732263 +0200
@@ -3,7 +3,7 @@
<param
name="url">https://github.com/inspektor-gadget/inspektor-gadget.git</param>
<param name="scm">git</param>
<param name="exclude">.git</param>
- <param name="revision">refs/tags/v0.55.0</param>
+ <param name="revision">refs/tags/v0.55.1</param>
<param name="versionformat">@PARENT_TAG@</param>
<param name="versionrewrite-pattern">v(.*)</param>
<param name="changesgenerate">enable</param>
++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.aJtS0g/_old 2026-08-28 19:55:22.364734361 +0200
+++ /var/tmp/diff_new_pack.aJtS0g/_new 2026-08-28 19:55:22.375734745 +0200
@@ -3,6 +3,6 @@
<param
name="url">https://github.com/inspektor-gadget/inspektor-gadget</param>
<param
name="changesrevision">7a314380ff61534ea70df9fb086505f958b2dff9</param></service><service
name="tar_scm">
<param
name="url">https://github.com/inspektor-gadget/inspektor-gadget.git</param>
- <param
name="changesrevision">5ea2a82caee991d2a5ef2a3fd280d63ca902d34f</param></service></servicedata>
+ <param
name="changesrevision">b4a42119fe583a119aa5e975c3834558d91610a5</param></service></servicedata>
(No newline at EOF)
++++++ inspektor-gadget-0.55.0.obscpio -> inspektor-gadget-0.55.1.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/inspektor-gadget-0.55.0/.golangci.yml
new/inspektor-gadget-0.55.1/.golangci.yml
--- old/inspektor-gadget-0.55.0/.golangci.yml 2026-08-03 16:21:26.000000000
+0200
+++ new/inspektor-gadget-0.55.1/.golangci.yml 2026-08-21 08:20:46.000000000
+0200
@@ -1,6 +1,6 @@
version: "2"
run:
- go: 1.26.5
+ go: 1.26.6
build-tags:
- docs
linters:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/inspektor-gadget-0.55.0/Dockerfiles/gadget-builder.Dockerfile
new/inspektor-gadget-0.55.1/Dockerfiles/gadget-builder.Dockerfile
--- old/inspektor-gadget-0.55.0/Dockerfiles/gadget-builder.Dockerfile
2026-08-03 16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/Dockerfiles/gadget-builder.Dockerfile
2026-08-21 08:20:46.000000000 +0200
@@ -1,7 +1,7 @@
ARG CLANG_LLVM_VERSION=18
ARG BPFTOOL_VERSION=v7.3.0
ARG LIBBPF_VERSION=v1.3.0
-ARG GOLANG_VERSION=1.26.5
+ARG GOLANG_VERSION=1.26.6
ARG RUST_VERSION=1.87.0
# Args need to be redefined on each stage
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/inspektor-gadget-0.55.0/Dockerfiles/gadget.Dockerfile
new/inspektor-gadget-0.55.1/Dockerfiles/gadget.Dockerfile
--- old/inspektor-gadget-0.55.0/Dockerfiles/gadget.Dockerfile 2026-08-03
16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/Dockerfiles/gadget.Dockerfile 2026-08-21
08:20:46.000000000 +0200
@@ -1,6 +1,6 @@
# Dockerfile for Inspektor Gadget.
-ARG
BUILDER_IMAGE=golang:1.26.5-trixie@sha256:116489021a0d8ca3facf79f84ee69052cff88733547150a644d45c5eaa91dc43
+ARG
BUILDER_IMAGE=golang:1.26.6-trixie@sha256:b75d466dd608587fd66cca705a307ba65b889827d06ad61d6a75f0482b51b7c7
ARG
BASE_IMAGE=gcr.io/distroless/static-debian12@sha256:ce46866b3a5170db3b49364900fb3168dc0833dfb46c26da5c77f22abb01d8c3
# Prepare and build gadget artifacts in a container
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/inspektor-gadget-0.55.0/Dockerfiles/gpu-ebpf-bridge.Dockerfile
new/inspektor-gadget-0.55.1/Dockerfiles/gpu-ebpf-bridge.Dockerfile
--- old/inspektor-gadget-0.55.0/Dockerfiles/gpu-ebpf-bridge.Dockerfile
2026-08-03 16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/Dockerfiles/gpu-ebpf-bridge.Dockerfile
2026-08-21 08:20:46.000000000 +0200
@@ -1,4 +1,4 @@
-ARG
BUILDER_IMAGE=golang:1.26.5-trixie@sha256:116489021a0d8ca3facf79f84ee69052cff88733547150a644d45c5eaa91dc43
+ARG
BUILDER_IMAGE=golang:1.26.6-trixie@sha256:b75d466dd608587fd66cca705a307ba65b889827d06ad61d6a75f0482b51b7c7
# Debian rather than distroless/static because the -tags nvml build
# requires cgo, which links libc dynamically. The bridge then
# dlopen()s libnvidia-ml.so.1 at runtime from the host (bind-mounted
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/inspektor-gadget-0.55.0/Dockerfiles/ig-tests.Dockerfile
new/inspektor-gadget-0.55.1/Dockerfiles/ig-tests.Dockerfile
--- old/inspektor-gadget-0.55.0/Dockerfiles/ig-tests.Dockerfile 2026-08-03
16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/Dockerfiles/ig-tests.Dockerfile 2026-08-21
08:20:46.000000000 +0200
@@ -1,4 +1,4 @@
-ARG
BUILDER_IMAGE=golang:1.26.5-trixie@sha256:116489021a0d8ca3facf79f84ee69052cff88733547150a644d45c5eaa91dc43
+ARG
BUILDER_IMAGE=golang:1.26.6-trixie@sha256:b75d466dd608587fd66cca705a307ba65b889827d06ad61d6a75f0482b51b7c7
ARG
BASE_IMAGE=gcr.io/distroless/static-debian11:latest@sha256:1dbe426d60caed5d19597532a2d74c8056cd7b1674042b88f7328690b5ead8ed
FROM --platform=${BUILDPLATFORM} ${BUILDER_IMAGE} AS builder
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/inspektor-gadget-0.55.0/Dockerfiles/ig.Dockerfile
new/inspektor-gadget-0.55.1/Dockerfiles/ig.Dockerfile
--- old/inspektor-gadget-0.55.0/Dockerfiles/ig.Dockerfile 2026-08-03
16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/Dockerfiles/ig.Dockerfile 2026-08-21
08:20:46.000000000 +0200
@@ -1,4 +1,4 @@
-ARG
BUILDER_IMAGE=golang:1.26.5-trixie@sha256:116489021a0d8ca3facf79f84ee69052cff88733547150a644d45c5eaa91dc43
+ARG
BUILDER_IMAGE=golang:1.26.6-trixie@sha256:b75d466dd608587fd66cca705a307ba65b889827d06ad61d6a75f0482b51b7c7
ARG
BASE_IMAGE=gcr.io/distroless/static-debian11:latest@sha256:1dbe426d60caed5d19597532a2d74c8056cd7b1674042b88f7328690b5ead8ed
FROM --platform=${BUILDPLATFORM} ${BUILDER_IMAGE} AS builder
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/inspektor-gadget-0.55.0/Dockerfiles/kubectl-gadget.Dockerfile
new/inspektor-gadget-0.55.1/Dockerfiles/kubectl-gadget.Dockerfile
--- old/inspektor-gadget-0.55.0/Dockerfiles/kubectl-gadget.Dockerfile
2026-08-03 16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/Dockerfiles/kubectl-gadget.Dockerfile
2026-08-21 08:20:46.000000000 +0200
@@ -6,7 +6,7 @@
# image is valid, even scratch. Alpine is used by default as a tradeoff
# between size and tools available in the image.
-ARG
BUILDER_IMAGE=golang:1.26.5-trixie@sha256:116489021a0d8ca3facf79f84ee69052cff88733547150a644d45c5eaa91dc43
+ARG
BUILDER_IMAGE=golang:1.26.6-trixie@sha256:b75d466dd608587fd66cca705a307ba65b889827d06ad61d6a75f0482b51b7c7
ARG
BASE_IMAGE=gcr.io/distroless/static-debian11:latest@sha256:1dbe426d60caed5d19597532a2d74c8056cd7b1674042b88f7328690b5ead8ed
FROM --platform=${BUILDPLATFORM} ${BUILDER_IMAGE} AS builder
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/inspektor-gadget-0.55.0/docs/reference/requirements.md
new/inspektor-gadget-0.55.1/docs/reference/requirements.md
--- old/inspektor-gadget-0.55.0/docs/reference/requirements.md 2026-08-03
16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/docs/reference/requirements.md 2026-08-21
08:20:46.000000000 +0200
@@ -53,3 +53,8 @@
$ sudo ig -r podman --podman-socketpath /run/user/$UID/podman/podman.sock
list-containers
$ sudo ig -r podman --podman-socketpath /run/user/$UID/podman/podman.sock
snapshot process
```
+
+The Podman API can find existing containers but does not notify us when new
+containers are created. Inspektor Gadget uses the [`fanotify+ebpf` container
+hook](../spec/operators/kubemanager.md) to detect new containers, but this hook
+does not support rootless containers.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/inspektor-gadget-0.55.0/examples/container-hook/Dockerfile
new/inspektor-gadget-0.55.1/examples/container-hook/Dockerfile
--- old/inspektor-gadget-0.55.0/examples/container-hook/Dockerfile
2026-08-03 16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/examples/container-hook/Dockerfile
2026-08-21 08:20:46.000000000 +0200
@@ -1,4 +1,4 @@
-FROM
golang:1.26.5-trixie@sha256:116489021a0d8ca3facf79f84ee69052cff88733547150a644d45c5eaa91dc43
AS builder
+FROM
golang:1.26.6-trixie@sha256:b75d466dd608587fd66cca705a307ba65b889827d06ad61d6a75f0482b51b7c7
AS builder
# Cache go modules so they won't be downloaded at each build
COPY go.mod go.sum /gadget/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/inspektor-gadget-0.55.0/examples/go.mod
new/inspektor-gadget-0.55.1/examples/go.mod
--- old/inspektor-gadget-0.55.0/examples/go.mod 2026-08-03 16:21:26.000000000
+0200
+++ new/inspektor-gadget-0.55.1/examples/go.mod 2026-08-21 08:20:46.000000000
+0200
@@ -147,7 +147,7 @@
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.54.0 // indirect
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect
- golang.org/x/mod v0.37.0 // indirect
+ golang.org/x/mod v0.40.0 // indirect
golang.org/x/net v0.57.0 // indirect
golang.org/x/oauth2 v0.36.0 // indirect
golang.org/x/sync v0.22.0 // indirect
@@ -185,3 +185,6 @@
// use fork to get support for application/vnd.oci.empty.v1+json image
replace github.com/notaryproject/notation-go =>
github.com/inspektor-gadget/notation-go v1.3.3
+
+// keep in sync with root module to preserve tracer/types import path
+replace go.opentelemetry.io/ebpf-profiler =>
github.com/inspektor-gadget/opentelemetry-ebpf-profiler
v0.0.202611-0.20260715114040-ef6cf29492c8
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/inspektor-gadget-0.55.0/examples/go.sum
new/inspektor-gadget-0.55.1/examples/go.sum
--- old/inspektor-gadget-0.55.0/examples/go.sum 2026-08-03 16:21:26.000000000
+0200
+++ new/inspektor-gadget-0.55.1/examples/go.sum 2026-08-21 08:20:46.000000000
+0200
@@ -190,6 +190,8 @@
github.com/inconshreveable/mousetrap v1.1.0/go.mod
h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/inspektor-gadget/notation-go v1.3.3
h1:yygDXeFVU3zvYzaNWwhRkTMiJNq4iWnn7Ssayek00RI=
github.com/inspektor-gadget/notation-go v1.3.3/go.mod
h1:/1kuq5WuLF6Gaer5re0Z6HlkQRlKYO4EbWWT/L7J1Uw=
+github.com/inspektor-gadget/opentelemetry-ebpf-profiler
v0.0.202611-0.20260715114040-ef6cf29492c8
h1:uAAxfhFJY2k26LvrHwdZdy7gTRo3ZFSTeSrWSPKjirk=
+github.com/inspektor-gadget/opentelemetry-ebpf-profiler
v0.0.202611-0.20260715114040-ef6cf29492c8/go.mod
h1:YcOGWpHl5DRZQxxSLH9P2a4MI51eexSeSWODzPY5FTc=
github.com/jcmturner/aescts/v2 v2.0.0
h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
github.com/jcmturner/aescts/v2 v2.0.0/go.mod
h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
github.com/jcmturner/dnsutils/v2 v2.0.0
h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
@@ -411,8 +413,6 @@
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod
h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0=
go.opentelemetry.io/contrib/instrumentation/runtime v0.67.0
h1:fM78cKITJ2r08cl+nw5i+hI9zWAu3iak8o1Os/ca2Ck=
go.opentelemetry.io/contrib/instrumentation/runtime v0.67.0/go.mod
h1:ybmlzIqGcQzwt5lAfi8TpSnHo/CI3yv1Czodmm+OJa8=
-go.opentelemetry.io/ebpf-profiler v0.0.202536
h1:RokX9rsyO9uEbdHSC5145jYZIxIXk//u9cJTSh6Vy30=
-go.opentelemetry.io/ebpf-profiler v0.0.202536/go.mod
h1:oGg4sNNmbpAuXZtzBGnHp7tCSeEWRK7ij4TltZdqsAY=
go.opentelemetry.io/otel v1.43.0
h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
go.opentelemetry.io/otel v1.43.0/go.mod
h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0
h1:MdKucPl/HbzckWWEisiNqMPhRrAOQX8r4jTuGr636gk=
@@ -452,8 +452,8 @@
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod
h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
-golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
+golang.org/x/mod v0.40.0 h1:hUv+3cXcdRHz08UmSiOob7sadHig73uo5bkXxQ/tvUs=
+golang.org/x/mod v0.40.0/go.mod h1:0/weTWkPWGBikyTWAX3dkjVztMmBA5hM0DH6BElSupE=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/inspektor-gadget-0.55.0/examples/kube-container-collection/Dockerfile
new/inspektor-gadget-0.55.1/examples/kube-container-collection/Dockerfile
--- old/inspektor-gadget-0.55.0/examples/kube-container-collection/Dockerfile
2026-08-03 16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/examples/kube-container-collection/Dockerfile
2026-08-21 08:20:46.000000000 +0200
@@ -1,4 +1,4 @@
-FROM
golang:1.26.5-trixie@sha256:116489021a0d8ca3facf79f84ee69052cff88733547150a644d45c5eaa91dc43
AS builder
+FROM
golang:1.26.6-trixie@sha256:b75d466dd608587fd66cca705a307ba65b889827d06ad61d6a75f0482b51b7c7
AS builder
# Cache go modules so they won't be downloaded at each build
COPY go.mod go.sum /gadget/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/inspektor-gadget-0.55.0/go.mod
new/inspektor-gadget-0.55.1/go.mod
--- old/inspektor-gadget-0.55.0/go.mod 2026-08-03 16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/go.mod 2026-08-21 08:20:46.000000000 +0200
@@ -221,7 +221,7 @@
go.opentelemetry.io/collector/pdata v1.53.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.24.0 // indirect
- golang.org/x/mod v0.37.0 // indirect
+ golang.org/x/mod v0.40.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect
)
@@ -233,4 +233,5 @@
// - u32 key type for generic_params map
// - GetStackCacheMap() accessor for userspace cleanup
// - GetPerfEntryEbpfProgram() accessor for perf_event OTel stack correlation
+// Please keep in sync with examples/go.mod
replace go.opentelemetry.io/ebpf-profiler =>
github.com/inspektor-gadget/opentelemetry-ebpf-profiler
v0.0.202611-0.20260715114040-ef6cf29492c8
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/inspektor-gadget-0.55.0/go.sum
new/inspektor-gadget-0.55.1/go.sum
--- old/inspektor-gadget-0.55.0/go.sum 2026-08-03 16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/go.sum 2026-08-21 08:20:46.000000000 +0200
@@ -522,8 +522,8 @@
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod
h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
-golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
+golang.org/x/mod v0.40.0 h1:hUv+3cXcdRHz08UmSiOob7sadHig73uo5bkXxQ/tvUs=
+golang.org/x/mod v0.40.0/go.mod h1:0/weTWkPWGBikyTWAX3dkjVztMmBA5hM0DH6BElSupE=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -609,8 +609,8 @@
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod
h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod
h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod
h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q=
-golang.org/x/tools v0.47.0/go.mod
h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA=
+golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI=
+golang.org/x/tools v0.49.0/go.mod
h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/inspektor-gadget-0.55.0/pkg/container-collection/container-collection.go
new/inspektor-gadget-0.55.1/pkg/container-collection/container-collection.go
---
old/inspektor-gadget-0.55.0/pkg/container-collection/container-collection.go
2026-08-03 16:21:26.000000000 +0200
+++
new/inspektor-gadget-0.55.1/pkg/container-collection/container-collection.go
2026-08-21 08:20:46.000000000 +0200
@@ -205,6 +205,12 @@
// AddContainer adds a container to the collection.
func (cc *ContainerCollection) AddContainer(container *Container) {
+ if err :=
eventtypes.ValidateContainerID(container.Runtime.ContainerID); err != nil {
+ log.Warnf("container collection: ignoring container with
invalid ID: %s", err)
+ container.close()
+ return
+ }
+
for _, enricher := range cc.containerEnrichers {
ok := enricher(container)
// Enrichers can decide to drop a container
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/inspektor-gadget-0.55.0/pkg/container-hook/bpf/execruntime.bpf.c
new/inspektor-gadget-0.55.1/pkg/container-hook/bpf/execruntime.bpf.c
--- old/inspektor-gadget-0.55.0/pkg/container-hook/bpf/execruntime.bpf.c
2026-08-03 16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/pkg/container-hook/bpf/execruntime.bpf.c
2026-08-21 08:20:46.000000000 +0200
@@ -12,17 +12,31 @@
const volatile u64 tracer_group = 0;
// ig_fa_pick_ctx keeps context for kprobe/kretprobe
fsnotify_remove_first_event
+//
+// A single slot is enough: all callers of fsnotify_remove_first_event hold
+// group->notification_lock across the call, so at most one task at a time can
+// be inside that function for the Inspektor Gadget fanotify group, and that
+// task is always the single IG reader goroutine.
+//
+// An array is used rather than a hash so that storing the context can never
+// fail (no -E2BIG on a full map) and so that a leftover value, if a kretprobe
+// were ever missed, is simply overwritten by the next call instead of wedging
+// the map permanently.
struct {
- __uint(type, BPF_MAP_TYPE_HASH);
- __uint(max_entries, 64);
- __type(key, u64); // tgid_pid
- __type(value, u64); // dummy
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __uint(max_entries, 1);
+ __type(key, u32);
+ // tgid_pid of the IG task currently inside
+ // fsnotify_remove_first_event, or 0 if none. 0 is a valid "empty"
+ // marker: only the idle task has tgid_pid == 0 and it never calls
+ // fsnotify_remove_first_event.
+ __type(value, u64);
} ig_fa_pick_ctx SEC(".maps");
// ig_fa_records is consumed by userspace
struct {
__uint(type, BPF_MAP_TYPE_QUEUE);
- __uint(max_entries, 64);
+ __uint(max_entries, 1);
__type(value, struct record);
} ig_fa_records SEC(".maps");
@@ -52,16 +66,18 @@
SEC("kprobe/fsnotify_remove_first_event")
int BPF_KPROBE(ig_fa_pick_e, struct fsnotify_group *group)
{
- u64 current_pid_tgid;
- u64 dummy = 0;
+ u32 zero = 0;
+ u64 *ctx_pid_tgid;
if (tracer_group != (u64)group)
return 0;
- current_pid_tgid = bpf_get_current_pid_tgid();
+ ctx_pid_tgid = bpf_map_lookup_elem(&ig_fa_pick_ctx, &zero);
+ if (!ctx_pid_tgid)
+ return 0;
// Keep context for kretprobe/fsnotify_remove_first_event
- bpf_map_update_elem(&ig_fa_pick_ctx, ¤t_pid_tgid, &dummy, 0);
+ *ctx_pid_tgid = bpf_get_current_pid_tgid();
return 0;
}
@@ -71,16 +87,23 @@
{
struct record *record;
u64 current_pid_tgid;
+ u64 *ctx_pid_tgid;
u32 event_pid;
- u64 *exists;
+ u32 zero = 0;
// current_pid_tgid is the Inspektor Gadget task
current_pid_tgid = bpf_get_current_pid_tgid();
- exists = bpf_map_lookup_elem(&ig_fa_pick_ctx, ¤t_pid_tgid);
- if (!exists)
+ ctx_pid_tgid = bpf_map_lookup_elem(&ig_fa_pick_ctx, &zero);
+ if (!ctx_pid_tgid || *ctx_pid_tgid != current_pid_tgid)
return 0;
+ // Reset the context on all paths below: leaving it set would let a
later
+ // call from the same task on a different fanotify group (the pid file
+ // group is read by another goroutine, and goroutines share threads) be
+ // mistaken for a call on our group and push a bogus record.
+ *ctx_pid_tgid = 0;
+
// event_pid is the thread that triggered the fanotify event.
// Since Inspektor Gadget uses FAN_REPORT_TID, this is the thread id
// and not the process id.
@@ -90,16 +113,11 @@
if (!record) {
// no record found but we need to push an empty record in the
queue to
// ensure userspace understands that there is no record for
this event
- goto fail;
+ bpf_map_push_elem(&ig_fa_records, &empty_record, 0);
+ return 0;
}
bpf_map_push_elem(&ig_fa_records, record, 0);
- bpf_map_delete_elem(&ig_fa_pick_ctx, ¤t_pid_tgid);
- return 0;
-
-fail:
- bpf_map_push_elem(&ig_fa_records, &empty_record, 0);
- bpf_map_delete_elem(&ig_fa_pick_ctx, ¤t_pid_tgid);
return 0;
}
@@ -134,6 +152,10 @@
bpf_get_current_comm(&record->caller_comm, sizeof(record->caller_comm));
record->mntns_id = BPF_CORE_READ(task, nsproxy, mnt_ns, ns.inum);
record->pid = tgid;
+ // euid.val is a kuid_t: it is always relative to the initial user
+ // namespace, so a process that mapped itself to uid 0 in a user
+ // namespace is not seen as root here.
+ record->euid = BPF_CORE_READ(task, cred, euid.val);
record->args_size = 0;
ret = bpf_probe_read_user_str(record->args, ARGSIZE,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/inspektor-gadget-0.55.0/pkg/container-hook/bpf/execruntime.h
new/inspektor-gadget-0.55.1/pkg/container-hook/bpf/execruntime.h
--- old/inspektor-gadget-0.55.0/pkg/container-hook/bpf/execruntime.h
2026-08-03 16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/pkg/container-hook/bpf/execruntime.h
2026-08-21 08:20:46.000000000 +0200
@@ -14,6 +14,8 @@
struct record {
__u64 mntns_id;
__u32 pid;
+ // euid of the caller, in the initial user namespace
+ __u32 euid;
unsigned int args_size;
__u8 caller_comm[TASK_COMM_LEN];
__u8 args[FULL_MAX_ARGS_ARR];
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/inspektor-gadget-0.55.0/pkg/container-hook/execruntime_arm64_bpfel.go
new/inspektor-gadget-0.55.1/pkg/container-hook/execruntime_arm64_bpfel.go
--- old/inspektor-gadget-0.55.0/pkg/container-hook/execruntime_arm64_bpfel.go
2026-08-03 16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/pkg/container-hook/execruntime_arm64_bpfel.go
2026-08-21 08:20:46.000000000 +0200
@@ -17,9 +17,11 @@
_ structs.HostLayout
MntnsId uint64
Pid uint32
+ Euid uint32
ArgsSize uint32
CallerComm [16]uint8
Args [5120]uint8
+ _ [4]byte
}
// Names of all BPF objects in the ELF.
Binary files
old/inspektor-gadget-0.55.0/pkg/container-hook/execruntime_arm64_bpfel.o and
new/inspektor-gadget-0.55.1/pkg/container-hook/execruntime_arm64_bpfel.o differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/inspektor-gadget-0.55.0/pkg/container-hook/execruntime_x86_bpfel.go
new/inspektor-gadget-0.55.1/pkg/container-hook/execruntime_x86_bpfel.go
--- old/inspektor-gadget-0.55.0/pkg/container-hook/execruntime_x86_bpfel.go
2026-08-03 16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/pkg/container-hook/execruntime_x86_bpfel.go
2026-08-21 08:20:46.000000000 +0200
@@ -17,9 +17,11 @@
_ structs.HostLayout
MntnsId uint64
Pid uint32
+ Euid uint32
ArgsSize uint32
CallerComm [16]uint8
Args [5120]uint8
+ _ [4]byte
}
// Names of all BPF objects in the ELF.
Binary files
old/inspektor-gadget-0.55.0/pkg/container-hook/execruntime_x86_bpfel.o and
new/inspektor-gadget-0.55.1/pkg/container-hook/execruntime_x86_bpfel.o differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/inspektor-gadget-0.55.0/pkg/container-hook/tracer.go
new/inspektor-gadget-0.55.1/pkg/container-hook/tracer.go
--- old/inspektor-gadget-0.55.0/pkg/container-hook/tracer.go 2026-08-03
16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/pkg/container-hook/tracer.go 2026-08-21
08:20:46.000000000 +0200
@@ -32,6 +32,7 @@
package containerhook
import (
+ "bufio"
"errors"
"fmt"
"io"
@@ -44,6 +45,7 @@
"sync"
"sync/atomic"
"time"
+ "unsafe"
"github.com/cilium/ebpf"
"github.com/cilium/ebpf/link"
@@ -57,6 +59,7 @@
"github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets"
"github.com/inspektor-gadget/inspektor-gadget/pkg/kallsyms/symscache"
"github.com/inspektor-gadget/inspektor-gadget/pkg/kfilefields"
+ "github.com/inspektor-gadget/inspektor-gadget/pkg/types"
"github.com/inspektor-gadget/inspektor-gadget/pkg/utils/host"
)
@@ -91,6 +94,11 @@
// pid files store a string with a int32 value, so 11 characters.
// Keep a larger buffer to be able to notice errors with strconv.Atoi.
pidFileMaxSize = int64(32)
+
+ // fanotifyEventMetadataSize is the size in bytes of a single fanotify
+ // event as read by go-fanotify's GetEvent(). It is used to size the
+ // read buffer to exactly one event; see initFanotify.
+ fanotifyEventMetadataSize =
int(unsafe.Sizeof(unix.FanotifyEventMetadata{}))
)
var (
@@ -218,7 +226,37 @@
// Flags for the fd installed when reading a fanotify event (e.g. flag
for
// the runc fd or the pid file fd).
openFlags := os.O_RDONLY | unix.O_LARGEFILE | unix.O_CLOEXEC
- return fanotify.Initialize(fanotifyFlags, openFlags)
+ notifyFD, err := fanotify.Initialize(fanotifyFlags, openFlags)
+ if err != nil {
+ return nil, err
+ }
+
+ // Shrink the read buffer to a single event.
+ //
+ // go-fanotify wraps the fanotify fd in a bufio.Reader with the default
+ // 4096-byte buffer, while each event read by GetEvent() is only
+ // fanotifyEventMetadataSize (24) bytes. A single read() syscall would
+ // therefore drain as many events as fit in the buffer (~170) at once,
even
+ // though the notifier processes them one at a time. That has two
harmful
+ // consequences:
+ //
+ // 1. Coherence with the ebpf ig_fa_records queue. Each fanotify exec
event
+ // has a matching record pushed by the ebpf program. The notifier
reads
+ // one fanotify event, then LookupAndDelete's its record before
handling
+ // the next. If a single read() pulls many events ahead, records
pile up
+ // and overflow the fixed-size queue, causing "lookup record: key
does
+ // not exist" and lost events.
+ // 2. File-descriptor pressure. For permission events the kernel
installs
+ // one fd per event *during that read()*. Draining ~170 events
installs
+ // ~170 fds at once, which can hit RLIMIT_NOFILE and make the
kernel fail
+ // to create the fd (EMFILE/ENFILE).
+ //
+ // Sizing the buffer to exactly one event guarantees each read() picks a
+ // single fanotify event (and installs at most one fd), keeping the
notifier
+ // in lockstep with the ig_fa_records queue.
+ notifyFD.Rd = bufio.NewReaderSize(notifyFD.File,
fanotifyEventMetadataSize)
+
+ return notifyFD, nil
}
// Supported detects if RuncNotifier is supported in the current environment
@@ -387,6 +425,10 @@
// containers detected by ContainerNotifier, but it can also be called for
// containers detected externally such as initial containers.
func (n *ContainerNotifier) AddWatchContainerTermination(containerID string,
containerPID int) error {
+ if err := types.ValidateContainerID(containerID); err != nil {
+ return err
+ }
+
n.containersMu.Lock()
defer n.containersMu.Unlock()
@@ -711,6 +753,9 @@
// cri-o appends userdata to bundleDir,
// so we trim it here to get the correct containerID
containerID :=
filepath.Base(filepath.Clean(strings.TrimSuffix(bundleDir, "userdata")))
+ if err := types.ValidateContainerID(containerID); err != nil {
+ return fmt.Errorf("invalid container ID from bundle %q: %w",
bundleDir, err)
+ }
n.pendingMu.Lock()
defer n.pendingMu.Unlock()
@@ -852,6 +897,10 @@
if containerName == "" || containerID == "" || bundleDir == "" ||
pidFile == "" {
return
}
+ if err := types.ValidateContainerID(containerID); err != nil {
+ log.Warnf("container-hook: ignoring conmon event with invalid
container ID: %s", err)
+ return
+ }
n.futureMu.Lock()
n.futureContainers[containerID] = &futureContainer{
@@ -958,6 +1007,14 @@
return nil
}
+ // Only the real root can start containers: this prevents an
unprivileged
+ // user from injecting a fake container by executing the container
runtime.
+ if record.Euid != 0 {
+ log.Debugf("fanotify: skip event from %q (pid %d) with euid %d",
+ pathFromProcfs, record.Pid, record.Euid)
+ return nil
+ }
+
callerComm := strings.TrimRight(string(record.CallerComm[:]), "\x00")
cmdlineArr := []string{}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/inspektor-gadget-0.55.0/pkg/container-utils/runtime-client/interface.go
new/inspektor-gadget-0.55.1/pkg/container-utils/runtime-client/interface.go
--- old/inspektor-gadget-0.55.0/pkg/container-utils/runtime-client/interface.go
2026-08-03 16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/pkg/container-utils/runtime-client/interface.go
2026-08-21 08:20:46.000000000 +0200
@@ -140,10 +140,13 @@
return "", fmt.Errorf("invalid container runtime %q, it
should be %q",
containerID, expectedRuntime)
}
- return split[1], nil
+ containerID = split[1]
}
- return split[0], nil
+ if err := types.ValidateContainerID(containerID); err != nil {
+ return "", err
+ }
+ return containerID, nil
}
func EnrichWithK8sMetadata(container *ContainerData, labels map[string]string)
{
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/inspektor-gadget-0.55.0/pkg/container-utils/runtime-client/interface_test.go
new/inspektor-gadget-0.55.1/pkg/container-utils/runtime-client/interface_test.go
---
old/inspektor-gadget-0.55.0/pkg/container-utils/runtime-client/interface_test.go
1970-01-01 01:00:00.000000000 +0100
+++
new/inspektor-gadget-0.55.1/pkg/container-utils/runtime-client/interface_test.go
2026-08-21 08:20:46.000000000 +0200
@@ -0,0 +1,29 @@
+// Copyright 2026 The Inspektor Gadget authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package runtimeclient
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/inspektor-gadget/inspektor-gadget/pkg/types"
+)
+
+func TestParseContainerIDValidatesID(t *testing.T) {
+ containerID, err := ParseContainerID(types.RuntimeNameDocker,
"docker://a\nb")
+ require.Error(t, err)
+ require.Empty(t, containerID)
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/inspektor-gadget-0.55.0/pkg/symbolizer/debuginfod/debuginfod.go
new/inspektor-gadget-0.55.1/pkg/symbolizer/debuginfod/debuginfod.go
--- old/inspektor-gadget-0.55.0/pkg/symbolizer/debuginfod/debuginfod.go
2026-08-03 16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/pkg/symbolizer/debuginfod/debuginfod.go
2026-08-21 08:20:46.000000000 +0200
@@ -114,7 +114,7 @@
}
defer file.Close()
- // Check if the file is empty
+ // Check if the file is empty or too large
if fi, err := file.Stat(); err != nil {
log.Warnf("Failed to stat debuginfo file %s: %v", path, err)
return nil, nil
@@ -122,6 +122,9 @@
suggestedCmd := fmt.Sprintf("rm -f %s", path)
log.Warnf("Debuginfo %s for %s in %s is empty. Suggested
remedial: %q", buildIDStr, task.Name, path, suggestedCmd)
return nil, nil
+ } else if fi.Size() > symbolizer.MaxExecutableSize {
+ log.Warnf("Debuginfo file %s too large (%d bytes, max %d)",
path, fi.Size(), symbolizer.MaxExecutableSize)
+ return nil, nil
}
return symbolizer.NewSymbolTableFromFile(file)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/inspektor-gadget-0.55.0/pkg/symbolizer/table.go
new/inspektor-gadget-0.55.1/pkg/symbolizer/table.go
--- old/inspektor-gadget-0.55.0/pkg/symbolizer/table.go 2026-08-03
16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/pkg/symbolizer/table.go 2026-08-21
08:20:46.000000000 +0200
@@ -61,34 +61,34 @@
}
defer elfFile.Close()
- symtab, err := elfFile.Symbols()
- if err != nil {
- // No symbols found. This is not an error.
- return &SymbolTable{
- RuntimeBaseAddrCache: make(map[BaseAddrCacheKey]uint64),
- }, nil
- }
-
symbolCount := 0
- for _, sym := range symtab {
- if sym.Name == "" {
- continue
+ iterErr := elfFile.IterateSymbols(elf.SHT_SYMTAB, func(sym elf.Symbol)
bool {
+ if sym.Size == 0 || sym.Name == "" {
+ return false
}
- if sym.Size == 0 {
- continue
- }
- if len(sym.Name) > MaxSymbolLength {
- sym.Name = sym.Name[:MaxSymbolLength]
+ name := sym.Name
+ if len(name) > MaxSymbolLength {
+ name = name[:MaxSymbolLength]
}
symbols = append(symbols, &Symbol{
- Name: sym.Name,
+ Name: name,
Value: sym.Value,
Size: sym.Size,
})
symbolCount++
- if symbolCount > MaxSymbolCount {
- return nil, fmt.Errorf("too many symbols: %d (exceeds
limit %d)", symbolCount, MaxSymbolCount)
+ return symbolCount > MaxSymbolCount
+ })
+ if iterErr != nil {
+ // If iteration failed entirely (e.g. no section), return empty
table.
+ if symbols == nil {
+ return &SymbolTable{
+ RuntimeBaseAddrCache:
make(map[BaseAddrCacheKey]uint64),
+ }, nil
}
+ return nil, iterErr
+ }
+ if symbolCount > MaxSymbolCount {
+ return nil, fmt.Errorf("too many symbols: %d (exceeds limit
%d)", symbolCount, MaxSymbolCount)
}
slices.SortFunc(symbols, func(a, b *Symbol) int {
if a.Value < b.Value {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/inspektor-gadget-0.55.0/pkg/types/types.go
new/inspektor-gadget-0.55.1/pkg/types/types.go
--- old/inspektor-gadget-0.55.0/pkg/types/types.go 2026-08-03
16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/pkg/types/types.go 2026-08-21
08:20:46.000000000 +0200
@@ -16,7 +16,9 @@
import (
"encoding/json"
+ "errors"
"fmt"
+ "path"
"strings"
"time"
@@ -25,6 +27,26 @@
type EventType string
+// ValidateContainerID rejects container IDs that are unsafe to use in logs,
+// paths, or runtime metadata. It uses the same rules as runc's validateID():
+// a non-empty string of [A-Za-z0-9_+-.] that is usable as a file name.
+func ValidateContainerID(containerID string) error {
+ if containerID == "" {
+ return errors.New("container ID is empty")
+ }
+ if strings.ContainsFunc(containerID, func(r rune) bool {
+ return (r < 'a' || r > 'z') && (r < 'A' || r > 'Z') && (r < '0'
|| r > '9') &&
+ r != '_' && r != '+' && r != '-' && r != '.'
+ }) {
+ return fmt.Errorf("container ID %q contains invalid
characters", containerID)
+ }
+ // Reject IDs that cannot be used as a file name, such as "." and "..".
+ if "/"+containerID != path.Clean("/"+containerID) {
+ return fmt.Errorf("container ID %q is not usable as a file
name", containerID)
+ }
+ return nil
+}
+
var node string
func init() {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/inspektor-gadget-0.55.0/pkg/types/types_test.go
new/inspektor-gadget-0.55.1/pkg/types/types_test.go
--- old/inspektor-gadget-0.55.0/pkg/types/types_test.go 2026-08-03
16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/pkg/types/types_test.go 2026-08-21
08:20:46.000000000 +0200
@@ -63,3 +63,29 @@
assert.NoError(t, err)
assert.Equal(t, expected.PodLabels, actual.PodLabels)
}
+
+func TestValidateContainerID(t *testing.T) {
+ for _, containerID := range []string{
+ "0123456789abcdef",
+ "container-1",
+ "container_1",
+ "container.1",
+ "container+1",
+ "...",
+ } {
+ assert.NoError(t, ValidateContainerID(containerID))
+ }
+
+ for _, containerID := range []string{
+ "",
+ ".",
+ "..",
+ "a\nb",
+ "../container",
+ "container/name",
+ "container name",
+ "container\x1b[31m",
+ } {
+ assert.Error(t, ValidateContainerID(containerID))
+ }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/inspektor-gadget-0.55.0/pkg/uprobetracer/tracer.go
new/inspektor-gadget-0.55.1/pkg/uprobetracer/tracer.go
--- old/inspektor-gadget-0.55.0/pkg/uprobetracer/tracer.go 2026-08-03
16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/pkg/uprobetracer/tracer.go 2026-08-21
08:20:46.000000000 +0200
@@ -32,6 +32,7 @@
package uprobetracer
import (
+ "debug/elf"
"errors"
"fmt"
"os"
@@ -47,6 +48,7 @@
"github.com/inspektor-gadget/inspektor-gadget/pkg/kfilefields"
"github.com/inspektor-gadget/inspektor-gadget/pkg/logger"
"github.com/inspektor-gadget/inspektor-gadget/pkg/utils/host"
+ "github.com/inspektor-gadget/inspektor-gadget/pkg/utils/safeelf"
"github.com/inspektor-gadget/inspektor-gadget/pkg/utils/secureopen"
)
@@ -188,10 +190,19 @@
return nil, fmt.Errorf("opening %q: %w", attachPath, err)
}
switch t.progType {
- case ProgUprobe:
- return ex.Uprobe(t.attachSymbol, t.prog, nil)
- case ProgUretprobe:
- return ex.Uretprobe(t.attachSymbol, t.prog, nil)
+ case ProgUprobe, ProgUretprobe:
+ // Resolve symbol in IG's hardened code, then pass the file
offset
+ // to cilium/ebpf. This bypasses cilium/ebpf's Symbols()/
+ // DynamicSymbols() path which doesn't limit memory consumption.
+ offset, err := resolveSymbolOffset(file, t.attachSymbol)
+ if err != nil {
+ return nil, fmt.Errorf("resolving symbol %q: %w",
t.attachSymbol, err)
+ }
+ opts := &link.UprobeOptions{Address: offset}
+ if t.progType == ProgUprobe {
+ return ex.Uprobe("", t.prog, opts)
+ }
+ return ex.Uretprobe("", t.prog, opts)
case ProgUSDT:
attachInfo, err := getUsdtInfo(attachPath, t.attachSymbol)
if err != nil {
@@ -207,6 +218,38 @@
}
}
+// resolveSymbolOffset resolves a symbol name to a file offset using bounded
+// iteration. This avoids loading the full string table into memory.
+func resolveSymbolOffset(file *os.File, symbol string) (uint64, error) {
+ ef, err := safeelf.NewFile(file)
+ if err != nil {
+ return 0, fmt.Errorf("parsing ELF: %w", err)
+ }
+ defer ef.Close()
+
+ for _, typ := range []elf.SectionType{elf.SHT_SYMTAB, elf.SHT_DYNSYM} {
+ var found bool
+ var addr uint64
+ iterErr := ef.IterateSymbols(typ, func(sym elf.Symbol) bool {
+ if elf.ST_TYPE(sym.Info) != elf.STT_FUNC {
+ return false
+ }
+ if sym.Name == symbol {
+ addr = sym.Value
+ found = true
+ }
+ return found
+ })
+ if found {
+ return vaddr2ElfOffset(ef.File, addr)
+ }
+ if iterErr != nil {
+ return 0, iterErr
+ }
+ }
+ return 0, fmt.Errorf("symbol %q not found", symbol)
+}
+
// try attaching to a container, will update `containerPid2Inodes`
func (t *Tracer[Event]) attach(containerPid uint32) {
var attachedRealInodes []uint64
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/inspektor-gadget-0.55.0/pkg/uprobetracer/usdt.go
new/inspektor-gadget-0.55.1/pkg/uprobetracer/usdt.go
--- old/inspektor-gadget-0.55.0/pkg/uprobetracer/usdt.go 2026-08-03
16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/pkg/uprobetracer/usdt.go 2026-08-21
08:20:46.000000000 +0200
@@ -37,6 +37,11 @@
// standard upper bound for ELF note fields; 1 MiB is a generous
arbitrary
// cap — legitimate USDT notes are typically under 1 KB.
maxNoteFieldSize = 1024 * 1024
+
+ // maxNoteCount limits the number of notes iterated to prevent CPU
denial
+ // of service from a crafted section with millions of tiny valid notes.
+ // 10,000 is far more than any legitimate binary would have.
+ maxNoteCount = 10000
)
type noteHeader struct {
@@ -119,6 +124,7 @@
// walk through USDT notes, and match with providerName and probeName
// For details of the structure of ELF notes, please refer to
// https://man7.org/linux/man-pages/man5/elf.5.html, the `Notes (Nhdr)`
section
+ noteCount := 0
for {
var header noteHeader
err = binary.Read(notesReader, elfReader.ByteOrder, &header)
@@ -129,6 +135,11 @@
return nil, fmt.Errorf("reading USDT note header: %w",
err)
}
+ noteCount++
+ if noteCount > maxNoteCount {
+ return nil, fmt.Errorf("too many USDT notes (%d, max
%d)", noteCount, maxNoteCount)
+ }
+
alignedNameSize := alignUp(uint64(header.NameSize), 4)
alignedDescSize := alignUp(uint64(header.DescSize), 4)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/inspektor-gadget-0.55.0/pkg/utils/safeelf/safeelf.go
new/inspektor-gadget-0.55.1/pkg/utils/safeelf/safeelf.go
--- old/inspektor-gadget-0.55.0/pkg/utils/safeelf/safeelf.go 2026-08-03
16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/pkg/utils/safeelf/safeelf.go 2026-08-21
08:20:46.000000000 +0200
@@ -12,23 +12,47 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// Package safeelf provides panic-safe wrappers around debug/elf.
+// Package safeelf provides panic-safe, hardened wrappers around debug/elf.
//
// Go's debug/elf is not hardened against adversarial inputs and may panic on
-// malformed data. Since Inspektor Gadget parses ELF files from untrusted
-// containers in a privileged process, we wrap all operations in recover() to
-// turn panics into errors.
-//
-// This approach is inspired by cilium/ebpf's internal SafeELFFile:
-// https://github.com/cilium/ebpf/blob/main/internal/elf.go
+// malformed data or allocate excessive memory for crafted sections. Since
+// Inspektor Gadget parses ELF files from untrusted containers in a privileged
+// process, this package:
+// - Wraps all operations in recover() to turn panics into errors
+// - Replaces the unbounded symbol accessors with a bounded iterator
package safeelf
import (
+ "bufio"
+ "bytes"
"debug/elf"
+ "errors"
"fmt"
"io"
)
+const (
+ // maxStrtabSectionSize is the maximum size of a .strtab/.dynstr
section.
+ // Measured on large real-world binaries, .strtab stays well below this:
+ // dockerd 8.8 MiB, ig 8.6 MiB, docker 2.8 MiB, runc 0.6 MiB. The same
+ // 16 MiB bound is used by opentelemetry-ebpf-profiler for ELF string
+ // tables (libpf/pfelf.maxBytesLargeSection).
+ maxStrtabSectionSize = 16 * 1024 * 1024
+
+ // maxSymbolNameSize is the maximum size of a single symbol name.
+ maxSymbolNameSize = 64 * 1024
+
+ // symtabReadBufferSize is the buffer used to stream symbol table
entries.
+ symtabReadBufferSize = 64 * 1024
+
+ // maxSymbolCount is the maximum number of symbols iterated.
+ maxSymbolCount = 10 * 1000 * 1000
+
+ // maxSymtabSectionSize is the maximum size of a .symtab/.dynsym
section.
+ // It matches maxSymbolCount entries of the largest symbol entry size.
+ maxSymtabSectionSize = maxSymbolCount * int(elf.Sym64Size)
+)
+
// File wraps an *elf.File with panic recovery on operations that may crash
// on malformed input.
type File struct {
@@ -53,26 +77,255 @@
return &File{f}, nil
}
-// Symbols is the safe version of elf.File.Symbols.
-func (f *File) Symbols() (syms []elf.Symbol, err error) {
- defer func() {
- if r := recover(); r != nil {
- syms = nil
- err = fmt.Errorf("panic reading ELF symbols: %v", r)
+// ErrUnboundedSymbols is returned by Symbols and DynamicSymbols. Callers must
+// use IterateSymbols instead.
+var ErrUnboundedSymbols = errors.New("safeelf: unbounded symbol table read,
use IterateSymbols instead")
+
+// Symbols shadows the promoted elf.File.Symbols and always fails.
+//
+// debug/elf returns the whole table as a []elf.Symbol, which costs ~187 bytes
+// per symbol once names and slice growth are counted. Bounding the section
+// sizes does not bound that slice, so a crafted binary can still force a
+// multi-gigabyte allocation in a privileged process. This method only exists
+// to shadow the embedded *elf.File, which would otherwise be promoted and
+// silently reachable.
+func (f *File) Symbols() ([]elf.Symbol, error) {
+ return nil, ErrUnboundedSymbols
+}
+
+// DynamicSymbols shadows the promoted elf.File.DynamicSymbols and always
fails.
+// See Symbols.
+func (f *File) DynamicSymbols() ([]elf.Symbol, error) {
+ return nil, ErrUnboundedSymbols
+}
+
+// symbolEntry is the internal parsed ELF symbol entry used during iteration.
+type symbolEntry struct {
+ info uint8
+ other uint8
+ shndx uint16
+ value uint64
+ size uint64
+ nameOff uint32
+}
+
+// symbolIterator iterates over ELF symbol table entries without loading the
+// symbol table or string table into memory.
+type symbolIterator struct {
+ symtab *bufio.Reader
+ strtab []byte
+ order func([]byte) uint64
+ order32 func([]byte) uint32
+ order16 func([]byte) uint16
+ entrySize int
+ class elf.Class
+ count int
+}
+
+// next returns the next symbol entry. Returns io.EOF when done.
+func (it *symbolIterator) next() (symbolEntry, error) {
+ if it.count >= maxSymbolCount {
+ return symbolEntry{}, fmt.Errorf("symbol count exceeds limit
(%d)", maxSymbolCount)
+ }
+
+ var buf [24]byte // max(Sym64Size, Sym32Size)
+ d := buf[:it.entrySize]
+ if _, err := io.ReadFull(it.symtab, d); err != nil {
+ if errors.Is(err, io.EOF) {
+ return symbolEntry{}, io.EOF
}
- }()
+ return symbolEntry{}, fmt.Errorf("reading symbol entry: %w",
err)
+ }
+
+ var entry symbolEntry
+ switch it.class {
+ case elf.ELFCLASS64:
+ entry.nameOff = it.order32(d[0:4])
+ entry.info = d[4]
+ entry.other = d[5]
+ entry.shndx = it.order16(d[6:8])
+ entry.value = it.order(d[8:16])
+ entry.size = it.order(d[16:24])
+ case elf.ELFCLASS32:
+ entry.nameOff = it.order32(d[0:4])
+ entry.value = uint64(it.order32(d[4:8]))
+ entry.size = uint64(it.order32(d[8:12]))
+ entry.info = d[12]
+ entry.other = d[13]
+ entry.shndx = it.order16(d[14:16])
+ }
- return f.File.Symbols()
+ it.count++
+ return entry, nil
}
-// DynamicSymbols is the safe version of elf.File.DynamicSymbols.
-func (f *File) DynamicSymbols() (syms []elf.Symbol, err error) {
+// symbolName returns the name of the given symbol entry from the string
+// table. The string table is bounded by maxStrtabSectionSize and read once
+// when the iterator is created, so this is a pure in-memory lookup.
+func (it *symbolIterator) symbolName(entry symbolEntry) (string, error) {
+ off := uint64(entry.nameOff)
+ if off >= uint64(len(it.strtab)) {
+ return "", fmt.Errorf("symbol name offset %d out of string
table bounds (size %d)",
+ off, len(it.strtab))
+ }
+
+ if off == 0 {
+ return "", nil
+ }
+
+ name := it.strtab[off:]
+ if len(name) > maxSymbolNameSize {
+ name = name[:maxSymbolNameSize]
+ }
+
+ i := bytes.IndexByte(name, 0)
+ if i < 0 {
+ return "", fmt.Errorf("symbol name at offset %d is unterminated
within %d bytes",
+ off, len(name))
+ }
+
+ return string(name[:i]), nil
+}
+
+// newSymbolIterator creates an iterator for the given symbol table type.
+// Returns nil with no error if the section does not exist.
+func (f *File) newSymbolIterator(typ elf.SectionType) (_ *symbolIterator, err
error) {
defer func() {
if r := recover(); r != nil {
- syms = nil
- err = fmt.Errorf("panic reading ELF dynamic symbols:
%v", r)
+ err = fmt.Errorf("panic creating symbol iterator: %v",
r)
}
}()
- return f.File.DynamicSymbols()
+ symtabSection := f.SectionByType(typ)
+ if symtabSection == nil {
+ return nil, nil
+ }
+
+ if symtabSection.Flags&elf.SHF_COMPRESSED != 0 {
+ return nil, fmt.Errorf("compressed symbol table section not
supported")
+ }
+
+ var entrySize int
+ switch f.Class {
+ case elf.ELFCLASS64:
+ entrySize = int(elf.Sym64Size) // 24
+ case elf.ELFCLASS32:
+ entrySize = int(elf.Sym32Size) // 16
+ default:
+ return nil, fmt.Errorf("unsupported ELF class: %v", f.Class)
+ }
+
+ if symtabSection.Size > uint64(maxSymtabSectionSize) {
+ return nil, fmt.Errorf("symbol table section too large: %d
bytes (max %d)",
+ symtabSection.Size, maxSymtabSectionSize)
+ }
+
+ if symtabSection.Size%uint64(entrySize) != 0 {
+ return nil, fmt.Errorf("symbol table size %d is not a multiple
of entry size %d",
+ symtabSection.Size, entrySize)
+ }
+
+ if symtabSection.ReaderAt == nil {
+ return nil, fmt.Errorf("symbol table section has no ReaderAt")
+ }
+
+ // Validate the linked string table section.
+ link := symtabSection.Link
+ if int(link) >= len(f.Sections) {
+ return nil, fmt.Errorf("symbol table link %d out of range (have
%d sections)",
+ link, len(f.Sections))
+ }
+
+ strtabSection := f.Sections[link]
+ if strtabSection.Type != elf.SHT_STRTAB {
+ return nil, fmt.Errorf("linked section %d has type %v, expected
SHT_STRTAB",
+ link, strtabSection.Type)
+ }
+
+ if strtabSection.Flags&elf.SHF_COMPRESSED != 0 {
+ return nil, fmt.Errorf("compressed string table section not
supported")
+ }
+
+ if strtabSection.Size > maxStrtabSectionSize {
+ return nil, fmt.Errorf("string table section too large: %d
bytes (max %d)",
+ strtabSection.Size, maxStrtabSectionSize)
+ }
+
+ if strtabSection.ReaderAt == nil {
+ return nil, fmt.Errorf("string table section has no ReaderAt")
+ }
+
+ // Read the string table once. Its size is bounded above, and resolving
+ // names with one read per symbol instead would let a crafted binary
with
+ // many symbols burn CPU in the privileged process.
+ strtab := make([]byte, strtabSection.Size)
+ if _, err := io.ReadFull(io.NewSectionReader(strtabSection.ReaderAt, 0,
+ int64(strtabSection.Size)), strtab); err != nil {
+ return nil, fmt.Errorf("reading string table: %w", err)
+ }
+
+ bo := f.ByteOrder
+
+ // Skip the first entry, which is all zeros per the ELF spec.
+ symtabReader := io.NewSectionReader(symtabSection.ReaderAt,
+ int64(entrySize), int64(symtabSection.Size)-int64(entrySize))
+
+ return &symbolIterator{
+ symtab: bufio.NewReaderSize(symtabReader,
symtabReadBufferSize),
+ strtab: strtab,
+ order32: bo.Uint32,
+ order16: bo.Uint16,
+ order: func(b []byte) uint64 {
+ return bo.Uint64(b)
+ },
+ entrySize: entrySize,
+ class: f.Class,
+ }, nil
+}
+
+// IterateSymbols calls fn for each symbol in the given section type
(SHT_SYMTAB
+// or SHT_DYNSYM). Returns nil if the section doesn't exist. fn returns true to
+// stop iteration early. Symbol table entries are streamed, and every section
+// read is bounded, so memory use does not depend on the number of symbols.
+//
+// Unlike elf.File.DynamicSymbols, the version fields (HasVersion,
VersionIndex,
+// Version and Library) are not populated for SHT_DYNSYM: doing so requires
+// parsing .gnu.version and .gnu.version_r, which no caller needs. All other
+// fields match debug/elf exactly.
+func (f *File) IterateSymbols(typ elf.SectionType, fn func(sym elf.Symbol)
bool) error {
+ iter, err := f.newSymbolIterator(typ)
+ if err != nil {
+ return err
+ }
+ if iter == nil {
+ return nil
+ }
+
+ for {
+ entry, err := iter.next()
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ return nil
+ }
+ return fmt.Errorf("iterating symbols: %w", err)
+ }
+
+ name, err := iter.symbolName(entry)
+ if err != nil {
+ return fmt.Errorf("reading symbol name: %w", err)
+ }
+
+ sym := elf.Symbol{
+ Name: name,
+ Info: entry.info,
+ Other: entry.other,
+ Section: elf.SectionIndex(entry.shndx),
+ Value: entry.value,
+ Size: entry.size,
+ }
+
+ if fn(sym) {
+ return nil
+ }
+ }
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/inspektor-gadget-0.55.0/tools/bench/Dockerfile
new/inspektor-gadget-0.55.1/tools/bench/Dockerfile
--- old/inspektor-gadget-0.55.0/tools/bench/Dockerfile 2026-08-03
16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/tools/bench/Dockerfile 2026-08-21
08:20:46.000000000 +0200
@@ -1,4 +1,4 @@
-FROM --platform=${BUILDPLATFORM}
golang:1.26.5-alpine@sha256:0178a641fbb4858c5f1b48e34bdaabe0350a330a1b1149aabd498d0699ff5fb2
AS builder
+FROM --platform=${BUILDPLATFORM}
golang:1.26.6-alpine@sha256:3889b425f035be855a72fb4755265311293b6d414521f0a519d819df32222d83
AS builder
ARG TARGETARCH
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/inspektor-gadget-0.55.0/tools/dnstester/Dockerfile
new/inspektor-gadget-0.55.1/tools/dnstester/Dockerfile
--- old/inspektor-gadget-0.55.0/tools/dnstester/Dockerfile 2026-08-03
16:21:26.000000000 +0200
+++ new/inspektor-gadget-0.55.1/tools/dnstester/Dockerfile 2026-08-21
08:20:46.000000000 +0200
@@ -1,4 +1,4 @@
-FROM --platform=${BUILDPLATFORM}
golang:1.26.5-alpine@sha256:0178a641fbb4858c5f1b48e34bdaabe0350a330a1b1149aabd498d0699ff5fb2
AS builder
+FROM --platform=${BUILDPLATFORM}
golang:1.26.6-alpine@sha256:3889b425f035be855a72fb4755265311293b6d414521f0a519d819df32222d83
AS builder
ARG TARGETARCH
++++++ inspektor-gadget.obsinfo ++++++
--- /var/tmp/diff_new_pack.aJtS0g/_old 2026-08-28 19:55:24.935824251 +0200
+++ /var/tmp/diff_new_pack.aJtS0g/_new 2026-08-28 19:55:24.944824566 +0200
@@ -1,5 +1,5 @@
name: inspektor-gadget
-version: 0.55.0
-mtime: 1785766886
-commit: 5ea2a82caee991d2a5ef2a3fd280d63ca902d34f
+version: 0.55.1
+mtime: 1787293246
+commit: b4a42119fe583a119aa5e975c3834558d91610a5
++++++ vendor.tar.gz ++++++
/work/SRC/openSUSE:Factory/inspektor-gadget/vendor.tar.gz
/work/SRC/openSUSE:Factory/.inspektor-gadget.new.1265/vendor.tar.gz differ:
char 133, line 2