Skip to content

Commit aa1f5c1

Browse files
committed
Add extract-sbom command to native-image-utils
This tool relies on a native library, libextract_sbom.a, which is currently Linux only and allows for the native-image-utils launcher, to read the gzip compressed SBOM bytes from another native image.
1 parent 11b2232 commit aa1f5c1

7 files changed

Lines changed: 547 additions & 0 deletions

File tree

substratevm/mx.substratevm/mx_substratevm.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2266,6 +2266,7 @@ def _native_image_utils_extra_jvm_args():
22662266
build_args=svm_experimental_options([
22672267
'-H:-ParseRuntimeOptions',
22682268
'-H:+TreatAllTypeReachableConditionsAsTypeReached',
2269+
'--features=com.oracle.svm.configure.command.sbom.SbomExtractFeature',
22692270
]),
22702271
extra_jvm_args=_native_image_utils_extra_jvm_args(),
22712272
home_finder=False,

substratevm/mx.substratevm/suite.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,28 @@
945945
"jacoco" : "exclude",
946946
},
947947

948+
"com.oracle.svm.native.extractsbom": {
949+
"subDir": "src",
950+
"native": "static_lib",
951+
"deliverable" : "extract_sbom",
952+
"os_arch": {
953+
"linux": {
954+
"<others>": {
955+
"cflags": ["-g", "-Wall", "-fPIC" ],
956+
},
957+
},
958+
"<others>": {
959+
"<others>": {
960+
"ignore": "only supported on linux",
961+
},
962+
},
963+
},
964+
"multitarget": {
965+
"libc": ["glibc", "default"],
966+
},
967+
"jacoco" : "exclude",
968+
},
969+
948970
"com.oracle.svm.native.reporterchelper": {
949971
"subDir": "src",
950972
"native": "shared_lib",
@@ -2395,6 +2417,7 @@
23952417
"dependency:com.oracle.svm.native.libchelper/*",
23962418
"dependency:com.oracle.svm.native.jvm.posix/*",
23972419
"dependency:com.oracle.svm.native.libcontainer/*",
2420+
"dependency:com.oracle.svm.native.extractsbom/*",
23982421
"file:debug/include",
23992422
"file:src/com.oracle.svm.core/src/com/oracle/svm/core/gc/shared/include",
24002423
],

substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/ConfigurationTool.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.util.Map;
3232

3333
import com.oracle.svm.configure.command.ConfigurationCommand;
34+
import com.oracle.svm.configure.command.ConfigurationCommandExtractSbom;
3435
import com.oracle.svm.configure.command.ConfigurationCommandFileCommand;
3536
import com.oracle.svm.configure.command.ConfigurationGenerateCommand;
3637
import com.oracle.svm.configure.command.ConfigurationGenerateConditionalsCommand;
@@ -58,13 +59,15 @@ public class ConfigurationTool {
5859
ConfigurationCommand processTraceCommand = new ConfigurationProcessTraceCommand();
5960
ConfigurationCommand generateFiltersCommand = new ConfigurationGenerateFiltersCommand();
6061
ConfigurationCommand conditionalsCommand = new ConfigurationGenerateConditionalsCommand();
62+
ConfigurationCommand sbomExtractCommand = new ConfigurationCommandExtractSbom();
6163

6264
commands.put(helpCommand.getName(), helpCommand);
6365
commands.put(generateCommand.getName(), generateCommand);
6466
commands.put(commandFileCommand.getName(), commandFileCommand);
6567
commands.put(processTraceCommand.getName(), processTraceCommand);
6668
commands.put(conditionalsCommand.getName(), conditionalsCommand);
6769
commands.put(generateFiltersCommand.getName(), generateFiltersCommand);
70+
commands.put(sbomExtractCommand.getName(), sbomExtractCommand);
6871
}
6972

7073
public static Collection<ConfigurationCommand> getCommands() {
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
26+
package com.oracle.svm.configure.command;
27+
28+
import java.io.IOException;
29+
import java.nio.file.Files;
30+
import java.nio.file.Path;
31+
import java.util.Iterator;
32+
33+
import com.oracle.svm.configure.ConfigurationUsageException;
34+
import com.oracle.svm.configure.command.sbom.SbomExtractLibrary;
35+
36+
public final class ConfigurationCommandExtractSbom extends ConfigurationCommand {
37+
38+
private static final String IMAGE_PATH_OPT = "--image-path";
39+
private static final String EXTRACT_CMD = "extract-sbom";
40+
41+
@Override
42+
public String getName() {
43+
return EXTRACT_CMD;
44+
}
45+
46+
@Override
47+
public void apply(Iterator<String> argumentsIterator) throws IOException {
48+
Path imagePath = null;
49+
while (argumentsIterator.hasNext()) {
50+
String[] optionValue = argumentsIterator.next().split(OPTION_VALUE_SEP, OPTION_VALUE_LENGTH);
51+
String option = optionValue[OPTION_INDEX];
52+
String value = (optionValue.length > 1) ? optionValue[VALUE_INDEX] : null;
53+
switch (option) {
54+
case IMAGE_PATH_OPT:
55+
imagePath = requirePath(option, value);
56+
break;
57+
}
58+
}
59+
if (imagePath == null) {
60+
throw new ConfigurationUsageException("Argument must be provided for: " + IMAGE_PATH_OPT);
61+
}
62+
if (!Files.exists(imagePath)) {
63+
throw new ConfigurationUsageException("Binary does not exist or is not readable: " + imagePath);
64+
}
65+
int exitCode = SbomExtractLibrary.extractSbom(imagePath);
66+
if (exitCode != 0) {
67+
throw new RuntimeException("Failed to extract SBOM. See previous messages for defails.");
68+
}
69+
}
70+
71+
@Override
72+
public String getUsage() {
73+
return String.format("native-image-utils %s %s=<native-binary>", EXTRACT_CMD, IMAGE_PATH_OPT);
74+
}
75+
76+
@Override
77+
protected String getDescription0() {
78+
return """
79+
extracts an embedded SBOM from a native image binary.
80+
--image-path=<path>
81+
the path to the binary where the SBOM is embedded.
82+
""".replace("\n", System.lineSeparator());
83+
}
84+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright (c) 2026, 2026, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.svm.configure.command.sbom;
26+
27+
import org.graalvm.nativeimage.hosted.Feature;
28+
29+
import com.oracle.svm.shared.singletons.traits.BuiltinTraits.BuildtimeAccessOnly;
30+
import com.oracle.svm.shared.singletons.traits.BuiltinTraits.NoLayeredCallbacks;
31+
import com.oracle.svm.shared.singletons.traits.SingletonTraits;
32+
33+
/**
34+
* Marker feature used at build-time to add linking for the extract_sbom static library.
35+
*/
36+
@SingletonTraits(access = BuildtimeAccessOnly.class, layeredCallbacks = NoLayeredCallbacks.class)
37+
public class SbomExtractFeature implements Feature {
38+
@Override
39+
public void afterRegistration(AfterRegistrationAccess access) {
40+
// Nothing. This is only a hook to enable the extract_sbom.a library at build time
41+
}
42+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright (c) 2026, 2026, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.svm.configure.command.sbom;
26+
27+
import java.nio.file.Path;
28+
import java.util.List;
29+
30+
import org.graalvm.nativeimage.ImageSingletons;
31+
import org.graalvm.nativeimage.Platform;
32+
import org.graalvm.nativeimage.Platforms;
33+
import org.graalvm.nativeimage.c.CContext;
34+
import org.graalvm.nativeimage.c.function.CFunction;
35+
import org.graalvm.nativeimage.c.function.CFunction.Transition;
36+
import org.graalvm.nativeimage.c.function.CLibrary;
37+
import org.graalvm.nativeimage.c.type.CCharPointer;
38+
import org.graalvm.nativeimage.c.type.CTypeConversion;
39+
import org.graalvm.nativeimage.c.type.CTypeConversion.CCharPointerHolder;
40+
41+
/**
42+
* Provides Java-level access to the native {@code libextract_sbom} implementation.
43+
*/
44+
@CContext(SbomExtractLibraryDirectives.class)
45+
@CLibrary(value = "extract_sbom", requireStatic = true)
46+
public class SbomExtractLibrary {
47+
48+
public static int extractSbom(Path executable) {
49+
CCharPointerHolder exe = CTypeConversion.toCString(executable.toAbsolutePath().toString());
50+
return extractSbomNative(exe.get());
51+
}
52+
53+
@CFunction(value = "extract_sbom", transition = Transition.NO_TRANSITION)
54+
private static native int extractSbomNative(CCharPointer executable);
55+
56+
}
57+
58+
@Platforms(Platform.HOSTED_ONLY.class)
59+
class SbomExtractLibraryDirectives implements CContext.Directives {
60+
/**
61+
* True if {@link SbomExtractLibrary} should be linked.
62+
*/
63+
@Override
64+
public boolean isInConfiguration() {
65+
return Platform.includedIn(Platform.LINUX.class) && ImageSingletons.contains(SbomExtractFeature.class);
66+
}
67+
68+
@Override
69+
public List<String> getLibraries() {
70+
return List.of("elf");
71+
}
72+
}

0 commit comments

Comments
 (0)