MCPcopy Index your code
hub / github.com/RsyncProject/rsync / secure_mkstemp

Function secure_mkstemp

syscall.c:2023–2131  ·  view source on GitHub ↗

Secure version of mkstemp that prevents symlink attacks on parent directories. Like secure_relative_open(), this walks the path checking each component with O_NOFOLLOW to prevent TOCTOU race conditions. The template may be relative or absolute, but must not contain ../ components. Returns fd on success, -1 on error. */

Source from the content-addressed store, hash-verified

2021 Returns fd on success, -1 on error.
2022*/
2023int secure_mkstemp(char *template, mode_t perms)
2024{
2025#if !defined(O_NOFOLLOW) || !defined(O_DIRECTORY) || !defined(AT_FDCWD)
2026 /* Fall back to regular mkstemp on old systems */
2027 return do_mkstemp(template, perms);
2028#else
2029 char *lastslash;
2030 int dirfd = AT_FDCWD;
2031 int fd = -1;
2032
2033 if (!template) {
2034 errno = EINVAL;
2035 return -1;
2036 }
2037 if (strncmp(template, "../", 3) == 0 || strstr(template, "/../")) {
2038 errno = EINVAL;
2039 return -1;
2040 }
2041
2042 /* For absolute paths, start the secure walk from "/" rather than CWD. */
2043 if (template[0] == '/') {
2044 dirfd = open("/", O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
2045 if (dirfd < 0)
2046 return -1;
2047 }
2048
2049 /* Find the last slash to separate directory from filename */
2050 lastslash = strrchr(template, '/');
2051 if (lastslash) {
2052 char *path_copy = my_strdup(template, __FILE__, __LINE__);
2053 if (!path_copy)
2054 return -1;
2055
2056 /* Null-terminate at the last slash to get directory part */
2057 path_copy[lastslash - template] = '\0';
2058
2059 /* Walk the directory path securely */
2060 for (const char *part = strtok(path_copy, "/");
2061 part != NULL;
2062 part = strtok(NULL, "/"))
2063 {
2064 int next_fd = openat(dirfd, part, O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
2065 if (next_fd == -1) {
2066 int save_errno = errno;
2067 free(path_copy);
2068 if (dirfd != AT_FDCWD) close(dirfd);
2069 errno = (save_errno == ELOOP) ? ELOOP : save_errno;
2070 return -1;
2071 }
2072 if (dirfd != AT_FDCWD) close(dirfd);
2073 dirfd = next_fd;
2074 }
2075 free(path_copy);
2076 }
2077
2078 /* Now create the temp file in the securely-opened directory */
2079 perms |= S_IWUSR;
2080

Callers 1

open_tmpfileFunction · 0.85

Calls 3

do_mkstempFunction · 0.85
my_strdupFunction · 0.85
rand_bytesFunction · 0.85

Tested by

no test coverage detected