I am wondering if anyone could assist me with this, I am try to figure out how to handle a time of check, time of use problem and drop privileges when they are not needed, in case the for example it is a symbolic link to the file which could be changed to say the shadow file. Assuming the function below is invoked while the calling process is running with elevated privileges.
int
updatefile(char *file)
{
int fd;
if (access(file, R_OK|W_OK)) {
perror("access()");
return (-1);
}
fd = open(file, O_RDWR);
/*
* file is written to here.
*/
printf("Updated %s on...\n", file);
system("date");
/*
* elevated privileges are required here...
*/
return (0);
}
Assuming that your access function checks the file type and determines if the user has the appropriate privileges to manipulate the file, you are concerned about a potential TOCTTOU error between the call to access and the call to open.
The typical way to avoid this would be:
int updatefile(char *file)
{
int fd = -1;
if(-1 != (fd = open(file, R_OK | W_OK)))
{
struct stat buf;
if(0 == fstat(fd, &buf))
{
/* perform any necessary check on the here */
/* do what ever else you need to do */
/* write to the file here */
/* gain elevated permissions here */
/* do privileged task */
/* drop back to normal permissions here */
close(fd);
}
else
{
/* handle error stating the file */
}
}
else
{
/* handle error for not opening file */
}
}
The reason that this works, is that we postpone doing any checks on the file till after we get a "handle" to the file. We can tell if the user doesn't have the permissions to open the file by the value of errno in the outer else block;
If we are able to get a "handle" to the file, we then can do what ever checks we want. Because we maintain the "handle" from the time that we open the file, through when we perform our checks and finally when we use the file; a malicious would not be able to modify the file system between check and use.
Hope this helps
T.
Related
I want to open a file in read only mode in kernel but before i do that i want to check if the file has permission to read, how can i check it? Because to even check that i would need a file pointer pointing to the input file.
filp_open(args->inputfile, O_RDONLY, 0);
Is there any way to check it before opening it? I tried using, but it always fails
if (!fileptr->f_op->read)
{
error = -EACCES;
printk("reading input file failed\n");
}
You should use access(char *filepath,int mode) that checks file access rights.
modedescribes what you want to check: F_OK (existence), or an OR combination of R_OK(read), W_OK(write) or X_OK(execute).
So for your problem, you could use:
#include <unistd.h>
...
if( access( filename, R_OK ) != -1 ) {
// can read file
} else {
// cannot read file
}
i've been trying to redirect the output to a file and reading from file instead of stdin by using a function, but it doesnt seem to be working as when i redirect into a file and check to see if a file has been created with the output there is nothing there. what could be wrong with this function.
/* Redirect a standard I/O file descriptor to a file
* Arguments: filename the file to/from which the standard I/O file
* descriptor should be redirected
* flags indicates whether the file should be opened for reading
* or writing
* destfd the standard I/O file descriptor which shall be
* redirected
* Returns: -1 on error, else destfd
*/
int redirect(char *filename, int flags, int destfd){
int ret;
if(flags == 0){
destfd = open(filename,O_RDONLY);
if (destfd < 0){
return -1;
}
ret = dup2(0,destfd);
if(ret < 0){
return -1;
}
close(destfd);
}
if(flags == 1){
destfd = open(filename,O_APPEND|O_WRONLY);
if (destfd < 0){
return -1;
}
ret = dup2(destfd,1);
if(ret < 0){
return -1;
}
close(destfd);
}
return destfd;
}
There are several problems with your code, not least of which the really awful formatting which make it very hard to read.
For example this call to dup2 is backwards - it's replacing the recently opened destfd with a copy of stdin.
ret = dup2(0,destfd);
a then a few lines later you close destfd.
Your if statements could benefit from you learning about else and else if
if(flags == 0) {
// code
} else if(flags == 1) {
// code
}
Really though you could simplify the whole function by treating the flags parameter as the same flags you'd pass to open and have destfd as the file descriptor you want to replace.
int redirect(char *filename,int flags, int destfd)
{
int fd;
fd=open(filename,flags,S_IRUSR|S_IWUSR);
if(fd!=-1)
{
if(dup2(fd,destfd)==-1)
{
close(fd);
fd=-1;
}
else
{
close(fd);
}
}
return fd;
}
Then you could call it like
redirect("output.txt",O_CREAT|O_WRONLY,1); // Redirect stdout
redirect("input.txt",O_RDONLY,0); // Redirect stdin
The os function dup2() should provide what you need (if not references to exactly what you need).
More specifically, you can dup2() the stdin file descriptor to another file descriptor, do other stuff with stdin, and then copy it back when you want.
The dup() function duplicates an open file descriptor. Specifically, it provides an alternate interface to the service provided by the fcntl() function using the F_DUPFD constant command value, with 0 for its third argument. The duplicated file descriptor shares any locks with the original.
On success, dup() returns a new file descriptor that has the following in common with the original:
Same open file (or pipe)
Same file pointer (both file descriptors share one file pointer)
Same access mode (read, write, or read/write)
Everything I said can be found on the manpage of dup
I am trying to open a file in c using open() and I need to check that the file is a regular file (it can't be a directory or a block file). Every time I run open() my returned file discriptor is 3 - even when I don't enter a valid filename!
Here's what I have
/*
* Checks to see if the given filename is
* a valid file
*/
int isValidFile(char *filename) {
// We assume argv[1] is a filename to open
int fd;
fd = open(filename,O_RDWR|O_CREAT,0644);
printf("fd = %d\n", fd);
/* fopen returns 0, the NULL pointer, on failure */
}
Can anyone tell me how to validate input files?
Thanks!
Try this:
int file_isreg(const char *path) {
struct stat st;
if (stat(path, &st) < 0)
return -1;
return S_ISREG(st.st_mode);
}
This code will return 1 if regular, 0 if not, -1 on error (with errno set).
If you want to check the file via its file descriptor returned by open(2), then try:
int fd_isreg(int fd) {
struct stat st;
if (fstat(fd, &st) < 0)
return -1;
return S_ISREG(st.st_mode);
}
You can find more examples here, (specifically in the path.c file).
You should also include the following headers in your code (as stated on stat(2) manual page):
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
For future reference, here is an excerpt of the stat(2) manpage regarding the POSIX macros available for st_mode field validations:
S_ISREG(m) is it a regular file?
S_ISDIR(m) directory?
S_ISCHR(m) character device?
S_ISBLK(m) block device?
S_ISFIFO(m) FIFO (named pipe)?
S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.)
S_ISSOCK(m) socket? (Not in POSIX.1-1996.)
int isValidFile(char *filename) {
// We assume argv[1] is a filename to open
int fd;
fd = open(filename,O_RDWR|***O_CREAT***,0644);
printf("fd = %d\n", fd);
/* fopen returns 0, the NULL pointer, on failure */
}
you are using 0_CREAT which prompts the function to create if the file doesn't exist.this in the table its number is 3 (0,1,2 being std input std output and std error)
Wrong: check if the file is OK, then if it is, go open it and use it.
Right: go open it. If you can't, report the problem and bail out. Otherwise, use it (checking and reporting errors after each opetation).
Why: you have just checked that a file is OK. That's fine, but you cannot assume it will be OK in 0.000000017 seconds from now. Perhaps the disk wil overheat and break down. Perhaps some other process will mass-delete your entire file collection. Perhaps your cat will trip over the network cable. So let's just check if it's OK again, and then go open it. Wow, what a great idea! No wait...
So, here is the function that should create and write string into a /proc/minifwdb:
int write_to_file(char* rule)
{
FILE* fin;
fin = fopen("/proc/minifwdb", "a");
if (!fin)
{
printf("Could not open the file /proc/minifwdb, exiting...\n");
return 1;
}
if (fprintf(fin, "%s\n", rule) < 0)
return 1;
fclose(fin);
return 0;
}
When fopen() is called, it returns NULL. And there is no such file as /proc/minifwdb currently. Do I need to create it using LKM, and then use it to write the info?
I am also trying to create it from the user that has no root access. Any suggestions?
Files in /proc are used as an interface between user space and the kernel.
It is possible to use such a file to pass a string from user space into the kernel, but the kernel code that wants to receive it is responsible for creating the file.
I am looking for a way to check and make sure a file is readable, writeable, and exists, and if it is not I want to print a message stating so. I believe the information I am looking for can be found using fstat(), I just don't know the correct way to get it.
If open sets a specific errno if I try to open a unreadable, unwriteable, or non-existant file with O_RDRW, I think that would be the ideal solution.
Here is what I have tried:
//function to open the file
int f_open(const char *filename){
int fid;
if ((fid = open (filename, O_RDWR)) < -1){
return -1;
}
struct stat fileStat;
if (fstat(fid, &fileStat) < 0){
return -1;
}
//check write permission
if (!S_IWUSR(fileStat.st_mode)){
printf("Not writeable\n");
return -1;
}
//check read permissions
if (!S_IRUSR(fileStat.st_mode)){
printf("Not readable\n");
return -1;
}
return fid;
}
I am receiving the following error when I try and compile:
tester.c: In function 'f_open':
tester.c:56:14: error: called object '128' is not a function
tester.c:60:14: error: called object '256' is not a function
The macros you are using are bit values, not functions.
//check write permission
if ((S_IWUSR & fileStat.st_mode) == 0){
printf("Not writeable\n");
return -1;
}
Example Here: http://codewiki.wikidot.com/c:system-calls:fstat
EDIT: The 'access' function indicated above is a better choice IWUSR doesnt tell you if YOU can write it, it tells you if the owner can.
You can use access for permission checking
int rw = access(filename, R_OK | W_OK);
if (rw == 0) {
/* read/write granted */
}