Avoid TOCTOU in sudo_mkdir_parents; Coverity CID 204357

This commit is contained in:
Todd C. Miller
2019-10-24 20:04:32 -06:00
parent 8552b283be
commit 6c6f0567ba

View File

@@ -40,6 +40,7 @@
#endif /* HAVE_STRINGS_H */ #endif /* HAVE_STRINGS_H */
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <pwd.h> #include <pwd.h>
#include <grp.h> #include <grp.h>
@@ -58,32 +59,46 @@
bool bool
sudo_mkdir_parents_v1(char *path, uid_t uid, gid_t gid, mode_t mode, bool quiet) sudo_mkdir_parents_v1(char *path, uid_t uid, gid_t gid, mode_t mode, bool quiet)
{ {
struct stat sb;
char *slash = path; char *slash = path;
debug_decl(sudo_mkdir_parents, SUDO_DEBUG_UTIL) debug_decl(sudo_mkdir_parents, SUDO_DEBUG_UTIL)
/* cppcheck-suppress nullPointerRedundantCheck */ /* cppcheck-suppress nullPointerRedundantCheck */
while ((slash = strchr(slash + 1, '/')) != NULL) { while ((slash = strchr(slash + 1, '/')) != NULL) {
struct stat sb;
int dfd;
*slash = '\0'; *slash = '\0';
sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
"mkdir %s, mode 0%o, uid %d, gid %d", path, (unsigned int)mode, "mkdir %s, mode 0%o, uid %d, gid %d", path, (unsigned int)mode,
(int)uid, (int)gid); (int)uid, (int)gid);
if (mkdir(path, mode) == 0) { reopen:
if (uid != (uid_t)-1 && gid != (gid_t)-1) { dfd = open(path, O_RDONLY|O_NONBLOCK);
if (chown(path, uid, gid) != 0) { if (dfd == -1) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO, if (errno != ENOENT) {
"%s: unable to chown %d:%d %s", __func__, if (!quiet)
(int)uid, (int)gid, path); sudo_warn(U_("unable to open %s"), path);
} goto bad;
} }
} else { if (mkdir(path, mode) == 0) {
if (errno != EEXIST) { if (uid != (uid_t)-1 && gid != (gid_t)-1) {
if (chown(path, uid, gid) != 0) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
"%s: unable to chown %d:%d %s", __func__,
(int)uid, (int)gid, path);
}
}
} else {
if (errno == EEXIST)
goto reopen;
if (!quiet) if (!quiet)
sudo_warn(U_("unable to mkdir %s"), path); sudo_warn(U_("unable to mkdir %s"), path);
goto bad; goto bad;
} }
} else {
/* Already exists, make sure it is a directory. */ /* Already exists, make sure it is a directory. */
if (stat(path, &sb) != 0) { int rc = fstat(dfd, &sb);
close(dfd);
if (rc != 0) {
if (!quiet) if (!quiet)
sudo_warn(U_("unable to stat %s"), path); sudo_warn(U_("unable to stat %s"), path);
goto bad; goto bad;