File replacing in linux kernel - c

I need to replace a file with another one on a VFS (having both struct file) in a Linux kernel module. I tried 2 ways of doing that but both have some problems.
So I have 2 files correctly initialized, the first solution was:
vfs_truncate(&filp_one->f_path, 0);
err = vfs_copy_file_range(filp_two, 0, filp_one, 0, file_size, 0);
where file_size is the size of filp_two, I need the truncate because if the size of filp_one is bigger than filp_two I could have a dirty copy.
In this case, the problem is that another process can modify the file between the two operations and if I try to lock with:
inode_lock(filp_one->f_inode);
vfs_truncate(&filp_one->f_path, 0);
err = vfs_copy_file_range(filp_two, 0, filp_one, 0, file_size, 0);
inode_unlock(filp_one->f_inode);
the result is a deadlock.
The other solution and maybe better I thought was to rename filp_two and then unlink.
vfs_rename(parent, filp_two_dentry , parent, filp_one_dentry, NULL, RENAME_WHITEOUT);
I also locked with rename_lock, but I omitted because that's not the point.
In this case, the problem is that all the other open file structs after one rename will return an error "already freed". So I wanted to know if exists a way to update the file descriptors avoiding close and open again.
Looking into the source I saw the d_move function d_move, so I added this line, but nothing changes:
d_exchange(filp_one_dentry, filp_two_dentry);
Thanks for your attention and sorry for my English
P.S. I know that is not preferable to work with files in this way

Related

Why would the read system call stop working halfway through a program?

I'm working on an assignment that involves creating files and manipulating characters within them using what the lecturer describes as "File and System I/O calls" in C.
Specifically, I am using open, creat, read, write, lseek, close, and unlink.
Without revealing too much and violating academic integrity, essentially the assignment just entails creating files, copying characters between them, changing the characters, etc.
All of this was going perfectly until a certain point of the program after which read just... Wouldn't work. It doesn't matter what file I am accessing, or what other calls I put before it- for instance, I have tried closing and re-opening a file before trying to read, writing before reading (worked perfectly, put the characters right at the file position the lseek intended), etc.
I have checked the returns of all previous commands, none are giving errors other than the read, which is giving me errorno 9. Having looked this up, it appears to refer to having an incorrect file descriptor, but this doesn't make sense to me as I can use the same fid for any other command. Using ls -l, I confirmed that I have read and write permission (groups and public do not, if that helps).
I am at a total loss of where to go troubleshooting from here, any help would be immensely appreciated. Here is the code snippet in question:
readStatus = lseek(WWWfid,500,0);
if (readStatus<0) {
printf("error with lseek");
return 0;
}
/*printf("Read status: %i\n", readStatus);/*DEBUG*/
writeStatus = write(WWWfid, "wtf", 3);
if (writeStatus<0) {
printf("error with write");
return 0;
}
readStatus = read(WWWfid, buffer, 26);
int errorNum = errno;
/*buffer[27] = '\0';*/
if (readStatus<0) {
printf("error with read before loop, error %i\n", errorNum);
return 0;
}
I can likely include more without invoking the wroth of my uni but I'd prefer not to- also seems likely to be irrelevant given that all proceeding code appears to be functioning correctly.
Thanks for reading, please let me know if you have any insight at all

Kernel module check if file exists

I'm making some extensions to the kernel module nandsim, and I'm having trouble finding the correct way to test if a file exists before opening it. I've read this question, which covers how the basic open/read/write operations go, but I'm having trouble figuring out if and how the normal open(2) flags apply here.
I'm well aware that file reading and writing in kernel modules is bad practice; this code already exists in the kernel and is already reading and writing files. I am simply trying to make a few adjustments to what is already in place. At present, when the module is loaded and instructed to use a cache file (specified as a string path when invoking modprobe), it uses filp_open() to open the file or create it if it does not exist:
/* in nandsim.c */
...
module_param(cache_file, charp, 0400);
...
MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory");
...
struct file *cfile;
cfile = filp_open(cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
You might ask, "what do you really want to do here?" I want to include a header for the cache file, such that it can be reused if the system needs to be reset. By including information about the nand page geometry and page count at the beginning of this file, I can more readily simulate a number of error conditions that otherwise would be impossible within the nandsim framework. If I can bring down the nandsim module during file operations, or modify the backing file to model a real-world fault mode, I can recreate the net effect of these error conditions.
This would allow me to bring the simulated device back online using nandsim, and assess how well a fault-tolerant file system is doing its job.
My thought process was to modify it as follows, such that it would fail trying to force creation of a file which already exists:
struct file *cfile;
cfile = filp_open(cache_file, O_CREAT | O_EXCL | O_RDWR | O_LARGEFILE, 0600);
if(IS_ERR(cfile)){
printk(KERN_INFO "File didn't exist: %ld", PTR_ERR(cfile));
/* Do header setup for first-time run of NAND simulation */
}
else{
/* Read header and validate against system parameters. Recover operations */
}
What I'm seeing is an error, but it is not the one I would have expected. It is reporting errno 14, EFAULT (bad address) instead of errno 17 EEXIST (File exists). I don't want to run with this because I would like this to be as idiomatic and correct as possible.
Is there some other way I should be doing this?
Do I need to somehow specify that the file path is in user address space? If so, why is that not the case in the code as it was?
EDIT: I was able to get a reliable error by trying to open with only O_RDWR and O_LARGEFILE, which resulted in ENOENT. It is still not clear why my original approach was incorrect, nor what the best way to accomplish my goal is. That said, if someone more experienced could comment on this, I can add it as a solution.
Indeed, filp_open expects a file path which is in kernel address space. Proof is the use of getname_kernel. You can mimic this for your use case with something like this:
struct filename *name = getname(cache_file);
struct file *cfile = ERR_CAST(name);
if (!IS_ERR(name)) {
cfile = file_open_name(name, O_CREAT | O_EXCL | O_RDWR | O_LARGEFILE, 0600);
if (IS_ERR(cfile))
return PTR_ERR(cfile);
putname(name);
}
Note that getname expects a user-space address and is the equivalent of getname_kernel.

How to properly get contents of DLL file for PE parsing?

I'm trying to get the RVA of a function in kernel32.dll which means I need to use the offsets to find different structures in the file until I can get the IMAGE_EXPORT_DIRECTORY structure. However I know a lot of methods and ways of getting the contents of files interpret and leave certain characters and stuff out which would make this a nearly impossible task. So I want to know the best way to go about getting the contents of a dll file to copy into a character array.
Update: For anyone interested I created a function for mapping the dll into memory.
void* GetFileImage(char path[])
{
HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
if(hFile == INVALID_HANDLE_VALUE){return NULL;}
HANDLE file_map = CreateFileMapping(hFile, NULL, PAGE_READONLY|SEC_IMAGE, 0, 0, "KernelMap");
if(file_map == INVALID_HANDLE_VALUE){return NULL;}
LPVOID file_image = MapViewOfFile(file_map, FILE_MAP_READ, 0, 0, 0);
if(file_image == 0){return NULL;}
return file_image;
}
There are multiple ways. Not that many multiple, though.
1.If you are trying to parse a system loaded file such as kernel32.dll which are loaded into memory on system startup, you can directly use GetModuleHandle to grab the loaded base address and start parsing through PE (assuming you are familiar with the PE structure and static/delay loading of dlls and its exports).
2.If the dll you are trying to parse is not one of the system loaded, you can load them using LoadLibrary, which will return you the loaded base address, thus enabling you to parse the PE.
3.You can also do CreatFileMapping/MapViewOfFile to map the dll in your own virtual memory to parse.
The msdn article suggested by #David Thomas will be of great help:: Peering Inside the PE

DeleteFile() or unlink() calls succeed but doesn't remove file

I am facing this strange problem.
To delete a file unlink() API is called in my code. This call removes the file and succeeds on non-windows platforms. On windows it succeeds (returns 0) but doesn't remove the file.
To experiment I added a loop to call same API repeatedly. In second iteration I got an Permission denied error, Error code =13. Though read/write attributes are set on file and program has full permission to access the file.
I then called DeleteFile() instead of unlink() API. To my surprise I see the same result,call succeeded i.e. returned 1 but file is not removed physically.
I checked through unlocker utility, no other program is accessing the file except the program which is trying to remove this file.
Does anyone has idea what else could be wrong ?
Edit1:
Just to ensure file was not opened at the time of removing it. I saved the handle when file was created and tried to close before removing the file but I got error "'UNOPENED' (Errcode: 9 - Bad file descriptor)". Thus I conclude the file was not open at the time of removing it.
Edit2
As requested, here is the simplified version of code used to create and remove the file.
// Code to create the file
int create_file(const char* path)
{
HANDLE osfh; /* OS handle of opened file */
DWORD fileaccess; /* OS file access (requested) */
DWORD fileshare; /* OS file sharing mode */
DWORD filecreate; /* OS method of opening/creating */
DWORD fileattrib; /* OS file attribute flags */
SECURITY_ATTRIBUTES SecurityAttributes;
SecurityAttributes.nLength= sizeof(SecurityAttributes);
SecurityAttributes.lpSecurityDescriptor= NULL;
SecurityAttributes.bInheritHandle= !(oflag & _O_NOINHERIT);
fileaccess= GENERIC_WRITE;
fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
filecreate= CREATE_NEW;
if ((osfh= CreateFile(path, fileaccess, fileshare, &SecurityAttributes,
filecreate, fileattrib, NULL)) == INVALID_HANDLE_VALUE)
{
// error handling
}
}
//Code to delete the file -
int remove_file (const char* name)
{
if ((err = unlink(name)) == -1)
{ //Error handling }
}
Edit3
As pointed by Joachim Pileborg and icabod, that DeleteFile() does not remove file if it is still open. As suggested by Remy Lebeau, to use process explorer. I found that one handle to file was indeed open when I closed that from process explorer file deleted like a charm :)
I had also mentioned in the Edit1 when I tried to close the file I got an error. It happened because the file descriptor I get from createfile() is not the actual handle returned by CreateFile() API instead a logical mapped handle due to underlying code complexities to support other non-windows platforms. Anyways, now I understood the root cause of problem but I was expecting if a file with open handle is passed to DeleteFile() API then it should fail in first attempt rather succeed and wait for open handles to close.
Assuming that you call your Createfile function, then later call your remove_file function... you still have a handle open to the file. The WinAPI function CreateFile, if it succeeds, keeps a handle open on the file. In your provided code, you don't close that handle.
From the documentation on DeleteFile:
The DeleteFile function marks a file for deletion on close. Therefore, the file deletion does not occur until the last handle to the file is closed. Subsequent calls to CreateFile to open the file fail with ERROR_ACCESS_DENIED.
My guess is that you still have a handle open, and when you close that handle the file will be deleted.
However, your sample code is incomplete, so it is difficult to tell.

Find the oldest file within a directory in C on Windows

I am working on a C project and I am trying to find the oldest file within a directory so that that once the oldest file has been found, it is then deleted. I can not find anything on how to do this in C using windows, have found ways to do it in Linux but I need a version for Windows.
Basically you scan the directory, same as in Linux (but you could check out the Boost library also).
The data about time and date are already available in the directory scan structure
HANDLE fh;
FILETIME oldest = {-1U, -1U};
// Buffer to hold file name
oldestFile = malloc(MAX_PATH);
fd = malloc(sizeof(WIN32_FIND_DATA));
if (INVALID_HANDLE_VALUE == (fh = FindFirstFile(directory_name, fd)))
// Signal error, free memory, (and return an error code?)
// OK to proceed
do
{
if(fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
continue;
//
if ((fd->ftCreationTime.dwHighDateTime < oldest.dwHighDateTime)
|| (fd->ftCreationTime.dwHighDateTime == oldest.dwHighDateTime
&& fd->ftCreationTime.dwLowDateTime < oldest.dwLowDateTime))
{
oldest.dwHighDateTime = fd->ftCreationTime.dwHighDateTime; // ftLastAccessTime? ftLastWriteTime?
oldest.dwLowDateTime = fd ->ft CreationTime.dwLowDateTime;
strncpy(oldestFile, MAX_PATH, fd->cFileName);
}
} while(FindNextFile(fh, fd));
FindClose(fh);
free(fd); fd = NULL;
You'll want to use the FindFirstFile/FindNextFile combination on Windows to get the files in the directory. You can then either use stat as you would in Linux, or GetFileAttributesEx to check the dates.
Since windows is POSIX compliant, you should be able to read a directory and do a stat() on the files.
You could use the GetFileAttributesEx() function which populates a WIN32_FILE_ATTRIBUTE_DATA struct which has three time related members:
ftCreationTime
ftLastAccessTime
ftLastWriteTime
You can compare whichever of these is more relevant and keep track of the oldest file found during iteration. Once iteration is over, delete it using DeleteFile(). The time members are of type FILETIME and can be compared using CompareFileTime().
Or use the GetFileTime() to obtain the relevant time attribute, as commented by BeyondSora.
For finding the details of file in windows you'll have to refer to File Allocation Table which includes all the details about the files.
Check here for the coding part to read FAT

Resources