Skip to content

Commit

Permalink
Parse SPDX License IDs from scripts
Browse files Browse the repository at this point in the history
IDs representing a GPL v2 license are translated into "GPL" to be
recognised by the kernel.

Licenses defined in a BpfScript config block take precedence over SPDX
IDs.
  • Loading branch information
ajor committed May 8, 2024
1 parent c2d1d1c commit 305df52
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 1 deletion.
6 changes: 5 additions & 1 deletion man/adoc/bpftrace.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ x86_64, arm64, s390x, arm32, loongarch64, mips64, ppc64, riscv64

The license of a bpftrace script affects how it can be run, as the Linux kernel limits the functionality available to non-GPL licensed programs.

A license can be specified by setting the <<license>> config variable.
A license can be specified by setting the <<license>> config variable or by including a single-line comment containing a SPDX License ID:

----
// SPDX-License-Identifier: GPL-2.0-or-later
----

If a license is not explicitly declared, bpftrace will assume that the script is GPL v2 compatible.

Expand Down
31 changes: 31 additions & 0 deletions src/driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,31 @@ extern bpftrace::location loc;

namespace bpftrace {

namespace {
std::string_view parse_license()
{
std::string_view program = Log::get().get_source();
constexpr std::string_view spdx_id_marker = "SPDX-License-Identifier: ";
auto spdx_id_pos = program.find(spdx_id_marker);
if (spdx_id_pos == program.npos)
return {};

auto license_pos = spdx_id_pos + spdx_id_marker.size();
auto eol_pos = program.find("\n", spdx_id_pos + 1);
if (eol_pos == program.npos)
return {};

auto license = program.substr(license_pos, eol_pos - license_pos);

// Try to translate some known GPL-v2-compatible licenses into a format
// understood by the Linux kernel
if (license.find("GPL-2.0") == 0)
return "GPL";

return license;
}
} // namespace

Driver::Driver(BPFtrace &bpftrace, std::ostream &o)
: bpftrace_(bpftrace), out_(o)
{
Expand All @@ -31,6 +56,12 @@ int Driver::parse_str(std::string_view script)

int Driver::parse()
{
if (auto license = parse_license(); !license.empty()) {
LOG(V1) << "Found license from SPDX ID: " << license;
ConfigSetter config_setter(bpftrace_.config_, ConfigSource::default_);
config_setter.set(ConfigKeyString::license, std::string{ license });
}

// Reset previous state if we parse more than once
root.reset();

Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ add_executable(bpftrace_test
mocks.cpp
output.cpp
parser.cpp
parser_licenses.cpp
portability_analyser.cpp
procmon.cpp
probe.cpp
Expand Down
65 changes: 65 additions & 0 deletions tests/parser_licenses.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include <optional>
#include <string>
#include <string_view>

#include "bpftrace.h"
#include "driver.h"
#include "gtest/gtest.h"

namespace bpftrace::test::parser_licenses {

void test(std::string_view input, std::optional<std::string> expected_license)
{
BPFtrace bpftrace;
Driver driver{ bpftrace };
ASSERT_EQ(0, driver.parse_str(input));
EXPECT_EQ(expected_license,
bpftrace.config_.try_get(ConfigKeyString::license));
}

TEST(ParserLicenses, GPL_v2_only)
{
test(R"(
// SPDX-License-Identifier: GPL-2.0-only
BEGIN {}
)",
"GPL");
}

TEST(ParserLicenses, GPL_v2_or_later)
{
test(R"(
// SPDX-License-Identifier: GPL-2.0-or-later
BEGIN {}
)",
"GPL");
}

TEST(ParserLicenses, GPL_v1)
{
test(R"(
// SPDX-License-Identifier: GPL-1.0-only
BEGIN {}
)",
"GPL-1.0-only");
}

TEST(ParserLicenses, GPL_v3)
{
test(R"(
// SPDX-License-Identifier: GPL-3.0-only
BEGIN {}
)",
"GPL-3.0-only");
}

TEST(ParserLicenses, Apache_2)
{
test(R"(
// SPDX-License-Identifier: Apache-2.0
BEGIN {}
)",
"Apache-2.0");
}

} // namespace bpftrace::test::parser_licenses
21 changes: 21 additions & 0 deletions tests/runtime/license
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,24 @@ EXPECT stdin:1:51-57: ERROR: helper bpf_probe_read_str can only be used in GPL-c
TIMEOUT 5
WILL_FAIL

NAME spdx_allowed
PROG // SPDX-License-Identifier: GPL-2.0-or-later
BEGIN { printf("\"%s\"\n", str(0)); exit(); }
EXPECT ""
TIMEOUT 5

NAME spdx_not_allowed
PROG // SPDX-License-Identifier: Apache-2.0
BEGIN { printf("%s\n", str(0)); }
EXPECT stdin:2:24-30: ERROR: helper bpf_probe_read_str can only be used in GPL-compatible programs
BEGIN { printf("%s\n", str(0)); }
~~~~~~
TIMEOUT 5
WILL_FAIL

NAME config_override_spdx
PROG // SPDX-License-Identifier: Some-unknown-GPL-compatible-license
config = { license = "GPL" }
BEGIN { printf("\"%s\"\n", str(0)); exit(); }
EXPECT ""
TIMEOUT 5

0 comments on commit 305df52

Please sign in to comment.