Skip to content

Commit 19109a3

Browse files
manifests: set proper SELinux labels for '/boot/efi' and '/boot/lost+found'
Issue: osbuild/osbuild#1877
1 parent 3627bdd commit 19109a3

8 files changed

+606
-45
lines changed

build.sh

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,12 @@ patch_osbuild() {
173173
mv /usr/bin/osbuild-mpp /usr/lib/osbuild/tools/
174174

175175
# Now all the software is under the /usr/lib/osbuild dir and we can patch
176-
patch -d /usr/lib/osbuild -p1 < /usr/lib/coreos-assembler/0001-hacks-for-coreos-selinux-issues.patch
176+
cat /usr/lib/coreos-assembler/0001-org.osbuild.mkdir-support-creating-dirs-on-mounts.patch \
177+
/usr/lib/coreos-assembler/0001-parsing-add-parse_location_ext.patch \
178+
/usr/lib/coreos-assembler/0002-org.osbuild.selinux-support-operating-on-mounts.patch \
179+
/usr/lib/coreos-assembler/0003-org.osbuild.selinux-support-for-specifying-where-fil.patch \
180+
| patch -d /usr/lib/osbuild -p1
181+
177182

178183
# And then move the files back; supermin appliance creation will need it back
179184
# in the places delivered by the RPM.

src/0001-hacks-for-coreos-selinux-issues.patch

Lines changed: 0 additions & 44 deletions
This file was deleted.
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
From 362a1ea2485ea2c49e6c250a0446bd5a33b2062c Mon Sep 17 00:00:00 2001
2+
From: Nikita Dubrovskii <[email protected]>
3+
Date: Mon, 30 Sep 2024 15:46:31 +0200
4+
Subject: [PATCH] org.osbuild.mkdir: support creating dirs on mounts
5+
6+
This allows creating new directories on mounts:
7+
```
8+
- type: org.osbuild.mkdir
9+
options:
10+
paths:
11+
- path: mount:///boot/efi
12+
devices:
13+
disk: ...
14+
mounts:
15+
- name: boot
16+
target: /boot
17+
...
18+
```
19+
---
20+
stages/org.osbuild.mkdir | 22 ++++++++++++----------
21+
stages/org.osbuild.mkdir.meta.json | 21 ++++++++++++++++++---
22+
2 files changed, 30 insertions(+), 13 deletions(-)
23+
24+
diff --git a/stages/org.osbuild.mkdir b/stages/org.osbuild.mkdir
25+
index f04549f6..d2d11a7a 100755
26+
--- a/stages/org.osbuild.mkdir
27+
+++ b/stages/org.osbuild.mkdir
28+
@@ -3,23 +3,26 @@ import os
29+
import sys
30+
31+
import osbuild.api
32+
-from osbuild.util.path import in_tree
33+
+from osbuild.util import parsing
34+
35+
36+
-def main(tree, options):
37+
+def main(args):
38+
+ options = args["options"]
39+
+
40+
for item in options["paths"]:
41+
path = item["path"]
42+
mode = item.get("mode", 0o777)
43+
parents = item.get("parents", False)
44+
exist_ok = item.get("exist_ok", False)
45+
46+
- if not path.startswith("/"):
47+
- print("WARNING: relative path used, this is discouraged!")
48+
-
49+
- target = os.path.join(tree, path.lstrip("/"))
50+
- if not in_tree(target, tree):
51+
- raise ValueError(f"path {path} not in tree")
52+
+ if "://" not in path:
53+
+ if not path.startswith("/"):
54+
+ print("WARNING: relative path used, this is discouraged!")
55+
+ path = f"tree:///{path}"
56+
+ else:
57+
+ path = f"tree://{path}"
58+
59+
+ target = parsing.parse_location(path, args)
60+
if parents:
61+
os.makedirs(target, mode=mode, exist_ok=exist_ok)
62+
else:
63+
@@ -33,5 +36,4 @@ def main(tree, options):
64+
65+
66+
if __name__ == "__main__":
67+
- args = osbuild.api.arguments()
68+
- sys.exit(main(args["tree"], args["options"]))
69+
+ sys.exit(main(osbuild.api.arguments()))
70+
diff --git a/stages/org.osbuild.mkdir.meta.json b/stages/org.osbuild.mkdir.meta.json
71+
index 5534120a..6cebaaf5 100644
72+
--- a/stages/org.osbuild.mkdir.meta.json
73+
+++ b/stages/org.osbuild.mkdir.meta.json
74+
@@ -1,5 +1,5 @@
75+
{
76+
- "summary": "Create directories within the tree.",
77+
+ "summary": "Create directories within the tree or mount.",
78+
"description": [
79+
"Can create one or more directories, optionally also the",
80+
"intermediate directories. The stage can gracefully handle",
81+
@@ -31,8 +31,23 @@
82+
],
83+
"properties": {
84+
"path": {
85+
- "type": "string",
86+
- "pattern": "^\\/?(?!\\.\\.)((?!\\/\\.\\.\\/).)+$"
87+
+ "anyOf": [
88+
+ {
89+
+ "type": "string",
90+
+ "description": "Target path, if a tree",
91+
+ "pattern": "^\\/?(?!\\.\\.)((?!\\/\\.\\.\\/).)+$"
92+
+ },
93+
+ {
94+
+ "type": "string",
95+
+ "description": "Target path, if a mount",
96+
+ "pattern": "^mount://.+"
97+
+ },
98+
+ {
99+
+ "type": "string",
100+
+ "description": "Target path, if a tree",
101+
+ "pattern": "^tree://.+"
102+
+ }
103+
+ ]
104+
},
105+
"mode": {
106+
"type": "number",
107+
--
108+
2.47.0
109+
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
From e36f51ff5787a62323c0a9ad8987c81c9a6aba09 Mon Sep 17 00:00:00 2001
2+
From: Nikita Dubrovskii <[email protected]>
3+
Date: Fri, 18 Oct 2024 12:28:32 +0200
4+
Subject: [PATCH 1/3] parsing: add parse_location_ext
5+
6+
New fucntion returns tuple of 'root' and 'url path', which could be
7+
useful in contexts, where knowing 'root' is required, for example setting
8+
selinux labels.
9+
---
10+
osbuild/util/parsing.py | 25 +++++++++++++++++++------
11+
1 file changed, 19 insertions(+), 6 deletions(-)
12+
13+
diff --git a/osbuild/util/parsing.py b/osbuild/util/parsing.py
14+
index f8fb2768..2c03b123 100644
15+
--- a/osbuild/util/parsing.py
16+
+++ b/osbuild/util/parsing.py
17+
@@ -2,7 +2,7 @@
18+
19+
import os
20+
import re
21+
-from typing import Dict, Union
22+
+from typing import Dict, Tuple, Union
23+
from urllib.parse import ParseResult, urlparse
24+
25+
26+
@@ -72,9 +72,9 @@ def parse_input(url: ParseResult, args: Dict) -> os.PathLike:
27+
return root
28+
29+
30+
-def parse_location(location: str, args: Dict) -> str:
31+
+def parse_location_ext(location: str, args: Dict) -> Tuple[str, str]:
32+
"""
33+
- Parses the location URL to derive the corresponding file path.
34+
+ Parses the location URL to derive the corresponding root and file path.
35+
36+
Parameters:
37+
- location (str): The location URL to be parsed.
38+
@@ -97,11 +97,24 @@ def parse_location(location: str, args: Dict) -> str:
39+
if not url.path.startswith("/"):
40+
raise ValueError(f"url.path from location must start with '/', got: {url.path}")
41+
42+
- path = os.path.relpath(url.path, "/")
43+
+ return root, url.path
44+
+
45+
+
46+
+def parse_location(location: str, args: Dict) -> str:
47+
+ """
48+
+ Parses the location URL to derive the corresponding file path.
49+
+
50+
+ Parameters:
51+
+ - location (str): The location URL to be parsed.
52+
+ - args (Dict): A dictionary containing arguments including mounts and
53+
+ path information as passed by osbuild.api.arguments()
54+
+ """
55+
+
56+
+ root, urlpath = parse_location_ext(location, args)
57+
+ path = os.path.relpath(urlpath, "/")
58+
path = os.path.join(root, path)
59+
path = os.path.normpath(path)
60+
-
61+
- if url.path.endswith("/"):
62+
+ if urlpath.endswith("/"):
63+
path = os.path.join(path, ".")
64+
65+
return path
66+
--
67+
2.47.0
68+
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
From beacc9e146cb3c104ff69a06e439e76656dc8df3 Mon Sep 17 00:00:00 2001
2+
From: Nikita Dubrovskii <[email protected]>
3+
Date: Thu, 17 Oct 2024 12:57:00 +0200
4+
Subject: [PATCH 2/3] org.osbuild.selinux: support operating on mounts
5+
6+
This adds support for specifying paths to operate on,
7+
rather than just the root of the target:
8+
```
9+
- type: org.osbuild.selinux
10+
options:
11+
file_contexts: etc/selinux/targeted/contexts/files/file_contexts
12+
targets:
13+
- tree:///path/to/dir
14+
- mount://root/path/to/dir
15+
devices:
16+
disk: ...
17+
mounts:
18+
- name: root
19+
source: disk
20+
target: /
21+
```
22+
---
23+
stages/org.osbuild.selinux | 52 ++++++++++++++++------------
24+
stages/org.osbuild.selinux.meta.json | 19 ++++++++++
25+
2 files changed, 49 insertions(+), 22 deletions(-)
26+
27+
diff --git a/stages/org.osbuild.selinux b/stages/org.osbuild.selinux
28+
index 563d827b..da1ad39a 100755
29+
--- a/stages/org.osbuild.selinux
30+
+++ b/stages/org.osbuild.selinux
31+
@@ -4,36 +4,44 @@ import pathlib
32+
import sys
33+
34+
import osbuild.api
35+
-from osbuild.util import selinux
36+
+from osbuild.util import parsing, selinux
37+
38+
39+
-def main(tree, options):
40+
+def main(args, options):
41+
file_contexts = options.get("file_contexts")
42+
exclude_paths = options.get("exclude_paths")
43+
44+
- if file_contexts:
45+
- file_contexts = os.path.join(f"{tree}", options["file_contexts"])
46+
- if exclude_paths:
47+
- exclude_paths = [os.path.join(tree, p.lstrip("/")) for p in exclude_paths]
48+
- selinux.setfiles(file_contexts, os.fspath(tree), "", exclude_paths=exclude_paths)
49+
+ # Get the path where the tree is
50+
+ tree = args["tree"]
51+
52+
- labels = options.get("labels", {})
53+
- for path, label in labels.items():
54+
- fullpath = os.path.join(tree, path.lstrip("/"))
55+
- selinux.setfilecon(fullpath, label)
56+
+ # Set labels on each target
57+
+ for target in options.get("targets", ["tree:///"]):
58+
+ root, target = parsing.parse_location_ext(target, args)
59+
+ target = target.lstrip("/")
60+
61+
- if options.get("force_autorelabel", False):
62+
- stamp = pathlib.Path(tree, ".autorelabel")
63+
- # Creating just empty /.autorelabel resets only the type of files.
64+
- # To ensure that the full context is reset, we write "-F" into the file.
65+
- # This mimics the behavior of `fixfiles -F boot`. The "-F" option is
66+
- # then passed to `selinux-autorelabel` script [0].
67+
- # Note that this is missing from the selinux(8) and selinux_config(5) man-pages
68+
- # [0] https://src.fedoraproject.org/rpms/policycoreutils/blob/rawhide/f/selinux-autorelabel#_54
69+
- stamp.write_text("-F", encoding="utf-8")
70+
+ if file_contexts:
71+
+ file_contexts = os.path.join(f"{tree}", options["file_contexts"])
72+
+ if exclude_paths:
73+
+ exclude_paths = [os.path.join(root, target, p.lstrip("/")) for p in exclude_paths]
74+
+ selinux.setfiles(file_contexts, os.fspath(root), target, exclude_paths=exclude_paths)
75+
+
76+
+ labels = options.get("labels", {})
77+
+ for path, label in labels.items():
78+
+ fullpath = os.path.join(root, path.lstrip("/"))
79+
+ selinux.setfilecon(fullpath, label)
80+
+
81+
+ if options.get("force_autorelabel", False):
82+
+ stamp = pathlib.Path(root, ".autorelabel")
83+
+ # Creating just empty /.autorelabel resets only the type of files.
84+
+ # To ensure that the full context is reset, we write "-F" into the file.
85+
+ # This mimics the behavior of `fixfiles -F boot`. The "-F" option is
86+
+ # then passed to `selinux-autorelabel` script [0].
87+
+ # Note that this is missing from the selinux(8) and selinux_config(5) man-pages
88+
+ # [0] https://src.fedoraproject.org/rpms/policycoreutils/blob/rawhide/f/selinux-autorelabel#_54
89+
+ stamp.write_text("-F", encoding="utf-8")
90+
91+
92+
if __name__ == '__main__':
93+
- args = osbuild.api.arguments()
94+
- r = main(args["tree"], args["options"])
95+
+ _args = osbuild.api.arguments()
96+
+ r = main(_args, _args["options"])
97+
sys.exit(r)
98+
diff --git a/stages/org.osbuild.selinux.meta.json b/stages/org.osbuild.selinux.meta.json
99+
index 30dbddae..3476df9d 100644
100+
--- a/stages/org.osbuild.selinux.meta.json
101+
+++ b/stages/org.osbuild.selinux.meta.json
102+
@@ -33,6 +33,25 @@
103+
}
104+
],
105+
"properties": {
106+
+ "targets": {
107+
+ "description": "Array of target paths to operate on",
108+
+ "type": "array",
109+
+ "additionalItems": false,
110+
+ "items": {
111+
+ "oneOf": [
112+
+ {
113+
+ "type": "string",
114+
+ "description": "Target path, if a mount",
115+
+ "pattern": "^mount://.+"
116+
+ },
117+
+ {
118+
+ "type": "string",
119+
+ "description": "Target path, if a tree",
120+
+ "pattern": "^tree://.+"
121+
+ }
122+
+ ]
123+
+ }
124+
+ },
125+
"file_contexts": {
126+
"type": "string",
127+
"description": "Path to the active SELinux policy's `file_contexts`"
128+
--
129+
2.47.0
130+

0 commit comments

Comments
 (0)