diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-11 17:42:44 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-11 17:42:44 -0400 |
commit | c079512aad9718c12c6bb1b661880b15a73dfd69 (patch) | |
tree | b8cb70b4d40102bb806287fe7592b713e032a16c | |
parent | 6b44fccdb8cdcc7c1df522529307566aa89a4ab1 (diff) | |
parent | 0ff9848067b7b950a4ed70de7f5028600a2157e3 (diff) |
Merge tag 'loadpin-v5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux
Pull security/loadpin updates from Kees Cook:
- Allow exclusion of specific file types (Ke Wu)
* tag 'loadpin-v5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
security/loadpin: Allow to exclude specific file types
-rw-r--r-- | Documentation/admin-guide/LSM/LoadPin.rst | 10 | ||||
-rw-r--r-- | security/loadpin/loadpin.c | 48 |
2 files changed, 58 insertions, 0 deletions
diff --git a/Documentation/admin-guide/LSM/LoadPin.rst b/Documentation/admin-guide/LSM/LoadPin.rst index 32070762d24c..716ad9b23c9a 100644 --- a/Documentation/admin-guide/LSM/LoadPin.rst +++ b/Documentation/admin-guide/LSM/LoadPin.rst | |||
@@ -19,3 +19,13 @@ block device backing the filesystem is not read-only, a sysctl is | |||
19 | created to toggle pinning: ``/proc/sys/kernel/loadpin/enabled``. (Having | 19 | created to toggle pinning: ``/proc/sys/kernel/loadpin/enabled``. (Having |
20 | a mutable filesystem means pinning is mutable too, but having the | 20 | a mutable filesystem means pinning is mutable too, but having the |
21 | sysctl allows for easy testing on systems with a mutable filesystem.) | 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``. | ||
diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c index 79131efa9634..81519c804888 100644 --- a/security/loadpin/loadpin.c +++ b/security/loadpin/loadpin.c | |||
@@ -37,6 +37,8 @@ static void report_load(const char *origin, struct file *file, char *operation) | |||
37 | } | 37 | } |
38 | 38 | ||
39 | static int enforce = IS_ENABLED(CONFIG_SECURITY_LOADPIN_ENFORCE); | 39 | static int enforce = IS_ENABLED(CONFIG_SECURITY_LOADPIN_ENFORCE); |
40 | static char *exclude_read_files[READING_MAX_ID]; | ||
41 | static int ignore_read_file_id[READING_MAX_ID] __ro_after_init; | ||
40 | static struct super_block *pinned_root; | 42 | static struct super_block *pinned_root; |
41 | static DEFINE_SPINLOCK(pinned_root_spinlock); | 43 | static DEFINE_SPINLOCK(pinned_root_spinlock); |
42 | 44 | ||
@@ -121,6 +123,13 @@ static int loadpin_read_file(struct file *file, enum kernel_read_file_id id) | |||
121 | struct super_block *load_root; | 123 | struct super_block *load_root; |
122 | const char *origin = kernel_read_file_id_str(id); | 124 | const char *origin = kernel_read_file_id_str(id); |
123 | 125 | ||
126 | /* If the file id is excluded, ignore the pinning. */ | ||
127 | if ((unsigned int)id < ARRAY_SIZE(ignore_read_file_id) && | ||
128 | ignore_read_file_id[id]) { | ||
129 | report_load(origin, file, "pinning-excluded"); | ||
130 | return 0; | ||
131 | } | ||
132 | |||
124 | /* This handles the older init_module API that has a NULL file. */ | 133 | /* This handles the older init_module API that has a NULL file. */ |
125 | if (!file) { | 134 | if (!file) { |
126 | if (!enforce) { | 135 | if (!enforce) { |
@@ -179,10 +188,47 @@ static struct security_hook_list loadpin_hooks[] __lsm_ro_after_init = { | |||
179 | LSM_HOOK_INIT(kernel_load_data, loadpin_load_data), | 188 | LSM_HOOK_INIT(kernel_load_data, loadpin_load_data), |
180 | }; | 189 | }; |
181 | 190 | ||
191 | static void __init parse_exclude(void) | ||
192 | { | ||
193 | int i, j; | ||
194 | char *cur; | ||
195 | |||
196 | /* | ||
197 | * Make sure all the arrays stay within expected sizes. This | ||
198 | * is slightly weird because kernel_read_file_str[] includes | ||
199 | * READING_MAX_ID, which isn't actually meaningful here. | ||
200 | */ | ||
201 | BUILD_BUG_ON(ARRAY_SIZE(exclude_read_files) != | ||
202 | ARRAY_SIZE(ignore_read_file_id)); | ||
203 | BUILD_BUG_ON(ARRAY_SIZE(kernel_read_file_str) < | ||
204 | ARRAY_SIZE(ignore_read_file_id)); | ||
205 | |||
206 | for (i = 0; i < ARRAY_SIZE(exclude_read_files); i++) { | ||
207 | cur = exclude_read_files[i]; | ||
208 | if (!cur) | ||
209 | break; | ||
210 | if (*cur == '\0') | ||
211 | continue; | ||
212 | |||
213 | for (j = 0; j < ARRAY_SIZE(ignore_read_file_id); j++) { | ||
214 | if (strcmp(cur, kernel_read_file_str[j]) == 0) { | ||
215 | pr_info("excluding: %s\n", | ||
216 | kernel_read_file_str[j]); | ||
217 | ignore_read_file_id[j] = 1; | ||
218 | /* | ||
219 | * Can not break, because one read_file_str | ||
220 | * may map to more than on read_file_id. | ||
221 | */ | ||
222 | } | ||
223 | } | ||
224 | } | ||
225 | } | ||
226 | |||
182 | static int __init loadpin_init(void) | 227 | static int __init loadpin_init(void) |
183 | { | 228 | { |
184 | pr_info("ready to pin (currently %senforcing)\n", | 229 | pr_info("ready to pin (currently %senforcing)\n", |
185 | enforce ? "" : "not "); | 230 | enforce ? "" : "not "); |
231 | parse_exclude(); | ||
186 | security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin"); | 232 | security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin"); |
187 | return 0; | 233 | return 0; |
188 | } | 234 | } |
@@ -195,3 +241,5 @@ DEFINE_LSM(loadpin) = { | |||
195 | /* Should not be mutable after boot, so not listed in sysfs (perm == 0). */ | 241 | /* Should not be mutable after boot, so not listed in sysfs (perm == 0). */ |
196 | module_param(enforce, int, 0); | 242 | module_param(enforce, int, 0); |
197 | MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning"); | 243 | MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning"); |
244 | module_param_array_named(exclude, exclude_read_files, charp, NULL, 0); | ||
245 | MODULE_PARM_DESC(exclude, "Exclude pinning specific read file types"); | ||