Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Ke Wu and committed by
Kees Cook
0ff98480 cd6c84d8

+58
+10
Documentation/admin-guide/LSM/LoadPin.rst
··· 19 19 created to toggle pinning: ``/proc/sys/kernel/loadpin/enabled``. (Having 20 20 a mutable filesystem means pinning is mutable too, but having the 21 21 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``.
+48
security/loadpin/loadpin.c
··· 45 45 } 46 46 47 47 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; 48 50 static struct super_block *pinned_root; 49 51 static DEFINE_SPINLOCK(pinned_root_spinlock); 50 52 ··· 131 129 struct super_block *load_root; 132 130 const char *origin = kernel_read_file_id_str(id); 133 131 132 + /* If the file id is excluded, ignore the pinning. */ 133 + if ((unsigned int)id < ARRAY_SIZE(ignore_read_file_id) && 134 + ignore_read_file_id[id]) { 135 + report_load(origin, file, "pinning-excluded"); 136 + return 0; 137 + } 138 + 134 139 /* This handles the older init_module API that has a NULL file. */ 135 140 if (!file) { 136 141 if (!enforce) { ··· 196 187 LSM_HOOK_INIT(kernel_load_data, loadpin_load_data), 197 188 }; 198 189 190 + static void __init parse_exclude(void) 191 + { 192 + int i, j; 193 + char *cur; 194 + 195 + /* 196 + * Make sure all the arrays stay within expected sizes. This 197 + * is slightly weird because kernel_read_file_str[] includes 198 + * READING_MAX_ID, which isn't actually meaningful here. 199 + */ 200 + BUILD_BUG_ON(ARRAY_SIZE(exclude_read_files) != 201 + ARRAY_SIZE(ignore_read_file_id)); 202 + BUILD_BUG_ON(ARRAY_SIZE(kernel_read_file_str) < 203 + ARRAY_SIZE(ignore_read_file_id)); 204 + 205 + for (i = 0; i < ARRAY_SIZE(exclude_read_files); i++) { 206 + cur = exclude_read_files[i]; 207 + if (!cur) 208 + break; 209 + if (*cur == '\0') 210 + continue; 211 + 212 + for (j = 0; j < ARRAY_SIZE(ignore_read_file_id); j++) { 213 + if (strcmp(cur, kernel_read_file_str[j]) == 0) { 214 + pr_info("excluding: %s\n", 215 + kernel_read_file_str[j]); 216 + ignore_read_file_id[j] = 1; 217 + /* 218 + * Can not break, because one read_file_str 219 + * may map to more than on read_file_id. 220 + */ 221 + } 222 + } 223 + } 224 + } 225 + 199 226 static int __init loadpin_init(void) 200 227 { 201 228 pr_info("ready to pin (currently %senforcing)\n", 202 229 enforce ? "" : "not "); 230 + parse_exclude(); 203 231 security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin"); 204 232 return 0; 205 233 } ··· 249 203 /* Should not be mutable after boot, so not listed in sysfs (perm == 0). */ 250 204 module_param(enforce, int, 0); 251 205 MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning"); 206 + module_param_array_named(exclude, exclude_read_files, charp, NULL, 0); 207 + MODULE_PARM_DESC(exclude, "Exclude pinning specific read file types");