1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
From e1a02faa656420a3c32fc8733e0566c2e430e6d6 Mon Sep 17 00:00:00 2001
From: Qu Wenruo <wqu@suse.com>
Date: Sun, 3 Jan 2021 16:00:14 +0000
Subject: [PATCH] modutils: check ELF header before calling finit_module()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
finit_module() and init_module() system calls have clear specification
to only accept valid ELF image.
Although we try finit_module() on compressed modules to let the kernel
determine if it's an ELF image, but it's not ideal, especially when
newer kernel will complain when some invalid files/memory is passed in.
Treat the kernel better by just doing a very basic ELF header check
before calling finit_module().
Signed-off-by: Qu Wenruo <wqu at suse.com>
---
modutils/modprobe-small.c | 33 ++++++++++++++++++++++++++++++++-
modutils/modutils.c | 37 ++++++++++++++++++++++++++++++++++++-
2 files changed, 68 insertions(+), 2 deletions(-)
diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c
index b61651621..4763e0811 100644
--- a/modutils/modprobe-small.c
+++ b/modutils/modprobe-small.c
@@ -24,6 +24,7 @@
//kbuild:lib-$(CONFIG_MODPROBE_SMALL) += modprobe-small.o
#include "libbb.h"
+#include <elf.h> /* for ELF header magic */
/* After libbb.h, since it needs sys/types.h on some systems */
#include <sys/utsname.h> /* uname() */
#include <fnmatch.h>
@@ -249,6 +250,33 @@ static const char *moderror(int err)
}
}
+#ifdef __NR_finit_module
+/*
+ * Return:
+ * 0 on success,
+ * <0 for error.
+ *
+ * finit_module()/init_module() only accepts ELF format.
+ * Do basic ELF check to avoid calling finit_module() with compressed module.
+ */
+static int check_elf_header(int fd)
+{
+ unsigned char buf[EI_NIDENT];
+ int ret;
+
+ ret = pread(fd, buf, sizeof(buf), 0);
+ if (ret < sizeof(buf))
+ return -EIO;
+ if (buf[EI_MAG0] != ELFMAG0 ||
+ buf[EI_MAG1] != ELFMAG1 ||
+ buf[EI_MAG2] != ELFMAG2 ||
+ buf[EI_MAG3] != ELFMAG3)
+ return -EINVAL;
+ /* Other more comprehensive check will be done inside kernel */
+ return 0;
+}
+#endif
+
static int load_module(const char *fname, const char *options)
{
#if 1
@@ -272,7 +300,10 @@ static int load_module(const char *fname, const char *options)
{
int fd = open(fname, O_RDONLY | O_CLOEXEC);
if (fd >= 0) {
- r = finit_module(fd, options, 0) != 0;
+ if (!check_elf_header(fd))
+ r = finit_module(fd, options, 0) != 0;
+ else
+ r = 1;
close(fd);
}
}
diff --git a/modutils/modutils.c b/modutils/modutils.c
index f7ad5e805..037d609e4 100644
--- a/modutils/modutils.c
+++ b/modutils/modutils.c
@@ -7,6 +7,7 @@
*/
#include "modutils.h"
+#include <elf.h>
#include <sys/syscall.h>
#define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)
@@ -186,6 +187,33 @@ void* FAST_FUNC try_to_mmap_module(const char *filename, size_t *image_size_p)
}
#endif
+#ifdef __NR_finit_module
+/*
+ * Return:
+ * 0 on success,
+ * <0 for error.
+ *
+ * finit_module()/init_module() only accepts ELF format.
+ * Do basic ELF check to avoid calling finit_module() with compressed module.
+ */
+static int check_elf_header(int fd)
+{
+ unsigned char buf[EI_NIDENT];
+ int ret;
+
+ ret = pread(fd, buf, sizeof(buf), 0);
+ if (ret < sizeof(buf))
+ return -EIO;
+ if (buf[EI_MAG0] != ELFMAG0 ||
+ buf[EI_MAG1] != ELFMAG1 ||
+ buf[EI_MAG2] != ELFMAG2 ||
+ buf[EI_MAG3] != ELFMAG3)
+ return -EINVAL;
+ /* Other more comprehensive check will be done inside kernel */
+ return 0;
+}
+#endif
+
/* Return:
* 0 on success,
* -errno on open/read error,
@@ -212,12 +240,19 @@ int FAST_FUNC bb_init_module(const char *filename, const char *options)
* to only allow loading of modules off of secure storage (like a read-
* only rootfs) which needs the finit_module call. If it fails, we fall
* back to normal module loading to support compressed modules.
+ *
+ * Note that finit_module()/init_module() only accept ELF image, do
+ * basic check before calling finit_module() to avoid kernel
+ * complaining.
*/
# ifdef __NR_finit_module
{
int fd = open(filename, O_RDONLY | O_CLOEXEC);
if (fd >= 0) {
- rc = finit_module(fd, options, 0) != 0;
+ if (!check_elf_header(fd))
+ rc = finit_module(fd, options, 0) != 0;
+ else
+ rc = 1;
close(fd);
if (rc == 0)
return rc;
|