Skip to content

Commit 9573124

Browse files
committed
Limit permissions for Android images.
Remove the use of the `--privileged` flag for Android images and instead use an seccomp permissions. The provided profile is derived from the docker documentation, with slight modifications to allow `clone` and `clone3`. The documentation is [docker seccomp](https://docs.docker.com/engine/security/seccomp/#significant-syscalls-blocked-by-the-default-profile), which details the syscalls blocked by docker. The same is true for podman. We merely modified these settings to allow `personality` syscall, which then allows us to use our Android images.
1 parent 6baac54 commit 9573124

File tree

6 files changed

+207
-5
lines changed

6 files changed

+207
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
2020
### Changed
2121

2222
- #747 - reduced android image sizes.
23+
- #746 - limit image permissions for android images.
2324
- #377 - update WINE versions to 7.0.
2425
- #734 - patch `arm-unknown-linux-gnueabihf` to build for ARMv6, and add architecture for crosstool-ng-based images.
2526
- #709 - Update Emscripten targets to `emcc` version 3.1.10

src/cli.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::str::FromStr;
22
use std::{env, path::PathBuf};
33

44
use crate::cargo::Subcommand;
5-
use crate::errors::Result;
5+
use crate::errors::*;
66
use crate::rustc::TargetList;
77
use crate::Target;
88

src/docker.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
use std::io::Write;
12
use std::path::{Path, PathBuf};
23
use std::process::{Command, ExitStatus};
34
use std::{env, fs};
45

56
use crate::cargo::Root;
67
use crate::errors::*;
78
use crate::extensions::{CommandExt, SafeCommand};
9+
use crate::file::write_file;
810
use crate::id;
911
use crate::{Config, Target};
1012
use atty::Stream;
@@ -14,6 +16,11 @@ const DOCKER_IMAGES: &[&str] = &include!(concat!(env!("OUT_DIR"), "/docker-image
1416
const CROSS_IMAGE: &str = "ghcr.io/cross-rs";
1517
const DOCKER: &str = "docker";
1618
const PODMAN: &str = "podman";
19+
// secured profile based off the docker documentation for denied syscalls:
20+
// https://docs.docker.com/engine/security/seccomp/#significant-syscalls-blocked-by-the-default-profile
21+
// note that we've allow listed `clone` and `clone3`, which is necessary
22+
// to fork the process, and which podman allows by default.
23+
const SECCOMP: &str = include_str!("seccomp.json");
1724

1825
// determine if the container engine is docker. this fixes issues with
1926
// any aliases (#530), and doesn't fail if an executable suffix exists.
@@ -186,8 +193,20 @@ pub fn run(
186193

187194
docker.arg("--rm");
188195

189-
if target.needs_docker_privileged() {
190-
docker.arg("--privileged");
196+
// docker uses seccomp now on all installations
197+
if target.needs_docker_seccomp() {
198+
let path = env::current_dir()
199+
.wrap_err("couldn't get current directory")?
200+
.canonicalize()
201+
.wrap_err_with(|| "when canonicalizing current_dir".to_string())?
202+
.join("target")
203+
.join(target.triple())
204+
.join("seccomp.json");
205+
if !path.exists() {
206+
write_file(&path, false)?.write_all(SECCOMP.as_bytes())?;
207+
}
208+
209+
docker.args(&["--security-opt", &format!("seccomp={}", path.display())]);
191210
}
192211

193212
// We need to specify the user for Docker, but not for Podman.

src/file.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::fs::File;
1+
use std::fs::{self, File};
22
use std::io::Read;
33
use std::path::Path;
44

@@ -19,3 +19,19 @@ fn read_(path: &Path) -> Result<String> {
1919
.wrap_err_with(|| format!("couldn't read {}", path.display()))?;
2020
Ok(s)
2121
}
22+
23+
pub fn write_file(path: impl AsRef<Path>, overwrite: bool) -> Result<File> {
24+
let path = path.as_ref();
25+
fs::create_dir_all(&path.parent().ok_or_else(|| {
26+
eyre::eyre!(format!(
27+
"could not find parent directory for `{}`",
28+
path.display()
29+
))
30+
})?)
31+
.wrap_err_with(|| format!("couldn't create directory `{}`", path.display()))?;
32+
fs::OpenOptions::new()
33+
.write(true)
34+
.create_new(!overwrite)
35+
.open(&path)
36+
.wrap_err(format!("could't write to file `{}`", path.display()))
37+
}

src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ impl Target {
211211
!native && (self.is_linux() || self.is_windows() || self.is_bare_metal())
212212
}
213213

214-
fn needs_docker_privileged(&self) -> bool {
214+
fn needs_docker_seccomp(&self) -> bool {
215215
let arch_32bit = self.triple().starts_with("arm")
216216
|| self.triple().starts_with("i586")
217217
|| self.triple().starts_with("i686");

src/seccomp.json

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
{
2+
"defaultAction": "SCMP_ACT_ALLOW",
3+
"syscalls": [
4+
{
5+
"names": [
6+
"add_key",
7+
"get_kernel_syms",
8+
"keyctl",
9+
"move_pages",
10+
"nfsservctl",
11+
"perf_event_open",
12+
"pivot_root",
13+
"query_module",
14+
"request_key",
15+
"sysfs",
16+
"_sysctl",
17+
"uselib",
18+
"userfaultfd",
19+
"ustat"
20+
],
21+
"action": "SCMP_ACT_ERRNO",
22+
"errnoRet": 1
23+
},
24+
{
25+
"names": [
26+
"acct"
27+
],
28+
"action": "SCMP_ACT_ERRNO",
29+
"errnoRet": 1,
30+
"excludes": {
31+
"caps": [
32+
"CAP_SYS_PACCT"
33+
]
34+
}
35+
},
36+
{
37+
"names": [
38+
"bpf",
39+
"lookup_dcookie",
40+
"mount",
41+
"quotactl",
42+
"quotactl_fd",
43+
"setns",
44+
"swapon",
45+
"swapoff",
46+
"umount",
47+
"umount2",
48+
"unshare",
49+
"vm86",
50+
"vm86old",
51+
"pciconfig_read",
52+
"pciconfig_write",
53+
"salinfo_log_open",
54+
"salinfo_event_open",
55+
"sys_cacheflush",
56+
"rtas"
57+
],
58+
"action": "SCMP_ACT_ERRNO",
59+
"errnoRet": 1,
60+
"excludes": {
61+
"caps": [
62+
"CAP_SYS_ADMIN"
63+
]
64+
}
65+
},
66+
{
67+
"names": [
68+
"clock_adjtime",
69+
"clock_settime",
70+
"settimeofday",
71+
"stime"
72+
],
73+
"action": "SCMP_ACT_ERRNO",
74+
"errnoRet": 1,
75+
"excludes": {
76+
"caps": [
77+
"CAP_SYS_TIME"
78+
]
79+
}
80+
},
81+
{
82+
"names": [
83+
"create_module",
84+
"delete_module",
85+
"finit_module",
86+
"init_module"
87+
],
88+
"action": "SCMP_ACT_ERRNO",
89+
"errnoRet": 1,
90+
"excludes": {
91+
"caps": [
92+
"CAP_SYS_MODULE"
93+
]
94+
}
95+
},
96+
{
97+
"names": [
98+
"get_mempolicy",
99+
"mbind",
100+
"set_mempolicy"
101+
],
102+
"action": "SCMP_ACT_ERRNO",
103+
"errnoRet": 1,
104+
"excludes": {
105+
"caps": [
106+
"CAP_SYS_NICE"
107+
]
108+
}
109+
},
110+
{
111+
"names": [
112+
"ioperm",
113+
"iopl"
114+
],
115+
"action": "SCMP_ACT_ERRNO",
116+
"errnoRet": 1,
117+
"excludes": {
118+
"caps": [
119+
"CAP_SYS_RAWIO"
120+
]
121+
}
122+
},
123+
{
124+
"names": [
125+
"kcmp",
126+
"process_vm_readv",
127+
"process_vm_writev",
128+
"ptrace"
129+
],
130+
"action": "SCMP_ACT_ERRNO",
131+
"errnoRet": 1,
132+
"excludes": {
133+
"caps": [
134+
"CAP_SYS_PTRACE"
135+
]
136+
}
137+
},
138+
{
139+
"names": [
140+
"kexec_file_load",
141+
"kexec_load",
142+
"reboot"
143+
],
144+
"action": "SCMP_ACT_ERRNO",
145+
"errnoRet": 1,
146+
"excludes": {
147+
"caps": [
148+
"CAP_SYS_BOOT"
149+
]
150+
}
151+
},
152+
{
153+
"names": [
154+
"name_to_handle_at",
155+
"open_by_handle_at"
156+
],
157+
"action": "SCMP_ACT_ERRNO",
158+
"errnoRet": 1,
159+
"excludes": {
160+
"caps": [
161+
"CAP_DAC_READ_SEARCH"
162+
]
163+
}
164+
}
165+
]
166+
}

0 commit comments

Comments
 (0)