blob: e8da45363d6b5e80269aabac9e2f3175ed284bc3 [file] [log] [blame]
This patch adds dircrypto ring in the init session.
With this patch, all other processes will have access to the dircrypto ring.
When the key for decoding an encrypted ext4 directory is added, all other
processes will be able to read the decoded information, assuming they have access
rights to that directory.
Patch by Gwendal Grignou <gwendal@chromium.org>
diff --git a/configure.ac b/configure.ac
index f2f3aea..a814437 100644
--- a/configure.ac
+++ b/configure.ac
@@ -34,6 +34,37 @@ PKG_CHECK_MODULES([UDEV], [libudev >= 146], [have_udev=yes], [have_udev=no])
AM_CONDITIONAL([HAVE_UDEV], [test "$have_udev" = yes])
+AC_MSG_CHECKING([wether to add a keyring for ext4 crypto])
+AC_ARG_WITH(
+ [dircrypto-keyring],
+ [AS_HELP_STRING(
+ [--with-dircrypto-keyring],
+ [add crypto keyring for directory encryption])],
+ [],
+ [with_dircrypto_keyring=auto]
+)
+
+KEYUTILS_LIBS=""
+
+AS_IF(
+ [test "$with_dircrypto_keyring" != "no"],
+ [
+ AC_CHECK_HEADER([keyutils.h],
+ [AC_CHECK_LIB([keyutils], [keyctl_read], [have_keyutils="yes"])]
+ )
+ if test "$have_keyutils" != "yes"; then
+ if test "$with_dircrypto_keyring" = "yes"; then
+ AC_MSG_ERROR([The keyutils library (or developer files) was not found])
+ fi
+ else
+ KEYUTILS_LIBS="-lkeyutils"
+ AC_DEFINE([ADD_DIRCRYPTO_RING], 1, [Use keyutils and kernel keyring])
+ fi
+ ]
+)
+
+AC_SUBST(KEYUTILS_LIBS)
+
# Checks for header files.
AC_CHECK_HEADERS([valgrind/valgrind.h])
diff --git a/init/Makefile.am b/init/Makefile.am
index 91410b1..7069ffa 100644
--- a/init/Makefile.am
+++ b/init/Makefile.am
@@ -62,6 +62,7 @@ init_LDADD = \
$(NIH_DBUS_LIBS) \
$(DBUS_LIBS) \
$(SELINUX_LIBS) \
+ $(KEYUTILS_LIBS) \
-lrt
diff --git a/init/main.c b/init/main.c
index 10d6c27..821ed53 100644
--- a/init/main.c
+++ b/init/main.c
@@ -43,6 +43,11 @@
#include <syslog.h>
#include <unistd.h>
+#ifdef ADD_DIRCRYPTO_RING
+#include <ext2fs/ext2_fs.h>
+#include <keyutils.h>
+#endif
+
#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
#endif
@@ -125,6 +130,11 @@ main (int argc,
char **args;
char *arg_end = NULL;
int ret;
+#ifdef ADD_DIRCRYPTO_RING
+ int root_fd;
+ struct ext4_encryption_policy policy;
+ key_serial_t keyring_id;
+#endif
argv0 = argv[0];
nih_main_init (argv0);
@@ -294,6 +304,49 @@ main (int argc,
(int)getpid (), (int)getppid ());
#endif /* DEBUG */
+#ifdef ADD_DIRCRYPTO_RING
+#define EXT4_IOC_GET_ENCRYPTION_POLICY \
+ _IOW('f', 21, struct ext4_encryption_policy)
+ /*
+ * Set a keyring for the session to hold ext4 crypto keys.
+ * The session is at the root of all processes, so any users who wish
+ * to access a directory protected by ext4 crypto can access the key.
+ *
+ * Set only a session keyring when needed.
+ * A kernel patch is needed (see crbug/593893).
+ * Upstream kernel does not have the patch yet
+ * (See https://lkml.org/lkml/2016/3/17/491).
+ */
+ int fd = open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
+ if (fd == -1) {
+ nih_warn("%s: %s", _("Unable to open / directory: %s"),
+ strerror (errno));
+ ret = EINVAL;
+ } else {
+ ret = ioctl(fd, EXT4_IOC_GET_ENCRYPTION_POLICY, &policy);
+ if (ret)
+ ret = errno;
+ close(fd);
+ }
+ if (ret != EINVAL && ret != EOPNOTSUPP && ret != ENOTTY) {
+ keyring_id = add_key ("keyring", "dircrypt", 0, 0,
+ KEY_SPEC_SESSION_KEYRING);
+ if (keyring_id == -1) {
+ nih_warn ("%s: %s",
+ _("Unable to create dircrypt keyring: %s"),
+ strerror (errno));
+ } else {
+ keyctl_setperm(keyring_id,
+ KEY_POS_VIEW | KEY_POS_SEARCH |
+ KEY_POS_LINK | KEY_POS_READ |
+ KEY_USR_ALL);
+ keyctl_setperm(KEY_SPEC_SESSION_KEYRING,
+ KEY_POS_VIEW | KEY_POS_SEARCH |
+ KEY_POS_LINK | KEY_POS_READ |
+ KEY_USR_ALL);
+ }
+ }
+#endif
/* Reset the signal state and install the signal handler for those
* signals we actually want to catch; this also sets those that