Understanding linux kernel data structures for handling file descriptors - c

My goal is to modify a process's open file descriptor's access permission. For eg, there is a process whose PID is known, which has 2 file descriptors open apart from the standard 3. One was opened with read only permission and other was opened with write only permission. I want to modify the file descriptors permission from read only to read and write. After which, the file descriptor can be used to write the object it was created with.
I have written a kernel module that gives me access to the file descriptor of the process identified by its PID. I searched the header and forums to understand how the linux data structure works for handling the file descriptor but I am still confused. What I found out is, every process has its own task_struct, which contains a member for all open files under, which contains an array of open file descriptor. I do not know how it links from here on with the inode.
I found out that there is member of struct file, called as f_mode that gives us the permissions but I cannot find a method to call it. When I access it directly, it gives me an unsigned int but I don't know what value maps to what? Also, I am not sure if this is the data member which stores the access permissions. If I modify this would it change the access permissions for file descriptor?
The code is given below:
static int __init mainInit(void){
int pid=13433;
struct task_struct * task;
struct files_struct * files;
struct fdtable * filestable;
struct path files_path;
//Get Task structure from PID
task = pid_task(find_vpid(pid), PIDTYPE_PID );
//Get open FIles from the task tstructure
files = task->files;
filestable=files_fdtable(files);
int i=0;
char *cwd;
char *buf = (char *)kmalloc(GFP_KERNEL,100*sizeof(char));
while(filestable->fd[i] != NULL){
files_path = filestable->fd[i]->f_path;
cwd=d_path(&files_path,buf, 100*sizeof(char));
printk(KERN_INFO "Open FD with %d with name %s with access %x\n", i, cwd,filestable->fd[i]->f_mode);
//printk(KERN_INFO "FMode read:%x Fmodewrite:%x\n",FMODE_READ,FMODE_WRITE);
//Check access mode
if(filestable->fd[i]->f_mode==FMODE_READ){
printk(KERN_INFO "File has access FMODE_READ\n");
}else if(filestable->fd[i]->f_mode==FMODE_WRITE){
printk(KERN_INFO "File has access FMODE_WRTIE\n");
}
i++;
}
return 0;
}
static void __exit mainExit(void){
printk(KERN_INFO "Goodbye Kernel!. Returning to normal useless world!\n");
}
module_init(mainInit);
module_exit(mainExit);

Related

fstat st_size says file size is 0 when unlinking file

Somewhere online I've seen a technique to immediately unlink a temporary file after opening it, since you will discard it anyway. As per my understanding of the man-page for unlink, the file will not be unlinked as long as it has an open file descriptor.
When I execute the following piece of code:
char *file, *command;
asprintf(&file, "/tmp/tempXXXXXX");
int fd = mkstemp(file);
unlink(file);
asprintf(&command, "some_command > %s", file); /*Writes n bytes in temp file*/
FILE *f = popen(command, "re");
pclose(f);
struct stat sbuf;
fstat(fd, &sbuf);
printf("%i\n", sbuf.st_size);
close(fd);
free(file);
free(command);
exit(0);
It will print a size of 0. However, if I comment unlink(file), it will show the correct file size. I would expect both scenarios to show the correct size of the file, since unlink should wait till no processes have the file open anymore. What am I missing here?
You're missing the fact that the file referred to by your fd is not the same file as that created by your call to popen().
In a POSIX-like shell, some_command > some_file will create some_file if it does not already exist, otherwise it will truncate some_file.
Your call to popen() invokes a shell, which in turn creates or truncates the output file before invoking some_command as per POSIX.
Since you have unlinked some_file before the call to popen(), the file is created anew: that is, the output file set up by your popen() shell is allocated under a different inode than the (now anonymous) file created by your previous call to mkstemp().
You can see that the files are different if you compare st_ino values from your fstat() (by fd) and a separate call to stat() (by name) after the popen().

How to delete a file in C using a file-descriptor?

In my code, I create a file with a random name using mkstemp() function (Im on Linux). What this function returns is an int being a file descriptor.
int fd;
char temp[] = "tempXXXXXX";
fd = mkstemp(temp);
Later I can access the file using fdopen() through that int file descriptor.
FILE *file_ptr = NULL;
file_ptr = fdopen(fd);
But at the end of my program, I would like to see if the file still exists with the random name it was given when I created it (the program should change that file name if successful). I can set a flag if the rename() function run on that file is successful, but I still don't know how to delete it when I only have its file descriptor.
if rename files => remove the temp file
How can I do that? Or is there a way to get the files name if I have its file descriptor?
Neither C nor POSIX (since you are using POSIX library functions) defines a way to delete a file via an open file descriptor. And that makes sense, because the kind of deletion you're talking about is actually to remove a directory entry, not the file itself. The same file can be hard linked into the directory tree in multiple places, with multiple names. The OS takes care of removing its data from storage, or at least marking it as available for reuse, after the last hard link to it is removed from the directory tree and no process any longer has it open.
A file descriptor is associated directly with a file, not with any particular path, notwithstanding the fact that under many circumstances, you obtain one via a path. This has several consequences, among them that once a process opens a file, that file cannot be pulled out from under it by manipulating the directory tree. And that is the basis for one of the standard approaches to your problem: unlink (delete) it immediately after opening it, before losing its name. Example:
#include <stdlib.h>
#include <unistd.h>
int make_temp_file() {
char filename[] = "my_temp_file_XXXXXX";
int fd;
fd = mkstemp(filename);
if (fd == -1) {
// handle failure to open ...
} else {
// file successfully opened, now unlink it
int result = unlink(filename);
// ... check for and handle error conditions ...
}
return fd;
}
Not only does that (nearly) ensure that the temp file does not outlive the need for it, but it also prevents the contents from being accessible to users and processes to which the owning process does not explicitly grant access.
Even though this doesn't exactly answer the question you're asking about mkstemp, consider creating a temporary file that will automatically be deleted, unless you rename it.
Instead of mkstemp you could call open combined with the creation flag O_TMPFILE to create a temporary, unnamed file that is automatically deleted when file is closed.
See open(2):
O_TMPFILE (since Linux 3.11)
Create an unnamed temporary regular file. The pathname argu‐
ment specifies a directory; an unnamed inode will be created
in that directory's filesystem. Anything written to the
resulting file will be lost when the last file descriptor is
closed, unless the file is given a name.
Instead of a filename, you call open with the path where you prefer to place the temporary file, like:
temp_fd = open("/path/to/dir", O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR);
If you like to give the temporary file a permanent location/name, you can call linkat on it later:
linkat(temp_fd, NULL, AT_FDCWD, "/path/for/file", AT_EMPTY_PATH);
Note: Filesystem support is required for O_TMPFILE, but mainstream Linux filesystems do support it.
readlink provide you the name of your file depending of the file descriptor if you use the path /proc/self/fd/ adding you fd.
Then use remove for deleting the file passing the name readlink gave you
ssize_t readlink(const char *path, char *buf, size_t bufsiz); (also load ernno)
int remove(const char *filename); (returns zero is successful, otherwise nonzero)
I hope something like that could helped you ?
⚠ Don't copy/past this you must edit "filename"; _BUFFER, _BUFSIZE ⚠
#include<stdio.h>
#include <unistd.h>
#include <stdlib.h>
int delete_file(int fd) {
char *str_fd = itoa(fd, str_fd, 10);
char *path = strcat("/proc/self/fd/", str_fd);
if (read_link(path, buffer, bufsize) == -1)
return -1;
int del = remove(filename);
if (!del)
printf("The file is Deleted successfully");
else
printf("The file is not Deleted");
return 0;
}
(feel free to edit this, i didn't test the code and i let you handel the buffer and buffer size)

How to get the "file name" from struct file* in the kernel?

I want to know on what file in /sys/* the functionstatic ssize_t
sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos) were called. the question is how to get the file name/path by having struct file *file ?
struct file {
mode_t f_mode;
loff_t f_pos;
unsigned short f_flags;
unsigned short f_count;
unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;
struct file *f_next, *f_prev;
int f_owner; /* pid or -pgrp where SIGIO should be sent */
struct inode * f_inode;
struct file_operations * f_op;
unsigned long f_version;
void *private_data; /* needed for tty driver, and maybe others */
};
EDIT:
I understand there is no one-to-one mapping between inode to a name, but I must know the major/minor/file descriptor and can search for some of the inode's name in the file system.
Actuall you can retrieve the file path used to open the file. In linux struct file represents an opened file and has the path used to open that file associate with the structure. Before 2.6.20 it was a member called f_dentry and from 2.6.20 it is a new member called f_path. You can use function d_path() to retrieve the full path of your file directly.
Refer to the following Linux source code:
http://lxr.free-electrons.com/source/include/linux/fs.h?v=3.10#L763
http://lxr.free-electrons.com/source/fs/dcache.c?v=3.0#L2626
And also answer:
How can I get a filename from a file descriptor inside a kernel module?
In Linux and other Unix-like OSs, a file object can be pointed to by any number of names, and the file object itself has no pointers back to any of them. Names are not a feature of the file, they are just an external index.

Pointer in struct issue

I have probably pointer problem with fp, cause I get (SIGSEGV) error.
But I'm not much experienced in C and I doesn't see it.
What I'm trying to do. I do Server application for simple game, I handle clients in new threads. I use function pthread_create, it has handle function called handle_client, I need to get in some argumets socketdescritpor(it works) and filedescriptor for writing logs(there is probably the problem).
In my main I open the log file, then I put the filedescriptor to my struct, I get the struct inside the handle_client function and in this function I want to get back the file decriptor (fp) of the log file, to be able write to file. I use fflush(fp) to save the data after each fprintf, I open the file once and then each client should be able write to file throuhgt this descripor, but I've probably done something bad with pointers (I mean geting fp in and out from the struct, there is piece of my code where I do this action.) Thx for help.
struct
typedef struct
{
int fd;
FILE *fp; //filepointer for logs file
} my_thread_context_t;
main
int main(int argc, char *argv[]) {
FILE * fp;
fp = fopen("Serverlog.log","w");//delete last file
fclose(fp);
fp = fopen("Serverlog.log","a+");
my_thread_context_t ctx;
//bind server
//listen
while(1) {
//accept
ctx.fp = fp;// add file pointer to structure
int check = pthread_create(&thread, NULL,handle_client,&ctx);
//other code
}
hadle_client function
void * handle_client(void * void_context){
my_thread_context_t * context = (my_thread_context_t *) void_context;
FILE *fp; //pointer na soubor s logy
fp = context->fp;//get the filepointer for logs
//other code ..
}
It looks like many threads can access your my_thread_context_t::fp and that is exactly the problem. The FILE* type is really a (opaque) pointer to structure used by the C library. This structure contents may get corrupted (or non-consistent) when more than one thread modifies it. You must synchronize access to your my_thread_context_t::fp. I would suggest creating a mutex (see pthread_mutex_init, pthread_mutex_lock, pthread_mutex_unlock) inside your ctx structure. Each thread should lock it before it starts writing to a file and unlock it when its finished writing - a separate (inline) function for this puprpose would be even better design, e.g:
typedef struct
{
int fd;
pthread_mutex_t mutex;
FILE *fp; //filepointer for logs file
} my_thread_context_t;
my_thread_context_t ctx;
fp = fopen("Serverlog.log","a+");
pthread_mutex_init(&ctx.mutex);
ctx.fp = fp;
inline void write_to_log(my_thread_context_t* pCtx,const char* pcszMessage)
{
pthread_mutex_lock(&(pCtx->mutex));
/* here write to the log file */
pthread_mutex_unlock(&(pCtx->mutex));
}
If you do it this way, it is not only safe, but you also do not have to invoke fflush
after every write (unless you want your log to be always in sync).
Don't forget to call pthread_mutex_destroy after all threads are finished (e.g. after all neccesary ptrhead_joins).

How can I get a filename from a file descriptor inside a kernel module?

I need to get the name of a file from a given file descriptor, inside a small linux kernel module that I wrote. I tried the solution given at Getting Filename from file descriptor in C, but for some reason, it prints out garbage values (on using readlink on /proc/self/fd/NNN as mentioned in the solution). How can I do it?
Don't call SYS_readlink - use the same method that procfs does when one of those links is read. Start with the code in proc_pid_readlink() and proc_fd_link() in fs/proc/base.c.
Broadly, given an int fd and a struct files_struct *files from the task you're interested in (which you have taken a reference to), you want to do:
char *tmp;
char *pathname;
struct file *file;
struct path *path;
spin_lock(&files->file_lock);
file = fcheck_files(files, fd);
if (!file) {
spin_unlock(&files->file_lock);
return -ENOENT;
}
path = &file->f_path;
path_get(path);
spin_unlock(&files->file_lock);
tmp = (char *)__get_free_page(GFP_KERNEL);
if (!tmp) {
path_put(path);
return -ENOMEM;
}
pathname = d_path(path, tmp, PAGE_SIZE);
path_put(path);
if (IS_ERR(pathname)) {
free_page((unsigned long)tmp);
return PTR_ERR(pathname);
}
/* do something here with pathname */
free_page((unsigned long)tmp);
If your code is running in process-context (eg. invoked through a syscall) and the file descriptor is from the current process, then you can use current->files for the current task's struct files_struct *.

Resources