I'm responding to the original question, how can a kernel module access files in the procfs
.
How a Kernel Module Accesses Files in Special Filesystems
I found the following to be a useful reference:
https://elixir.bootlin.com/linux/latest/source/fs/proc/proc_sysctl.c#L1790
I think it's setting sysctl
values from the kernel command line. The sequence appears to be as follows:
A. Mount the procfs
filesystem
proc_fs_type = get_fs_type("proc");
*proc_mnt = kern_mount(proc_fs_type);
B. Open the file at a path relative to the root of the procfs
file = file_open_root((*proc_mnt)->mnt_root, *proc_mnt, path, O_WRONLY, 0);
C. Read/Write the file
int kernel_read_file(struct file *file, loff_t offset, void **buf, size_t buf_size, size_t *file_size, enum kernel_read_file_id id)
wret = kernel_write(file, val, len, &pos);
D. Close the file
err = filp_close(file, NULL);
D. Cleanup the filesystem mount
kern_unmount(proc_mnt);
put_filesystem(proc_fs_type);
Should a Kernel Module Access Files in Special Filesystems
Yes, procfs
mostly provides user space with read/write access to kernel-level data. Since a kernel module runs in the kernel, if a more direct sequence of API calls exist that allow the module to access such data, use of such API would be preferred as it is likely much cleaner, less code, and more efficient.
However, a dynamically-loaded kernel module doesn't have (clean) direct access to all symbols (or data structures) in the kernel.
A kernel module can only access functions and variables that are
Cases where a kernel module needs to access data that is not exposed through such EXPORTED
API but accessible through files in procfs
or any other special filesystem seem like legitimate cases for accessing such files from kernel modules.
As a general design principle, it is my understanding, that the kernel aims to implement mechanisms without forcing a particular policy. Any feature implemented in a way that forces a policy where user-space has access to data, but a kernel module does not is poorly designed.
Kernel module code, by design, run at the same privilege level as the rest of the kernel. There is no fool-proof way to deny a kernel module access to any data that any other part of the kernel can access. Any such attempts can be circumvented with beautifully ugly hacks.
As an extreme example, on x86 machines, the kernel module can use in-line assembly to directly access control registers, walk page tables, and have it's way with any region of memory it so desires. The same goes for interrupt and exception handlers.