aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 05:10:33 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 05:10:33 +0000
commitabcc5e018c5932ff900b09aad2c53cecced44be6 (patch)
treeaac272e0ee4230388fcb775ba5e352c8ded3aebd
parentc613ab273be552a046aaa7d8dadb1958e59da980 (diff)
parentd3e36182e87f07b0e0bfaa6d14c8950a1c43bdfd (diff)
downloadminijail-android14-mainline-sdkext-release.tar.gz
Snap for 10453563 from d3e36182e87f07b0e0bfaa6d14c8950a1c43bdfd to mainline-sdkext-releaseaml_sdk_341510000aml_sdk_341410000aml_sdk_341110080aml_sdk_341110000aml_sdk_341010000aml_sdk_340912010android14-mainline-sdkext-release
Change-Id: I0ef8762e4092f3c206d1d316a9f7772afb32f40c
-rw-r--r--Android.bp58
-rw-r--r--HACKING.md6
-rw-r--r--LICENSE4
-rw-r--r--Makefile46
-rw-r--r--NOTICE4
-rw-r--r--OWNERS11
-rw-r--r--PREUPLOAD.cfg3
-rw-r--r--README.md64
-rw-r--r--arch.h2
-rw-r--r--bpf.c4
-rw-r--r--bpf.h2
-rw-r--r--common.mk2
-rw-r--r--config_parser.c7
-rw-r--r--config_parser.h2
-rw-r--r--config_parser_unittest.cc2
-rw-r--r--dump_constants.cc2
-rw-r--r--elfparse.c2
-rw-r--r--elfparse.h2
-rw-r--r--gen_constants-inl.h6
-rwxr-xr-xgen_constants.sh2
-rw-r--r--gen_syscalls-inl.h36
-rwxr-xr-xgen_syscalls.sh2
-rw-r--r--landlock.h132
-rw-r--r--landlock_util.c65
-rw-r--r--landlock_util.h106
-rw-r--r--libconstants.h2
-rw-r--r--libminijail-private.h2
-rw-r--r--libminijail.c411
-rw-r--r--libminijail.h29
-rw-r--r--libminijail_unittest.cc457
-rw-r--r--libminijailpreload.c2
-rw-r--r--libsyscalls.h2
-rw-r--r--minijail0.16
-rw-r--r--minijail0.513
-rw-r--r--minijail0.c2
-rwxr-xr-xminijail0.sh2
-rw-r--r--minijail0_cli.c73
-rw-r--r--minijail0_cli.h2
-rw-r--r--minijail0_cli_unittest.cc19
-rw-r--r--parse_seccomp_policy.cc4
-rwxr-xr-xplatform2_preinstall.sh2
-rw-r--r--rust/OWNERS2
-rw-r--r--rust/minijail-sys/Android.bp35
-rw-r--r--rust/minijail-sys/Cargo.toml2
-rw-r--r--rust/minijail-sys/build.rs13
-rw-r--r--rust/minijail-sys/cargo2android.json13
-rw-r--r--rust/minijail-sys/lib.rs12
-rw-r--r--rust/minijail-sys/libminijail.rs52
-rw-r--r--rust/minijail-sys/patches/Android.bp.patch16
-rw-r--r--rust/minijail/Android.bp33
-rw-r--r--rust/minijail/Cargo.toml7
-rw-r--r--rust/minijail/cargo2android.json9
-rw-r--r--rust/minijail/src/lib.rs20
-rw-r--r--rust/minijail/tests/fork_remap.rs2
-rw-r--r--scoped_minijail.h2
-rw-r--r--signal_handler.c2
-rw-r--r--signal_handler.h2
-rw-r--r--syscall_filter.c24
-rw-r--r--syscall_filter.h2
-rw-r--r--syscall_filter_unittest.cc2
-rw-r--r--syscall_filter_unittest_macros.h2
-rw-r--r--syscall_wrapper.c2
-rw-r--r--syscall_wrapper.h2
-rw-r--r--system.c59
-rw-r--r--system.h16
-rw-r--r--system_unittest.cc168
-rw-r--r--test/landlock.conf7
-rw-r--r--test/read_stdin2
-rw-r--r--test_util.cc2
-rw-r--r--test_util.h2
-rw-r--r--testrunner.cc2
-rw-r--r--tools/Android.bp32
-rwxr-xr-xtools/generate_constants_json.py19
-rwxr-xr-xtools/repo_upload_warning21
-rw-r--r--unittest_util.h104
-rw-r--r--util.c85
-rw-r--r--util.h36
-rw-r--r--util_unittest.cc16
78 files changed, 1913 insertions, 514 deletions
diff --git a/Android.bp b/Android.bp
index 0a80f77..fc25a10 100644
--- a/Android.bp
+++ b/Android.bp
@@ -52,6 +52,7 @@ license {
libminijailSrcFiles = [
"bpf.c",
+ "landlock_util.c",
"libminijail.c",
"signal_handler.c",
"syscall_filter.c",
@@ -74,10 +75,10 @@ cc_defaults {
"-DALLOW_DEBUG_LOGGING",
"-DALLOW_DUPLICATE_SYSCALLS",
"-DDEFAULT_PIVOT_ROOT=\"/var/empty\"",
+ "-DBINDMOUNT_ALLOWED_PREFIXES=\"\"",
"-Wall",
"-Werror",
],
- c_std: "gnu11",
target: {
darwin: {
enabled: false,
@@ -459,6 +460,9 @@ cc_test {
},
},
data: ["test/*"],
+ test_options: {
+ tags: ["no-remote"],
+ }
}
@@ -550,55 +554,3 @@ cc_binary {
static_libs: ["libminijail_generated"],
shared_libs: minijailCommonLibraries + ["libminijail"],
}
-
-rust_defaults {
- name: "libminijail_rust_defaults",
- target: {
- darwin: {
- enabled: false,
- },
- },
-}
-
-// This target was generated by cargo2android.py --run --device, with some
-// manual fixes.
-rust_library {
- name: "libminijail_sys",
- defaults: ["libminijail_rust_defaults"],
- host_supported: true,
- crate_name: "minijail_sys",
- srcs: ["rust/minijail-sys/lib.rs"],
- edition: "2018",
- rustlibs: [
- "liblibc",
- ],
- shared_libs: [
- "libcap",
- "libminijail",
- ],
- apex_available: [
- "//apex_available:platform",
- "com.android.compos",
- "com.android.virt",
- ],
-}
-
-// This target was generated by cargo2android.py --run --device, with some
-// manual fixes.
-rust_library {
- name: "libminijail_rust",
- defaults: ["libminijail_rust_defaults"],
- host_supported: true,
- crate_name: "minijail",
- srcs: ["rust/minijail/src/lib.rs"],
- edition: "2018",
- rustlibs: [
- "liblibc",
- "libminijail_sys",
- ],
- apex_available: [
- "//apex_available:platform",
- "com.android.compos",
- "com.android.virt",
- ],
-}
diff --git a/HACKING.md b/HACKING.md
index 612e505..415b65e 100644
--- a/HACKING.md
+++ b/HACKING.md
@@ -38,10 +38,10 @@ Building the tests will automatically execute them.
## Code Review
We use [Android Review] for Minijail code review. The easiest way to submit
-changes for review is using `repo upload` on a Chromium OS or Android checkout.
+changes for review is using `repo upload` on a ChromiumOS or Android checkout.
Go to [Android Review HTTP Credentials] to obtain credentials to push code. For
more detailed instructions see the [Android source documentation] or the
-[Chromium OS documentation].
+[ChromiumOS documentation].
## Source Style
@@ -81,6 +81,6 @@ Please keep it in sync with [minijail0_cli.c].
[Android Review]: https://android-review.googlesource.com/
[Android Review HTTP Credentials]: https://android-review.googlesource.com/settings/#HTTPCredentials
[Android source documentation]: https://source.android.com/setup/start
-[Chromium OS documentation]: https://chromium.googlesource.com/chromiumos/docs/+/HEAD/developer_guide.md
+[ChromiumOS documentation]: https://chromium.googlesource.com/chromiumos/docs/+/HEAD/developer_guide.md
[Google Markdown style guide]: https://github.com/google/styleguide/blob/gh-pages/docguide/style.md
[Google Test]: https://github.com/google/googletest
diff --git a/LICENSE b/LICENSE
index e0967d1..3e0a62d 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-/* Copyright 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright 2012 The ChromiumOS Authors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
- * * Neither the name of Google Inc. nor the names of its
+ * * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
diff --git a/Makefile b/Makefile
index f44f867..4759736 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Copyright 2012 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -17,15 +17,35 @@ BUILD_STATIC_LIBS ?= no
DEFAULT_PIVOT_ROOT ?= /var/empty
CPPFLAGS += -DDEFAULT_PIVOT_ROOT='"$(DEFAULT_PIVOT_ROOT)"'
+# These are configurable strictness settings. Not every use case for Minijail
+# has the same requirements.
+
+# Allow seccomp to fail without a warning. You probably don't want this.
ifeq ($(USE_seccomp),no)
CPPFLAGS += -DUSE_SECCOMP_SOFTFAIL
endif
+# Prevent Minijail configuration files from residing in a noexec
+# filesystem.
+#
+# The rationale here is that a configuration file that controls how a program
+# executes should be subject to the same restrictions as the executable it
+# controls. In essence, a configuration file should be considered to have as
+# much power as an executable. Files can only be executed from filesystems *not*
+# mounted as noexec, so configuration files should not reside in noexec
+# filesystems.
+#
+# For example, on ChromeOS executable filesystems are mounted read-only. Noexec
+# filesystems are allowed to be mounted read-write. If a configuration file
+# were allowed to reside in a noexec filesystem, an attacker would be able to
+# influence how a program is executed by modifying the configuration file.
BLOCK_NOEXEC_CONF ?= no
ifeq ($(BLOCK_NOEXEC_CONF),yes)
CPPFLAGS += -DBLOCK_NOEXEC_CONF
endif
+# Prevent Minijail configuration files from residing in a partition different
+# from the partition mounted at /. This is primarily used in ChromeOS.
ENFORCE_ROOTFS_CONF ?= no
ifeq ($(ENFORCE_ROOTFS_CONF),yes)
CPPFLAGS += -DENFORCE_ROOTFS_CONF
@@ -40,6 +60,26 @@ CPPFLAGS += -DSECCOMP_DEFAULT_RET_LOG
endif
endif
+# Prevent Minijail from following symlinks when performing bind mounts.
+# BINDMOUNT_ALLOWED_PREFIXES allows some flexibility. This is especially useful
+# for directories that are not normally modifiable by non-root users.
+# If a process can modify these directories, they probably don't need to mess
+# with Minijail bind mounts to gain root privileges.
+BINDMOUNT_ALLOWED_PREFIXES ?= /dev,/sys
+CPPFLAGS += -DBINDMOUNT_ALLOWED_PREFIXES='"$(BINDMOUNT_ALLOWED_PREFIXES)"'
+BLOCK_SYMLINKS_IN_BINDMOUNT_PATHS ?= no
+ifeq ($(BLOCK_SYMLINKS_IN_BINDMOUNT_PATHS),yes)
+CPPFLAGS += -DBLOCK_SYMLINKS_IN_BINDMOUNT_PATHS
+endif
+
+# Prevents symlinks from being followed in the /tmp folder.
+# Symlinks could be followed to modify arbitrary files when a process
+# had access to the /tmp folder.
+BLOCK_SYMLINKS_IN_NONINIT_MOUNTNS_TMP ?= no
+ifeq ($(BLOCK_SYMLINKS_IN_NONINIT_MOUNTNS_TMP),yes)
+CPPFLAGS += -DBLOCK_SYMLINKS_IN_NONINIT_MOUNTNS_TMP
+endif
+
ifeq ($(USE_ASAN),yes)
CPPFLAGS += -fsanitize=address -fno-omit-frame-pointer
LDFLAGS += -fsanitize=address -fno-omit-frame-pointer
@@ -80,7 +120,7 @@ endif
UNITTEST_LIBS += $(GTEST_LIBS)
CORE_OBJECT_FILES := libminijail.o syscall_filter.o signal_handler.o \
- bpf.o util.o system.o syscall_wrapper.o \
+ bpf.o landlock_util.o util.o system.o syscall_wrapper.o \
config_parser.o libconstants.gen.o libsyscalls.gen.o
UNITTEST_DEPS += $(CORE_OBJECT_FILES)
@@ -161,7 +201,7 @@ clean: CLEAN(util_unittest)
CXX_BINARY(parse_seccomp_policy): parse_seccomp_policy.o syscall_filter.o \
- bpf.o util.o libconstants.gen.o libsyscalls.gen.o
+ bpf.o landlock_util.o util.o libconstants.gen.o libsyscalls.gen.o
clean: CLEAN(parse_seccomp_policy)
diff --git a/NOTICE b/NOTICE
index b9e779f..f194a5d 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Copyright 2014 The ChromiumOS Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/OWNERS b/OWNERS
index 2823db3..39d7470 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,5 +1,10 @@
set noparent
-include OWNERS_GENERAL
+# Android: exclude upstream owners so that code review requests will be routed
+# to the Android/downstream owners below.
+#include OWNERS_GENERAL
+adelva@google.com
+victorhsieh@google.com
+
# Emeritus.
-drewry@google.com
-keescook@google.com
+#drewry@google.com
+#keescook@google.com
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 254a062..c7d9e54 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -3,3 +3,6 @@ clang_format = true
[Builtin Hooks Options]
clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c
+
+[Hook Scripts]
+repo_upload_warning = ./tools/repo_upload_warning ${PREUPLOAD_COMMIT}
diff --git a/README.md b/README.md
index 71a34c6..fea1fe6 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@ The Minijail homepage is
https://google.github.io/minijail/.
The main source repo is
-https://android.googlesource.com/platform/external/minijail/.
+https://chromium.googlesource.com/chromiumos/platform/minijail.
There might be other copies floating around, but this is the official one!
@@ -12,7 +12,7 @@ There might be other copies floating around, but this is the official one!
## What is it?
-Minijail is a sandboxing and containment tool used in Chrome OS and Android.
+Minijail is a sandboxing and containment tool used in ChromeOS and Android.
It provides an executable that can be used to launch and sandbox other programs,
and a library that can be used by code to sandbox itself.
@@ -21,12 +21,12 @@ and a library that can be used by code to sandbox itself.
You're one `git clone` away from happiness.
```
-$ git clone https://android.googlesource.com/platform/external/minijail
+$ git clone https://chromium.googlesource.com/chromiumos/platform/minijail
$ cd minijail
```
Releases are tagged as `linux-vXX`:
-https://android.googlesource.com/platform/external/minijail/+refs
+https://chromium.googlesource.com/chromiumos/platform/minijail/+refs
## Building
@@ -49,14 +49,14 @@ We've got a couple of contact points.
* [minijail-dev@google.com]: Internal Google developer mailing list.
* [crbug.com/list]: Existing bug reports & feature requests.
* [crbug.com/new]: File new bug reports & feature requests.
-* [AOSP Gerrit]: Code reviews.
+* [Chromium Gerrit]: Code reviews.
[minijail@chromium.org]: https://groups.google.com/a/chromium.org/forum/#!forum/minijail
[minijail-users@google.com]: https://groups.google.com/a/google.com/forum/#!forum/minijail-users
[minijail-dev@google.com]: https://groups.google.com/a/google.com/forum/#!forum/minijail-dev
[crbug.com/list]: https://crbug.com/?q=component:OS>Systems>Minijail
[crbug.com/new]: https://bugs.chromium.org/p/chromium/issues/entry?components=OS>Systems>Minijail
-[AOSP Gerrit]: https://android-review.googlesource.com/q/project:platform/external/minijail
+[Chromium Gerrit]: https://chromium-review.googlesource.com/q/project:chromiumos/platform/minijail
## Talks and presentations
@@ -67,7 +67,7 @@ The following talk serves as a good introduction to Minijail and how it can be u
## Example usage
-The Chromium OS project has a comprehensive
+The ChromiumOS project has a comprehensive
[sandboxing](https://chromium.googlesource.com/chromiumos/docs/+/master/sandboxing.md)
document that is largely based on Minijail.
@@ -100,7 +100,7 @@ Q. "Why is it called minijail0?"
A. It is minijail0 because it was a rewrite of an earlier program named
minijail, which was considerably less mini, and in particular had a dependency
-on libchrome (the Chrome OS packaged version of Chromium's //base). We needed a
+on libchrome (the ChromeOS packaged version of Chromium's //base). We needed a
new name to not collide with the deprecated one.
We didn't want to call it minijail2 or something that would make people
@@ -114,51 +114,3 @@ controlled surprise system call use.
https://crrev.com/c/4585/ added the original implementation.
Source: Conversations with original authors, ellyjones@ and wad@.
-
-## How to manually upgrade Minijail on Chrome OS
-
-Minijail is manually upgraded on Chrome OS so that there is a way to test
-changes in the Chrome OS commit queue. Committed changes have already passed
-Android's presubmit checks, but the ebuild upgrade CL goes through the Chrome
-OS commit queue and must pass the tests before any additional changes are
-available for use on Chrome OS. To upgrade minijail on Chrome OS, complete the
-following steps.
-
-```bash
-# Sync Minijail repo
-cd ~/chromiumos/src/aosp/external/minijail
-git checkout m/main
-repo sync .
-
-# Set up local branch.
-cd ~/trunk/src/third_party/chromiumos-overlay/
-repo start minijail . # replace minijail with the local branch name you want.
-
-# Run upgrade script.
-~/trunk/chromite/scripts/cros_uprev --force --overlay-type public \
- --packages chromeos-base/minijail:dev-rust/minijail-sys:dev-rust/minijail
-```
-
-At this point the Minijail-related packages should be upgraded, so you may want
-to add the changes to a commit and do some local testing before uploading a
-change list. Here are the recommended local tests to try (make sure you are
-**not** working on the minijail packages first i.e. `cros_workon list-all`):
-
-```bash
-# Check build.
-./build_packages --board=${BOARD}
-
-# Check unit tests.
-FEATURES=test emerge-${BOARD} chromeos-base/minijail dev-rust/minijail-sys \
- dev-rust/minijail
-
-# Check integration tests.
-cros deploy <DUT> chromeos-base/minijail
-tast run <DUT> security.Minijail.* security.MinijailSeccomp
-```
-
-Finally, when uploading the CL make sure to include the list of changes
-since the last uprev. The command to generate the list is as follows:
-```bash
-git log --oneline --no-merges <previous hash in ebuild file>..HEAD
-```
diff --git a/arch.h b/arch.h
index 253b45f..a1f43ba 100644
--- a/arch.h
+++ b/arch.h
@@ -1,5 +1,5 @@
/* arch.h
- * Copyright 2014 The Chromium OS Authors. All rights reserved.
+ * Copyright 2014 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
diff --git a/bpf.c b/bpf.c
index d8bf46c..3c60b47 100644
--- a/bpf.c
+++ b/bpf.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright 2012 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -362,7 +362,7 @@ int bpf_label_id(struct bpf_labels *labels, const char *label)
}
end = begin + labels->count;
for (id = 0; begin < end; ++begin, ++id) {
- if (!strcmp(label, begin->label)) {
+ if (streq(label, begin->label)) {
return id;
}
}
diff --git a/bpf.h b/bpf.h
index bbde437..900a828 100644
--- a/bpf.h
+++ b/bpf.h
@@ -1,5 +1,5 @@
/* bpf.h
- * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Copyright 2012 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
diff --git a/common.mk b/common.mk
index 77879d8..48fe830 100644
--- a/common.mk
+++ b/common.mk
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Copyright 2012 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
diff --git a/config_parser.c b/config_parser.c
index 4972cf5..9b3aa22 100644
--- a/config_parser.c
+++ b/config_parser.c
@@ -1,4 +1,4 @@
-/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+/* Copyright 2021 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -87,7 +87,7 @@ bool parse_config_line(const char *config_line, struct config_entry *entry)
static bool match_special_directive(const char *line)
{
- return (strcmp(line, "% minijail-config-file v0\n") == 0);
+ return streq(line, "% minijail-config-file v0\n");
}
bool parse_config_file(FILE *config_file, struct config_entry_list *list)
@@ -131,8 +131,9 @@ bool parse_config_file(FILE *config_file, struct config_entry_list *list)
/*
* getmultiline() behaves similarly with getline(3). It returns -1
* when read into EOF or the following errors.
+ * Caveat: EINVAL may happen when EOF is encountered in a valid stream.
*/
- if (errno == EINVAL || errno == ENOMEM) {
+ if ((errno == EINVAL && config_file == NULL) || errno == ENOMEM) {
return false;
}
diff --git a/config_parser.h b/config_parser.h
index 36c96db..b158e5c 100644
--- a/config_parser.h
+++ b/config_parser.h
@@ -1,4 +1,4 @@
-/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+/* Copyright 2021 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
diff --git a/config_parser_unittest.cc b/config_parser_unittest.cc
index a9c6571..2e4ad17 100644
--- a/config_parser_unittest.cc
+++ b/config_parser_unittest.cc
@@ -1,4 +1,4 @@
-/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+/* Copyright 2021 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
diff --git a/dump_constants.cc b/dump_constants.cc
index f3d7074..6a0a3ba 100644
--- a/dump_constants.cc
+++ b/dump_constants.cc
@@ -1,4 +1,4 @@
-/* Copyright 2018 The Chromium OS Authors. All rights reserved.
+/* Copyright 2018 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
diff --git a/elfparse.c b/elfparse.c
index 96caa59..958a8cd 100644
--- a/elfparse.c
+++ b/elfparse.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+/* Copyright 2014 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
diff --git a/elfparse.h b/elfparse.h
index 4fdd0a1..9083e0c 100644
--- a/elfparse.h
+++ b/elfparse.h
@@ -1,5 +1,5 @@
/* elfparse.h
- * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Copyright 2014 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
diff --git a/gen_constants-inl.h b/gen_constants-inl.h
index 8a09adb..d09349c 100644
--- a/gen_constants-inl.h
+++ b/gen_constants-inl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+/* Copyright 2014 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -73,3 +73,7 @@ struct fscrypt_policy_v1 {
#if !defined(FS_IOC_GET_ENCRYPTION_POLICY_EX)
#define FS_IOC_GET_ENCRYPTION_POLICY_EX _IOWR('f', 22, __u8[9])
#endif
+
+#if !defined(MADV_FREE)
+#define MADV_FREE 8
+#endif
diff --git a/gen_constants.sh b/gen_constants.sh
index 20f9f42..628a13d 100755
--- a/gen_constants.sh
+++ b/gen_constants.sh
@@ -1,6 +1,6 @@
#!/bin/sh
-# Copyright 2015 The Chromium OS Authors. All rights reserved.
+# Copyright 2015 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/gen_syscalls-inl.h b/gen_syscalls-inl.h
index d7c43aa..e631424 100644
--- a/gen_syscalls-inl.h
+++ b/gen_syscalls-inl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+/* Copyright 2014 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -77,3 +77,37 @@
#ifndef __NR_faccessat2
#define __NR_faccessat2 439
#endif
+
+#ifndef __NR_rseq
+#ifdef __x86_64__
+#define __NR_rseq 334
+#elif __i386__
+#define __NR_rseq 386
+#elif __arm64__
+#define __NR_rseq 293
+#endif
+#endif /* __NR_rseq */
+
+#ifndef __NR_clone3
+#define __NR_clone3 435
+#endif
+
+#ifndef __NR_userfaultfd
+#ifdef __x86_64__
+#define __NR_userfaultfd 323
+#elif __i386__
+#define __NR_userfaultfd 374
+#elif __arm64__
+#define __NR_userfaultfd 282
+#endif
+#endif /* __NR_userfaultfd */
+
+#ifndef __NR_membarrier
+#ifdef __x86_64__
+#define __NR_membarrier 324
+#elif __i386__
+#define __NR_membarrier 375
+#elif __arm64__
+#define __NR_membarrier 283
+#endif
+#endif /* __NR_membarrier */
diff --git a/gen_syscalls.sh b/gen_syscalls.sh
index 7e1707c..d5155e8 100755
--- a/gen_syscalls.sh
+++ b/gen_syscalls.sh
@@ -1,6 +1,6 @@
#!/bin/sh
-# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Copyright 2012 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/landlock.h b/landlock.h
new file mode 100644
index 0000000..1ce5b80
--- /dev/null
+++ b/landlock.h
@@ -0,0 +1,132 @@
+/* Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * Landlock system definitions.
+ *
+ * These definitions are based on <linux/landlock.h>. However, because we
+ * can't guarantee that header will be available on all systems that need to
+ * build Minijail, they are extracted here.
+ */
+
+#ifndef _LANDLOCK_H
+#define _LANDLOCK_H
+
+#include <linux/types.h>
+
+/**
+ * struct landlock_ruleset_attr - Ruleset definition
+ *
+ * Argument of sys_landlock_create_ruleset(). This structure can grow in
+ * future versions.
+ */
+struct minijail_landlock_ruleset_attr {
+ /**
+ * @handled_access_fs: Bitmask of actions (cf. `Filesystem flags`_)
+ * that is handled by this ruleset and should then be forbidden if no
+ * rule explicitly allow them. This is needed for backward
+ * compatibility reasons.
+ */
+ __u64 handled_access_fs;
+};
+
+/*
+ * sys_landlock_create_ruleset() flags:
+ *
+ * - %LANDLOCK_CREATE_RULESET_VERSION: Get the highest supported Landlock ABI
+ * version.
+ */
+#ifndef LANDLOCK_CREATE_RULESET_VERSION
+#define LANDLOCK_CREATE_RULESET_VERSION (1U << 0)
+#endif
+
+/**
+ * enum landlock_rule_type - Landlock rule type
+ *
+ * Argument of sys_landlock_add_rule().
+ */
+enum minijail_landlock_rule_type {
+ /**
+ * @LANDLOCK_RULE_PATH_BENEATH: Type of a &struct
+ * landlock_path_beneath_attr .
+ */
+ LANDLOCK_RULE_PATH_BENEATH = 1,
+};
+
+/**
+ * struct landlock_path_beneath_attr - Path hierarchy definition
+ *
+ * Argument of sys_landlock_add_rule().
+ */
+struct minijail_landlock_path_beneath_attr {
+ /**
+ * @allowed_access: Bitmask of allowed actions for this file hierarchy
+ * (cf. `Filesystem flags`_).
+ */
+ __u64 allowed_access;
+ /**
+ * @parent_fd: File descriptor, open with ``O_PATH``, which identifies
+ * the parent directory of a file hierarchy, or just a file.
+ */
+ __s32 parent_fd;
+ /*
+ * This struct is packed to avoid trailing reserved members.
+ * Cf. security/landlock/syscalls.c:build_check_abi()
+ */
+} __attribute__((__packed__));
+
+#ifndef LANDLOCK_ACCESS_FS_EXECUTE
+#define LANDLOCK_ACCESS_FS_EXECUTE (1ULL << 0)
+#endif
+
+#ifndef LANDLOCK_ACCESS_FS_WRITE_FILE
+#define LANDLOCK_ACCESS_FS_WRITE_FILE (1ULL << 1)
+#endif
+
+#ifndef LANDLOCK_ACCESS_FS_READ_FILE
+#define LANDLOCK_ACCESS_FS_READ_FILE (1ULL << 2)
+#endif
+
+#ifndef LANDLOCK_ACCESS_FS_READ_DIR
+#define LANDLOCK_ACCESS_FS_READ_DIR (1ULL << 3)
+#endif
+
+#ifndef LANDLOCK_ACCESS_FS_REMOVE_DIR
+#define LANDLOCK_ACCESS_FS_REMOVE_DIR (1ULL << 4)
+#endif
+
+#ifndef LANDLOCK_ACCESS_FS_REMOVE_FILE
+#define LANDLOCK_ACCESS_FS_REMOVE_FILE (1ULL << 5)
+#endif
+
+#ifndef LANDLOCK_ACCESS_FS_MAKE_CHAR
+#define LANDLOCK_ACCESS_FS_MAKE_CHAR (1ULL << 6)
+#endif
+
+#ifndef LANDLOCK_ACCESS_FS_MAKE_DIR
+#define LANDLOCK_ACCESS_FS_MAKE_DIR (1ULL << 7)
+#endif
+
+#ifndef LANDLOCK_ACCESS_FS_MAKE_REG
+#define LANDLOCK_ACCESS_FS_MAKE_REG (1ULL << 8)
+#endif
+
+#ifndef LANDLOCK_ACCESS_FS_MAKE_SOCK
+#define LANDLOCK_ACCESS_FS_MAKE_SOCK (1ULL << 9)
+#endif
+
+#ifndef LANDLOCK_ACCESS_FS_MAKE_FIFO
+#define LANDLOCK_ACCESS_FS_MAKE_FIFO (1ULL << 10)
+#endif
+
+#ifndef LANDLOCK_ACCESS_FS_MAKE_BLOCK
+#define LANDLOCK_ACCESS_FS_MAKE_BLOCK (1ULL << 11)
+#endif
+
+#ifndef LANDLOCK_ACCESS_FS_MAKE_SYM
+#define LANDLOCK_ACCESS_FS_MAKE_SYM (1ULL << 12)
+#endif
+
+#endif /* _LANDLOCK_H */
diff --git a/landlock_util.c b/landlock_util.c
new file mode 100644
index 0000000..2aa8336
--- /dev/null
+++ b/landlock_util.c
@@ -0,0 +1,65 @@
+/* Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Define _GNU_SOURCE because we need O_PATH to resolve correctly. */
+#define _GNU_SOURCE
+
+#include "landlock_util.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include "util.h"
+
+
+int landlock_create_ruleset(const struct
+ minijail_landlock_ruleset_attr *const attr,
+ const size_t size, const __u32 flags)
+{
+ return syscall(__NR_landlock_create_ruleset, attr, size, flags);
+}
+
+int landlock_add_rule(const int ruleset_fd,
+ const enum minijail_landlock_rule_type rule_type,
+ const void *const rule_attr, const __u32 flags)
+{
+ return syscall(__NR_landlock_add_rule, ruleset_fd, rule_type,
+ rule_attr, flags);
+}
+
+int landlock_restrict_self(const int ruleset_fd,
+ const __u32 flags)
+{
+ return syscall(__NR_landlock_restrict_self, ruleset_fd, flags);
+}
+
+bool populate_ruleset_internal(const char *const path,
+ const int ruleset_fd,
+ const uint64_t allowed_access)
+{
+ struct minijail_landlock_path_beneath_attr path_beneath = {
+ .parent_fd = -1,
+ };
+ struct stat statbuf;
+ attribute_cleanup_fd int parent_fd = open(path, O_PATH | O_CLOEXEC);
+ path_beneath.parent_fd = parent_fd;
+ if (path_beneath.parent_fd < 0) {
+ pwarn("Failed to open \"%s\"", path);
+ return false;
+ }
+ if (fstat(path_beneath.parent_fd, &statbuf)) {
+ return false;
+ }
+ path_beneath.allowed_access = allowed_access;
+ if (!S_ISDIR(statbuf.st_mode)) {
+ path_beneath.allowed_access &= ACCESS_FILE;
+ }
+ if (landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
+ &path_beneath, 0)) {
+ pwarn("Failed to update ruleset \"%s\"", path);
+ return false;
+ }
+ return true;
+}
diff --git a/landlock_util.h b/landlock_util.h
new file mode 100644
index 0000000..ab1b472
--- /dev/null
+++ b/landlock_util.h
@@ -0,0 +1,106 @@
+/* Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * Landlock functions and constants.
+ */
+
+#ifndef _LANDLOCK_UTIL_H_
+#define _LANDLOCK_UTIL_H_
+
+#include <asm/unistd.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "landlock.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef __NR_landlock_create_ruleset
+#define __NR_landlock_create_ruleset 444
+#endif
+
+#ifndef __NR_landlock_add_rule
+#define __NR_landlock_add_rule 445
+#endif
+
+#ifndef __NR_landlock_restrict_self
+#define __NR_landlock_restrict_self 446
+#endif
+
+#define ACCESS_FS_ROUGHLY_READ ( \
+ LANDLOCK_ACCESS_FS_READ_FILE | \
+ LANDLOCK_ACCESS_FS_READ_DIR)
+
+#define ACCESS_FS_ROUGHLY_READ_EXECUTE ( \
+ LANDLOCK_ACCESS_FS_EXECUTE | \
+ LANDLOCK_ACCESS_FS_READ_FILE | \
+ LANDLOCK_ACCESS_FS_READ_DIR)
+
+#define ACCESS_FS_ROUGHLY_BASIC_WRITE ( \
+ LANDLOCK_ACCESS_FS_WRITE_FILE | \
+ LANDLOCK_ACCESS_FS_REMOVE_DIR | \
+ LANDLOCK_ACCESS_FS_REMOVE_FILE | \
+ LANDLOCK_ACCESS_FS_MAKE_DIR | \
+ LANDLOCK_ACCESS_FS_MAKE_REG)
+
+#define ACCESS_FS_ROUGHLY_EDIT ( \
+ LANDLOCK_ACCESS_FS_WRITE_FILE | \
+ LANDLOCK_ACCESS_FS_REMOVE_DIR | \
+ LANDLOCK_ACCESS_FS_REMOVE_FILE)
+
+#define ACCESS_FS_ROUGHLY_FULL_WRITE ( \
+ LANDLOCK_ACCESS_FS_WRITE_FILE | \
+ LANDLOCK_ACCESS_FS_REMOVE_DIR | \
+ LANDLOCK_ACCESS_FS_REMOVE_FILE | \
+ LANDLOCK_ACCESS_FS_MAKE_CHAR | \
+ LANDLOCK_ACCESS_FS_MAKE_DIR | \
+ LANDLOCK_ACCESS_FS_MAKE_REG | \
+ LANDLOCK_ACCESS_FS_MAKE_SOCK | \
+ LANDLOCK_ACCESS_FS_MAKE_FIFO | \
+ LANDLOCK_ACCESS_FS_MAKE_BLOCK | \
+ LANDLOCK_ACCESS_FS_MAKE_SYM)
+
+#define ACCESS_FILE ( \
+ LANDLOCK_ACCESS_FS_EXECUTE | \
+ LANDLOCK_ACCESS_FS_WRITE_FILE | \
+ LANDLOCK_ACCESS_FS_READ_FILE)
+
+#define HANDLED_ACCESS_TYPES (ACCESS_FS_ROUGHLY_READ_EXECUTE | \
+ ACCESS_FS_ROUGHLY_FULL_WRITE)
+
+/*
+ * Performs Landlock create ruleset syscall.
+ *
+ * Returns the ruleset file descriptor on success, returns an error code
+ * otherwise.
+ */
+extern int landlock_create_ruleset(const struct
+ minijail_landlock_ruleset_attr *const attr,
+ const size_t size, const __u32 flags);
+
+/* Performs Landlock add rule syscall. */
+extern int landlock_add_rule(const int ruleset_fd,
+ const enum minijail_landlock_rule_type rule_type,
+ const void *const rule_attr, const __u32 flags);
+
+/* Performs Landlock restrict self syscall. */
+extern int landlock_restrict_self(const int ruleset_fd,
+ const __u32 flags);
+
+/* Populates the landlock ruleset for a path and any needed paths beneath. */
+extern bool populate_ruleset_internal(const char *const path,
+ const int ruleset_fd,
+ const uint64_t allowed_access);
+
+#ifdef __cplusplus
+}; /* extern "C" */
+#endif
+
+#endif /* _LANDLOCK_UTIL_H_ */
diff --git a/libconstants.h b/libconstants.h
index c289955..0548de9 100644
--- a/libconstants.h
+++ b/libconstants.h
@@ -1,4 +1,4 @@
-/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+/* Copyright 2015 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
diff --git a/libminijail-private.h b/libminijail-private.h
index 8feec55..6351f8e 100644
--- a/libminijail-private.h
+++ b/libminijail-private.h
@@ -1,5 +1,5 @@
/* libminijail-private.h
- * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Copyright 2011 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
diff --git a/libminijail.c b/libminijail.c
index aab1294..bb60904 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright 2012 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -36,6 +36,7 @@
#include <syscall.h>
#include <unistd.h>
+#include "landlock_util.h"
#include "libminijail-private.h"
#include "libminijail.h"
@@ -72,6 +73,15 @@
(MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME | MS_NODIRATIME | \
MS_RELATIME | MS_RDONLY)
+/*
+ * TODO(b/235960683): Drop this after CrOS upgrades to glibc >= 2.34
+ * because MS_NOSYMFOLLOW will be defined in sys/mount.h.
+ */
+#ifndef MS_NOSYMFOLLOW
+/* Added locally in kernels 4.x+. */
+#define MS_NOSYMFOLLOW 256
+#endif
+
struct minijail_rlimit {
int type;
rlim_t cur;
@@ -101,6 +111,12 @@ struct hook {
struct hook *next;
};
+struct fs_rule {
+ char *path;
+ uint64_t landlock_flags;
+ struct fs_rule *next;
+};
+
struct preserved_fd {
int parent_fd;
int child_fd;
@@ -112,46 +128,46 @@ struct minijail {
* accounted for in minijail_pre{enter|exec}() below.
*/
struct {
- int uid : 1;
- int gid : 1;
- int inherit_suppl_gids : 1;
- int set_suppl_gids : 1;
- int keep_suppl_gids : 1;
- int use_caps : 1;
- int capbset_drop : 1;
- int set_ambient_caps : 1;
- int vfs : 1;
- int enter_vfs : 1;
- int pids : 1;
- int ipc : 1;
- int uts : 1;
- int net : 1;
- int enter_net : 1;
- int ns_cgroups : 1;
- int userns : 1;
- int disable_setgroups : 1;
- int seccomp : 1;
- int remount_proc_ro : 1;
- int no_new_privs : 1;
- int seccomp_filter : 1;
- int seccomp_filter_tsync : 1;
- int seccomp_filter_logging : 1;
- int seccomp_filter_allow_speculation : 1;
- int chroot : 1;
- int pivot_root : 1;
- int mount_dev : 1;
- int mount_tmp : 1;
- int do_init : 1;
- int run_as_init : 1;
- int pid_file : 1;
- int cgroups : 1;
- int alt_syscall : 1;
- int reset_signal_mask : 1;
- int reset_signal_handlers : 1;
- int close_open_fds : 1;
- int new_session_keyring : 1;
- int forward_signals : 1;
- int setsid : 1;
+ bool uid : 1;
+ bool gid : 1;
+ bool inherit_suppl_gids : 1;
+ bool set_suppl_gids : 1;
+ bool keep_suppl_gids : 1;
+ bool use_caps : 1;
+ bool capbset_drop : 1;
+ bool set_ambient_caps : 1;
+ bool vfs : 1;
+ bool enter_vfs : 1;
+ bool pids : 1;
+ bool ipc : 1;
+ bool uts : 1;
+ bool net : 1;
+ bool enter_net : 1;
+ bool ns_cgroups : 1;
+ bool userns : 1;
+ bool disable_setgroups : 1;
+ bool seccomp : 1;
+ bool remount_proc_ro : 1;
+ bool no_new_privs : 1;
+ bool seccomp_filter : 1;
+ bool seccomp_filter_tsync : 1;
+ bool seccomp_filter_logging : 1;
+ bool seccomp_filter_allow_speculation : 1;
+ bool chroot : 1;
+ bool pivot_root : 1;
+ bool mount_dev : 1;
+ bool mount_tmp : 1;
+ bool do_init : 1;
+ bool run_as_init : 1;
+ bool pid_file : 1;
+ bool cgroups : 1;
+ bool alt_syscall : 1;
+ bool reset_signal_mask : 1;
+ bool reset_signal_handlers : 1;
+ bool close_open_fds : 1;
+ bool new_session_keyring : 1;
+ bool forward_signals : 1;
+ bool setsid : 1;
} flags;
uid_t uid;
gid_t gid;
@@ -180,6 +196,9 @@ struct minijail {
struct minijail_remount *remounts_head;
struct minijail_remount *remounts_tail;
size_t tmpfs_size;
+ bool using_minimalistic_mountns;
+ struct fs_rule *fs_rules_head;
+ struct fs_rule *fs_rules_tail;
char *cgroups[MAX_CGROUPS];
size_t cgroup_count;
struct minijail_rlimit rlimits[MAX_RLIMITS];
@@ -282,6 +301,40 @@ void minijail_preenter(struct minijail *j)
free_remounts_list(j);
}
+/* Adds a rule for a given path to apply once minijail is entered. */
+int add_fs_restriction_path(struct minijail *j,
+ const char *path,
+ uint64_t landlock_flags)
+{
+ struct fs_rule *r = calloc(1, sizeof(*r));
+ if (!r)
+ return -ENOMEM;
+ r->path = strdup(path);
+ r->landlock_flags = landlock_flags;
+
+ if (j->fs_rules_tail) {
+ j->fs_rules_tail->next = r;
+ j->fs_rules_tail = r;
+ } else {
+ j->fs_rules_head = r;
+ j->fs_rules_tail = r;
+ }
+
+ return 0;
+}
+
+bool mount_has_bind_flag(struct mountpoint *m) {
+ return !!(m->flags & MS_BIND);
+}
+
+bool mount_has_readonly_flag(struct mountpoint *m) {
+ return !!(m->flags & MS_RDONLY);
+}
+
+bool mount_events_allowed(struct mountpoint *m) {
+ return !!(m->flags & MS_SHARED) || !!(m->flags & MS_SLAVE);
+}
+
/*
* Strip out flags meant for the child.
* We keep things that are inherited across execve(2).
@@ -324,6 +377,7 @@ struct minijail API *minijail_new(void)
struct minijail *j = calloc(1, sizeof(struct minijail));
if (j) {
j->remount_mode = MS_PRIVATE;
+ j->using_minimalistic_mountns = false;
}
return j;
}
@@ -474,6 +528,50 @@ void API minijail_log_seccomp_filter_failures(struct minijail *j)
}
}
+void API minijail_set_using_minimalistic_mountns(struct minijail *j)
+{
+ j->using_minimalistic_mountns = true;
+}
+
+void API minijail_add_minimalistic_mountns_fs_rules(struct minijail *j)
+{
+ struct mountpoint *m = j->mounts_head;
+ bool landlock_enabled_by_profile = false;
+ if (!j->using_minimalistic_mountns)
+ return;
+
+ /* Apply Landlock rules. */
+ while (m) {
+ landlock_enabled_by_profile = true;
+ minijail_add_fs_restriction_rx(j, m->dest);
+ /* Allow rw if mounted as writable, or mount flags allow mount events.*/
+ if (!mount_has_readonly_flag(m) || mount_events_allowed(m))
+ minijail_add_fs_restriction_rw(j, m->dest);
+ m = m->next;
+ }
+ if (landlock_enabled_by_profile) {
+ minijail_enable_default_fs_restrictions(j);
+ minijail_add_fs_restriction_edit(j, "/dev");
+ minijail_add_fs_restriction_ro(j, "/proc");
+ if (j->flags.vfs)
+ minijail_add_fs_restriction_rw(j, "/tmp");
+ }
+}
+
+void API minijail_enable_default_fs_restrictions(struct minijail *j)
+{
+ // Common library locations.
+ minijail_add_fs_restriction_rx(j, "/lib");
+ minijail_add_fs_restriction_rx(j, "/lib64");
+ minijail_add_fs_restriction_rx(j, "/usr/lib");
+ minijail_add_fs_restriction_rx(j, "/usr/lib64");
+ // Common locations for services invoking Minijail.
+ minijail_add_fs_restriction_rx(j, "/bin");
+ minijail_add_fs_restriction_rx(j, "/sbin");
+ minijail_add_fs_restriction_rx(j, "/usr/sbin");
+ minijail_add_fs_restriction_rx(j, "/usr/bin");
+}
+
void API minijail_use_caps(struct minijail *j, uint64_t capmask)
{
/*
@@ -719,7 +817,7 @@ char API *minijail_get_original_path(struct minijail *j,
* "/chroot/path/exe", the source of that mount,
* "/some/path/exe" is what should be returned.
*/
- if (!strcmp(b->dest, path_inside_chroot))
+ if (streq(b->dest, path_inside_chroot))
return strdup(b->src);
/*
@@ -812,6 +910,74 @@ int API minijail_create_session(struct minijail *j)
return 0;
}
+int API minijail_add_fs_restriction_rx(struct minijail *j, const char *path)
+{
+ return !add_fs_restriction_path(j, path,
+ ACCESS_FS_ROUGHLY_READ_EXECUTE);
+}
+
+int API minijail_add_fs_restriction_ro(struct minijail *j, const char *path)
+{
+ return !add_fs_restriction_path(j, path, ACCESS_FS_ROUGHLY_READ);
+}
+
+int API minijail_add_fs_restriction_rw(struct minijail *j, const char *path)
+{
+ return !add_fs_restriction_path(j, path,
+ ACCESS_FS_ROUGHLY_READ | ACCESS_FS_ROUGHLY_BASIC_WRITE);
+}
+
+int API minijail_add_fs_restriction_advanced_rw(struct minijail *j,
+ const char *path)
+{
+ return !add_fs_restriction_path(j, path,
+ ACCESS_FS_ROUGHLY_READ | ACCESS_FS_ROUGHLY_FULL_WRITE);
+}
+
+int API minijail_add_fs_restriction_edit(struct minijail *j,
+ const char *path)
+{
+ return !add_fs_restriction_path(j, path,
+ ACCESS_FS_ROUGHLY_READ | ACCESS_FS_ROUGHLY_EDIT);
+}
+
+static bool is_valid_bind_path(const char *path)
+{
+ if (!block_symlinks_in_bindmount_paths()) {
+ return true;
+ }
+
+ /*
+ * tokenize() will modify both the |prefixes| pointer and the contents
+ * of the string, so:
+ * -Copy |BINDMOUNT_ALLOWED_PREFIXES| since it lives in .rodata.
+ * -Save the original pointer for free()ing.
+ */
+ char *prefixes = strdup(BINDMOUNT_ALLOWED_PREFIXES);
+ attribute_cleanup_str char *orig_prefixes = prefixes;
+ (void)orig_prefixes;
+
+ char *prefix = NULL;
+ bool found_prefix = false;
+ if (!is_canonical_path(path)) {
+ while ((prefix = tokenize(&prefixes, ",")) != NULL) {
+ if (path_is_parent(prefix, path)) {
+ found_prefix = true;
+ break;
+ }
+ }
+ if (!found_prefix) {
+ /*
+ * If the path does not include one of the allowed
+ * prefixes, fail.
+ */
+ warn("path '%s' is not a canonical path", path);
+ return false;
+ }
+ }
+ return true;
+}
+
int API minijail_mount_with_data(struct minijail *j, const char *src,
const char *dest, const char *type,
unsigned long flags, const char *data)
@@ -840,7 +1006,7 @@ int API minijail_mount_with_data(struct minijail *j, const char *src,
* people use these in practice, it's probably OK. If they want
* the kernel defaults, they can pass data="" instead of NULL.
*/
- if (!strcmp(type, "tmpfs")) {
+ if (streq(type, "tmpfs")) {
/* tmpfs defaults to mode=1777 and size=50%. */
data = "mode=0755,size=10M";
}
@@ -895,10 +1061,30 @@ int API minijail_bind(struct minijail *j, const char *src, const char *dest,
{
unsigned long flags = MS_BIND;
+ /*
+ * Check for symlinks in bind-mount source paths to warn the user early.
+ * Minijail will perform one final check immediately before the mount()
+ * call.
+ */
+ if (!is_valid_bind_path(src)) {
+ warn("src '%s' is not a valid bind mount path", src);
+ return -ELOOP;
+ }
+
+ /*
+ * Symlinks in |dest| are blocked by the ChromiumOS LSM:
+ * <kernel>/security/chromiumos/lsm.c#77
+ */
+
if (!writeable)
flags |= MS_RDONLY;
- return minijail_mount(j, src, dest, "", flags);
+ /*
+ * |type| is ignored for bind mounts, use it to signal that this mount
+ * came from minijail_bind().
+ * TODO(b/238362528): Implement a better way to signal this.
+ */
+ return minijail_mount(j, src, dest, "minijail_bind", flags);
}
int API minijail_add_remount(struct minijail *j, const char *mount_name,
@@ -1337,6 +1523,8 @@ int minijail_unmarshal(struct minijail *j, char *serialized, size_t length)
j->filter_prog = NULL;
j->hooks_head = NULL;
j->hooks_tail = NULL;
+ j->fs_rules_head = NULL;
+ j->fs_rules_tail = NULL;
if (j->user) { /* stale pointer */
char *user = consumestr(&serialized, &length);
@@ -1693,7 +1881,9 @@ static int mount_one(const struct minijail *j, struct mountpoint *m,
{
int ret;
char *dest;
- int remount = 0;
+ bool do_remount = false;
+ bool has_bind_flag = mount_has_bind_flag(m);
+ bool has_remount_flag = !!(m->flags & MS_REMOUNT);
unsigned long original_mnt_flags = 0;
/* We assume |dest| has a leading "/". */
@@ -1708,39 +1898,73 @@ static int mount_one(const struct minijail *j, struct mountpoint *m,
return -ENOMEM;
}
- ret =
- setup_mount_destination(m->src, dest, j->uid, j->gid,
- (m->flags & MS_BIND), &original_mnt_flags);
+ ret = setup_mount_destination(m->src, dest, j->uid, j->gid,
+ has_bind_flag);
if (ret) {
warn("cannot create mount target '%s'", dest);
goto error;
}
/*
- * Bind mounts that change the 'ro' flag have to be remounted since
- * 'bind' and other flags can't both be specified in the same command.
- * Remount after the initial mount.
+ * Remount bind mounts that:
+ * - Come from the minijail_bind() API, and
+ * - Add the 'ro' flag
+ * since 'bind' and other flags can't both be specified in the same
+ * mount(2) call.
+ * Callers using minijail_mount() to perform bind mounts are expected to
+ * know what they're doing and call minijail_mount() with MS_REMOUNT as
+ * needed.
+ * Therefore, if the caller is asking for a remount (using MS_REMOUNT),
+ * there is no need to do an extra remount here.
*/
- if ((m->flags & MS_BIND) &&
- ((m->flags & MS_RDONLY) != (original_mnt_flags & MS_RDONLY))) {
- remount = 1;
+ if (has_bind_flag && strcmp(m->type, "minijail_bind") == 0 &&
+ !has_remount_flag) {
/*
- * Restrict the mount flags to those that are user-settable in a
- * MS_REMOUNT request, but excluding MS_RDONLY. The
- * user-requested mount flags will dictate whether the remount
- * will have that flag or not.
+ * Grab the mount flags of the source. These are used to figure
+ * out whether the bind mount needs to be remounted read-only.
*/
- original_mnt_flags &= (MS_USER_SETTABLE_MASK & ~MS_RDONLY);
+ if (get_mount_flags(m->src, &original_mnt_flags)) {
+ warn("cannot get mount flags for '%s'", m->src);
+ goto error;
+ }
+
+ if ((m->flags & MS_RDONLY) !=
+ (original_mnt_flags & MS_RDONLY)) {
+ do_remount = 1;
+ /*
+ * Restrict the mount flags to those that are
+ * user-settable in a MS_REMOUNT request, but excluding
+ * MS_RDONLY. The user-requested mount flags will
+ * dictate whether the remount will have that flag or
+ * not.
+ */
+ original_mnt_flags &=
+ (MS_USER_SETTABLE_MASK & ~MS_RDONLY);
+ }
+ }
+
+ /*
+ * Do a final check for symlinks in |m->src|.
+ * |m->src| will only contain a valid path when purely bind-mounting
+ * (but not when remounting a bind mount).
+ *
+ * Short of having a version of mount(2) that can take fd's, this is the
+ * smallest we can make the TOCTOU window.
+ */
+ if (has_bind_flag && !has_remount_flag && !is_valid_bind_path(m->src)) {
+ warn("src '%s' is not a valid bind mount path", m->src);
+ goto error;
}
ret = mount(m->src, dest, m->type, m->flags, m->data);
if (ret) {
- pwarn("cannot bind-mount '%s' as '%s' with flags %#lx", m->src,
- dest, m->flags);
+ pwarn("cannot mount '%s' as '%s' with flags %#lx", m->src, dest,
+ m->flags);
goto error;
}
- if (remount) {
+ /* Remount *after* the initial mount. */
+ if (do_remount) {
ret =
mount(m->src, dest, NULL,
m->flags | original_mnt_flags | MS_REMOUNT, m->data);
@@ -1774,6 +1998,8 @@ static void process_mounts_or_die(const struct minijail *j)
pdie("mount_dev failed");
if (j->mounts_head && mount_one(j, j->mounts_head, dev_path)) {
+ warn("mount_one failed with /dev at '%s'", dev_path);
+
if (dev_path)
mount_dev_cleanup(dev_path);
@@ -1876,8 +2102,14 @@ static int mount_tmp(const struct minijail *j)
pdie("tmpfs size spec error");
else if ((size_t)ret >= sizeof(data))
pdie("tmpfs size spec too large");
- return mount("none", "/tmp", "tmpfs", MS_NODEV | MS_NOEXEC | MS_NOSUID,
- data);
+
+ unsigned long flags = MS_NODEV | MS_NOEXEC | MS_NOSUID;
+
+ if (block_symlinks_in_noninit_mountns_tmp()) {
+ flags |= MS_NOSYMFOLLOW;
+ }
+
+ return mount("none", "/tmp", "tmpfs", flags, data);
}
static int remount_proc_readonly(const struct minijail *j)
@@ -2164,6 +2396,45 @@ static void drop_caps(const struct minijail *j, unsigned int last_valid_cap)
cap_free(caps);
}
+/* Creates a ruleset for current inodes then calls landlock_restrict_self(). */
+static void apply_landlock_restrictions(const struct minijail *j)
+{
+ struct fs_rule *r;
+ attribute_cleanup_fd int ruleset_fd = -1;
+
+ r = j->fs_rules_head;
+ while (r) {
+ if (ruleset_fd < 0) {
+ struct minijail_landlock_ruleset_attr ruleset_attr = {
+ .handled_access_fs = HANDLED_ACCESS_TYPES
+ };
+ ruleset_fd = landlock_create_ruleset(
+ &ruleset_attr, sizeof(ruleset_attr), 0);
+ if (ruleset_fd < 0) {
+ const int err = errno;
+ pwarn("Failed to create a ruleset");
+ switch (err) {
+ case ENOSYS:
+ pwarn("Landlock is not supported by the current kernel");
+ break;
+ case EOPNOTSUPP:
+ pwarn("Landlock is currently disabled by kernel config");
+ break;
+ }
+ return;
+ }
+ }
+ populate_ruleset_internal(r->path, ruleset_fd, r->landlock_flags);
+ r = r->next;
+ }
+
+ if (ruleset_fd >= 0) {
+ if (landlock_restrict_self(ruleset_fd, 0)) {
+ pdie("Failed to enforce ruleset");
+ }
+ }
+}
+
static void set_seccomp_filter(const struct minijail *j)
{
/*
@@ -2457,8 +2728,14 @@ void API minijail_enter(const struct minijail *j)
*/
drop_ugid(j);
drop_caps(j, last_valid_cap);
+
+ // Landlock is applied as late as possible. If no_new_privs is
+ // set, then it can be applied after dropping caps.
+ apply_landlock_restrictions(j);
set_seccomp_filter(j);
} else {
+ apply_landlock_restrictions(j);
+
/*
* If we're not setting no_new_privs,
* we need to set seccomp filter *before* dropping privileges.
@@ -3659,6 +3936,12 @@ void API minijail_destroy(struct minijail *j)
free(c);
}
j->hooks_tail = NULL;
+ while (j->fs_rules_head) {
+ struct fs_rule *r = j->fs_rules_head;
+ j->fs_rules_head = r->next;
+ free(r);
+ }
+ j->fs_rules_tail = NULL;
if (j->user)
free(j->user);
if (j->suppl_gid_list)
diff --git a/libminijail.h b/libminijail.h
index d2dce7a..1125169 100644
--- a/libminijail.h
+++ b/libminijail.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright 2012 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -106,6 +106,10 @@ void minijail_use_seccomp(struct minijail *j);
void minijail_no_new_privs(struct minijail *j);
void minijail_use_seccomp_filter(struct minijail *j);
void minijail_set_seccomp_filter_tsync(struct minijail *j);
+/* Sets using_minimalistic_mountns to true. */
+void minijail_set_using_minimalistic_mountns(struct minijail *j);
+void minijail_add_minimalistic_mountns_fs_rules(struct minijail *j);
+void minijail_enable_default_fs_restrictions(struct minijail *j);
/*
* Allow speculative execution features that may cause data leaks across
* processes, by setting the SECCOMP_FILTER_FLAG_SPEC_ALLOW seccomp flag.
@@ -188,6 +192,26 @@ int minijail_rlimit(struct minijail *j, int type, rlim_t cur, rlim_t max);
int minijail_add_to_cgroup(struct minijail *j, const char *path);
/*
+ * These functions are used for filesystem restrictions.
+ */
+
+/* Adds a read-execute path. */
+int minijail_add_fs_restriction_rx(struct minijail *j, const char *path);
+
+/* Adds a read-only path. */
+int minijail_add_fs_restriction_ro(struct minijail *j, const char *path);
+
+/* Adds a path with read and basic write permissions. */
+int minijail_add_fs_restriction_rw(struct minijail *j, const char *path);
+
+/* Adds a path with read and advanced write permissions. */
+int minijail_add_fs_restriction_advanced_rw(struct minijail *j,
+ const char *path);
+
+/* Adds a path with read and write permissions that exclude create. */
+int minijail_add_fs_restriction_edit(struct minijail *j, const char *path);
+
+/*
* Install signal handlers in the minijail process that forward received
* signals to the jailed child process.
*/
@@ -503,7 +527,8 @@ int minijail_wait(struct minijail *j);
/*
* Frees the given minijail. It does not matter if the process is inside the
- * minijail or not.
+ * minijail or not. It will not kill the process, see minijail_kill() if that is
+ * desired.
*/
void minijail_destroy(struct minijail *j);
diff --git a/libminijail_unittest.cc b/libminijail_unittest.cc
index 868b7d7..7ffbde5 100644
--- a/libminijail_unittest.cc
+++ b/libminijail_unittest.cc
@@ -1,4 +1,4 @@
-/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+/* Copyright 2016 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -23,9 +23,11 @@
#include <set>
#include <string>
+#include "landlock_util.h"
#include "libminijail-private.h"
#include "libminijail.h"
#include "scoped_minijail.h"
+#include "unittest_util.h"
#include "util.h"
namespace {
@@ -101,6 +103,21 @@ std::map<std::string, std::string> GetNamespaces(
return namespaces;
}
+void set_preload_path(minijail *j) {
+#if defined(__ANDROID__)
+ // libminijailpreload.so isn't available in android, so skip trying to load
+ // it. Even without the preload, all the test cases either pass or are skipped
+ // for other reasons.
+ return;
+#endif
+ // We need to get the absolute path because entering a new mntns will
+ // implicitly chdir(/) for us.
+ char *preload_path = realpath(kPreloadPath, nullptr);
+ ASSERT_NE(preload_path, nullptr);
+ minijail_set_preload_path(j, preload_path);
+ free(preload_path);
+}
+
} // namespace
/* Silence unused variable warnings. */
@@ -569,7 +586,7 @@ TEST(Test, minijail_run_env_pid_pipes) {
GTEST_SKIP();
ScopedMinijail j(minijail_new());
- minijail_set_preload_path(j.get(), kPreloadPath);
+ set_preload_path(j.get());
char *argv[4];
argv[0] = const_cast<char*>(kCatPath);
@@ -632,7 +649,7 @@ TEST(Test, minijail_run_fd_env_pid_pipes) {
GTEST_SKIP();
ScopedMinijail j(minijail_new());
- minijail_set_preload_path(j.get(), kPreloadPath);
+ set_preload_path(j.get());
char *argv[4];
argv[0] = const_cast<char*>(kShellPath);
@@ -722,7 +739,7 @@ TEST(Test, minijail_run_env_pid_pipes_with_local_preload) {
ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
// Use the preload library from this test build.
- ASSERT_EQ(0, minijail_set_preload_path(j.get(), "./libminijailpreload.so"));
+ set_preload_path(j.get());
int child_stderr;
mj_run_ret =
@@ -938,7 +955,7 @@ TEST(Test, test_minijail_preserve_fd) {
status = read(read_pipe[0], buf, 8);
EXPECT_EQ(status, (int)teststr_len);
buf[teststr_len] = 0;
- EXPECT_EQ(strcmp(buf, teststr), 0);
+ EXPECT_STREQ(buf, teststr);
status = minijail_wait(j);
EXPECT_EQ(status, 0);
@@ -1006,11 +1023,68 @@ TEST(Test, test_minijail_reset_signal_handlers) {
minijail_destroy(j);
}
+// Test that bind mounting onto a non-existing location works.
+TEST(Test, test_bind_mount_nonexistent_dest) {
+ TemporaryDir dir;
+ ASSERT_TRUE(dir.is_valid());
+
+ // minijail_bind() expects absolute paths, but TemporaryDir::path can return
+ // relative paths on Linux.
+ std::string path = dir.path;
+ if (!is_android()) {
+ std::string cwd(getcwd(NULL, 0));
+ path = cwd + "/" + path;
+ }
+
+ std::string path_src = path + "/src";
+ std::string path_dest = path + "/dest";
+
+ EXPECT_EQ(mkdir(path_src.c_str(), 0700), 0);
+
+ ScopedMinijail j(minijail_new());
+ int bind_res = minijail_bind(j.get(), path_src.c_str(), path_dest.c_str(),
+ 0 /*writable*/);
+ EXPECT_EQ(bind_res, 0);
+}
+
+// Test that bind mounting with a symlink behaves according to build-time
+// configuration.
+TEST(Test, test_bind_mount_symlink) {
+ TemporaryDir dir;
+ ASSERT_TRUE(dir.is_valid());
+
+ // minijail_bind() expects absolute paths, but TemporaryDir::path can return
+ // relative paths on Linux.
+ std::string path = dir.path;
+ if (!is_android()) {
+ std::string cwd(getcwd(NULL, 0));
+ path = cwd + "/" + path;
+ }
+
+ std::string path_src = path + "/src";
+ std::string path_dest = path + "/dest";
+ std::string path_sym = path + "/symlink";
+
+ EXPECT_EQ(mkdir(path_src.c_str(), 0700), 0);
+ EXPECT_EQ(mkdir(path_dest.c_str(), 0700), 0);
+ EXPECT_EQ(symlink(path_src.c_str(), path_sym.c_str()), 0);
+
+ ScopedMinijail j(minijail_new());
+ int bind_res = minijail_bind(j.get(), path_sym.c_str(), path_dest.c_str(),
+ 0 /*writable*/);
+ if (block_symlinks_in_bindmount_paths()) {
+ EXPECT_NE(bind_res, 0);
+ } else {
+ EXPECT_EQ(bind_res, 0);
+ }
+ EXPECT_EQ(unlink(path_sym.c_str()), 0);
+}
+
namespace {
// Tests that require userns access.
// Android unit tests don't currently support entering user namespaces as
-// unprivileged users due to having an older kernel. Chrome OS unit tests
+// unprivileged users due to having an older kernel. ChromeOS unit tests
// don't support it either due to being in a chroot environment (see man 2
// clone for more information about failure modes with the CLONE_NEWUSER flag).
class NamespaceTest : public ::testing::Test {
@@ -1119,7 +1193,7 @@ TEST_F(NamespaceTest, test_namespaces) {
{minijail_run_pid_pipes, minijail_run_pid_pipes_no_preload}) {
for (const auto& test_function : test_functions) {
ScopedMinijail j(minijail_new());
- minijail_set_preload_path(j.get(), kPreloadPath);
+ set_preload_path(j.get());
// Enter all the namespaces we can.
minijail_namespace_cgroups(j.get());
@@ -1155,7 +1229,7 @@ TEST_F(NamespaceTest, test_namespaces) {
ssize_t read_ret = read(child_stdout, buf, 8);
EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
buf[teststr_len] = 0;
- EXPECT_EQ(strcmp(buf, teststr), 0);
+ EXPECT_STREQ(buf, teststr);
// Grab the set of namespaces in every container process. They must not
// match the ones in the init namespace, and they must all match each
@@ -1214,11 +1288,7 @@ TEST_F(NamespaceTest, test_enter_ns) {
// Finally enter those namespaces.
j = minijail_new();
- // We need to get the absolute path because entering a new mntns will
- // implicitly chdir(/) for us.
- char *path = realpath(kPreloadPath, nullptr);
- ASSERT_NE(nullptr, path);
- minijail_set_preload_path(j, path);
+ set_preload_path(j);
minijail_namespace_net(j);
minijail_namespace_vfs(j);
@@ -1396,6 +1466,367 @@ TEST_F(NamespaceTest, test_remount_one_shared) {
minijail_destroy(j);
}
+// Test that using minijail_mount() for bind mounts works.
+TEST_F(NamespaceTest, test_remount_ro_using_mount) {
+ int status;
+ char uidmap[kBufferSize], gidmap[kBufferSize];
+ constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
+ constexpr gid_t kTargetGid = 1000;
+
+ if (!userns_supported_)
+ GTEST_SKIP();
+
+ struct minijail *j = minijail_new();
+
+ minijail_namespace_pids(j);
+ minijail_namespace_vfs(j);
+ minijail_mount_tmp(j);
+ minijail_run_as_init(j);
+
+ // Perform userns mapping.
+ minijail_namespace_user(j);
+ snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
+ snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
+ minijail_change_uid(j, kTargetUid);
+ minijail_change_gid(j, kTargetGid);
+ minijail_uidmap(j, uidmap);
+ minijail_gidmap(j, gidmap);
+ minijail_namespace_user_disable_setgroups(j);
+
+ // Perform a RO remount using minijail_mount().
+ minijail_mount(j, "none", "/", "none", MS_REMOUNT | MS_BIND | MS_RDONLY);
+
+ char *argv[] = {"/bin/true", nullptr};
+ minijail_run_no_preload(j, argv[0], argv);
+
+ status = minijail_wait(j);
+ EXPECT_EQ(status, 0);
+
+ minijail_destroy(j);
+}
+
+namespace {
+
+// Tests that require Landlock support.
+//
+// These subclass NamespaceTest because they also require userns access.
+// TODO(akhna): ideally, Landlock unit tests should be able to run w/o
+// namespace_pids or namespace_user.
+class LandlockTest : public NamespaceTest {
+ protected:
+ static void SetUpTestCase() {
+ run_landlock_tests_ = LandlockSupported() && UsernsSupported();
+ }
+
+ // Whether Landlock tests should be run.
+ static bool run_landlock_tests_;
+
+ static bool LandlockSupported() {
+ // Check the Landlock version w/o creating a ruleset file descriptor.
+ int landlock_version = landlock_create_ruleset(
+ NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
+ if (landlock_version <= 0) {
+ const int err = errno;
+ warn("Skipping Landlock tests");
+ switch (err) {
+ case ENOSYS:
+ warn("Landlock not supported by the current kernel.");
+ break;
+ case EOPNOTSUPP:
+ warn("Landlock is currently disabled.");
+ break;
+ }
+ return false;
+ }
+ return true;
+ }
+
+ // Sets up a minijail to make Landlock syscalls and child processes.
+ void SetupLandlockTestingNamespaces(struct minijail *j) {
+ minijail_namespace_pids(j);
+ minijail_namespace_user(j);
+ }
+};
+
+bool LandlockTest::run_landlock_tests_;
+
+// Constants used in Landlock tests.
+constexpr char kBinPath[] = "/bin";
+constexpr char kEtcPath[] = "/etc";
+constexpr char kLibPath[] = "/lib";
+constexpr char kLib64Path[] = "/lib64";
+constexpr char kTmpPath[] = "/tmp";
+constexpr char kLsPath[] = "/bin/ls";
+constexpr char kTestSymlinkScript[] = R"(
+ unlink /tmp/test-sym-link-1;
+ ln -s /bin /tmp/test-sym-link-1
+ )";
+
+} // namespace
+
+TEST_F(LandlockTest, test_rule_rx_allow) {
+ int mj_run_ret;
+ int status;
+ char *argv[3];
+ if (!run_landlock_tests_)
+ GTEST_SKIP();
+ ScopedMinijail j(minijail_new());
+ SetupLandlockTestingNamespaces(j.get());
+ minijail_add_fs_restriction_rx(j.get(), kBinPath);
+ minijail_add_fs_restriction_rx(j.get(), kEtcPath);
+ minijail_add_fs_restriction_rx(j.get(), kLibPath);
+ minijail_add_fs_restriction_rx(j.get(), kLib64Path);
+
+ argv[0] = const_cast<char*>(kLsPath);
+ argv[1] = const_cast<char*>(kCatPath);
+ argv[2] = NULL;
+
+ mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
+ EXPECT_EQ(mj_run_ret, 0);
+ status = minijail_wait(j.get());
+ EXPECT_EQ(status, 0);
+}
+
+TEST_F(LandlockTest, test_rule_rx_deny) {
+ int mj_run_ret;
+ int status;
+ char *argv[3];
+ if (!run_landlock_tests_)
+ GTEST_SKIP();
+ ScopedMinijail j(minijail_new());
+ SetupLandlockTestingNamespaces(j.get());
+ // Add irrelevant Landlock rule.
+ minijail_add_fs_restriction_rx(j.get(), "/var");
+
+ argv[0] = const_cast<char*>(kLsPath);
+ argv[1] = const_cast<char*>(kCatPath);
+ argv[2] = NULL;
+
+ mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
+ EXPECT_EQ(mj_run_ret, 0);
+ status = minijail_wait(j.get());
+ EXPECT_NE(status, 0);
+}
+
+TEST_F(LandlockTest, test_rule_ro_allow) {
+ int mj_run_ret;
+ int status;
+ char *argv[3];
+ if (!run_landlock_tests_)
+ GTEST_SKIP();
+ ScopedMinijail j(minijail_new());
+ SetupLandlockTestingNamespaces(j.get());
+ minijail_add_fs_restriction_rx(j.get(), kBinPath);
+ minijail_add_fs_restriction_rx(j.get(), kEtcPath);
+ minijail_add_fs_restriction_rx(j.get(), kLibPath);
+ minijail_add_fs_restriction_rx(j.get(), kLib64Path);
+ // Add RO rule.
+ minijail_add_fs_restriction_ro(j.get(), "/var");
+
+ argv[0] = const_cast<char*>(kLsPath);
+ argv[1] = "/var";
+ argv[2] = NULL;
+
+ mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
+ EXPECT_EQ(mj_run_ret, 0);
+ status = minijail_wait(j.get());
+ EXPECT_EQ(status, 0);
+}
+
+TEST_F(LandlockTest, test_rule_ro_deny) {
+ int mj_run_ret;
+ int status;
+ char *argv[3];
+ if (!run_landlock_tests_)
+ GTEST_SKIP();
+ ScopedMinijail j(minijail_new());
+ SetupLandlockTestingNamespaces(j.get());
+ minijail_add_fs_restriction_rx(j.get(), kBinPath);
+ minijail_add_fs_restriction_rx(j.get(), kEtcPath);
+ minijail_add_fs_restriction_rx(j.get(), kLibPath);
+ minijail_add_fs_restriction_rx(j.get(), kLib64Path);
+ // No RO rule for /var, because we want the cmd to fail.
+
+ argv[0] = const_cast<char*>(kLsPath);
+ argv[1] = "/var";
+ argv[2] = NULL;
+
+ mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
+ EXPECT_EQ(mj_run_ret, 0);
+ status = minijail_wait(j.get());
+ EXPECT_NE(status, 0);
+}
+
+TEST_F(LandlockTest, test_rule_rw_allow) {
+ int mj_run_ret;
+ int status;
+ char *argv[4];
+ if (!run_landlock_tests_)
+ GTEST_SKIP();
+ ScopedMinijail j(minijail_new());
+ SetupLandlockTestingNamespaces(j.get());
+ minijail_add_fs_restriction_rx(j.get(), kBinPath);
+ minijail_add_fs_restriction_rx(j.get(), kEtcPath);
+ minijail_add_fs_restriction_rx(j.get(), kLibPath);
+ minijail_add_fs_restriction_rx(j.get(), kLib64Path);
+ // Add RW Landlock rule.
+ minijail_add_fs_restriction_rw(j.get(), kTmpPath);
+
+ argv[0] = const_cast<char*>(kShellPath);
+ argv[1] = "-c";
+ argv[2] = "exec echo 'bar' > /tmp/baz";
+ argv[3] = NULL;
+
+ mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
+ EXPECT_EQ(mj_run_ret, 0);
+ status = minijail_wait(j.get());
+ EXPECT_EQ(status, 0);
+}
+
+TEST_F(LandlockTest, test_rule_rw_deny) {
+ int mj_run_ret;
+ int status;
+ char *argv[4];
+ if (!run_landlock_tests_)
+ GTEST_SKIP();
+ ScopedMinijail j(minijail_new());
+ SetupLandlockTestingNamespaces(j.get());
+ minijail_add_fs_restriction_rx(j.get(), kBinPath);
+ minijail_add_fs_restriction_rx(j.get(), kEtcPath);
+ minijail_add_fs_restriction_rx(j.get(), kLibPath);
+ minijail_add_fs_restriction_rx(j.get(), kLib64Path);
+ // No RW rule, because we want the cmd to fail.
+
+ argv[0] = const_cast<char*>(kShellPath);
+ argv[1] = "-c";
+ argv[2] = "exec echo 'bar' > /tmp/baz";
+ argv[3] = NULL;
+
+ mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
+ EXPECT_EQ(mj_run_ret, 0);
+ status = minijail_wait(j.get());
+ EXPECT_NE(status, 0);
+}
+
+TEST_F(LandlockTest, test_rule_allow_symlinks_advanced_rw) {
+ int mj_run_ret;
+ int status;
+ if (!run_landlock_tests_)
+ GTEST_SKIP();
+ ScopedMinijail j(minijail_new());
+ SetupLandlockTestingNamespaces(j.get());
+ minijail_add_fs_restriction_rx(j.get(), kBinPath);
+ minijail_add_fs_restriction_rx(j.get(), kEtcPath);
+ minijail_add_fs_restriction_rx(j.get(), kLibPath);
+ minijail_add_fs_restriction_rx(j.get(), kLib64Path);
+ minijail_add_fs_restriction_advanced_rw(j.get(), kTmpPath);
+
+ char* const argv[] = {"sh", "-c", const_cast<char*>(kTestSymlinkScript),
+ nullptr};
+
+ mj_run_ret = minijail_run_no_preload(j.get(), kShellPath, argv);
+ EXPECT_EQ(mj_run_ret, 0);
+ status = minijail_wait(j.get());
+ EXPECT_EQ(status, 0);
+}
+
+TEST_F(LandlockTest, test_rule_deny_symlinks_basic_rw) {
+ int mj_run_ret;
+ int status;
+ if (!run_landlock_tests_)
+ GTEST_SKIP();
+ ScopedMinijail j(minijail_new());
+ SetupLandlockTestingNamespaces(j.get());
+ minijail_add_fs_restriction_rx(j.get(), kBinPath);
+ minijail_add_fs_restriction_rx(j.get(), kEtcPath);
+ minijail_add_fs_restriction_rx(j.get(), kLibPath);
+ minijail_add_fs_restriction_rx(j.get(), kLib64Path);
+ minijail_add_fs_restriction_rw(j.get(), kTmpPath);
+
+ char* const argv[] = {"sh", "-c", const_cast<char*>(kTestSymlinkScript),
+ nullptr};
+
+ mj_run_ret = minijail_run_no_preload(j.get(), kShellPath, argv);
+ EXPECT_EQ(mj_run_ret, 0);
+ status = minijail_wait(j.get());
+ EXPECT_NE(status, 0);
+}
+
+TEST_F(LandlockTest, test_rule_rx_cannot_write) {
+ int mj_run_ret;
+ int status;
+ char *argv[4];
+ if (!run_landlock_tests_)
+ GTEST_SKIP();
+ ScopedMinijail j(minijail_new());
+ SetupLandlockTestingNamespaces(j.get());
+ minijail_add_fs_restriction_rx(j.get(), kBinPath);
+ minijail_add_fs_restriction_rx(j.get(), kEtcPath);
+ minijail_add_fs_restriction_rx(j.get(), kLibPath);
+ minijail_add_fs_restriction_rx(j.get(), kLib64Path);
+ minijail_add_fs_restriction_rx(j.get(), kTmpPath);
+
+ argv[0] = const_cast<char*>(kShellPath);
+ argv[1] = "-c";
+ argv[2] = "exec echo 'bar' > /tmp/baz";
+ argv[3] = NULL;
+
+ mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
+ EXPECT_EQ(mj_run_ret, 0);
+ status = minijail_wait(j.get());
+ EXPECT_NE(status, 0);
+}
+
+TEST_F(LandlockTest, test_rule_ro_cannot_wx) {
+ int mj_run_ret;
+ int status;
+ char *argv[4];
+ if (!run_landlock_tests_)
+ GTEST_SKIP();
+ ScopedMinijail j(minijail_new());
+ SetupLandlockTestingNamespaces(j.get());
+ minijail_add_fs_restriction_ro(j.get(), kBinPath);
+ minijail_add_fs_restriction_ro(j.get(), kEtcPath);
+ minijail_add_fs_restriction_ro(j.get(), kLibPath);
+ minijail_add_fs_restriction_ro(j.get(), kLib64Path);
+ minijail_add_fs_restriction_ro(j.get(), kTmpPath);
+
+ argv[0] = const_cast<char*>(kShellPath);
+ argv[1] = "-c";
+ argv[2] = "exec echo 'bar' > /tmp/baz";
+ argv[3] = NULL;
+
+ mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
+ EXPECT_EQ(mj_run_ret, 0);
+ status = minijail_wait(j.get());
+ EXPECT_NE(status, 0);
+}
+
+TEST_F(LandlockTest, test_rule_rw_cannot_exec) {
+ int mj_run_ret;
+ int status;
+ char *argv[4];
+ if (!run_landlock_tests_)
+ GTEST_SKIP();
+ ScopedMinijail j(minijail_new());
+ SetupLandlockTestingNamespaces(j.get());
+ minijail_add_fs_restriction_rw(j.get(), kBinPath);
+ minijail_add_fs_restriction_rw(j.get(), kEtcPath);
+ minijail_add_fs_restriction_rw(j.get(), kLibPath);
+ minijail_add_fs_restriction_rw(j.get(), kLib64Path);
+ minijail_add_fs_restriction_rw(j.get(), kTmpPath);
+
+ argv[0] = const_cast<char*>(kShellPath);
+ argv[1] = "-c";
+ argv[2] = "exec echo 'bar' > /tmp/baz";
+ argv[3] = NULL;
+
+ mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
+ EXPECT_EQ(mj_run_ret, 0);
+ status = minijail_wait(j.get());
+ EXPECT_NE(status, 0);
+}
+
void TestCreateSession(bool create_session) {
int status;
int pipe_fds[2];
diff --git a/libminijailpreload.c b/libminijailpreload.c
index b5a3c75..17c8f97 100644
--- a/libminijailpreload.c
+++ b/libminijailpreload.c
@@ -1,5 +1,5 @@
/* libminijailpreload.c - preload hack library
- * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Copyright 2011 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
diff --git a/libsyscalls.h b/libsyscalls.h
index 29583ce..50a92a9 100644
--- a/libsyscalls.h
+++ b/libsyscalls.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+/* Copyright 2011 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
diff --git a/minijail0.1 b/minijail0.1
index a53ec6f..c323f2d 100644
--- a/minijail0.1
+++ b/minijail0.1
@@ -1,4 +1,4 @@
-.TH MINIJAIL0 "1" "March 2016" "Chromium OS" "User Commands"
+.TH MINIJAIL0 "1" "March 2016" "ChromiumOS" "User Commands"
.SH NAME
minijail0 \- sandbox a process
.SH SYNOPSIS
@@ -390,9 +390,9 @@ allows the operations to jail \fIprogram\fR.
.RE
.SH AUTHOR
-The Chromium OS Authors <chromiumos-dev@chromium.org>
+The ChromiumOS Authors <chromiumos-dev@chromium.org>
.SH COPYRIGHT
-Copyright \(co 2011 The Chromium OS Authors
+Copyright \(co 2011 The ChromiumOS Authors
License BSD-like.
.SH "SEE ALSO"
.BR libminijail.h ,
diff --git a/minijail0.5 b/minijail0.5
index 3e4f114..c0e18e8 100644
--- a/minijail0.5
+++ b/minijail0.5
@@ -1,4 +1,4 @@
-.TH MINIJAIL0 "5" "July 2011" "Chromium OS" "User Commands"
+.TH MINIJAIL0 "5" "July 2011" "ChromiumOS" "User Commands"
.SH NAME
minijail0 \- sandbox a process
.SH DESCRIPTION
@@ -6,10 +6,11 @@ minijail0 \- sandbox a process
Runs PROGRAM inside a sandbox. See \fBminijail0\fR(1) for details.
.SH EXAMPLES
-Safely switch from root to nobody while dropping all capabilities and
-inheriting any groups from nobody:
+Safely switch from user \fIroot\fR to \fInobody\fR, switch to primary group
+\fInobody\fR, drop all capabilities, and inherit any supplementary groups from
+user \fInobody\fR:
- # minijail0 -c 0 -G -u nobody /usr/bin/whoami
+ # minijail0 -u nobody -g nobody -c 0 -G /usr/bin/whoami
nobody
Run in a PID and VFS namespace without superuser capabilities (but still
@@ -183,9 +184,9 @@ will occupy a single line, without '=' and value. Otherwise, any string that
is given after the '=' is interpreted as the argument.
.SH AUTHOR
-The Chromium OS Authors <chromiumos-dev@chromium.org>
+The ChromiumOS Authors <chromiumos-dev@chromium.org>
.SH COPYRIGHT
-Copyright \(co 2011 The Chromium OS Authors
+Copyright \(co 2011 The ChromiumOS Authors
License BSD-like.
.SH "SEE ALSO"
.BR minijail0 (1)
diff --git a/minijail0.c b/minijail0.c
index 9b1fcf3..7ef74b5 100644
--- a/minijail0.c
+++ b/minijail0.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright 2012 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
diff --git a/minijail0.sh b/minijail0.sh
index cd5303a..21d9174 100755
--- a/minijail0.sh
+++ b/minijail0.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright 2020 The Chromium OS Authors. All rights reserved.
+# Copyright 2020 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/minijail0_cli.c b/minijail0_cli.c
index e366846..25aa930 100644
--- a/minijail0_cli.c
+++ b/minijail0_cli.c
@@ -1,4 +1,4 @@
-/* Copyright 2018 The Chromium OS Authors. All rights reserved.
+/* Copyright 2018 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -191,9 +191,9 @@ static void add_binding(struct minijail *j, char *arg)
if (dest == NULL || dest[0] == '\0')
dest = src;
int writable;
- if (flags == NULL || flags[0] == '\0' || !strcmp(flags, "0"))
+ if (flags == NULL || flags[0] == '\0' || streq(flags, "0"))
writable = 0;
- else if (!strcmp(flags, "1"))
+ else if (streq(flags, "1"))
writable = 1;
else
errx(1, "Bad value for <writable>: %s", flags);
@@ -213,7 +213,7 @@ static void add_rlimit(struct minijail *j, char *arg)
}
rlim_t cur_rlim;
rlim_t max_rlim;
- if (!strcmp(cur, "unlimited")) {
+ if (streq(cur, "unlimited")) {
cur_rlim = RLIM_INFINITY;
} else {
end = NULL;
@@ -221,7 +221,7 @@ static void add_rlimit(struct minijail *j, char *arg)
if (*end)
errx(1, "Bad soft limit: '%s'", cur);
}
- if (!strcmp(max, "unlimited")) {
+ if (streq(max, "unlimited")) {
max_rlim = RLIM_INFINITY;
} else {
end = NULL;
@@ -386,14 +386,14 @@ static void use_profile(struct minijail *j, const char *profile,
{
/* Note: New profiles should be added in minijail0_cli_unittest.cc. */
- if (!strcmp(profile, "minimalistic-mountns") ||
- !strcmp(profile, "minimalistic-mountns-nodev")) {
+ if (streq(profile, "minimalistic-mountns") ||
+ streq(profile, "minimalistic-mountns-nodev")) {
minijail_namespace_vfs(j);
if (minijail_bind(j, "/", "/", 0))
errx(1, "minijail_bind(/) failed");
if (minijail_bind(j, "/proc", "/proc", 0))
errx(1, "minijail_bind(/proc) failed");
- if (!strcmp(profile, "minimalistic-mountns")) {
+ if (streq(profile, "minimalistic-mountns")) {
if (minijail_bind(j, "/dev/log", "/dev/log", 0))
errx(1, "minijail_bind(/dev/log) failed");
minijail_mount_dev(j);
@@ -403,6 +403,7 @@ static void use_profile(struct minijail *j, const char *profile,
*tmp_size = DEFAULT_TMP_SIZE;
}
minijail_remount_proc_readonly(j);
+ minijail_set_using_minimalistic_mountns(j);
use_pivot_root(j, DEFAULT_PIVOT_ROOT, pivot_root, chroot);
} else
errx(1, "Unrecognized profile name '%s'", profile);
@@ -411,13 +412,13 @@ static void use_profile(struct minijail *j, const char *profile,
static void set_remount_mode(struct minijail *j, const char *mode)
{
unsigned long msmode;
- if (!strcmp(mode, "shared"))
+ if (streq(mode, "shared"))
msmode = MS_SHARED;
- else if (!strcmp(mode, "private"))
+ else if (streq(mode, "private"))
msmode = MS_PRIVATE;
- else if (!strcmp(mode, "slave"))
+ else if (streq(mode, "slave"))
msmode = MS_SLAVE;
- else if (!strcmp(mode, "unbindable"))
+ else if (streq(mode, "unbindable"))
msmode = MS_UNBINDABLE;
else
errx(1, "Unknown remount mode: '%s'", mode);
@@ -467,6 +468,11 @@ enum {
OPT_CONFIG,
OPT_ENV_ADD,
OPT_ENV_RESET,
+ OPT_FS_DEFAULT_PATHS,
+ OPT_FS_PATH_RX,
+ OPT_FS_PATH_RO,
+ OPT_FS_PATH_RW,
+ OPT_FS_PATH_ADVANCED_RW,
OPT_LOGGING,
OPT_PRELOAD_LIBRARY,
OPT_PROFILE,
@@ -501,6 +507,11 @@ static const struct option long_options[] = {
{"mount", required_argument, 0, 'k'},
{"bind-mount", required_argument, 0, 'b'},
{"ns-mount", no_argument, 0, 'v'},
+ {"fs-default-paths", no_argument, 0, OPT_FS_DEFAULT_PATHS},
+ {"fs-path-rx", required_argument, 0, OPT_FS_PATH_RX},
+ {"fs-path-ro", required_argument, 0, OPT_FS_PATH_RO},
+ {"fs-path-rw", required_argument, 0, OPT_FS_PATH_RW},
+ {"fs-path-advanced-rw", required_argument, 0, OPT_FS_PATH_ADVANCED_RW},
{0, 0, 0, 0},
};
@@ -615,6 +626,17 @@ static const char help_text[] =
"Uncommon options:\n"
" --allow-speculative-execution\n"
" Allow speculative execution by disabling mitigations.\n"
+" --fs-default-paths\n"
+" Adds a set of allowed paths to allow running common system \n"
+" executables.\n"
+" --fs-path-rx\n"
+" Adds an allowed read-execute path.\n"
+" --fs-path-ro\n"
+" Adds an allowed read-only path.\n"
+" --fs-path-rw\n"
+" Adds an allowed read-write path.\n"
+" --fs-path-advanced-rw\n"
+" Adds an allowed advanced read-write path.\n"
" --preload-library=<file>\n"
" Overrides the path to \"" PRELOADPATH "\".\n"
" This is only really useful for local testing.\n"
@@ -672,7 +694,7 @@ static int getopt_from_conf(const struct option *longopts,
const struct option *curr_opt;
for (curr_opt = &longopts[0]; curr_opt->name != NULL;
curr_opt = &longopts[++i])
- if (strcmp(entry->key, curr_opt->name) == 0)
+ if (streq(entry->key, curr_opt->name))
break;
if (curr_opt->name == NULL) {
errx(1,
@@ -953,9 +975,9 @@ int parse_args(struct minijail *j, int argc, char *const argv[],
add_rlimit(j, optarg);
break;
case 'T':
- if (!strcmp(optarg, "static"))
+ if (streq(optarg, "static"))
*elftype = ELFSTATIC;
- else if (!strcmp(optarg, "dynamic"))
+ else if (streq(optarg, "dynamic"))
*elftype = ELFDYNAMIC;
else {
errx(1, "ELF type must be 'static' or "
@@ -986,11 +1008,11 @@ int parse_args(struct minijail *j, int argc, char *const argv[],
minijail_namespace_set_hostname(j, optarg);
break;
case OPT_LOGGING:
- if (!strcmp(optarg, "auto"))
+ if (streq(optarg, "auto"))
log_to_stderr = -1;
- else if (!strcmp(optarg, "syslog"))
+ else if (streq(optarg, "syslog"))
log_to_stderr = 0;
- else if (!strcmp(optarg, "stderr"))
+ else if (streq(optarg, "stderr"))
log_to_stderr = 1;
else
errx(1,
@@ -1002,6 +1024,21 @@ int parse_args(struct minijail *j, int argc, char *const argv[],
case OPT_PRELOAD_LIBRARY:
*preload_path = optarg;
break;
+ case OPT_FS_DEFAULT_PATHS:
+ minijail_enable_default_fs_restrictions(j);
+ break;
+ case OPT_FS_PATH_RX:
+ minijail_add_fs_restriction_rx(j, optarg);
+ break;
+ case OPT_FS_PATH_RO:
+ minijail_add_fs_restriction_ro(j, optarg);
+ break;
+ case OPT_FS_PATH_RW:
+ minijail_add_fs_restriction_rw(j, optarg);
+ break;
+ case OPT_FS_PATH_ADVANCED_RW:
+ minijail_add_fs_restriction_advanced_rw(j, optarg);
+ break;
case OPT_SECCOMP_BPF_BINARY:
if (seccomp != None && seccomp != BpfBinaryFilter) {
errx(1, "Do not use -s, -S, or "
diff --git a/minijail0_cli.h b/minijail0_cli.h
index cd504b3..00a541c 100644
--- a/minijail0_cli.h
+++ b/minijail0_cli.h
@@ -1,4 +1,4 @@
-/* Copyright 2018 The Chromium OS Authors. All rights reserved.
+/* Copyright 2018 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
diff --git a/minijail0_cli_unittest.cc b/minijail0_cli_unittest.cc
index 7b20ecd..8674e07 100644
--- a/minijail0_cli_unittest.cc
+++ b/minijail0_cli_unittest.cc
@@ -1,4 +1,4 @@
-/* Copyright 2018 The Chromium OS Authors. All rights reserved.
+/* Copyright 2018 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -605,4 +605,21 @@ TEST_F(CliTest, conf_parsing) {
ASSERT_TRUE(parse_args_(argv));
}
+TEST_F(CliTest, conf_parsing_with_dac_override) {
+ std::vector<std::string> argv = {"-c 2", "--config",
+ source_path("test/valid.conf"),
+ "/bin/sh"};
+
+ ASSERT_TRUE(parse_args_(argv));
+}
+
+TEST_F(CliTest, conf_fs_path) {
+ std::vector<std::string> argv = {"-c 2", "--config",
+ source_path("test/landlock.conf"),
+ "/bin/sh"};
+
+ ASSERT_TRUE(parse_args_(argv));
+}
+
+
#endif // !__ANDROID__
diff --git a/parse_seccomp_policy.cc b/parse_seccomp_policy.cc
index a6daac5..e511156 100644
--- a/parse_seccomp_policy.cc
+++ b/parse_seccomp_policy.cc
@@ -1,4 +1,4 @@
-/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+/* Copyright 2016 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -73,7 +73,7 @@ int main(int argc, char** argv) {
FILE* f = stdin;
// If there is at least one additional unparsed argument, treat it as the
// policy script.
- if (argc > optind && strcmp(argv[optind], "-") != 0)
+ if (argc > optind && !streq(argv[optind], "-"))
f = fopen(argv[optind], "re");
if (!f)
pdie("fopen(%s) failed", argv[1]);
diff --git a/platform2_preinstall.sh b/platform2_preinstall.sh
index 7d19d99..418c9fc 100755
--- a/platform2_preinstall.sh
+++ b/platform2_preinstall.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-# Copyright 2015 The Chromium OS Authors. All rights reserved.
+# Copyright 2015 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/rust/OWNERS b/rust/OWNERS
index f8111bb..ae85cbb 100644
--- a/rust/OWNERS
+++ b/rust/OWNERS
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium OS Authors. All rights reserved.
+# Copyright 2019 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/rust/minijail-sys/Android.bp b/rust/minijail-sys/Android.bp
new file mode 100644
index 0000000..86c092e
--- /dev/null
+++ b/rust/minijail-sys/Android.bp
@@ -0,0 +1,35 @@
+// This file is generated by cargo2android.py --config cargo2android.json.
+// Do not modify this file as changes will be overridden on upgrade.
+
+
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "external_minijail_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-BSD
+ default_applicable_licenses: ["external_minijail_license"],
+}
+
+rust_library {
+ name: "libminijail_sys",
+ host_supported: true,
+ crate_name: "minijail_sys",
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.0.13",
+ srcs: ["lib.rs"],
+ edition: "2018",
+ rustlibs: [
+ "liblibc",
+ ],
+ shared_libs: [
+ "libcap",
+ "libminijail",
+ ],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.compos",
+ "com.android.virt",
+ ],
+}
diff --git a/rust/minijail-sys/Cargo.toml b/rust/minijail-sys/Cargo.toml
index 4c49c95..6745d14 100644
--- a/rust/minijail-sys/Cargo.toml
+++ b/rust/minijail-sys/Cargo.toml
@@ -2,7 +2,7 @@
name = "minijail-sys"
version = "0.0.13"
description = "Provides raw (unsafe) bindings to the libminijail C library."
-authors = ["The Chromium OS Authors"]
+authors = ["The ChromiumOS Authors"]
edition = "2018"
build = "build.rs"
diff --git a/rust/minijail-sys/build.rs b/rust/minijail-sys/build.rs
index f73191c..4aa172d 100644
--- a/rust/minijail-sys/build.rs
+++ b/rust/minijail-sys/build.rs
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Copyright 2019 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -85,15 +85,16 @@ fn bindings_generation() -> io::Result<()> {
println!("cargo:rerun-if-changed={}", header_path.display());
let status = Command::new(&bindgen)
.args(&["--default-enum-style", "rust"])
- .args(&["--blacklist-type", "__rlim64_t"])
+ .args(&["--blocklist-type", "__rlim64_t"])
.args(&["--raw-line", "pub type __rlim64_t = u64;"])
- .args(&["--blacklist-type", "__u\\d{1,2}"])
+ .args(&["--blocklist-type", "__u\\d{1,2}"])
.args(&["--raw-line", "pub type __u8 = u8;"])
.args(&["--raw-line", "pub type __u16 = u16;"])
.args(&["--raw-line", "pub type __u32 = u32;"])
- .args(&["--blacklist-type", "__uint64_t"])
- .args(&["--whitelist-function", "^minijail_.*"])
- .args(&["--whitelist-var", "^MINIJAIL_.*"])
+ .args(&["--blocklist-type", "__uint64_t"])
+ .args(&["--allowlist-function", "^minijail_.*"])
+ .args(&["--allowlist-var", "^MINIJAIL_.*"])
+ .arg("--size_t-is-usize")
.arg("--no-layout-tests")
.arg("--disable-header-comment")
.args(&["--output", gen_file.to_str().unwrap()])
diff --git a/rust/minijail-sys/cargo2android.json b/rust/minijail-sys/cargo2android.json
new file mode 100644
index 0000000..4fb4f8f
--- /dev/null
+++ b/rust/minijail-sys/cargo2android.json
@@ -0,0 +1,13 @@
+{
+ "run": true,
+ "device": true,
+ "apex-available": [
+ "//apex_available:platform",
+ "com.android.compos",
+ "com.android.virt"
+ ],
+ "patch": "patches/Android.bp.patch",
+ "lib-blocklist": [
+ "minijail.pic"
+ ]
+}
diff --git a/rust/minijail-sys/lib.rs b/rust/minijail-sys/lib.rs
index c418150..0285594 100644
--- a/rust/minijail-sys/lib.rs
+++ b/rust/minijail-sys/lib.rs
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Copyright 2019 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -18,15 +18,15 @@
//
// Generated in CrOS SDK chroot with:
// bindgen --default-enum-style rust \
-// --blacklist-type '__rlim64_t' \
+// --blocklist-type '__rlim64_t' \
// --raw-line 'pub type __rlim64_t = u64;' \
-// --blacklist-type '__u\d{1,2}' \
+// --blocklist-type '__u\d{1,2}' \
// --raw-line 'pub type __u8 = u8;' \
// --raw-line 'pub type __u16 = u16;' \
// --raw-line 'pub type __u32 = u32;' \
-// --blacklist-type '__uint64_t' \
-// --whitelist-function '^minijail_.*' \
-// --whitelist-var '^MINIJAIL_.*' \
+// --blocklist-type '__uint64_t' \
+// --allowlist-function '^minijail_.*' \
+// --allowlist-var '^MINIJAIL_.*' \
// --no-layout-tests \
// --output libminijail.rs \
// libminijail.h -- \
diff --git a/rust/minijail-sys/libminijail.rs b/rust/minijail-sys/libminijail.rs
index 42b1a8d..a867aee 100644
--- a/rust/minijail-sys/libminijail.rs
+++ b/rust/minijail-sys/libminijail.rs
@@ -10,7 +10,6 @@ pub type rlim_t = __rlim64_t;
pub type gid_t = __gid_t;
pub type uid_t = __uid_t;
pub type pid_t = __pid_t;
-pub type size_t = ::std::os::raw::c_ulong;
#[repr(C)]
pub struct sock_filter {
pub code: __u16,
@@ -68,7 +67,7 @@ extern "C" {
pub fn minijail_change_gid(j: *mut minijail, gid: gid_t);
}
extern "C" {
- pub fn minijail_set_supplementary_gids(j: *mut minijail, size: size_t, list: *const gid_t);
+ pub fn minijail_set_supplementary_gids(j: *mut minijail, size: usize, list: *const gid_t);
}
extern "C" {
pub fn minijail_keep_supplementary_gids(j: *mut minijail);
@@ -98,6 +97,15 @@ extern "C" {
pub fn minijail_set_seccomp_filter_tsync(j: *mut minijail);
}
extern "C" {
+ pub fn minijail_set_using_minimalistic_mountns(j: *mut minijail);
+}
+extern "C" {
+ pub fn minijail_add_minimalistic_mountns_fs_rules(j: *mut minijail);
+}
+extern "C" {
+ pub fn minijail_enable_default_fs_restrictions(j: *mut minijail);
+}
+extern "C" {
pub fn minijail_set_seccomp_filter_allow_speculation(j: *mut minijail);
}
extern "C" {
@@ -229,6 +237,36 @@ extern "C" {
) -> ::std::os::raw::c_int;
}
extern "C" {
+ pub fn minijail_add_fs_restriction_rx(
+ j: *mut minijail,
+ path: *const ::std::os::raw::c_char,
+ ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ pub fn minijail_add_fs_restriction_ro(
+ j: *mut minijail,
+ path: *const ::std::os::raw::c_char,
+ ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ pub fn minijail_add_fs_restriction_rw(
+ j: *mut minijail,
+ path: *const ::std::os::raw::c_char,
+ ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ pub fn minijail_add_fs_restriction_advanced_rw(
+ j: *mut minijail,
+ path: *const ::std::os::raw::c_char,
+ ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ pub fn minijail_add_fs_restriction_edit(
+ j: *mut minijail,
+ path: *const ::std::os::raw::c_char,
+ ) -> ::std::os::raw::c_int;
+}
+extern "C" {
pub fn minijail_forward_signals(j: *mut minijail) -> ::std::os::raw::c_int;
}
extern "C" {
@@ -256,7 +294,7 @@ extern "C" {
pub fn minijail_mount_tmp(j: *mut minijail);
}
extern "C" {
- pub fn minijail_mount_tmp_size(j: *mut minijail, size: size_t);
+ pub fn minijail_mount_tmp_size(j: *mut minijail, size: usize);
}
extern "C" {
pub fn minijail_mount_dev(j: *mut minijail);
@@ -320,6 +358,14 @@ extern "C" {
pub fn minijail_enter(j: *const minijail);
}
extern "C" {
+ pub fn minijail_run_env(
+ j: *mut minijail,
+ filename: *const ::std::os::raw::c_char,
+ argv: *const *mut ::std::os::raw::c_char,
+ envp: *const *mut ::std::os::raw::c_char,
+ ) -> ::std::os::raw::c_int;
+}
+extern "C" {
pub fn minijail_run(
j: *mut minijail,
filename: *const ::std::os::raw::c_char,
diff --git a/rust/minijail-sys/patches/Android.bp.patch b/rust/minijail-sys/patches/Android.bp.patch
new file mode 100644
index 0000000..fe5115c
--- /dev/null
+++ b/rust/minijail-sys/patches/Android.bp.patch
@@ -0,0 +1,16 @@
+diff --git a/rust/minijail-sys/Android.bp b/rust/minijail-sys/Android.bp
+index bdba0d7..788dc77 100644
+--- a/rust/minijail-sys/Android.bp
++++ b/rust/minijail-sys/Android.bp
+@@ -14,7 +14,10 @@ rust_library {
+ rustlibs: [
+ "liblibc",
+ ],
+- shared_libs: ["libcap"],
++ shared_libs: [
++ "libcap",
++ "libminijail",
++ ],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.compos",
diff --git a/rust/minijail/Android.bp b/rust/minijail/Android.bp
new file mode 100644
index 0000000..ba66d81
--- /dev/null
+++ b/rust/minijail/Android.bp
@@ -0,0 +1,33 @@
+// This file is generated by cargo2android.py --config cargo2android.json.
+// Do not modify this file as changes will be overridden on upgrade.
+
+
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "external_minijail_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-BSD
+ default_applicable_licenses: ["external_minijail_license"],
+}
+
+rust_library {
+ name: "libminijail_rust",
+ stem: "libminijail",
+ host_supported: true,
+ crate_name: "minijail",
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.2.3",
+ srcs: ["src/lib.rs"],
+ edition: "2018",
+ rustlibs: [
+ "liblibc",
+ "libminijail_sys",
+ ],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.compos",
+ "com.android.virt",
+ ],
+}
diff --git a/rust/minijail/Cargo.toml b/rust/minijail/Cargo.toml
index e6c08b8..5c4087f 100644
--- a/rust/minijail/Cargo.toml
+++ b/rust/minijail/Cargo.toml
@@ -2,14 +2,9 @@
name = "minijail"
version = "0.2.3"
description = "Provides a safe Rust friendly interface to libminijail."
-authors = ["The Chromium OS Authors"]
+authors = ["The ChromiumOS Authors"]
edition = "2018"
[dependencies]
libc = "0.2.44"
minijail-sys = { path = "../minijail-sys" } # provided by ebuild
-
-[[test]]
-name = "fork_remap"
-path = "tests/fork_remap.rs"
-harness = false
diff --git a/rust/minijail/cargo2android.json b/rust/minijail/cargo2android.json
new file mode 100644
index 0000000..d2adf3e
--- /dev/null
+++ b/rust/minijail/cargo2android.json
@@ -0,0 +1,9 @@
+{
+ "run": true,
+ "device": true,
+ "apex-available": [
+ "//apex_available:platform",
+ "com.android.compos",
+ "com.android.virt"
+ ]
+}
diff --git a/rust/minijail/src/lib.rs b/rust/minijail/src/lib.rs
index 5028041..5d7d7fe 100644
--- a/rust/minijail/src/lib.rs
+++ b/rust/minijail/src/lib.rs
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Copyright 2017 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -319,7 +319,11 @@ impl Display for Error {
SeccompViolation(s) => write!(f, "seccomp violation syscall #{}", s),
Killed(s) => write!(f, "killed with signal number {}", s),
ReturnCode(e) => write!(f, "exited with code {}", e),
- Wait(errno) => write!(f, "failed to wait: {}", io::Error::from_raw_os_error(*errno)),
+ Wait(errno) => write!(
+ f,
+ "failed to wait: {}",
+ io::Error::from_raw_os_error(*errno)
+ ),
}
}
}
@@ -465,7 +469,7 @@ impl Minijail {
}
pub fn set_supplementary_gids(&mut self, ids: &[libc::gid_t]) {
unsafe {
- minijail_set_supplementary_gids(self.jail, ids.len() as size_t, ids.as_ptr());
+ minijail_set_supplementary_gids(self.jail, ids.len(), ids.as_ptr());
}
}
pub fn keep_supplementary_gids(&mut self) {
@@ -767,7 +771,7 @@ impl Minijail {
}
pub fn mount_tmp_size(&mut self, size: usize) {
unsafe {
- minijail_mount_tmp_size(self.jail, size as size_t);
+ minijail_mount_tmp_size(self.jail, size);
}
}
pub fn mount_bind<P1: AsRef<Path>, P2: AsRef<Path>>(
@@ -920,6 +924,9 @@ impl Minijail {
///
/// This Function may abort in the child on error because a partially
/// entered jail isn't recoverable.
+ ///
+ /// Once this is invoked the object is no longer usable, after this call
+ /// this minijail object is invalid.
pub unsafe fn fork(&self, inheritable_fds: Option<&[RawFd]>) -> Result<pid_t> {
let m: Vec<(RawFd, RawFd)> = inheritable_fds
.unwrap_or(&[])
@@ -1000,7 +1007,8 @@ impl Minijail {
}
impl Drop for Minijail {
- /// Frees the Minijail created in Minijail::new.
+ /// Frees the Minijail created in Minijail::new. This will not terminate the
+ /// minijailed process.
fn drop(&mut self) {
unsafe {
// Destroys the minijail's memory. It is safe to do here because all references to
@@ -1189,7 +1197,7 @@ fi
#[test]
fn runnable_fd_success() {
let bin_file = File::open("/bin/true").unwrap();
- // On Chrome OS targets /bin/true is actually a script, so drop CLOEXEC to prevent ENOENT.
+ // On ChromeOS targets /bin/true is actually a script, so drop CLOEXEC to prevent ENOENT.
clear_cloexec(&bin_file).unwrap();
let j = Minijail::new().unwrap();
diff --git a/rust/minijail/tests/fork_remap.rs b/rust/minijail/tests/fork_remap.rs
index 6cf3415..21f7388 100644
--- a/rust/minijail/tests/fork_remap.rs
+++ b/rust/minijail/tests/fork_remap.rs
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium OS Authors. All rights reserved.
+// Copyright 2021 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/scoped_minijail.h b/scoped_minijail.h
index 38f1a91..160cd50 100644
--- a/scoped_minijail.h
+++ b/scoped_minijail.h
@@ -1,4 +1,4 @@
-/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+/* Copyright 2016 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
diff --git a/signal_handler.c b/signal_handler.c
index 175c9eb..77b32ca 100644
--- a/signal_handler.c
+++ b/signal_handler.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright 2012 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
diff --git a/signal_handler.h b/signal_handler.h
index 756273f..2b08018 100644
--- a/signal_handler.h
+++ b/signal_handler.h
@@ -1,5 +1,5 @@
/* signal_handler.h
- * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Copyright 2012 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
diff --git a/syscall_filter.c b/syscall_filter.c
index de5441c..c986f3c 100644
--- a/syscall_filter.c
+++ b/syscall_filter.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright 2012 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -34,21 +34,21 @@ int seccomp_can_softfail(void)
int str_to_op(const char *op_str)
{
- if (!strcmp(op_str, "==")) {
+ if (streq(op_str, "==")) {
return EQ;
- } else if (!strcmp(op_str, "!=")) {
+ } else if (streq(op_str, "!=")) {
return NE;
- } else if (!strcmp(op_str, "<")) {
+ } else if (streq(op_str, "<")) {
return LT;
- } else if (!strcmp(op_str, "<=")) {
+ } else if (streq(op_str, "<=")) {
return LE;
- } else if (!strcmp(op_str, ">")) {
+ } else if (streq(op_str, ">")) {
return GT;
- } else if (!strcmp(op_str, ">=")) {
+ } else if (streq(op_str, ">=")) {
return GE;
- } else if (!strcmp(op_str, "&")) {
+ } else if (streq(op_str, "&")) {
return SET;
- } else if (!strcmp(op_str, "in")) {
+ } else if (streq(op_str, "in")) {
return IN;
} else {
return 0;
@@ -705,7 +705,7 @@ int compile_file(const char *filename, FILE *policy_file,
* For each syscall, add either a simple ALLOW,
* or an arg filter block.
*/
- if (strcmp(policy_line, "1") == 0) {
+ if (streq(policy_line, "1")) {
/* Add simple ALLOW. */
append_allow_syscall(head, nr);
} else {
@@ -742,8 +742,8 @@ int compile_file(const char *filename, FILE *policy_file,
}
/* Reuse |line| in the next getline() call. */
}
- /* getline(3) returned -1. This can mean EOF or the below errors. */
- if (errno == EINVAL || errno == ENOMEM) {
+ /* getline(3) returned -1. This can mean EOF or an error. */
+ if (!feof(policy_file)) {
if (*arg_blocks) {
free_block_list(*arg_blocks);
*arg_blocks = NULL;
diff --git a/syscall_filter.h b/syscall_filter.h
index 304f8c0..dac5c2e 100644
--- a/syscall_filter.h
+++ b/syscall_filter.h
@@ -1,5 +1,5 @@
/* syscall_filter.h
- * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Copyright 2012 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
diff --git a/syscall_filter_unittest.cc b/syscall_filter_unittest.cc
index 79755f9..c202b02 100644
--- a/syscall_filter_unittest.cc
+++ b/syscall_filter_unittest.cc
@@ -1,4 +1,4 @@
-/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+/* Copyright 2016 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
diff --git a/syscall_filter_unittest_macros.h b/syscall_filter_unittest_macros.h
index b58dd7e..3848541 100644
--- a/syscall_filter_unittest_macros.h
+++ b/syscall_filter_unittest_macros.h
@@ -1,4 +1,4 @@
-/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+/* Copyright 2016 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
diff --git a/syscall_wrapper.c b/syscall_wrapper.c
index dd6f826..dfdbfcd 100644
--- a/syscall_wrapper.c
+++ b/syscall_wrapper.c
@@ -1,4 +1,4 @@
-/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+/* Copyright 2016 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
diff --git a/syscall_wrapper.h b/syscall_wrapper.h
index 7769108..c1988ac 100644
--- a/syscall_wrapper.h
+++ b/syscall_wrapper.h
@@ -1,4 +1,4 @@
-/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+/* Copyright 2016 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
diff --git a/system.c b/system.c
index 711e29e..f112cbc 100644
--- a/system.c
+++ b/system.c
@@ -1,4 +1,4 @@
-/* Copyright 2017 The Chromium OS Authors. All rights reserved.
+/* Copyright 2017 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -284,11 +284,30 @@ int mkdir_p(const char *path, mode_t mode, bool isdir)
}
/*
+ * get_mount_flags: Obtain the mount flags of the mount where |source| lives.
+ */
+int get_mount_flags(const char *source, unsigned long *mnt_flags)
+{
+ if (mnt_flags) {
+ struct statvfs stvfs_buf;
+ int rc = statvfs(source, &stvfs_buf);
+ if (rc) {
+ rc = errno;
+ pwarn("failed to look up mount flags: source=%s",
+ source);
+ return -rc;
+ }
+ *mnt_flags = stvfs_buf.f_flag;
+ }
+ return 0;
+}
+
+/*
* setup_mount_destination: Ensures the mount target exists.
* Creates it if needed and possible.
*/
int setup_mount_destination(const char *source, const char *dest, uid_t uid,
- uid_t gid, bool bind, unsigned long *mnt_flags)
+ uid_t gid, bool bind)
{
int rc;
struct stat st_buf;
@@ -329,20 +348,6 @@ int setup_mount_destination(const char *source, const char *dest, uid_t uid,
domkdir = S_ISDIR(st_buf.st_mode) ||
(!bind && (S_ISBLK(st_buf.st_mode) ||
S_ISCHR(st_buf.st_mode)));
-
- /* If bind mounting, also grab the mount flags of the source. */
- if (bind && mnt_flags) {
- struct statvfs stvfs_buf;
- rc = statvfs(source, &stvfs_buf);
- if (rc) {
- rc = errno;
- pwarn(
- "failed to look up mount flags: source=%s",
- source);
- return -rc;
- }
- *mnt_flags = stvfs_buf.f_flag;
- }
} else {
/* The source is a relative path -- assume it's a pseudo fs. */
@@ -367,8 +372,8 @@ int setup_mount_destination(const char *source, const char *dest, uid_t uid,
if (rc)
return rc;
if (!domkdir) {
- attribute_cleanup_fd int fd = open(
- dest, O_RDWR | O_CREAT | O_CLOEXEC, 0700);
+ attribute_cleanup_fd int fd =
+ open(dest, O_RDWR | O_CREAT | O_CLOEXEC, 0700);
if (fd < 0) {
rc = errno;
pwarn("open(%s) failed", dest);
@@ -542,3 +547,21 @@ bool seccomp_filter_flags_available(unsigned int flags)
return sys_seccomp(SECCOMP_SET_MODE_FILTER, flags, NULL) != -1 ||
errno != EINVAL;
}
+
+bool is_canonical_path(const char *path)
+{
+ attribute_cleanup_str char *rp = realpath(path, NULL);
+ if (!rp) {
+ return false;
+ }
+
+ if (streq(path, rp)) {
+ return true;
+ }
+
+ size_t path_len = strlen(path);
+ size_t rp_len = strlen(rp);
+ /* If |path| has a single trailing slash, that's OK. */
+ return path_len == rp_len + 1 && strncmp(path, rp, rp_len) == 0 &&
+ path[path_len - 1] == '/';
+}
diff --git a/system.h b/system.h
index b6a9a8d..8889d9d 100644
--- a/system.h
+++ b/system.h
@@ -1,4 +1,4 @@
-/* Copyright 2017 The Chromium OS Authors. All rights reserved.
+/* Copyright 2017 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -51,8 +51,10 @@ int write_proc_file(pid_t pid, const char *content, const char *basename);
int mkdir_p(const char *path, mode_t mode, bool isdir);
+int get_mount_flags(const char *source, unsigned long *mnt_flags);
+
int setup_mount_destination(const char *source, const char *dest, uid_t uid,
- uid_t gid, bool bind, unsigned long *mnt_flags);
+ uid_t gid, bool bind);
int lookup_user(const char *user, uid_t *uid, gid_t *gid);
int lookup_group(const char *group, gid_t *gid);
@@ -61,6 +63,16 @@ int seccomp_ret_log_available(void);
int seccomp_ret_kill_process_available(void);
bool seccomp_filter_flags_available(unsigned int flags);
+/*
+ * is_canonical_path: checks whether @path is a canonical path.
+ * This means:
+ * -Absolute.
+ * -No symlinks.
+ * -No /./, /../, or extra '/'.
+ * -Single trailing '/' is OK.
+ */
+bool is_canonical_path(const char *path);
+
#ifdef __cplusplus
}; /* extern "C" */
#endif
diff --git a/system_unittest.cc b/system_unittest.cc
index 97c1d4e..5fa8076 100644
--- a/system_unittest.cc
+++ b/system_unittest.cc
@@ -1,4 +1,4 @@
-/* Copyright 2017 The Chromium OS Authors. All rights reserved.
+/* Copyright 2017 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -20,6 +20,7 @@
#include <string>
#include "system.h"
+#include "unittest_util.h"
namespace {
@@ -35,91 +36,6 @@ constexpr const char kValidDir[] = "/";
// A random character device that should exist.
constexpr const char kValidCharDev[] = "/dev/null";
-constexpr bool is_android() {
-#if defined(__ANDROID__)
- return true;
-#else
- return false;
-#endif
-}
-
-// Returns a template path that can be used as an argument to mkstemp / mkdtemp.
-constexpr const char* temp_path_pattern() {
- if (is_android())
- return "/data/local/tmp/minijail.tests.XXXXXX";
- else
- return "minijail.tests.XXXXXX";
-}
-
-// Recursively deletes the subtree rooted at |path|.
-bool rmdir_recursive(const std::string& path) {
- auto callback = [](const char* child, const struct stat*, int file_type,
- struct FTW*) -> int {
- if (file_type == FTW_DP) {
- if (rmdir(child) == -1) {
- fprintf(stderr, "rmdir(%s): %s", child, strerror(errno));
- return -1;
- }
- } else if (file_type == FTW_F) {
- if (unlink(child) == -1) {
- fprintf(stderr, "unlink(%s): %s", child, strerror(errno));
- return -1;
- }
- }
- return 0;
- };
-
- return nftw(path.c_str(), callback, 128, FTW_DEPTH) == 0;
-}
-
-// Creates a temporary directory that will be cleaned up upon leaving scope.
-class TemporaryDir {
- public:
- TemporaryDir() : path(temp_path_pattern()) {
- if (mkdtemp(const_cast<char*>(path.c_str())) == nullptr)
- path.clear();
- }
- ~TemporaryDir() {
- if (!is_valid())
- return;
- rmdir_recursive(path.c_str());
- }
-
- bool is_valid() const { return !path.empty(); }
-
- std::string path;
-
- private:
- TemporaryDir(const TemporaryDir&) = delete;
- TemporaryDir& operator=(const TemporaryDir&) = delete;
-};
-
-// Creates a named temporary file that will be cleaned up upon leaving scope.
-class TemporaryFile {
- public:
- TemporaryFile() : path(temp_path_pattern()) {
- int fd = mkstemp(const_cast<char*>(path.c_str()));
- if (fd == -1) {
- path.clear();
- return;
- }
- close(fd);
- }
- ~TemporaryFile() {
- if (!is_valid())
- return;
- unlink(path.c_str());
- }
-
- bool is_valid() const { return !path.empty(); }
-
- std::string path;
-
- private:
- TemporaryFile(const TemporaryFile&) = delete;
- TemporaryFile& operator=(const TemporaryFile&) = delete;
-};
-
} // namespace
TEST(secure_noroot_set_and_locked, zero_mask) {
@@ -173,7 +89,7 @@ TEST(write_pid_to_path, basic) {
char data[6] = {};
EXPECT_EQ(5u, fread(data, 1, sizeof(data), fp));
fclose(fp);
- EXPECT_EQ(0, strcmp(data, "1234\n"));
+ EXPECT_STREQ(data, "1234\n");
}
// If the destination exists, there's nothing to do.
@@ -214,18 +130,13 @@ TEST(mkdir_p, create_tree) {
EXPECT_EQ(true, S_ISDIR(st.st_mode));
}
-// If the destination exists, there's nothing to do.
-TEST(setup_mount_destination, dest_exists) {
- // Pick some paths that should always exist. We pass in invalid pointers
- // for other args so we crash if the dest check doesn't short circuit.
- EXPECT_EQ(0, setup_mount_destination(nullptr, kValidDir, 0, 0, false,
- nullptr));
- EXPECT_EQ(0, setup_mount_destination(nullptr, "/proc", 0, 0, true, nullptr));
- EXPECT_EQ(0, setup_mount_destination(nullptr, "/dev", 0, 0, false, nullptr));
+// Return success on NULL pointer.
+TEST(get_mount_flags, null_ptr) {
+ ASSERT_EQ(0, get_mount_flags("/proc", nullptr));
}
-// Mount flags should be obtained for bind-mounts.
-TEST(setup_mount_destination, mount_flags) {
+// Successfully obtain mount flags.
+TEST(get_mount_flags, mount_flags) {
struct statvfs stvfs_buf;
ASSERT_EQ(0, statvfs("/proc", &stvfs_buf));
@@ -233,26 +144,34 @@ TEST(setup_mount_destination, mount_flags) {
ASSERT_TRUE(dir.is_valid());
unsigned long mount_flags = -1;
- // Passing -1 for user ID/group ID tells chown to make no changes.
- std::string proc = dir.path + "/proc";
- EXPECT_EQ(0, setup_mount_destination("/proc", proc.c_str(), -1, -1, true,
- &mount_flags));
+ ASSERT_EQ(0, get_mount_flags("/proc", &mount_flags));
EXPECT_EQ(stvfs_buf.f_flag, mount_flags);
- EXPECT_EQ(0, rmdir(proc.c_str()));
// Same thing holds for children of a mount.
mount_flags = -1;
- std::string proc_self = dir.path + "/proc_self";
- EXPECT_EQ(0, setup_mount_destination("/proc/self", proc_self.c_str(), -1, -1,
- true, &mount_flags));
+ ASSERT_EQ(0, get_mount_flags("/proc/self", &mount_flags));
EXPECT_EQ(stvfs_buf.f_flag, mount_flags);
- EXPECT_EQ(0, rmdir(proc_self.c_str()));
+}
+
+// Non-existent paths fail with the proper errno value.
+TEST(get_mount_flags, nonexistent_path) {
+ unsigned long mount_flags = -1;
+ ASSERT_EQ(-ENOENT, get_mount_flags("/does/not/exist", &mount_flags));
+}
+
+// If the destination exists, there's nothing to do.
+TEST(setup_mount_destination, dest_exists) {
+ // Pick some paths that should always exist. We pass in invalid pointers
+ // for other args so we crash if the dest check doesn't short circuit.
+ EXPECT_EQ(0, setup_mount_destination(nullptr, kValidDir, 0, 0, false));
+ EXPECT_EQ(0, setup_mount_destination(nullptr, "/proc", 0, 0, true));
+ EXPECT_EQ(0, setup_mount_destination(nullptr, "/dev", 0, 0, false));
}
// When given a bind mount where the source is relative, reject it.
TEST(setup_mount_destination, reject_relative_bind) {
// Pick a destination we know doesn't exist.
- EXPECT_NE(0, setup_mount_destination("foo", kNoSuchDir, 0, 0, true, nullptr));
+ EXPECT_NE(0, setup_mount_destination("foo", kNoSuchDir, 0, 0, true));
}
// A mount of a pseudo filesystem should make the destination dir.
@@ -262,8 +181,8 @@ TEST(setup_mount_destination, create_pseudo_fs) {
// Passing -1 for user ID/group ID tells chown to make no changes.
std::string no_chmod = dir.path + "/no_chmod";
- EXPECT_EQ(0, setup_mount_destination("none", no_chmod.c_str(), -1, -1, false,
- nullptr));
+ EXPECT_EQ(0, setup_mount_destination("none", no_chmod.c_str(), -1, -1,
+ false));
// We check it's a directory by deleting it as such.
EXPECT_EQ(0, rmdir(no_chmod.c_str()));
@@ -274,18 +193,15 @@ TEST(setup_mount_destination, create_pseudo_fs) {
if (!is_android()) {
std::string with_chmod = dir.path + "/with_chmod";
EXPECT_NE(0, setup_mount_destination("none", with_chmod.c_str(),
- UINT_MAX / 2, UINT_MAX / 2, false,
- nullptr));
+ UINT_MAX / 2, UINT_MAX / 2, false));
}
}
// If the source path does not exist, we should error out.
TEST(setup_mount_destination, missing_source) {
// The missing dest path is so we can exercise the source logic.
- EXPECT_NE(0, setup_mount_destination(kNoSuchDir, kNoSuchDir, 0, 0, false,
- nullptr));
- EXPECT_NE(0, setup_mount_destination(kNoSuchDir, kNoSuchDir, 0, 0, true,
- nullptr));
+ EXPECT_NE(0, setup_mount_destination(kNoSuchDir, kNoSuchDir, 0, 0, false));
+ EXPECT_NE(0, setup_mount_destination(kNoSuchDir, kNoSuchDir, 0, 0, true));
}
// A bind mount of a directory should create the destination dir.
@@ -296,7 +212,7 @@ TEST(setup_mount_destination, create_bind_dir) {
// Passing -1 for user ID/group ID tells chown to make no changes.
std::string child_dir = dir.path + "/child_dir";
EXPECT_EQ(0, setup_mount_destination(kValidDir, child_dir.c_str(), -1, -1,
- true, nullptr));
+ true));
// We check it's a directory by deleting it as such.
EXPECT_EQ(0, rmdir(child_dir.c_str()));
}
@@ -309,7 +225,7 @@ TEST(setup_mount_destination, create_bind_file) {
// Passing -1 for user ID/group ID tells chown to make no changes.
std::string child_file = dir.path + "/child_file";
EXPECT_EQ(0, setup_mount_destination(kValidFile, child_file.c_str(), -1, -1,
- true, nullptr));
+ true));
// We check it's a file by deleting it as such.
EXPECT_EQ(0, unlink(child_file.c_str()));
}
@@ -322,7 +238,7 @@ TEST(setup_mount_destination, create_char_dev) {
// Passing -1 for user ID/group ID tells chown to make no changes.
std::string child_dev = dir.path + "/child_dev";
EXPECT_EQ(0, setup_mount_destination(kValidCharDev, child_dev.c_str(), -1, -1,
- false, nullptr));
+ false));
// We check it's a directory by deleting it as such.
EXPECT_EQ(0, rmdir(child_dev.c_str()));
}
@@ -331,3 +247,19 @@ TEST(seccomp_actions_available, smoke) {
seccomp_ret_log_available();
seccomp_ret_kill_process_available();
}
+
+TEST(is_canonical_path, basic) {
+ EXPECT_FALSE(is_canonical_path("/proc/self"));
+ EXPECT_FALSE(is_canonical_path("relative"));
+ EXPECT_FALSE(is_canonical_path("/proc/./1"));
+ EXPECT_FALSE(is_canonical_path("/proc/../proc/1"));
+
+ EXPECT_TRUE(is_canonical_path("/"));
+ EXPECT_TRUE(is_canonical_path("/proc"));
+ EXPECT_TRUE(is_canonical_path("/proc/1"));
+}
+
+TEST(is_canonical_path, trailing_slash) {
+ EXPECT_TRUE(is_canonical_path("/proc/1/"));
+ EXPECT_FALSE(is_canonical_path("/proc/1//"));
+}
diff --git a/test/landlock.conf b/test/landlock.conf
new file mode 100644
index 0000000..65ffe81
--- /dev/null
+++ b/test/landlock.conf
@@ -0,0 +1,7 @@
+% minijail-config-file v0
+
+fs-default-paths
+fs-path-ro = /
+fs-path-rx = /lib
+fs-path-rw = /tmp
+fs-path-advanced-rw = /tmp \ No newline at end of file
diff --git a/test/read_stdin b/test/read_stdin
index 29578a6..6200bb5 100644
--- a/test/read_stdin
+++ b/test/read_stdin
@@ -1,6 +1,6 @@
#!/bin/bash
-# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Copyright 2012 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/test_util.cc b/test_util.cc
index cb751ff..bbe0215 100644
--- a/test_util.cc
+++ b/test_util.cc
@@ -1,4 +1,4 @@
-/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+/* Copyright 2021 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
diff --git a/test_util.h b/test_util.h
index e915086..7f923ed 100644
--- a/test_util.h
+++ b/test_util.h
@@ -1,5 +1,5 @@
/* test_util.h
- * Copyright 2021 The Chromium OS Authors. All rights reserved.
+ * Copyright 2021 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
diff --git a/testrunner.cc b/testrunner.cc
index 162f0e5..70010f2 100644
--- a/testrunner.cc
+++ b/testrunner.cc
@@ -1,4 +1,4 @@
-/* Copyright 2017 The Chromium OS Authors. All rights reserved.
+/* Copyright 2017 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
diff --git a/tools/Android.bp b/tools/Android.bp
index 71bb82d..62b3a88 100644
--- a/tools/Android.bp
+++ b/tools/Android.bp
@@ -31,14 +31,6 @@ python_binary_host {
"compiler.py",
"parser.py",
],
- version: {
- py2: {
- enabled: false,
- },
- py3: {
- enabled: true,
- },
- },
}
python_test_host {
@@ -53,14 +45,6 @@ python_test_host {
data: [
"testdata/arch_64.json",
],
- version: {
- py2: {
- enabled: false,
- },
- py3: {
- enabled: true,
- },
- },
}
python_test_host {
@@ -76,14 +60,6 @@ python_test_host {
data: [
"testdata/arch_64.json",
],
- version: {
- py2: {
- enabled: false,
- },
- py3: {
- enabled: true,
- },
- },
}
python_binary_host {
@@ -92,14 +68,6 @@ python_binary_host {
srcs: [
"generate_constants_json.py",
],
- version: {
- py2: {
- enabled: false,
- },
- py3: {
- enabled: true,
- },
- },
}
diff --git a/tools/generate_constants_json.py b/tools/generate_constants_json.py
index 6b38022..005fff8 100755
--- a/tools/generate_constants_json.py
+++ b/tools/generate_constants_json.py
@@ -38,6 +38,21 @@ _TABLE_ENTRY_RE = re.compile(
# number.
_TABLE_ENTRY_CONTENTS = re.compile(r'.*?(null|@[a-zA-Z0-9.]+).* (-?\d+)')
+# When testing clang-r458909, we found a new constant_entry pattern:
+# %struct.constant_entry { ptr @.str.894, i32 ptrtoint (ptr @.str.895 to i32) },
+# For the same constant, current clang-r458507 generates:
+# %struct.constant_entry { i8* getelementptr inbounds
+# ([19 x i8], [19 x i8]* @.str.894, i32 0, i32 0),
+# i32 ptrtoint ([9 x i8]* @.str.895 to i32) },
+# This is for a char* constant defined in linux-x86/libconstants.gen.c:
+# { "FS_KEY_DESC_PREFIX", (unsigned long) FS_KEY_DESC_PREFIX },
+# and FS_KEY_DESC_PREFIX is defined as a char* "fscrypt:"
+# Current output for that constant in constants.json is:
+# "FS_KEY_DESC_PREFIX": 0,
+# but that value does not seem to be useful or accurate.
+# So here we define a pattern to ignore such pointer constants:
+_IGNORED_ENTRY_CONTENTS = re.compile(r'.*? ptrto.* \(.*\)')
+
ParseResults = collections.namedtuple('ParseResults', ['table_name',
'table_entries'])
@@ -65,6 +80,8 @@ def parse_llvm_ir(ir):
for entry in _TABLE_ENTRY_RE.findall(line):
groups = _TABLE_ENTRY_CONTENTS.match(entry)
if not groups:
+ if _IGNORED_ENTRY_CONTENTS.match(entry):
+ continue
raise ValueError('Failed to parse table entry %r' % entry)
name, value = groups.groups()
if name == 'null':
@@ -113,6 +130,8 @@ def main(argv=None):
constants_json['arch_name'] = 'arm64'
elif constants_json['arch_nr'] == 0x40000028:
constants_json['arch_name'] = 'arm'
+ elif constants_json['arch_nr'] == 0xC00000F3:
+ constants_json['arch_name'] = 'riscv64'
else:
raise ValueError('Unknown architecture: 0x%08X' %
constants_json['arch_nr'])
diff --git a/tools/repo_upload_warning b/tools/repo_upload_warning
new file mode 100755
index 0000000..3333eba
--- /dev/null
+++ b/tools/repo_upload_warning
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+
+if git log -n 1 --format='%B' $1 | grep -q -E "^Ignore-Upstream-First: .+" ; then
+ # Change is explicitly marked as ok to skip upstream
+ exit 0
+elif git log -n 1 --format='%s' $1 | grep -q -E "^(UPSTREAM|Upstream): .+" ; then
+ # Change is explicitly marked as coming from the upstream
+ exit 0
+fi
+
+echo "WARNING: Here is not the upstream."
+echo ""
+echo "Do not submit changes to this repository directly. Please submit changes to upstream"
+echo "from https://chromium-review.googlesource.com/q/project:chromiumos/platform/minijail"
+echo ""
+echo "If the change is from the upstream, please prepend \"UPSTREAM: \" to the subject."
+echo ""
+echo "If indeed necessary, please add \"Ignore-Upstream-First: <reason>\" to commit message"
+echo "to bypass."
+
+exit 1
diff --git a/unittest_util.h b/unittest_util.h
new file mode 100644
index 0000000..4dcfe80
--- /dev/null
+++ b/unittest_util.h
@@ -0,0 +1,104 @@
+/* unittest_util.h
+ * Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Utility functions for unit tests.
+ */
+
+#include <errno.h>
+#include <ftw.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "util.h"
+
+namespace {
+
+constexpr bool is_android_constexpr() {
+#if defined(__ANDROID__)
+ return true;
+#else
+ return false;
+#endif
+}
+
+// Returns a template path that can be used as an argument to mkstemp / mkdtemp.
+constexpr const char* temp_path_pattern() {
+ if (is_android_constexpr())
+ return "/data/local/tmp/minijail.tests.XXXXXX";
+ else
+ return "minijail.tests.XXXXXX";
+}
+
+// Recursively deletes the subtree rooted at |path|.
+bool rmdir_recursive(const std::string& path) {
+ auto callback = [](const char* child, const struct stat*, int file_type,
+ struct FTW*) -> int {
+ if (file_type == FTW_DP) {
+ if (rmdir(child) == -1) {
+ fprintf(stderr, "rmdir(%s): %s\n", child, strerror(errno));
+ return -1;
+ }
+ } else if (file_type == FTW_F) {
+ if (unlink(child) == -1) {
+ fprintf(stderr, "unlink(%s): %s\n", child, strerror(errno));
+ return -1;
+ }
+ }
+ return 0;
+ };
+
+ return nftw(path.c_str(), callback, 128, FTW_DEPTH) == 0;
+}
+
+} // namespace
+
+// Creates a temporary directory that will be cleaned up upon leaving scope.
+class TemporaryDir {
+ public:
+ TemporaryDir() : path(temp_path_pattern()) {
+ if (mkdtemp(const_cast<char*>(path.c_str())) == nullptr)
+ path.clear();
+ }
+ ~TemporaryDir() {
+ if (!is_valid())
+ return;
+ rmdir_recursive(path.c_str());
+ }
+
+ bool is_valid() const { return !path.empty(); }
+
+ std::string path;
+
+ private:
+ TemporaryDir(const TemporaryDir&) = delete;
+ TemporaryDir& operator=(const TemporaryDir&) = delete;
+};
+
+// Creates a named temporary file that will be cleaned up upon leaving scope.
+class TemporaryFile {
+ public:
+ TemporaryFile() : path(temp_path_pattern()) {
+ int fd = mkstemp(const_cast<char*>(path.c_str()));
+ if (fd == -1) {
+ path.clear();
+ return;
+ }
+ close(fd);
+ }
+ ~TemporaryFile() {
+ if (!is_valid())
+ return;
+ unlink(path.c_str());
+ }
+
+ bool is_valid() const { return !path.empty(); }
+
+ std::string path;
+
+ private:
+ TemporaryFile(const TemporaryFile&) = delete;
+ TemporaryFile& operator=(const TemporaryFile&) = delete;
+};
diff --git a/util.c b/util.c
index f715b19..c8cf3a6 100644
--- a/util.c
+++ b/util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright 2012 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -33,42 +33,47 @@
* sendto(...) <- important
* exit_group(0) <- finish!
*/
+const char *const log_syscalls[] = {
#if defined(__x86_64__)
-#if defined(__ANDROID__)
-const char *const log_syscalls[] = {"socket", "connect", "fcntl", "writev"};
-#else
-const char *const log_syscalls[] = {"socket", "connect", "sendto", "writev"};
-#endif
+# if defined(__ANDROID__)
+ "socket", "connect", "fcntl", "writev",
+# else
+ "socket", "connect", "sendto", "writev",
+# endif
#elif defined(__i386__)
-#if defined(__ANDROID__)
-const char *const log_syscalls[] = {"socketcall", "writev", "fcntl64",
- "clock_gettime"};
-#else
-const char *const log_syscalls[] = {"socketcall", "time", "writev"};
-#endif
+# if defined(__ANDROID__)
+ "socketcall", "writev", "fcntl64", "clock_gettime",
+# else
+ "socketcall", "time", "writev",
+# endif
#elif defined(__arm__)
-#if defined(__ANDROID__)
-const char *const log_syscalls[] = {"clock_gettime", "connect", "fcntl64",
- "socket", "writev"};
-#else
-const char *const log_syscalls[] = {"socket", "connect", "gettimeofday", "send",
- "writev"};
-#endif
+# if defined(__ANDROID__)
+ "clock_gettime", "connect", "fcntl64", "socket", "writev",
+# else
+ "socket", "connect", "gettimeofday", "send", "writev",
+# endif
#elif defined(__aarch64__)
-#if defined(__ANDROID__)
-const char *const log_syscalls[] = {"connect", "fcntl", "sendto", "socket",
- "writev"};
-#else
-const char *const log_syscalls[] = {"socket", "connect", "send", "writev"};
-#endif
-#elif defined(__powerpc__) || defined(__ia64__) || defined(__hppa__) || \
- defined(__sparc__) || defined(__mips__)
-const char *const log_syscalls[] = {"socket", "connect", "send"};
+# if defined(__ANDROID__)
+ "connect", "fcntl", "sendto", "socket", "writev",
+# else
+ "socket", "connect", "send", "writev",
+# endif
+#elif defined(__hppa__) || \
+ defined(__ia64__) || \
+ defined(__mips__) || \
+ defined(__powerpc__) || \
+ defined(__sparc__)
+ "socket", "connect", "send",
#elif defined(__riscv)
-const char *const log_syscalls[] = {"socket", "connect", "sendto"};
+# if defined(__ANDROID__)
+ "connect", "fcntl", "sendto", "socket", "writev",
+# else
+ "socket", "connect", "sendto",
+# endif
#else
-#error "Unsupported platform"
+# error "Unsupported platform"
#endif
+};
const size_t log_syscalls_len = ARRAY_SIZE(log_syscalls);
@@ -161,7 +166,7 @@ int lookup_syscall(const char *name, size_t *ind)
size_t ind_tmp = 0;
const struct syscall_entry *entry = syscall_table;
for (; entry->name && entry->nr >= 0; ++entry) {
- if (!strcmp(entry->name, name)) {
+ if (streq(entry->name, name)) {
if (ind != NULL)
*ind = ind_tmp;
return entry->nr;
@@ -187,7 +192,7 @@ long int parse_single_constant(char *constant_str, char **endptr)
const struct constant_entry *entry = constant_table;
long int res = 0;
for (; entry->name; ++entry) {
- if (!strcmp(entry->name, constant_str)) {
+ if (streq(entry->name, constant_str)) {
*endptr = constant_str + strlen(constant_str);
return entry->value;
}
@@ -449,6 +454,22 @@ char *path_join(const char *external_path, const char *internal_path)
: path;
}
+bool path_is_parent(const char *parent, const char *child)
+{
+ /*
+ * -Make sure |child| starts with |parent|.
+ * -Make sure that if |child| is longer than |parent|, either:
+ * --the last character in |parent| is a path separator, or
+ * --the character immediately following |parent| in |child| is a path
+ * separator.
+ */
+ size_t parent_len = strlen(parent);
+ return strncmp(parent, child, parent_len) == 0 &&
+ (strlen(child) > parent_len ? (parent[parent_len - 1] == '/' ||
+ child[parent_len] == '/')
+ : false);
+}
+
void *consumebytes(size_t length, char **buf, size_t *buflength)
{
char *p = *buf;
diff --git a/util.h b/util.h
index 5ed9f94..c310572 100644
--- a/util.h
+++ b/util.h
@@ -1,5 +1,5 @@
/* util.h
- * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Copyright 2012 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -12,6 +12,7 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/types.h>
#include <syslog.h>
#include <unistd.h>
@@ -220,6 +221,24 @@ static inline bool seccomp_default_ret_log(void)
#endif
}
+static inline bool block_symlinks_in_bindmount_paths(void)
+{
+#if defined(BLOCK_SYMLINKS_IN_BINDMOUNT_PATHS)
+ return true;
+#else
+ return false;
+#endif
+}
+
+static inline bool block_symlinks_in_noninit_mountns_tmp(void)
+{
+#if defined(BLOCK_SYMLINKS_IN_NONINIT_MOUNTNS_TMP)
+ return true;
+#else
+ return false;
+#endif
+}
+
static inline size_t get_num_syscalls(void)
{
return syscall_table_size;
@@ -235,6 +254,14 @@ int parse_size(size_t *size, const char *sizespec);
char *strip(char *s);
/*
+ * streq: determine whether two strings are equal.
+ */
+static inline bool streq(const char *s1, const char *s2)
+{
+ return strcmp(s1, s2) == 0;
+}
+
+/*
* tokenize: locate the next token in @stringp using the @delim
* @stringp A pointer to the string to scan for tokens
* @delim The delimiter to split by
@@ -250,6 +277,13 @@ char *tokenize(char **stringp, const char *delim);
char *path_join(const char *external_path, const char *internal_path);
/*
+ * path_is_parent: checks whether @parent is a parent of @child.
+ * Note: this function does not evaluate '.' or '..' nor does it resolve
+ * symlinks.
+ */
+bool path_is_parent(const char *parent, const char *child);
+
+/*
* consumebytes: consumes @length bytes from a buffer @buf of length @buflength
* @length Number of bytes to consume
* @buf Buffer to consume from
diff --git a/util_unittest.cc b/util_unittest.cc
index b9e6dfc..b3a2350 100644
--- a/util_unittest.cc
+++ b/util_unittest.cc
@@ -1,4 +1,4 @@
-/* Copyright 2018 The Chromium OS Authors. All rights reserved.
+/* Copyright 2018 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -402,6 +402,20 @@ TEST(path_join, basic) {
free(path);
}
+TEST(path_is_parent, simple) {
+ EXPECT_TRUE(path_is_parent("/dev", "/dev/rtc"));
+ EXPECT_TRUE(path_is_parent("/dev/", "/dev/rtc"));
+ EXPECT_TRUE(path_is_parent("/sys", "/sys/power"));
+ EXPECT_TRUE(path_is_parent("/sys/power", "/sys/power/something"));
+ EXPECT_TRUE(path_is_parent("/sys", "/sys/sys/power"));
+
+ EXPECT_FALSE(path_is_parent("/dev", ""));
+ EXPECT_FALSE(path_is_parent("/dev", "/sys"));
+ EXPECT_FALSE(path_is_parent("/dev", "dev"));
+ EXPECT_FALSE(path_is_parent("/dev", "/sys/dev"));
+ EXPECT_FALSE(path_is_parent("/dev", "/device"));
+}
+
TEST(getmultiline, basic) {
std::string config =
"\n"