From c933a929f07421ec747cebb24d5e620fc2b97037 Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Tue, 15 Mar 2011 09:20:44 -0400 Subject: [PATCH] =?utf8?q?Bug=2032232=20=E2=80=93=20CVE-2010-4661:=20Arbit?= =?utf8?q?rary=20kernel=20module=20load?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Validate what is passed to the mount(8) command. In particular, only allow either well-known filesystems, filesystems already loaded or filesystem explicitly allowed by the administrator via the /etc/filesystems file. See https://bugs.freedesktop.org/show_bug.cgi?id=32232 for details. Signed-off-by: David Zeuthen --- src/device.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/src/device.c b/src/device.c index 21d9530..d6595b8 100644 --- a/src/device.c +++ b/src/device.c @@ -5891,6 +5891,27 @@ static const FSMountOptions fs_mount_options[] = { "udf", udf_defaults, udf_allow, udf_allow_uid_self, udf_allow_gid_self }, }; +static const gchar *well_known_filesystems[] = +{ + "btrfs", + "ext2", + "ext3", + "ext4", + "udf", + "iso9660", + "xfs", + "jfs", + "nilfs", + "reiserfs", + "reiser4", + "msdos", + "umsdos", + "vfat", + "exfat" + "ntfs", + NULL, +}; + /* ------------------------------------------------ */ static int num_fs_mount_options = sizeof(fs_mount_options) / sizeof(FSMountOptions); @@ -6225,6 +6246,86 @@ filesystem_mount_completed_cb (DBusGMethodInvocation *context, } } +static gboolean +is_in_filesystem_file (const gchar *filesystems_file, + const gchar *fstype) +{ + gchar *filesystems; + GError *error; + gboolean ret; + gchar **lines; + guint n; + + ret = FALSE; + filesystems = NULL; + lines = NULL; + + error = NULL; + if (!g_file_get_contents (filesystems_file, + &filesystems, + NULL, /* gsize *out_length */ + &error)) + { + g_warning ("Error reading /etc/filesystems: %s (%s %d)", + error->message, + g_quark_to_string (error->domain), + error->code); + g_error_free (error); + goto out; + } + + lines = g_strsplit (filesystems, "\n", -1); + for (n = 0; lines != NULL && lines[n] != NULL && !ret; n++) + { + gchar **tokens; + gint num_tokens; + g_strdelimit (lines[n], " \t", ' '); + g_strstrip (lines[n]); + tokens = g_strsplit (lines[n], " ", -1); + num_tokens = g_strv_length (tokens); + if (num_tokens == 1 && g_strcmp0 (tokens[0], fstype) == 0) + { + ret = TRUE; + } + g_strfreev (tokens); + } + + out: + g_strfreev (lines); + g_free (filesystems); + return ret; +} + +static gboolean +is_well_known_filesystem (const gchar *fstype) +{ + gboolean ret; + guint n; + + ret = FALSE; + for (n = 0; well_known_filesystems[n] != NULL; n++) + { + if (g_strcmp0 (well_known_filesystems[n], fstype) == 0) + { + ret = TRUE; + goto out; + } + } + out: + return ret; +} + +/* this is not a very efficient implementation but it's very rarely + * called so no real point in optimizing it... + */ +static gboolean +is_allowed_filesystem (const gchar *fstype) +{ + return is_well_known_filesystem (fstype) || + is_in_filesystem_file ("/proc/filesystems", fstype) || + is_in_filesystem_file ("/etc/filesystems", fstype); +} + static void device_filesystem_mount_authorized_cb (Daemon *daemon, Device *device, @@ -6255,6 +6356,35 @@ device_filesystem_mount_authorized_cb (Daemon *daemon, remove_dir_on_unmount = FALSE; error = NULL; + /* If the user requests the filesystem type, error out unless the + * filesystem type is + * + * - well-known [1]; or + * - in the /etc/filesystems file; or + * - in the /proc/filesystems file + * + * We do this because mount(8) on Linux allows loading any arbitrary + * kernel module (when invoked as root) by passing something appropriate + * to the -t option. So we have to validate whatever we pass. + * + * See https://bugs.freedesktop.org/show_bug.cgi?id=32232 for more + * details. + * + * [1] : since /etc/filesystems may be horribly out of date and not + * contain e.g. ext4 + */ + if (filesystem_type != NULL && strlen (filesystem_type) > 0 && + g_strcmp0 (filesystem_type, "auto") != 0) + { + if (!is_allowed_filesystem (filesystem_type)) + { + throw_error (context, ERROR_FAILED, + "Requested filesystem type is neither well-known nor " + "in /proc/filesystems nor in /etc/filesystems"); + goto out; + } + } + daemon_local_get_uid (device->priv->daemon, &caller_uid, context); if (device->priv->id_usage == NULL || strcmp (device->priv->id_usage, "filesystem") != 0) -- 2.7.4