Skip to content

Commit 0ff9848

Browse files
kewu1992kees
authored andcommitted
security/loadpin: Allow to exclude specific file types
Linux kernel already provide MODULE_SIG and KEXEC_VERIFY_SIG to make sure loaded kernel module and kernel image are trusted. This patch adds a kernel command line option "loadpin.exclude" which allows to exclude specific file types from LoadPin. This is useful when people want to use different mechanisms to verify module and kernel image while still use LoadPin to protect the integrity of other files kernel loads. Signed-off-by: Ke Wu <mikewu@google.com> Reviewed-by: James Morris <jamorris@linux.microsoft.com> [kees: fix array size issue reported by Coverity via Colin Ian King] Signed-off-by: Kees Cook <keescook@chromium.org>
1 parent cd6c84d commit 0ff9848

2 files changed

Lines changed: 58 additions & 0 deletions

File tree

Documentation/admin-guide/LSM/LoadPin.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,13 @@ block device backing the filesystem is not read-only, a sysctl is
1919
created to toggle pinning: ``/proc/sys/kernel/loadpin/enabled``. (Having
2020
a mutable filesystem means pinning is mutable too, but having the
2121
sysctl allows for easy testing on systems with a mutable filesystem.)
22+
23+
It's also possible to exclude specific file types from LoadPin using kernel
24+
command line option "``loadpin.exclude``". By default, all files are
25+
included, but they can be excluded using kernel command line option such
26+
as "``loadpin.exclude=kernel-module,kexec-image``". This allows to use
27+
different mechanisms such as ``CONFIG_MODULE_SIG`` and
28+
``CONFIG_KEXEC_VERIFY_SIG`` to verify kernel module and kernel image while
29+
still use LoadPin to protect the integrity of other files kernel loads. The
30+
full list of valid file types can be found in ``kernel_read_file_str``
31+
defined in ``include/linux/fs.h``.

security/loadpin/loadpin.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ static void report_load(const char *origin, struct file *file, char *operation)
4545
}
4646

4747
static int enforce = IS_ENABLED(CONFIG_SECURITY_LOADPIN_ENFORCE);
48+
static char *exclude_read_files[READING_MAX_ID];
49+
static int ignore_read_file_id[READING_MAX_ID] __ro_after_init;
4850
static struct super_block *pinned_root;
4951
static DEFINE_SPINLOCK(pinned_root_spinlock);
5052

@@ -129,6 +131,13 @@ static int loadpin_read_file(struct file *file, enum kernel_read_file_id id)
129131
struct super_block *load_root;
130132
const char *origin = kernel_read_file_id_str(id);
131133

134+
/* If the file id is excluded, ignore the pinning. */
135+
if ((unsigned int)id < ARRAY_SIZE(ignore_read_file_id) &&
136+
ignore_read_file_id[id]) {
137+
report_load(origin, file, "pinning-excluded");
138+
return 0;
139+
}
140+
132141
/* This handles the older init_module API that has a NULL file. */
133142
if (!file) {
134143
if (!enforce) {
@@ -187,10 +196,47 @@ static struct security_hook_list loadpin_hooks[] __lsm_ro_after_init = {
187196
LSM_HOOK_INIT(kernel_load_data, loadpin_load_data),
188197
};
189198

199+
static void __init parse_exclude(void)
200+
{
201+
int i, j;
202+
char *cur;
203+
204+
/*
205+
* Make sure all the arrays stay within expected sizes. This
206+
* is slightly weird because kernel_read_file_str[] includes
207+
* READING_MAX_ID, which isn't actually meaningful here.
208+
*/
209+
BUILD_BUG_ON(ARRAY_SIZE(exclude_read_files) !=
210+
ARRAY_SIZE(ignore_read_file_id));
211+
BUILD_BUG_ON(ARRAY_SIZE(kernel_read_file_str) <
212+
ARRAY_SIZE(ignore_read_file_id));
213+
214+
for (i = 0; i < ARRAY_SIZE(exclude_read_files); i++) {
215+
cur = exclude_read_files[i];
216+
if (!cur)
217+
break;
218+
if (*cur == '\0')
219+
continue;
220+
221+
for (j = 0; j < ARRAY_SIZE(ignore_read_file_id); j++) {
222+
if (strcmp(cur, kernel_read_file_str[j]) == 0) {
223+
pr_info("excluding: %s\n",
224+
kernel_read_file_str[j]);
225+
ignore_read_file_id[j] = 1;
226+
/*
227+
* Can not break, because one read_file_str
228+
* may map to more than on read_file_id.
229+
*/
230+
}
231+
}
232+
}
233+
}
234+
190235
static int __init loadpin_init(void)
191236
{
192237
pr_info("ready to pin (currently %senforcing)\n",
193238
enforce ? "" : "not ");
239+
parse_exclude();
194240
security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin");
195241
return 0;
196242
}
@@ -203,3 +249,5 @@ DEFINE_LSM(loadpin) = {
203249
/* Should not be mutable after boot, so not listed in sysfs (perm == 0). */
204250
module_param(enforce, int, 0);
205251
MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning");
252+
module_param_array_named(exclude, exclude_read_files, charp, NULL, 0);
253+
MODULE_PARM_DESC(exclude, "Exclude pinning specific read file types");

0 commit comments

Comments
 (0)