From: Joel Granados Date: Fri, 5 Dec 2025 08:43:11 +0000 (+0100) Subject: loadpin: Implement custom proc_handler for enforce X-Git-Tag: v7.0-rc1~52^2~8 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a2564d0688db20a1ee1660f45d7823075feb12a7;p=thirdparty%2Fkernel%2Flinux.git 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 --- diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c index 273ffbd6defe1..8aeec0c4327e6 100644 --- a/security/loadpin/loadpin.c +++ b/security/loadpin/loadpin.c @@ -52,32 +52,29 @@ static DEFINE_SPINLOCK(pinned_root_spinlock); static bool deny_reading_verity_digests; #endif +// initialized to false +static bool loadpin_root_writable; #ifdef CONFIG_SYSCTL -static struct ctl_table loadpin_sysctl_table[] = { + +static int proc_handler_loadpin(const struct ctl_table *table, int dir, + void *buffer, size_t *lenp, loff_t *ppos) +{ + if (!loadpin_root_writable && SYSCTL_USER_TO_KERN(dir)) + return -EINVAL; + return proc_dointvec_minmax(table, dir, buffer, lenp, ppos); +} + +static const struct ctl_table loadpin_sysctl_table[] = { { .procname = "enforce", .data = &enforce, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = SYSCTL_ONE, + .proc_handler = proc_handler_loadpin, + .extra1 = SYSCTL_ZERO, .extra2 = SYSCTL_ONE, }, }; - -static void set_sysctl(bool is_writable) -{ - /* - * If load pinning is not enforced via a read-only block - * device, allow sysctl to change modes for testing. - */ - if (is_writable) - loadpin_sysctl_table[0].extra1 = SYSCTL_ZERO; - else - loadpin_sysctl_table[0].extra1 = SYSCTL_ONE; -} -#else -static inline void set_sysctl(bool is_writable) { } #endif static void report_writable(struct super_block *mnt_sb, bool writable) @@ -131,7 +128,6 @@ static int loadpin_check(struct file *file, enum kernel_read_file_id id) struct super_block *load_root; const char *origin = kernel_read_file_id_str(id); bool first_root_pin = false; - bool load_root_writable; /* If the file id is excluded, ignore the pinning. */ if ((unsigned int)id < ARRAY_SIZE(ignore_read_file_id) && @@ -152,7 +148,6 @@ static int loadpin_check(struct file *file, enum kernel_read_file_id id) } load_root = file->f_path.mnt->mnt_sb; - load_root_writable = sb_is_writable(load_root); /* First loaded module/firmware defines the root for all others. */ spin_lock(&pinned_root_spinlock); @@ -168,8 +163,8 @@ static int loadpin_check(struct file *file, enum kernel_read_file_id id) spin_unlock(&pinned_root_spinlock); if (first_root_pin) { - report_writable(pinned_root, load_root_writable); - set_sysctl(load_root_writable); + loadpin_root_writable = sb_is_writable(pinned_root); + report_writable(pinned_root, loadpin_root_writable); report_load(origin, file, "pinned"); }