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

loadpin: Implement custom proc_handler for enforce

Add a new static variable (loadpin_root_writable) to keep the
write-ability state of enforce. Remove set_sysctl and const qualify
loadpin_sysctl_table (moves into .rodata) as there is no longer need to
change the value of extra1. The new proc_handler_loadpin returns -EINVAL
when loadpin_root_writable is false and the kernel var (enforce) is
being written. The old way of modifying the write-ability of enforce
stays in loadpin_check and is still set by calling sb_is_writable.

Signed-off-by: Joel Granados <joel.granados@kernel.org>

+16 -21
+16 -21
security/loadpin/loadpin.c
··· 52 52 static bool deny_reading_verity_digests; 53 53 #endif 54 54 55 + // initialized to false 56 + static bool loadpin_root_writable; 55 57 #ifdef CONFIG_SYSCTL 56 - static struct ctl_table loadpin_sysctl_table[] = { 58 + 59 + static int proc_handler_loadpin(const struct ctl_table *table, int dir, 60 + void *buffer, size_t *lenp, loff_t *ppos) 61 + { 62 + if (!loadpin_root_writable && SYSCTL_USER_TO_KERN(dir)) 63 + return -EINVAL; 64 + return proc_dointvec_minmax(table, dir, buffer, lenp, ppos); 65 + } 66 + 67 + static const struct ctl_table loadpin_sysctl_table[] = { 57 68 { 58 69 .procname = "enforce", 59 70 .data = &enforce, 60 71 .maxlen = sizeof(int), 61 72 .mode = 0644, 62 - .proc_handler = proc_dointvec_minmax, 63 - .extra1 = SYSCTL_ONE, 73 + .proc_handler = proc_handler_loadpin, 74 + .extra1 = SYSCTL_ZERO, 64 75 .extra2 = SYSCTL_ONE, 65 76 }, 66 77 }; 67 - 68 - static void set_sysctl(bool is_writable) 69 - { 70 - /* 71 - * If load pinning is not enforced via a read-only block 72 - * device, allow sysctl to change modes for testing. 73 - */ 74 - if (is_writable) 75 - loadpin_sysctl_table[0].extra1 = SYSCTL_ZERO; 76 - else 77 - loadpin_sysctl_table[0].extra1 = SYSCTL_ONE; 78 - } 79 - #else 80 - static inline void set_sysctl(bool is_writable) { } 81 78 #endif 82 79 83 80 static void report_writable(struct super_block *mnt_sb, bool writable) ··· 128 131 struct super_block *load_root; 129 132 const char *origin = kernel_read_file_id_str(id); 130 133 bool first_root_pin = false; 131 - bool load_root_writable; 132 134 133 135 /* If the file id is excluded, ignore the pinning. */ 134 136 if ((unsigned int)id < ARRAY_SIZE(ignore_read_file_id) && ··· 148 152 } 149 153 150 154 load_root = file->f_path.mnt->mnt_sb; 151 - load_root_writable = sb_is_writable(load_root); 152 155 153 156 /* First loaded module/firmware defines the root for all others. */ 154 157 spin_lock(&pinned_root_spinlock); ··· 163 168 spin_unlock(&pinned_root_spinlock); 164 169 165 170 if (first_root_pin) { 166 - report_writable(pinned_root, load_root_writable); 167 - set_sysctl(load_root_writable); 171 + loadpin_root_writable = sb_is_writable(pinned_root); 172 + report_writable(pinned_root, loadpin_root_writable); 168 173 report_load(origin, file, "pinned"); 169 174 } 170 175