What does open() system call is transferred to Kernel Module? - linux-kernel

I am writing a character device driver. In the sample code which I found over internet, mentions that we need to attach some file operations to this character device. In those file_operations there is one function named as open. But in that open call, there are not doing anything significant.
But if we want to use this character device, first we need to open the device and then only we can read/write anything on it. So I want to know how open() call is working exactly. Here is the link I am referring for character device driver :
http://appusajeev.wordpress.com/2011/06/18/writing-a-linux-character-device-driver/

The sequence for open() on the user side is very straightforward: it will invoke sys_open() on the kernel path, will do some path resolution and permission checking, then will path everything its got to dev_open() (and would not do anything else).
dev_open() gets parameters you have passed to it through the open() system call (+ quite a lot of information specific to kernel vfs subsystem, but this is rarely of concern).
Notice, that you're getting struct file parameter passed in. It has several useful fields:
struct file {
....
struct path f_path; // path of the file passed to open()
....
unsigned int f_flags; // 'flags' + 'mode' as passed to open()
fmode_t f_mode; // 'mode' as set by kernel (FMODE_READ/FMODE_WRITE)
loff_t f_pos; // position in file used by _llseek
struct fown_struct f_owner; // opening process credentials, like uid and euid
....
}
The rest you can dig out yourself by checking out examples in the source.

Related

When is an inode's file_operations linked to its character device file_operations?

I am reading the LDD3, and I would like to understand how the device driver file operations are called at the time a system call is performed.
From my understanding, when the open system call is performed, the struct file *filp gets its f_op attribute populated from the inode's i_fop.
But when/where does the inode get its i_fop attribute populated with the cdev's ops attribute?
My intuition is that when we call cdev_add in the driver, our device is added to the cdev_map with the MAJOR and MINOR numbers, but the inode is not yet linked to the character device. The inode would only be linked either when mknod is called to create the device file in the /dev directory, or when the device file is opened through the syscall.
The struct inode's i_fop member gets set to &def_chr_fops (in "fs/char_dev.c") for character special files by the init_special_inode() function (in "fs/inode.c"). That is called by the underlying filesystem (e.g. when it is populating its directory structures and inodes when mounted or when a new character special file is created in the filesystem by mknod().
When opening the file, the struct inode's i_fop is copied to the struct file's f_op member by the do_dentry_open() function called from the vfs_open() function (in "fs/open.c"). do_dentry_open() calls the open file operation handler. For character special files, the open file operation handler from def_chr_fops is the chrdev_open() function (in "fs/char_dev.c").
The chrdev_open() function looks up the struct cdev (if any) associated with the MAJOR/MINOR device number (from the inode's i_rdev member), copies the ops member from the struct cdev to the struct file's f_op member to replace the file operations, and calls the replacement open handler if there is one.

How do I perform IOCTLs on a device in a macos kernel extension?

In my Network Kernel Extension i need to modify the firewall rules. So i need to issue some ioctl()s to the /dev/pf device - what is the best way to achieve this?
I can't seem to find any kernel APIs for opening a device and then performing the relevant ioctl commands.
EDIT: Yes i know NKEs are deprecated, but unfortunately I cannot do what I want in the Network Extension API just yet.
The function VNOP_IOCTL, declared in <bsd/vnode_if.h>, looks like it should do what you want, but I've not tried it myself:
*!
#function VNOP_IOCTL
#abstract Call down to a filesystem or device driver to execute various control operations on or request data about a file.
#discussion Ioctl controls are typically associated with devices, but they can in fact be passed
down for any file; they are used to implement any of a wide range of controls and information requests.
fcntl() calls VNOP_IOCTL for several commands, and will attempt a VNOP_IOCTL if it is passed an unknown command,
though no copyin or copyout of arguments can occur in this case--the "arg" must be an integer value.
Filesystems can define their own fcntls using this mechanism. How ioctl commands are structured
is slightly complicated; see the manual page for ioctl(2).
#param vp The vnode to execute the command on.
#param command Identifier for action to take.
#param data Pointer to data; this can be an integer constant (of 32 bits only) or an address to be read from or written to,
depending on "command." If it is an address, it is valid and resides in the kernel; callers of VNOP_IOCTL() are
responsible for copying to and from userland.
#param ctx Context against which to authenticate ioctl request.
#return 0 for success or a filesystem-specific error.
*/
extern errno_t VNOP_IOCTL(vnode_t vp, u_long command, caddr_t data, int fflag, vfs_context_t ctx);
struct vnop_select_args {
struct vnodeop_desc *a_desc;
vnode_t a_vp;
int a_which;
int a_fflags;
void *a_wql;
vfs_context_t a_context;
};
It's exported as part of the BSD KPI.

Working of mmap()

I am trying to get an idea on how does memory mapping take place using the system call mmap.
So far I know mmap takes arguments from the user and returns a logical address of where the file is stored. When the user tries to access it takes this address to the map table converts it to a a physical address and carries the operation as requested.
However I found articles as code example and Theoretical explanation
What it mentions is the memory mapping is carried out as:
A. Using system call mmap ()
B. file operations using (struct file *filp, struct vm_area_struct *vma)
What I am trying to figure out is:
How the arguments passed in the mmap system call are used in the struct vm_area_struct *vma) More generally how are these 2 related.
for instance: the struct vm_area_struct has arguments such as starting address, ending address permissions,etc. How are the values sent by the user used to fill values of these variables.
I am trying to write a driver so, Does the kernal fill the values for variables in the structure for us and I simply use it to call and pass values to remap_pfn_range
And a more fundamental question, why is a different file systems operation needed. The fact that mmap returns the virtual address means that it has already achieved a mapping doesnt it ?
Finally I am not that clear about how the entire process would work in user as well as kernal space. Any documentation explaining the process in details would be helpful.

Retrieving command line argument of process at driver level

Hello I am writing a minifilter driver for intercepting all the irp packets from a certain process say a.exe .
So , in the driver code it can be done by applying a check on the command line arguments that started the process.
Does anyone know how can i retrieve the command line argument ??
Thanks in advance .
There's no supported way to do this from within kernel-mode. In fact, trying to access user-mode process information from the kernel is a pain in general. I would suggest firing up a request to a user-mode service, which can then find that information and pass it back down to your kernel component.
However, there an undocumented method to do it. If you can get a handle to an EPROCESS struct for the target process, you can get at a pointer to the PEB (process environment block) struct within it, which then has a pointer to an RTL_USER_PROCESS_PARAMETERS structure, which has a member called CommandLine.
Example:
UNICODE_STRING* commandLine = epProcess->Peb->ProcessParameters->CommandLine;
The downside to this is that EPROCESS is almost entirely opaque and PEB is semi-opaque too, meaning that it may change in future versions of Windows. I certainly wouldn't advocate trying this in production code.
Try using the NtQueryInformationProcess or ZwQueryInformationProcess function with the PROCESSINFOCLASS parameter as ProcessBasicInformation. The output parameter, ProcessInformation, will be a struct of type PROCESS_BASIC_INFORMATION. As Polynomial mentioned, this struct has a pointer to the process's PEB struct, which contains the information you are looking for in its ProcessParameters field.

Where do you store user context in Linux character drivers?

It's been a while since I worked on a Linux kernel module, and I seem to remember that there was a place to stash context in your open() open implementation that would be available in your other file_operations... For example, if I want to maintain some state associated with everyone that opens my device node, if either the inode structure or the file structure that is passed to all the file_operations functions had a void* I could fill, I could very easily support any number of users.... Is this possible?
Found the answer. the "struct file*" that's passed to all the file_operations functions has a field called "private_data"... It's a void*, so you can populate in open, use it in read(), write() and ioctl() and free it in release()..

Resources