Linux kernel: log all file access - linux-kernel

On a very constrained embedded Linux system, I wish to log all files that are opened/mapped/whatever for read and or write. In other words, all files that are accessed at least once. What would be the best approach? Because of "some" constraints, I would prefer NOT to modify/hack the file system, init scripts and the user-space level... I think that I would prefer to do things in the kernel. Even an insertion of printk in the right functions would be acceptable. If that matters, I'm using an ext3 filesystem.

Answering my own question. Patching the kernel file system driver is a working solution:
char *buf = (char*)__get_free_page(GFP_USER);
char *name = dentry_path_raw(file->f_dentry, buf, PAGE_SIZE);
printk("FILE OPEN read: %d write: %d %s\n", file->f_mode & FMODE_READ, file->f_mode & FMODE_WRITE, name);
free_page((unsigned long)buf);

Related

how to print debug from both user-space and kernel-space

I am learning embedded system
I need to print debug info on the console from both user-space daemon and kernel-space , I used printf for userspace and printk(KERN_CRIT) for kernel-space.
However, the output is mixed into a mess and out of order. I guess KERN_CRIT is very fast, Is there any clean way to do the job??
Thanks so much
ftrace can resolve your problem.
In linux kernel, you can use "trace_printk" instead of "printk" to log the information, and at the same time in user space you can write the log to the file "trace_marker".
For kernel space:
#include/linux/kernel.h
...
trace_printk("Hello, kernel trace printk !\n");
...
For user space
...
trace_fd = open("trace_marker", WR_ONLY);
void trace_write(const char *fmt, ...)
{
va_list ap;
char buf[256];
int n;
if (trace_fd < 0)
return;
va_start(ap, fmt);
n = vsnprintf(buf, 256, fmt, ap);
va_end(ap);
write(trace_fd, buf, n);
}
...
trace_write("Hello, trace in user space \n");
...
You can find detail information about ftrace in the linux kernel souce code, the path is Documentation/trace/ftrace.txt.
And there are some introduce about ftraces, please focus on trace_printk and trace marker.
Debugging the kernel using Ftrace - part 1
Debugging the kernel using Ftrace - part 2
This seems like a problem of synchronising between user and kernel space. Two solutions come to mind.
First, create a debugfs or sysfs interface which holds just one value representing a binary semaphore. Before printing, user program and kernel each will first "down" the value in debugfs or sysfs file. After printing it will "up" it. This can be achieved via wrapper function or macro.
Second, create a debugfs interface. Kernel will always send its logs to that interface rather than printk them. A user space daemon can constantly check that debugfs file. The user program wanting to print will also send its logs to the user space daemon. The daemon can use appropriate synchronisation mechanism like mutex, to ensure that logs never overlap.

IOCTL from kernel space

Roughly speaking, I am trying to issue an IOCTL call from kernel space without going to user space. (All the answers I found in SO propose going through user space).
Specifically, I try to fill the entropy pool (/dev/random) from kernel space (using a kernel module) [I know the dangers of doing this ;)]. Filling up the entropy pool from user space is done using IOCTL, e.g., rngaddentropy. Is there a way to do the same thing from kernel space?
You can use ioctl from the kernel space too.
Because ioctl command RNDADDENTROPY is file-specific, its processing should be implemented in the .unlocked_ioctl operation for /dev/random file (and it is actually implemented this way, see function random_ioctl).
For file-specific ioctl commands you may call .unlocked_ioctl file's operation directly:
// Open file
struct file* f = filp_open("/dev/random", O_WRONLY, 0);
// Replace user space with kernel space
mm_segment_t old_fs = get_fs();
set_fs(KERNEL_DS);
f->f_op->unlocked_ioctl(f, RNDADDENTROPY, entropy);
// Restore space
set_fs(old_fs);
// Close file
filp_close(f, 0);

Which functions are the write/read interface for the linux bsg driver

I am not a driver writer and have a question about what functions are actually called within the bsg driver when one does a write(2)/read(2) from user-land. My CentOS system is using Linux 2.6.32. Surprisingly, though I have the sources for the build used by this CentOS system installed, the bsg.c file isn't there (huh?). So, I downloaded from kernel.org the 2.6.32 sources.
I'm looking in .../linux-2.6.32.61/block/bsg.c. For that source version, my question, is this function (on line 661) called when I call write(2) from user land?
static ssize_t
bsg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
I'm trying to track down why I'm getting EINVAL when calling write(2) in some cases but not in others when attempting to get SCSI Log Sense data. If I'm on the right track in the driver sources, the only time that EINVAL is returned to the caller is the size of the data being written to the descriptor is not evenly divisible by sizeof(sg_io_v4) (defined in /usr/include/linux/bsg.h).
Andy
Yes it is the right function. In the same file you can find this static const struct file_operations bsg_fops which is the definition of the function to use when userspace does something with the device

To understand the concept of the loader in LINUX by simple example?

As I understand, the core of a boot loader is a loader program. By loader, I mean the program that will load another program. Or to be more specific first it will load itself then the high level image - for example kernel. Instead of making a bootloader, I thought to clear my doubts on loader by running on an OS that will load another program. I do understand that every process map is entirely independent to another. So, what I am trying to do is make a simple program hello_world.c this will print the great "hello world". Now, I want to make a loader program that will load this program hello world. As I understand the crux is in two steps
Load the hello world program on the RAM - loader address.
JMP to the Entry Address.
Since, this is to understand the concept, I am using the readymade utility readelf to read the address of the hello world binary. The intention here is not to make a ELF parser.
As all the process are independent and use virtual memory. This will fail, If I use the virtual memory addresses. Now, I am stuck over here, how can I achieve this?
#include "stdio.h"
#include <sys/mman.h>
int main( int argc, char **argv)
{
char *mem_ptr;
FILE *fp;
char *val;
char *exec;
mem_ptr = (char*) malloc(10*1024);
fp = fopen("./hello_world.out","rb");
fread(mem_ptr, 10240, 1, fp);
//val = mem_ptr + 0x8048300;
printf("The mem_ptr is %p\r\n",mem_ptr);
exec = mmap(NULL, 10240, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, 0x9c65008, 0);
memcpy(mem_ptr,exec,10240);
__asm__("jmp 0x9c65008");
fclose(fp);
return 0;
}
my rep is not enough to let me add comments.
As Chris Stratton said, your problem sounds ambiguous(still after editing!). Do you want to
Write a bootloader, that will load "Hello, World" instead of real OS? <--Actual Problem is saying this OR
Write a program, that will be running on OS(so full fledged OS will be there), and load another executable using this program?<--Comments are saying this
Answers will vary a lot depending on this.
In first case, bootloader is present on BIOS, that will fetch some predefined memory block to RAM. So what u need to do is just place your Hello, World at this place. There are many things regarding this, such as chain loading and all, but not sure if this is what you want achieve. If this is NOT something you wanted, why is bootstrap tag used?
In second case, fork() + exec() will do it for you. But be sure that this way, there will be two different address spaces. If you want them in the same address space, I am doubtful about daily used OS(for normal guys). Most of the your part sounds like this is what you want to do.
If you want to ask something different than this, please edit almost entire question and ask ONLY that part.(Avoid telling why you are trying to do something, what you think you already understand etc)

Running code at memory location in my OS

I am developing an OS in C (and some assembly of course) and now I want to allow it to load/run external (placed in the RAM-disk) programs. I have assembled a test program as raw machine code with nasm using '-f bin'. Everything else i found on the subject is loading code while running Windows or Linux. I load the program into memory using the following code:
#define BIN_ADDR 0xFF000
int run_bin(char *file) //Too many hacks at the moment
{
u32int size = 0;
char *bin = open_file(file, &size);
printf("Loaded [%d] bytes of [%s] into [%X]\n", size, file, bin);
char *reloc = (char *)BIN_ADDR; //no malloc because of the org statement in the prog
memset(reloc, 0, size);
memcpy(reloc, bin, size);
jmp_to_bin();
}
and the code to jump to it:
[global jmp_to_bin]
jmp_to_bin:
jmp [bin_loc] ;also tried a plain jump
bin_loc dd 0xFF000
This caused a GPF when I ran it. I could give you the registers at the GPF and/or a screenshot if needed.
Code for my OS is at https://github.com/farlepet/retro-os
Any help would be greatly appreciated.
You use identity mapping and flat memory space, hence address 0xff000 is gonna be in the BIOS ROM range. No wonder you can't copy stuff there. Better change that address ;)

Resources