Skip to content

Commit dcedb3a

Browse files
authored
Merge branch 'master' into AA/anotherPythonFix
2 parents 3179085 + 21d3bfa commit dcedb3a

File tree

374 files changed

+3491
-628
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

374 files changed

+3491
-628
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,6 @@ infra/base-images/base-builder/indexer/fuzzing_engine.a
1212
# IntelliJ IDEA
1313
/.idea
1414
**/*.iml
15+
16+
# Chronos
17+
ccaches/

docs/faq.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,30 @@ We currently do not have a good way to deduplicate timeout or OOM bugs.
105105
So, we report only one timeout and only one OOM bug per fuzz target.
106106
Once that bug is fixed, we will file another one, and so on.
107107

108-
Currently we do not offer ways to change the memory and time limits.
108+
## Can I change the default timeout and OOM for a fuzz target?
109+
110+
Yes, you can. For this, create a fuzz target options file named `<fuzz-target>.options`,
111+
where `<fuzz-target>` is the executable file name of the fuzz target, in the same
112+
directory as your `project.yaml`. The options file can contain fuzzer-specific
113+
configuration values, such as:
114+
115+
```
116+
[libfuzzer]
117+
rss_limit_mb = 6000
118+
timeout = 30
119+
```
120+
121+
## My library gracefully handles allocation failures, why are OOMs reported?
122+
123+
OOM detection is done *not* by instrumenting memory allocation routines such as `malloc`
124+
to have them return NULL, but using a separate watchdog thread that measures the resident
125+
set size (RSS) on a periodic basis. Therefore, your fuzz target might successfully
126+
allocate more than the configured max RSS, and yet get killed shortly afterwards.
127+
128+
The only reliable way to avoid this is for your fuzz target to use a custom allocator
129+
that will prevent allocating more memory than a given limit. You can find a more
130+
detailed discussion of this topic, as well as links to the solution implemented
131+
by a specific project, in [this issue](https://github.com/google/oss-fuzz/issues/1830).
109132

110133
## Can I launch an additional process (e.g. a daemon) from my fuzz target?
111134

docs/further-reading/fuzzer_environment.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,17 @@ or built as part of
2525
are not available on the bot runtime environment (where the fuzz targets run).
2626

2727
If you need these dependencies in the runtime environment, you can either:
28-
- Install the packages via Dockerfile
28+
29+
- (recommended) Build the dependencies statically in
30+
[build.sh]({{ site.baseurl }}/getting-started/new-project-guide/#buildsh)
31+
([example](https://github.com/google/oss-fuzz/blob/64f8b6593da141b97c98c7bc6f07df92c42ee010/projects/ffmpeg/build.sh#L26)).
32+
33+
- Or install the packages via Dockerfile
2934
([example](https://github.com/google/oss-fuzz/blob/2d5e2ef84f281e6ab789055aa735606d3122fda9/projects/tor/Dockerfile#L19))
3035
and then link statically against them
3136
([example](https://github.com/google/oss-fuzz/blob/2d5e2ef84f281e6ab789055aa735606d3122fda9/projects/tor/build.sh#L40)).
32-
- Or build the dependencies statically in
33-
[build.sh]({{ site.baseurl }}/getting-started/new-project-guide/#buildsh)
34-
([example](https://github.com/google/oss-fuzz/blob/64f8b6593da141b97c98c7bc6f07df92c42ee010/projects/ffmpeg/build.sh#L26)).
37+
**Dependencies built in this way will not be instrumented** and may prevent
38+
the fuzzer from finding bugs if they are involved in the execution of a fuzz target.
3539

3640
All build artifacts needed during fuzz target execution should be inside the
3741
`$OUT` directory. Only those artifacts are archived and used on the bots.

docs/getting-started/continuous_integration.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,21 @@ You can checkout CIFuzz configs for OSS-Fuzz projects. Example -
234234
[systemd](https://github.com/systemd/systemd/blob/main/.github/workflows/cifuzz.yml),
235235
[curl](https://github.com/curl/curl/blob/master/.github/workflows/fuzz.yml).
236236

237+
## Ubuntu 24.04 Support
238+
239+
CIFuzz supports building and running fuzzers in an Ubuntu 24.04 environment.
240+
Existing projects will continue to use the legacy environment (Ubuntu 20.04) by default,
241+
preserving current behavior.
242+
243+
To migrate your project to Ubuntu 24.04, add the following line to your `project.yaml`:
244+
245+
```yaml
246+
base_os_version: ubuntu-24-04
247+
```
248+
249+
For OSS-Fuzz projects, this file is located at `projects/<project_name>/project.yaml`.
250+
For external projects (ClusterFuzzLite), this file is typically located at `.clusterfuzzlite/project.yaml`.
251+
237252
## Understanding results
238253

239254
The results of CIFuzz can be found in two different places.

docs/getting-started/new_project_guide.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,10 @@ For an example, see
237237
[ecc-diff-fuzzer/Dockerfile](https://github.com/google/oss-fuzz/blob/master/projects/ecc-diff-fuzzer/Dockerfile).
238238
where we use `base-builder-rust`and install golang
239239

240+
Runtime dependencies of your project, such as third-party static libraries, will
241+
not be instrumented if you build them in the Dockerfile. In most cases, you will
242+
want to build them in `build.sh` instead.
243+
240244
## build.sh {#buildsh}
241245

242246
This file defines how to build binaries for [fuzz targets]({{ site.baseurl }}/reference/glossary/#fuzz-target) in your project.

infra/base-images/all.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ for image_name in ${IMAGE_LIST}; do
6262
fi
6363

6464
echo "Building ${tag} from ${dockerfile}..."
65-
docker build --pull -t "${tag}" -f "${dockerfile}" "${image_dir}"
65+
docker build -t "${tag}" -f "${dockerfile}" "${image_dir}"
6666
done
6767

68-
echo "All builds for version ${VERSION_TAG} completed successfully."
68+
echo "All builds for version ${VERSION_TAG} completed successfully."

infra/base-images/base-builder/indexer/index_build.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@
6161
# wrapper. Get around this by writing to a file instead.
6262
COMPILE_SETTINGS_PATH = INDEXER_DIR / 'compile_settings.json'
6363

64+
CLANG_TOOLCHAIN_BINARY_PREFIXES = (
65+
'clang-',
66+
'ld',
67+
'lld',
68+
'llvm-',
69+
)
70+
6471
EXTRA_CFLAGS = (
6572
'-fno-omit-frame-pointer '
6673
'-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION '
@@ -125,11 +132,15 @@ def set_up_wrapper_dir():
125132
shutil.rmtree(_TOOLCHAIN_WITH_WRAPPER)
126133
_TOOLCHAIN_WITH_WRAPPER.mkdir(parents=True)
127134

128-
# Set up symlinks to every binary except for clang.
135+
# Set up symlinks to toolchain binaries.
129136
wrapper_bin_dir = _TOOLCHAIN_WITH_WRAPPER / 'bin'
130137
wrapper_bin_dir.mkdir()
131138
for name in os.listdir(_CLANG_TOOLCHAIN / 'bin'):
132-
if name in ('clang', 'clang++'):
139+
# Symlink clang/llvm toolchain binaries, except for clang itself.
140+
# We have to be careful not to symlink other unrelated binaries, since other
141+
# parts of the build process may wrap those binaries (e.g.
142+
# make_build_replayable.py in OSS-Fuzz).
143+
if not name.startswith(CLANG_TOOLCHAIN_BINARY_PREFIXES):
133144
continue
134145

135146
os.symlink(_CLANG_TOOLCHAIN / 'bin' / name, wrapper_bin_dir / name)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/usr/bin/env python3
2+
# Copyright 2025 Google LLC.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
"""Constants pertaining to snapshot manifests."""
17+
18+
# pylint: disable=g-import-not-at-top
19+
try:
20+
import pathlib
21+
22+
Path = pathlib.Path
23+
except ImportError:
24+
import pathlib
25+
26+
Path = pathlib.Path
27+
28+
29+
# Source directory.
30+
SRC_DIR = Path("src")
31+
# Object directory.
32+
OBJ_DIR = Path("obj")
33+
# Directory for indexer data.
34+
INDEX_DIR = Path("idx")
35+
# Relative source file root in the index.
36+
INDEX_RELATIVE_SOURCES = INDEX_DIR / "relative"
37+
# Absolute source file root in the index.
38+
INDEX_ABSOLUTE_SOURCES = INDEX_DIR / "absolute"
39+
# The index database filename.
40+
INDEX_DB = Path("db.sqlite")
41+
# Library directory, where shared libraries are copied - inside obj.
42+
LIB_DIR = OBJ_DIR / "lib"
43+
# Manifest location
44+
MANIFEST_PATH = Path("manifest.json")
45+
46+
47+
# Where archive version 1 expects the lib directory to be mounted.
48+
LIB_MOUNT_PATH_V1 = Path("/ossfuzzlib")
49+
50+
# Will be replaced with the input file for target execution.
51+
INPUT_FILE = "<input_file>"
52+
# A file the target can write output to.
53+
OUTPUT_FILE = "<output_file>"
54+
# Will be replaced with any dynamic arguments.
55+
DYNAMIC_ARGS = "<dynamic_args>"
56+

infra/base-images/base-builder/indexer/manifest_types.py

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -36,23 +36,22 @@
3636
from typing import Any, Callable, Mapping, Self, Sequence
3737
import urllib.request
3838

39+
import manifest_constants
3940
import pathlib
4041

4142

42-
# Source directory.
43-
SRC_DIR = pathlib.Path("src")
44-
# Object directory.
45-
OBJ_DIR = pathlib.Path("obj")
46-
# Directory for indexer data.
47-
INDEX_DIR = pathlib.Path("idx")
48-
# The index database filename.
49-
INDEX_DB = pathlib.Path("db.sqlite")
50-
# Library directory, where shared libraries are copied - inside obj.
51-
LIB_DIR = OBJ_DIR / "lib"
52-
# Manifest location
53-
MANIFEST_PATH = pathlib.Path("manifest.json")
54-
# Where archive version 1 expects the lib directory to be mounted.
55-
_LIB_MOUNT_PATH_V1 = pathlib.Path("/ossfuzzlib")
43+
SRC_DIR = manifest_constants.SRC_DIR
44+
OBJ_DIR = manifest_constants.OBJ_DIR
45+
INDEX_DIR = manifest_constants.INDEX_DIR
46+
INDEX_DB = manifest_constants.INDEX_DB
47+
LIB_DIR = manifest_constants.LIB_DIR
48+
MANIFEST_PATH = manifest_constants.MANIFEST_PATH
49+
LIB_MOUNT_PATH_V1 = manifest_constants.LIB_MOUNT_PATH_V1
50+
51+
INPUT_FILE = manifest_constants.INPUT_FILE
52+
OUTPUT_FILE = manifest_constants.OUTPUT_FILE
53+
DYNAMIC_ARGS = manifest_constants.DYNAMIC_ARGS
54+
5655
# Min archive version we currently support.
5756
_MIN_SUPPORTED_ARCHIVE_VERSION = 1
5857
# The current version of the build archive format.
@@ -64,15 +63,6 @@
6463
f"latest_report_info/{os.getenv('PROJECT_NAME')}.json")
6564

6665

67-
# Will be replaced with the input file for target execution.
68-
INPUT_FILE = "<input_file>"
69-
# A file the target can write output to.
70-
OUTPUT_FILE = "<output_file>"
71-
# Will be replaced with any dynamic arguments.
72-
DYNAMIC_ARGS = "<dynamic_args>"
73-
74-
75-
7666
class RepositoryType(enum.StrEnum):
7767
"""The type of repository."""
7868

@@ -142,12 +132,13 @@ class BinaryConfig:
142132
143133
Attributes:
144134
kind: The kind of binary configuration.
145-
binary_args: The arguments to pass to the binary, for example
146-
"<input_file>".
135+
binary_name: The name of the executable file.
147136
"""
148137

149138
kind: BinaryConfigKind
150139

140+
binary_name: str
141+
151142
@classmethod
152143
def from_dict(cls, config_dict: Mapping[str, Any]) -> Self:
153144
"""Deserializes the correct `BinaryConfig` subclass from a dict."""
@@ -186,7 +177,6 @@ class HarnessKind(enum.StrEnum):
186177
class CommandLineBinaryConfig(BinaryConfig):
187178
"""Configuration for a command-line userspace binary."""
188179

189-
binary_name: str
190180
binary_args: list[str]
191181
# Additional environment variables to pass to the binary. They will overwrite
192182
# any existing environment variables with the same name.
@@ -285,7 +275,7 @@ class Manifest:
285275
def from_dict(cls, data: dict[str, Any]) -> Self:
286276
"""Creates a Manifest object from a deserialized dict."""
287277
if data["version"] == 1:
288-
lib_mount_path = _LIB_MOUNT_PATH_V1
278+
lib_mount_path = LIB_MOUNT_PATH_V1
289279
else:
290280
lib_mount_path = _get_mapped(data, "lib_mount_path", pathlib.Path)
291281
if data["version"] < 3:
@@ -358,7 +348,7 @@ def validate(self) -> None:
358348
f"Build archive version too high: {self.version}. Only supporting"
359349
f" up to {ARCHIVE_VERSION}."
360350
)
361-
if self.version == 1 and _LIB_MOUNT_PATH_V1 != self.lib_mount_path:
351+
if self.version == 1 and LIB_MOUNT_PATH_V1 != self.lib_mount_path:
362352
raise RuntimeError(
363353
"Build archive with version 1 has an alternative lib_mount_path set"
364354
f" ({self.lib_mount_path}). This is not a valid archive."
@@ -409,12 +399,6 @@ def save_build(
409399

410400
self.validate()
411401

412-
if not hasattr(self.binary_config, "binary_name"):
413-
raise RuntimeError(
414-
"Attempting to save a binary config type without binary_name."
415-
" This is not yet supported. Kind: {self.binary_config.kind}."
416-
)
417-
418402
with tempfile.NamedTemporaryFile() as tmp:
419403
mode = "w:gz" if archive_path.suffix.endswith("gz") else "w"
420404
with tarfile.open(tmp.name, mode) as tar:
@@ -459,7 +443,9 @@ def _save_dir(
459443

460444
dumped_self = self
461445
if self.index_db_version is None:
462-
index_db_version = _get_sqlite_db_user_version(index_dir / INDEX_DB)
446+
index_db_version = _get_sqlite_db_user_version(
447+
pathlib.Path(index_dir) / INDEX_DB
448+
)
463449
dumped_self = dataclasses.replace(
464450
self, index_db_version=index_db_version
465451
)

0 commit comments

Comments
 (0)