I have a piece of C code, a function to be specific, which operates on a FILE*.
Depending on which mode the FILE* was opened with there are certain things I can and cannot do.
Is there any way I can obtain the mode the FILE* was opened with?
That FILE* is all the info I can rely on, because it is created somewhere else in the program and the actual file-name is long lost before it reaches my function, and this I cannot influence.
I would prefer a portable solution.
Edit: I'm not interested in file-restrictions specifying which users can do what with the file. That is mostly irrelevant as it is dealt with upon file-opening. For this bit of code I only care about the open-mode.
On POSIX (and sufficiently similar) systems, fcntl(fileno(f), F_GETFL) will return the mode/flags for the open file in the form that would be passed to open (not fopen). To check whether it was opened read-only, read-write, or write-only, you can do something like:
int mode = fcntl(fileno(f), F_GETFL);
switch (mode & O_ACCMODE) {
case O_RDONLY: ...
case O_WRONLY: ...
case O_RDWR: ...
}
You can also check for flags like O_APPEND, etc.
Assuming Linux/Unix:
See fstat(), to get the details of file permissions.
To get the file descriptor us fileno() for that function
Related
I was reading: https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use
They showed this code to be buggy and I totally understand why it's so:
if (access("file", W_OK) != 0) {
exit(1);
}
// Attacker: symlink("/etc/passwd", "file");
fd = open("file", O_WRONLY);
// Actually writing over /etc/passwd
write(fd, buffer, sizeof(buffer));
But the real question is how to protect against this type of exploits?
You can use the O_NOFOLLOW flag. It will cause the open to fail if basename of the path is a symbolic link. That would solve the described attack.
To cover links along the directory path, you can check whether frealpath(fd, ...) matches what you would expect.
Another way to prevent a process from overwriting /etc/passwd is to run it as non-root so that it won't have permission. Or, you can use chroot - or more generally, a container - to prevent the host system's /etc/passwd being visible to the process.
More generally though, filesystem TOCTOU is unsolvable at the moment on Linux. You would need transaction support either on filesystem or system call level - which are lacking.
There is no failproof solution.
Be also aware of Rice's theorem. It might be relevant.
But you could adopt a system wide convention (and document it) that every program accessing a given file is using locking facilities like flock(2).
I'm writing a serial interface for an MCU, and I want to know how one would create a printf-like function to write to the serial UART. I can write to the UART, but to save memory and stack space, and avoid temp string buffers, I would prefer to do that write directly instead of doing sprintf() to a string and then writing the string via serial. There is no kernel and no file handling, so FILE* writes like those from fprintf() won't work (but sprintf() does).
Is there something that processes formatted strings for each char, so I can print char-by-char as it parses the format string, and applies the related arguments?
We are using newlib as part of the efm32-base project.
UPDATE
I would like to note that ultimately we implemented the _write() function because thats all newlib needs to light up printf.
Standard C printf family of functions don't have a "print to a character callback" type of functionality. Most embedded platforms don't support fprintf either.
First try digging around the C runtime for your platform, it might have a built-in solution. For example, ESP-IDF has ets_install_putc1() which essentially installs a callback for printf (though its ets_printf already prints to UART0).
Failing that, there are alternative printf implementations designed specifically for embedded applications which you can adapt to your needs.
For example mpaland/printf has a function taking the character printer callback as the first argument:
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...);
Also see this related question: Minimal implementation of sprintf or printf.
You had said [in your top comments] that you had GNU, so fopencookie for the hooks [I've used it before with success].
Attaching to stdout may be tricky, but doable.
Note that we have: FILE *stdout; (i.e. it's [just] a pointer). So, simply setting it to the [newly] opened stream should work.
So, I think you can do, either (1):
FILE *saved_stdout = stdout;
Or (2):
fclose(stdout);
Then, (3):
FILE *fc = fopencookie(...);
setlinebuf(fc); // and whatever else ...
stdout = fc;
You can [probably] adjust the order to suit (e.g. doing fclose first, etc.)
I had looked for something analogous to freopen or fdopen to fit your situation, but I didn't find anything, so doing stdout = ...; may be the option.
This works fine if you do not have any code that tries to write to fd 1 directly (e.g. write(1,"hello\n",6);).
Even in that case, there is probably a way.
UPDATE:
Do you know if FILE*stdout is a const? If so, I might need to do something crazy like FILE **p = &stdout and then *p = fopencookie(...)
You were right to be concerned, but not for quite the reason you think. Read on ...
stdout is writable but ...
Before I posted, I checked stdio.h, and it has:
extern FILE *stdout; /* Standard output stream. */
If you think about it, stdout must be writable.
Otherwise, we could never do:
fprintf(stdout,"hello world\n");
fflush(stdout);
Also, if we did a fork, then [in the child] if we wanted to set up stdout to go to a logfile, we'd need to be able to do:
freopen("child_logfile","w",stdout);
So, no worries ...
Trust but verify ...
Did I say "no worries"? I may have been premature ;-)
There is an issue.
Here is a sample test program:
#define _GNU_SOURCE
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#if 1 || DEBUG
#define dbgprt(_fmt...) \
do { \
fprintf(stderr,_fmt); \
fflush(stderr); \
} while (0)
#else
#define dbgprt(_fmt...) \
do { } while (0)
#endif
typedef struct {
int ioport;
} uartio_t;
char *arg = "argument";
ssize_t
my_write(void *cookie,const char *buf,size_t len)
{
uartio_t *uart = cookie;
ssize_t err;
dbgprt("my_write: ENTER ioport=%d buf=%p len=%zu\n",
uart->ioport,buf,len);
err = write(uart->ioport,buf,len);
dbgprt("my_write: EXIT err=%zd\n",err);
return err;
}
int
my_close(void *cookie)
{
uartio_t *uart = cookie;
dbgprt("my_close: ioport=%d\n",uart->ioport);
int err = close(uart->ioport);
uart->ioport = -1;
return err;
}
int
main(void)
{
cookie_io_functions_t cookie = {
.write = my_write,
.close = my_close
};
uartio_t uart;
printf("hello\n");
fflush(stdout);
uart.ioport = open("uart",O_WRONLY | O_TRUNC | O_CREAT,0644);
FILE *fc = fopencookie(&uart,"w",cookie);
FILE *saved_stdout = stdout;
stdout = fc;
printf("uart simple printf\n");
fprintf(stdout,"uart fprintf\n");
printf("uart printf with %s\n",arg);
fclose(fc);
stdout = saved_stdout;
printf("world\n");
return 0;
}
Program output:
After compiling, running with:
./uart >out 2>err
This should produce an expected result. But, we get (from head -100 out err uart):
==> out <==
hello
uart simple printf
world
==> err <==
my_write: ENTER ioport=3 buf=0xa90390 len=39
my_write: EXIT err=39
my_close: ioport=3
==> uart <==
uart fprintf
uart printf with argument
Whoa! What happened? The out file should just be:
hello
world
And, the uart file should have three lines instead of two:
uart printf
uart simple printf
uart printf with argument
But, the uart simple printf line went to out instead of [the intended] uart file.
Again, whoa!, what happened?!?!
Explanation:
The program was compiled with gcc. Recompiling with clang produces the desired results!
It turns out that gcc was trying to be too helpful. When compiling, it converted:
printf("uart simple printf\n");
Into:
puts("uart simple printf");
We see that if we disassemble the executable [or compile with -S and look at the .s file].
The puts function [apparently] bypasses stdout and uses glibc's internal version: _IO_stdout.
It appears that glibc's puts is a weak alias to _IO_puts and that uses _IO_stdout.
The _IO_* symbols are not directly accessible. They're what glibc calls "hidden" symbols--available only to glibc.so itself.
The real fix:
I discovered this after considerable hacking around. Those attempts/fixes are in an appendix below.
It turns out that glibc defines (e.g.) stdout as:
FILE *stdout = (FILE *) &_IO_2_1_stdout_;
Internally, glibc uses that internal name. So, if we change what stdout points to, it breaks that association.
In actual fact, only _IO_stdout is hidden. The versioned symbol is global but we have to know the name either from readelf output or by using some __GLIBC_* macros (i.e. a bit messy).
So, we need to modify the save/restore code to not change the value in stdout but memcpy to/from what stdout points to.
So, in a way, you were correct. It is [effectively] const [readonly].
So, for the above sample/test program, when we want to set a new stdout, we want:
FILE *fc = fopencookie(...);
FILE saved_stdout = *stdout;
*stdout = *fc;
When we want to restore the original:
*fc = *stdout;
fclose(fc);
*stdout = saved_stdout;
So, it really wasn't gcc that was the issue. The original save/restore we developed was incorrect. But, it was latent. Only when gcc called puts did the bug manifest itself.
Personal note: Aha! Now that I got this code working, it seems oddly familiar. I'm having a deja vu experience. I'm pretty sure that I've had to do the same in the past. But, it was so long ago, that I had completely forgotten about it.
Workarounds / fixes that semi-worked but are more complex:
Note: As mentioned, these workarounds are only to show what I tried before finding the simple fix above.
One workaround is to disable gcc's conversion from printf to puts.
The simplest way may be to [as mentioned] compile with clang. But, some web pages say that clang does the same thing as gcc. It does not do the puts optimization on my version of clang [for x86_64]: 7.0.1 -- YMMV
For gcc ...
A simple way is to compile with -fno-builtins. This fixes the printf->puts issue but disables [desirable] optimizations for memcpy, etc. It's also undocumented [AFAICT]
Another way is to force our own version of puts that calls fputs/fputc. We'd put that in (e.g.) puts.c and build and link against it:
#include <stdio.h>
int
puts(const char *str)
{
fputs(str,stdout);
fputc('\n',stdout);
}
When we just did: stdout = fc; we were deceiving glibc a bit [actually, glibc was deceiving us a bit] and that has now come back to haunt us.
The "clean" way would be to do freopen. But, AFAICT, there is no analogous function that works on a cookie stream. There may be one, but I haven't found it.
So, one of the "dirty" methods may be the only way. I think using the "custom" puts function method above would be the best bet.
Edit: It was after I reread the above "deceiving" sentence that I hit on the simple solution (i.e. It made me dig deeper into glibc source).
depending on your standard library implementation you need to write your own versions of fputc or _write functions.
I have a C++ program that creates an output file "A" with ofstream. This file is then read by some legacy C code that opens the file with _iobuf. The legacy code then creates its own output file "B" using _iobuf, and this file is then read by the C++ program using ifstream. This sequence is iterated many times, with the same file names for A and B in each iteration.
Occasionally, the C++ program cannot open the output file A for writing, and I must try several times before it succeeds. This occurs nondeterministically, and maybe once in a thousand iterations. Note that the C program never has to wait to open its input or output file, nor does the C++ program ever have to wait to open its input file. This informal observation is based on hundreds of thousands of iterations.
I'm wondering if this has something to do with mixing ofstream and _iobuf in the same program? Both the C++ code and the C code are linked into the same program. And the legacy C code is technically C++ code, but was written in a very C-like style. Is there anything I can do to eliminate this waiting to open the ofstream file? I do not want to change the legacy code if I can possibly avoid it.
Pseudo code (not compiled):
void someObject::someMethod()
{
for (int count = 0; count < someLimit; ++count)
{
newerObject::firstMethod();
olderObject::secondMethod();
newerObject::thirdMethod();
}
}
void newerObject::firstMethod()
{
// do some processing first
// then write the results of the processing to a file
ofstream A;
A.open("A", ofstream::out); // this sometimes must be tried multiple times
// write data to file A
A.close();
}
void olderObject::secondMethod()
{
FILE* f;
f = fopen("A", "rt"); // this always works the first time
// read data from file A
fclose(f);
// do some processing
f = fopen("B", "w");
// write data to file B
fclose(f);
}
void newerObject::thirdMethod()
{
ifstream B;
B.open("B"); // this always works the first time
// read data from file B
B.close();
// do some processing
}
Currently, as a work around, I put the ofstream::open in a do-while loop. I would love to get rid of this awkwardness. Thanks in advance for any advice you can give.
First off, the problem is almost certainly not the use of different methods to access the files: under the hood, the C and C++ I/O functions use the same system I/O facilities. You seem to be using Windows (on other systems files typically can be open multiple times simultaneously) and I don't know much about the system but I would suspect that the file system hasn't been updated to reflect that the file is closed when you try to open it. This may have to do with the "t" open flag: I don't know what this is about.
On UNIXes you can force the I/O operations to wait until the actual change on disk completed. Something like this could help avoiding the problem but has the significant cost that operations become hideously slow. On UNIXes one approach would be to blow away the file system entry the moment the file was opened successfully (after all, at this point its name isn't used anymore):
if (FILE* fp = fopen("file", "r")) {
remove("file");
// do processing
}
However, if I recall correctly on Windows you can neither remove the file nor rename it. Personally, in solving the problem I would proceed as follows:
Determine under which situations the file can't be opened, e.g. by keeping the file open and trying to open it. This is mainly intended to create a setup where the problem is reproducible so you can verify later that you indeed found a solution.
Once I found a way to reproduce the problem I would probably a better idea of the actual root cause and possibly googling would help. In any case this is the point where researching the root cause comes in.
Once the cause is understood it is hopefully easy to devise a solution. If not, opening the file multiple times under it is successful may very well be the right solution.
I would like to know how to check if I have write permissions to a folder.
I'm writing a C++ project and I should print some data to a result.txt file, but I need to know if I have permissions or not.
Is the check different between Linux and Windows? Because my project should run on Linux and currently I'm working in Visual Studio.
The portable way to check permissions is to try to open the file and check if that succeeded. If not, and errno (from the header <cerrno> is set to the value EACCES [yes, with one S], then you did not have sufficient permissions. This should work on both Unix/Linux and Windows. Example for stdio:
FILE *fp = fopen("results.txt", "w");
if (fp == NULL) {
if (errno == EACCES)
cerr << "Permission denied" << endl;
else
cerr << "Something went wrong: " << strerror(errno) << endl;
}
Iostreams will work a bit differently. AFAIK, they do not guarantee to set errno on both platforms, or report more specific errors than just "failure".
As Jerry Coffin wrote, don't rely on separate access test functions since your program will be prone to race conditions and security holes.
About the only reasonable thing to do is try to create the file, and if it fails, tell the user there was a problem. Any attempt at testing ahead of time, and only trying to create the file if you'll be able to create and write to it is open to problems from race conditions (had permission when you checked, but it was removed by the time you tried to use it, or vice versa) and corner cases (e.g., you have permission to create a file in that directory, but attempting to write there will exceed your disk quota). The only way to know is to try...
The most correct way to actually test for file write permission is to attempt to write to the file. The reason for this is because different platforms expose write permissions in very different ways. Even worse, just because the operating system tells you that you can (or cannot) write to a file, it might actually be lying, for instance, on a unix system, the file modes might allow writing, but the file is on read only media, or conversely, the file might actually be a character device created by the kernel for the processes' own use, so even though its filemodes are set to all zeroes, the kernel allows that process (and only that process) to muck with it all it likes.
Similar to the accepted answer but using the non-deprecated fopen_s function as well as modern C++ and append open mode to avoid destroying the file contents:
bool is_file_writable(const std::filesystem::path &file_path)
{
FILE* file_handle;
errno_t file_open_error;
if ((file_open_error = fopen_s(&file_handle, file_path.string().c_str(), "a")) != 0)
{
return false;
}
fclose(file_handle);
return true;
}
I know, that there's the is_open() function in C++, but I want one program to check if a file hasn't been opened by another application. Is there any way to do it using standard library?
EDIT - Clarified in the answers that this is for a Linux application.
Not only the standard library does not have this funcionality, it's not even possible in general. You could (on linux) check /proc/*/fd — but it is possible that your program does not have permission to do it on processes from other users (this is the default in Ubuntu, for instance).
No, the standard library has no such functionality.
If you control the other process (have source code), the best plan is to use advisory locks in both processes. This locking is defined in POSIX, and will be portable across operating systems.
In Linux, you can use the utility lsof to see what files are opened by other processes.
This is limited to what you have permissions for - you have to do the check as a privileged user, or you'll only get results for files opened by the same user as the one doing the check.
I only know of the command line utility, not of any system call you can use directly from C code.
In Linux, it's also possible to turn on mandatory locking for a given filesystem (mount -o mand), and set special flags on the file (chmod g-x,g+s). Then when your process attempts to acquire a write lock, it will fail if another process has the file open. This is hardly ever used, but if you completely control the system in question, it may be an option.
The following code may work.
int main(int argc, char ** argv)
{
int fd = open(argv[1], O_RDONLY);
if (fd < 0) {
perror("open");
return 1;
}
if (fcntl(fd, F_SETLEASE, F_WRLCK) && EAGAIN == errno) {
puts("file has been opened");
}
else {
fcntl(fd, F_SETLEASE, F_UNLCK);
puts("file has not been opened");
}
close(fd);
return 0;
}
Perhaps you could just try and get a full write lock? It'll fail if anyone else has it open for reading or writing.
fopen("myfile.txt", "r+")
If it's not cross platform and is Win32, then you can request even more fine-grained set of locks.
See here
and look at dwShareMode, value of 0, as well as the other parameters.
Nope. Unless other application uses advisory locks.
See http://docs.sun.com/app/docs/doc/816-0213/6m6ne37v5?a=view
Non-natively, you could call out to Sysinternals' handle.exe as a last resort...
As #Neil Butterworth says, the standard library doesnt.
In unix you can use fcntl to use file locks.
You could write a wrapper for your open function, that checks for a lock (and locks if none exists) a file if its open by no one else. You shold write a wrapper for close as well, that releases that lock on file close.
Seeing you have tagged linux -> there's a command-line too and API that have been added to the Linux kernel and do just that: inotify.
Here's the man page.
In Windows this little and dirty trick will work (if the file exists and you have the right permissions)
if ( 0 != rename("c:/foo.txt", "c:/foo.txt") ) {
printf("already opened\n");
}
It's likely to work also in Linux.