Skip to content

Commit b56f025

Browse files
authored
Merge pull request #184 from bluca/elf_notes
Import and relicense "Package Metadata for Executable Files" and "Dlopen Metadata for ELF Files" from systemd.io
2 parents e558411 + da4df6c commit b56f025

File tree

3 files changed

+436
-0
lines changed

3 files changed

+436
-0
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ BookToC: false
3737
* [Linux TPM PCR Registry](specs/linux_tpm_pcr_registry.md):
3838
An informative list of how TPM PCRs are used on a Linux system.
3939
([canonical online location](https://uapi-group.org/specifications/specs/linux_tpm_pcr_registry/))
40+
* [Package Metadata for Executable Files](specs/package_metadata_for_executable_files.md):
41+
Describes the format and mechanism to include packaging metadata in ELF/PE binaries.
42+
([canonical online location](https://uapi-group.org/specifications/specs/package_metadata_for_executable_files/))
43+
* [Dlopen Metadata for ELF Files](specs/elf_dlopen_metadata.md):
44+
Describes the format and mechanism to include dynamically loaded libraries metadata in ELF binaries.
45+
([canonical online location](https://uapi-group.org/specifications/specs/elf_dlopen_metadata/))
4046

4147
## Work in Progress
4248

specs/elf_dlopen_metadata.md

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
---
2+
title: Dlopen Metadata for ELF Files
3+
category: Interfaces
4+
layout: default
5+
version: 1.0
6+
SPDX-License-Identifier: CC-BY-4.0
7+
---
8+
9+
# `dlopen()` Metadata for ELF Files
10+
11+
| Version | Changes |
12+
|---------|---------|
13+
| 1.0 | Initial Release |
14+
15+
## Target Audience
16+
17+
The target audience for this specification is:
18+
19+
* Developers working on userspace subsystems that create ELF binaries that dynamically load libraries
20+
* Developers working on userspace subsystems that package ELF binaries that dynamically load libraries
21+
22+
## Motivation
23+
24+
Using `dlopen()` to load optional dependencies brings several advantages: programs can gracefully downgrade
25+
a feature when a library is not available, and the shared library is only loaded into the process (and its
26+
ELF constructors are run) only when the requested feature is actually used. But it also has some drawbacks,
27+
and the main one is that it is harder to track a program's dependencies, since unlike build-time dynamic
28+
linking there will not be a mention in the ELF metadata. This specification aims to solve this problem by
29+
providing a standardized specification for a custom ELF note that can be used to list `dlopen()`
30+
dependencies.
31+
32+
## Implementation
33+
34+
This document will attempt to define a common metadata format specification, so that multiple implementers
35+
might use it when coding upstream software, and packagers might use it when building packages and setting
36+
dependencies.
37+
38+
The metadata will be embedded in a series of new, 4-byte-aligned, allocated, 0-padded, read-only ELF header
39+
sections, in a JSON array containing name-value objects, either one ELF note per dependency or as a single
40+
note listing multiple dependencies in the top-level array. Implementers working on parsing ELF files should
41+
not assume a specific list of names, but parse anything that is included in the section, and should look for
42+
the note using the `note type`. Implementers working on build tools should strive to use the same names, for
43+
consistency. The most common will be listed here.
44+
45+
* Section header
46+
47+
```
48+
SECTION: `.note.dlopen`
49+
note type: `0x407c0c0a`
50+
Owner: `FDO` (FreeDesktop.org)
51+
Value: an array of JSON objects encoded as a zero-terminated UTF-8 string
52+
```
53+
54+
* JSON payload
55+
56+
```json
57+
[
58+
{
59+
"soname": ["libfoo.so.1"],
60+
"feature": "foo",
61+
"description": "Enables the foo feature",
62+
"priority": "recommended"
63+
}
64+
]
65+
```
66+
67+
The format is a single JSON array containing objects, encoded as a zero-terminated `UTF-8` string. Each key
68+
in each object shall be unique as per recommendations of [RFC8259](https://datatracker.ietf.org/doc/html/rfc8259#section-4).
69+
Strings shall not contain any control characters or use `\uXXX` escaping.
70+
71+
Reference implementations of [packaging tools for `.deb` and `.rpm`](https://github.com/systemd/package-notes)
72+
are available, and provide macros/helpers to parse the note when building packages and adding dependencies.
73+
74+
## Well-known keys
75+
76+
The metadata format is intentionally extensible, so that upstreams and later revisions of this spec can add
77+
their own information. The 'soname' array is required, with at least one element, everything else is
78+
optional. If alternative soname versions for the same library are supported at the same time, an array can
79+
be used, listing the most preferred first, and parsers are expected to select only the first one that is
80+
available on the system, as it is a mechanism to specify alternatives. If the `priority` field is used, it
81+
must follow the specification and use one of the values specified in the table. If it is not specified, a
82+
parser should assume 'recommended' if a priority is needed. If the `feature` field is used, it will identify
83+
an individual feature, and multiple entries using the same `feature` denote functionality that requires all
84+
of the libraries they specify in order to be enabled.
85+
86+
| Key name | Key type | Mandatory | Key description | Example value |
87+
|-------------|----------------------------|-----------|--------------------------------------------------------------------------|----------------------------------|
88+
| soname | array of strings | yes | The library names loaded by `dlopen()` | [ "libfoo.so.1", "libfoo.so.0" ] |
89+
| feature | string | no | A keyword identifying the feature that the library contributes to enable | "foo" |
90+
| description | string | no | A human-readable text string describing the feature | "Enables the foo feature" |
91+
| priority | string | no | The priority of the feature, one of: required, recommended, suggested | "recommended" |
92+
93+
### Priority definition
94+
95+
| Priority | Semantics |
96+
|-------------|--------------------------------------------------------------------------------------------------------------------------------------|
97+
| required | Core functionality needs the dependency, the binary will not work if it cannot be found |
98+
| recommended | Important functionality needs the dependency, the binary will work but in most cases the dependency should be provided |
99+
| suggested | Secondary functionality needs the dependency, the binary will work and the dependency is only needed for full-featured installations |
100+
101+
### Displaying `dlopen()` notes
102+
103+
The raw ELF section can be extracted using `objdump`:
104+
```console
105+
$ objdump -j .note.dlopen -s /usr/lib64/systemd/libsystemd-shared-257.so
106+
107+
/usr/lib64/systemd/libsystemd-shared-257.so: file format elf64-x86-64
108+
109+
Contents of section .note.dlopen:
110+
0334 04000000 8e000000 0a0c7c40 46444f00 ..........|@FDO.
111+
0344 5b7b2266 65617475 7265223a 22627066 [{"feature":"bpf
112+
0354 222c2264 65736372 69707469 6f6e223a ","description":
113+
0364 22537570 706f7274 20666972 6577616c "Support firewal
114+
0374 6c696e67 20616e64 2073616e 64626f78 ling and sandbox
115+
0384 696e6720 77697468 20425046 222c2270 ing with BPF","p
116+
0394 72696f72 69747922 3a227375 67676573 riority":"sugges
117+
03a4 74656422 2c22736f 6e616d65 223a5b22 ted","soname":["
118+
03b4 6c696262 70662e73 6f2e3122 2c226c69 libbpf.so.1","li
119+
03c4 62627066 2e736f2e 30225d7d 5d000000 bbpf.so.0"]}]...
120+
03d4 04000000 9e000000 0a0c7c40 46444f00 ..........|@FDO.
121+
...
122+
```
123+
124+
It is more convenient to use a higher level tool:
125+
```console
126+
$ dlopen-notes /usr/lib64/systemd/libsystemd-shared-257.so
127+
# /usr/lib64/systemd/libsystemd-shared-257.so
128+
[
129+
{
130+
"feature": "archive",
131+
"description": "Support for decompressing archive files",
132+
"priority": "suggested",
133+
"soname": [
134+
"libarchive.so.13"
135+
]
136+
},
137+
{
138+
"feature": "bpf",
139+
"description": "Support firewalling and sandboxing with BPF",
140+
"priority": "suggested",
141+
"soname": [
142+
"libbpf.so.1",
143+
"libbpf.so.0"
144+
]
145+
},
146+
...
147+
```
148+
149+
`dlopen-notes` can display the notes grouped in a few different ways.
150+
One option is to filter the libraries by "feature". This answers the
151+
question "what libraries are needed to provide specified features":
152+
153+
```console
154+
$ dlopen-notes.py -f archive,bpf /usr/lib64/systemd/libsystemd-shared-257.so
155+
# grouped by feature
156+
{
157+
"bpf": {
158+
"description": "Support firewalling and sandboxing with BPF",
159+
"sonames": {
160+
"libbpf.so.1": "suggested",
161+
"libbpf.so.0": "suggested"
162+
}
163+
},
164+
"archive": {
165+
"description": "Support for decompressing archive files",
166+
"sonames": {
167+
"libarchive.so.13": "suggested"
168+
}
169+
}
170+
}
171+
172+
The format that is used when building `deb` packages:
173+
```console
174+
$ dlopen-notes -s /usr/lib64/systemd/libsystemd-shared-257.so
175+
libarchive.so.13 suggested
176+
libbpf.so.0 suggested
177+
libbpf.so.1 suggested
178+
...
179+
```
180+
181+
The format that can be useful when building `rpm` packages:
182+
```console
183+
$ dlopen-notes --rpm-requires archive --rpm-recommends bpf /usr/lib64/systemd/libsystemd-shared-257.so
184+
Requires: libarchive.so.13()(64bit)
185+
Recommends: libbpf.so.1()(64bit)
186+
```

0 commit comments

Comments
 (0)