Warning: The Use of 'Tmpnam' Is Dangerous, Better Use 'Mkstemp'

warning: the use of `tmpnam' is dangerous, better use `mkstemp'

You're looking for mkdtemp:

mkdtemp - create a unique temporary directory

e.g.,

#include <stdlib.h>
#include <string.h>
...
char templatebuf[80];
char *mkdirectory = mkdtemp(strcpy(templatebuf, "/tmp/mkprogXXXXXX"));

using strcpy to ensure the parameter passed to mkdtemp is writable (c89), or

#include <stdlib.h>
...
char templatebuf[] = "/tmp/mkprogXXXXXX";
char *mkdirectory = mkdtemp(templatebuf);

with c99.

Since the feature is "new" (only standardized within the past ten years, though provided in the mid-1990s on Linux), you need to turn the feature on in the header files with a preprocessor definition (which may differ from one platform to another). The simplest for Linux is to define _GNU_SOURCE, e.g.,

gcc -D_GNU_SOURCE -o foo foo.c

tmpnam warning saying it is dangerous

From tmpnam manpage :

The tmpnam() function generates a different string each time it is called, up to TMP_MAX times. If it is called more than TMP_MAX times, the behavior is implementation defined.

Although tmpnam() generates names that are difficult to guess, it is nevertheless possible that between the time that tmpnam() returns a pathname, and the time that the program opens it, another program might create that pathname using open(2), or create it as a symbolic link. This can lead to security holes. To avoid such possibilities, use the open(2) O_EXCL flag to open the pathname. Or better yet, use mkstemp(3) or tmpfile(3).

Mktemp really create the file, so you are assured it works, whereas tmpnam returns a name, possibly already existing.

Any way to disable `tempnam' is dangerous, better use `mkstemp' gcc warning?

If you really only want the directory name, use the string constant macro P_tmpdir, defined in <stdio.h>.

Suppress warning: the use of `mktemp' is dangerous

I guess you need the path because you pass it to a library that only accepts path names as argument and not file descriptors or FILE pointers. If so you can create a temp dir with mkdtemp and place your file there, the actual name is then unimportant because the path is already unique because of the directory.

How to replace the use of tmpnam() in the following code snippet

The problem with tmpnam() is that it generates a name that is unique and does not exist when it returns, but that name is not guaranteed to be unique by the time you use it in a call to fopen() (or open()).

The key feature of the mkstemp() function is that it creates and opens a file with the new name, so that there isn't a TOCTOU (time of check, time of use) vulnerability. This cuts down the avenues for security risks.

Code designed to use tmpnam() usually needs a file name, so using tmpfile() is usually not an option; it doesn't provide a way to find the file name. If you don't need the file name then using tmpfile() works well and is Standard C, so it is widely available.

The specific case of tmpnam() and tmpnam_s() is interesting. Although tmpnam_s() avoids some string-related problems, it does not change the behaviour of tmpnam() in the way that causes the security problems addressed by mkstemp(). So, independent of the portability issues that arise from attempting to use tmpnam_s() (or any of the other *_s() functions from Annex K of the C11 or C18 standards), it doesn't fix the problem that causes tmpnam() to be deprecated.

You can arrange to use mkstemp() instead of tmpnam() and close the file descriptor before continuing with the other code:

tmpnam(name);             // Replace this

int fd = mkstemp(name); // With this…
if (fd >= 0)
close(fd);

It's not great, but it does ensure the file is created, which reduces the security vulnerabilities a bit, but not as much as using the file descriptor directly. You could (should) wrap that into a function.

Note that the mkstemp() returns a file descriptor; if you want a file stream, you can use fdopen() to create a file stream from the file descriptor. And if that fails, you probably want to remove the file (with remove() or unlink()).

So, that gives you a need for fmkstemp():

#include <stdio.h>
#include <stdlib.h> /* mkstemp() */
#include <unistd.h> /* close() */

extern FILE *fmkstemp(char *name); /* Add to a convenient header file */

FILE *fmkstemp(char *name)
{
int fd = mkstemp(name);
FILE *fp = 0;
if (fd >= 0)
{
fp = fdopen(fd, "w+");
if (fp == 0)
{
close(fd);
unlink(name);
}
}
return(fp);
}

Note that after you've used fmkstemp(), you use fclose() to close the file stream (and, behind the scenes, that closes the file descriptor).

Don't forget to remove the temporary file before exit. That's where a function registered with atexit() or one of its variants can be useful.

Reliable way to create temporary directory

The tmpnam() function doesn't create a directory; it generates a file name that didn't exist at somewhere about the time it was invoked, but which may exist by the time you try to use it with mkdir(), which does create directories. There is typically a plethora of related functions for doing roughly the same job, but they're different on each platform.

POSIX does provide mkdtemp() and mkstemp() — the former creates a directory, the latter a file; the same page documents both — where you specify the template to the function. That leaves you in charge of the directory within which the directory or file is created.

With both mkstemp() and mkdtemp(), the directory containing the new file or directory must already exist.

One of the primary problems with using tmpnam() is that you have essentially no control over where the file is created or what the filename looks like. Almost all the other functions give you some measure of control. Not being thread-safe is usually not a major issue — you can provide a buffer that will be used, making it thread-safe.



Related Topics



Leave a reply



Submit