Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolai Stange <nstange@suse.de>2018-09-05 14:08:44 +0200
committerMiroslav Benes <mbenes@suse.cz>2018-09-05 16:38:46 +0200
commita27fc643b58a3e737fc82885acc508cef0808bd0 (patch)
tree134cc82681abcdc815dd6d331d62ebc70f7158aa
parentbd113d8b6ae8a9d5bb463256923026051ee2697a (diff)
Fix for CVE-2018-10902 ("double free in midi subsystem")
Live patch for CVE-2018-10902. Upstream commit 39675f7a7c7e ("ALSA: rawmidi: Change resized buffers atomically"). KLP: CVE-2018-10902 References: bsc#1105323 CVE-2018-10902 Signed-off-by: Nicolai Stange <nstange@suse.de> Signed-off-by: Miroslav Benes <mbenes@suse.cz>
-rw-r--r--bsc1105323/livepatch_bsc1105323.c214
-rw-r--r--bsc1105323/livepatch_bsc1105323.h24
-rw-r--r--bsc1105323/patched_funcs.csv2
3 files changed, 240 insertions, 0 deletions
diff --git a/bsc1105323/livepatch_bsc1105323.c b/bsc1105323/livepatch_bsc1105323.c
new file mode 100644
index 0000000..676ef61
--- /dev/null
+++ b/bsc1105323/livepatch_bsc1105323.c
@@ -0,0 +1,214 @@
+/*
+ * livepatch_bsc1105323
+ *
+ * Fix for CVE-2018-10902, bsc#1105323
+ *
+ * Upstream commit:
+ * 39675f7a7c7e ("ALSA: rawmidi: Change resized buffers atomically")
+ *
+ * SLE12(-SP1) commit:
+ * 97b2705c10e83b61cfd8089e3afabae8c84210e4
+ *
+ * SLE12-SP2 commit:
+ * 57d39eb79ecfb8dbad9fbc3ed50f8d3a2c487275
+ *
+ * SLE12-SP3 commit:
+ * b9f77c7a236b7acdbe73a953557bdbf731de63ee ("Linux 4.4.144")
+ *
+ * SLE15 commit:
+ * 70b340bfd49f4e6328df613540bfea6f6068ff2a
+ *
+ *
+ * Copyright (c) 2018 SUSE
+ * Author: Nicolai Stange <nstange@suse.de>
+ *
+ * Based on the original Linux kernel code. Other copyrights apply.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if IS_ENABLED(CONFIG_SND_RAWMIDI)
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <sound/rawmidi.h>
+#include "livepatch_bsc1105323.h"
+#include "kallsyms_relocs.h"
+
+#if !IS_MODULE(CONFIG_SND_RAWMIDI)
+#error "Live patch supports only CONFIG_SND_RAWMIDI=m"
+#endif
+
+#define KLP_PATCHED_MODULE "snd_rawmidi"
+
+
+static int
+(*klp_snd_rawmidi_drain_output)(struct snd_rawmidi_substream *substream);
+
+static int
+(*klp_snd_rawmidi_drain_input)(struct snd_rawmidi_substream *substream);
+
+static struct klp_kallsyms_reloc klp_funcs[] = {
+ { "snd_rawmidi_drain_output", (void *)&klp_snd_rawmidi_drain_output,
+ "snd_rawmidi"},
+ { "snd_rawmidi_drain_input", (void *)&klp_snd_rawmidi_drain_input,
+ "snd_rawmidi"},
+};
+
+
+
+/* patched */
+int klp_snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
+ struct snd_rawmidi_params * params)
+{
+ /*
+ * Fix CVE-2018-10902
+ * -1 line, +1 line
+ */
+ char *newbuf, *oldbuf;
+ struct snd_rawmidi_runtime *runtime = substream->runtime;
+
+ if (substream->append && substream->use_count > 1)
+ return -EBUSY;
+ klp_snd_rawmidi_drain_output(substream);
+ if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) {
+ return -EINVAL;
+ }
+ if (params->avail_min < 1 || params->avail_min > params->buffer_size) {
+ return -EINVAL;
+ }
+ if (params->buffer_size != runtime->buffer_size) {
+ /*
+ * Fix CVE-2018-10902
+ * -2 lines, +1 line
+ */
+ newbuf = kmalloc(params->buffer_size, GFP_KERNEL);
+ if (!newbuf)
+ return -ENOMEM;
+ /*
+ * Fix CVE-2018-10902
+ * +2 lines
+ */
+ spin_lock_irq(&runtime->lock);
+ oldbuf = runtime->buffer;
+ runtime->buffer = newbuf;
+ runtime->buffer_size = params->buffer_size;
+ runtime->avail = runtime->buffer_size;
+ /*
+ * Fix CVE-2018-10902
+ * +3 lines
+ */
+ runtime->appl_ptr = runtime->hw_ptr = 0;
+ spin_unlock_irq(&runtime->lock);
+ kfree(oldbuf);
+ }
+ runtime->avail_min = params->avail_min;
+ substream->active_sensing = !params->no_active_sensing;
+ return 0;
+}
+
+/* patched */
+int klp_snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
+ struct snd_rawmidi_params * params)
+{
+ /*
+ * Fix CVE-2018-10902
+ * -1 line, +1 line
+ */
+ char *newbuf, *oldbuf;
+ struct snd_rawmidi_runtime *runtime = substream->runtime;
+
+ klp_snd_rawmidi_drain_input(substream);
+ if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) {
+ return -EINVAL;
+ }
+ if (params->avail_min < 1 || params->avail_min > params->buffer_size) {
+ return -EINVAL;
+ }
+ if (params->buffer_size != runtime->buffer_size) {
+ /*
+ * Fix CVE-2018-10902
+ * -2 lines, +1 line
+ */
+ newbuf = kmalloc(params->buffer_size, GFP_KERNEL);
+ if (!newbuf)
+ return -ENOMEM;
+ /*
+ * Fix CVE-2018-10902
+ * +2 lines
+ */
+ spin_lock_irq(&runtime->lock);
+ oldbuf = runtime->buffer;
+ runtime->buffer = newbuf;
+ runtime->buffer_size = params->buffer_size;
+ /*
+ * Fix CVE-2018-10902
+ * +3 lines
+ */
+ runtime->appl_ptr = runtime->hw_ptr = 0;
+ spin_unlock_irq(&runtime->lock);
+ kfree(oldbuf);
+ }
+ runtime->avail_min = params->avail_min;
+ return 0;
+}
+
+
+
+static int klp_patch_bsc1105323_module_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct module *mod = data;
+ int ret;
+
+ if (action != MODULE_STATE_COMING || strcmp(mod->name, KLP_PATCHED_MODULE))
+ return 0;
+
+ ret = __klp_resolve_kallsyms_relocs(klp_funcs, ARRAY_SIZE(klp_funcs));
+ WARN(ret, "livepatch: delayed kallsyms lookup failed. System is broken and can crash.\n");
+
+ return ret;
+}
+
+static struct notifier_block klp_patch_bsc1105323_module_nb = {
+ .notifier_call = klp_patch_bsc1105323_module_notify,
+ .priority = INT_MIN+1,
+};
+
+int livepatch_bsc1105323_init(void)
+{
+ int ret;
+
+ mutex_lock(&module_mutex);
+ if (find_module(KLP_PATCHED_MODULE)) {
+ ret = __klp_resolve_kallsyms_relocs(klp_funcs,
+ ARRAY_SIZE(klp_funcs));
+ if (ret)
+ goto out;
+ }
+
+ ret = register_module_notifier(&klp_patch_bsc1105323_module_nb);
+out:
+ mutex_unlock(&module_mutex);
+ return ret;
+}
+
+void livepatch_bsc1105323_cleanup(void)
+{
+ unregister_module_notifier(&klp_patch_bsc1105323_module_nb);
+}
+
+#endif /* IS_ENABLED(CONFIG_SND_RAWMIDI) */
diff --git a/bsc1105323/livepatch_bsc1105323.h b/bsc1105323/livepatch_bsc1105323.h
new file mode 100644
index 0000000..da420b8
--- /dev/null
+++ b/bsc1105323/livepatch_bsc1105323.h
@@ -0,0 +1,24 @@
+#ifndef _LIVEPATCH_BSC1105323_H
+#define _LIVEPATCH_BSC1105323_H
+
+#if IS_ENABLED(CONFIG_SND_RAWMIDI)
+
+int livepatch_bsc1105323_init(void);
+void livepatch_bsc1105323_cleanup(void);
+
+struct snd_rawmidi_substream;
+struct snd_rawmidi_params;
+
+int klp_snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
+ struct snd_rawmidi_params * params);
+int klp_snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
+ struct snd_rawmidi_params * params);
+
+#else /* !IS_ENABLED(CONFIG_SND_RAWMIDI) */
+
+static inline int livepatch_bsc1105323_init(void) { return 0; }
+
+static inline void livepatch_bsc1105323_cleanup(void) {}
+
+#endif /* IS_ENABLED(CONFIG_SND_RAWMIDI) */
+#endif /* _LIVEPATCH_BSC1105323_H */
diff --git a/bsc1105323/patched_funcs.csv b/bsc1105323/patched_funcs.csv
new file mode 100644
index 0000000..94c9839
--- /dev/null
+++ b/bsc1105323/patched_funcs.csv
@@ -0,0 +1,2 @@
+snd_rawmidi snd_rawmidi_output_params klp_snd_rawmidi_output_params IS_ENABLED(CONFIG_SND_RAWMIDI)
+snd_rawmidi snd_rawmidi_input_params klp_snd_rawmidi_input_params IS_ENABLED(CONFIG_SND_RAWMIDI)