Snap for 10453563 from d3e36182e87f07b0e0bfaa6d14c8950a1c43bdfd to mainline-art-release

Change-Id: Ia53f39b4894ed6f9103569507680453fff81ada0
diff --git a/Android.bp b/Android.bp
index 0a80f77..fc25a10 100644
--- a/Android.bp
+++ b/Android.bp
@@ -52,6 +52,7 @@
 
 libminijailSrcFiles = [
     "bpf.c",
+    "landlock_util.c",
     "libminijail.c",
     "signal_handler.c",
     "syscall_filter.c",
@@ -74,10 +75,10 @@
         "-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 @@
         },
     },
     data: ["test/*"],
+    test_options: {
+        tags: ["no-remote"],
+    }
 }
 
 
@@ -550,55 +554,3 @@
     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 @@
 ## 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 @@
 [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 @@
 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 @@
 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 @@
 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 @@
 
 
 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 @@
 
 [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 @@
 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 @@
 
 ## 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 @@
 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 @@
 * [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 @@
 
 ## 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 @@
 
 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 @@
 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 @@
 	}
 	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 @@
 
 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 @@
 	/*
 	 * 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 @@
 #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 *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 @@
 	 * 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_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 @@
 	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 *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_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 @@
 		 *    "/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 @@
 	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 @@
 		 * 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 @@
 {
 	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 @@
 	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 @@
 {
 	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 @@
 			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 @@
 		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 @@
 		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 @@
 	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 @@
 		 */
 		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 @@
 		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_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_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 @@
 
 /*
  * 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 @@
   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 @@
     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 @@
     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 @@
   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 @@
   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 @@
   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 @@
        {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 @@
       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 @@
       // 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 @@
   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 @@
 .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 @@
 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 @@
 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 @@
 	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 @@
 	}
 	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 @@
 		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 @@
 {
 	/* 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 @@
 			*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 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 @@
 	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 @@
     {"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 @@
 "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 @@
 	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 @@
 			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 @@
 				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 @@
 		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 @@
   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 @@
   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 @@
     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 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 @@
     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 @@
     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 @@
     ) -> ::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 @@
     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 @@
     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 @@
             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 @@
     }
     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 @@
     }
     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 @@
     ///
     /// 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 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 @@
     #[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 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 @@
 		 * 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 @@
 		}
 		/* 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 @@
 }
 
 /*
+ * 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 @@
 		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 @@
 	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 @@
 	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 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_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 @@
 // 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 @@
   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 @@
   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 @@
   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 @@
 
   // 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 @@
   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 @@
   // 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 @@
   // 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 @@
   // 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 @@
   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 @@
         "compiler.py",
         "parser.py",
     ],
-    version: {
-        py2: {
-            enabled: false,
-        },
-        py3: {
-            enabled: true,
-        },
-    },
 }
 
 python_test_host {
@@ -53,14 +45,6 @@
     data: [
         "testdata/arch_64.json",
     ],
-    version: {
-        py2: {
-            enabled: false,
-        },
-        py3: {
-            enabled: true,
-        },
-    },
 }
 
 python_test_host {
@@ -76,14 +60,6 @@
     data: [
         "testdata/arch_64.json",
     ],
-    version: {
-        py2: {
-            enabled: false,
-        },
-        py3: {
-            enabled: true,
-        },
-    },
 }
 
 python_binary_host {
@@ -92,14 +68,6 @@
     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 @@
 # 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 @@
             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 @@
         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 @@
 	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 @@
 	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 @@
 		   : 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 @@
 #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 @@
 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 *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 @@
   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"