mirror of
https://github.com/curl/curl.git
synced 2026-08-25 02:53:32 +03:00
fopen: add Curl_fopen() for better overwriting of files
Bug: https://curl.se/docs/CVE-2022-32207.html CVE-2022-32207 Reported-by: Harry Sintonen Closes #9050
This commit is contained in:
parent
46f8911d39
commit
20f9dd6bae
7 changed files with 154 additions and 15 deletions
|
|
@ -1067,6 +1067,7 @@ elseif(HAVE_LIBSOCKET)
|
|||
set(CMAKE_REQUIRED_LIBRARIES socket)
|
||||
endif()
|
||||
|
||||
check_symbol_exists(fchmod "${CURL_INCLUDES}" HAVE_FCHMOD)
|
||||
check_symbol_exists(basename "${CURL_INCLUDES}" HAVE_BASENAME)
|
||||
check_symbol_exists(socket "${CURL_INCLUDES}" HAVE_SOCKET)
|
||||
check_symbol_exists(select "${CURL_INCLUDES}" HAVE_SELECT)
|
||||
|
|
|
|||
|
|
@ -3438,6 +3438,7 @@ AC_CHECK_DECLS([getpwuid_r], [], [AC_DEFINE(HAVE_DECL_GETPWUID_R_MISSING, 1, "Se
|
|||
|
||||
|
||||
AC_CHECK_FUNCS([fnmatch \
|
||||
fchmod \
|
||||
geteuid \
|
||||
getpass_r \
|
||||
getppid \
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ LIB_CFILES = \
|
|||
escape.c \
|
||||
file.c \
|
||||
fileinfo.c \
|
||||
fopen.c \
|
||||
formdata.c \
|
||||
ftp.c \
|
||||
ftplistparser.c \
|
||||
|
|
@ -270,6 +271,7 @@ LIB_HFILES = \
|
|||
escape.h \
|
||||
file.h \
|
||||
fileinfo.h \
|
||||
fopen.h \
|
||||
formdata.h \
|
||||
ftp.h \
|
||||
ftplistparser.h \
|
||||
|
|
|
|||
19
lib/cookie.c
19
lib/cookie.c
|
|
@ -99,8 +99,8 @@ Example set of cookies:
|
|||
#include "curl_get_line.h"
|
||||
#include "curl_memrchr.h"
|
||||
#include "parsedate.h"
|
||||
#include "rand.h"
|
||||
#include "rename.h"
|
||||
#include "fopen.h"
|
||||
|
||||
/* The last 3 #include files should be in this order */
|
||||
#include "curl_printf.h"
|
||||
|
|
@ -1641,20 +1641,9 @@ static CURLcode cookie_output(struct Curl_easy *data,
|
|||
use_stdout = TRUE;
|
||||
}
|
||||
else {
|
||||
unsigned char randsuffix[9];
|
||||
|
||||
if(Curl_rand_hex(data, randsuffix, sizeof(randsuffix)))
|
||||
return 2;
|
||||
|
||||
tempstore = aprintf("%s.%s.tmp", filename, randsuffix);
|
||||
if(!tempstore)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
out = fopen(tempstore, FOPEN_WRITETEXT);
|
||||
if(!out) {
|
||||
error = CURLE_WRITE_ERROR;
|
||||
error = Curl_fopen(data, filename, &out, &tempstore);
|
||||
if(error)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
fputs("# Netscape HTTP Cookie File\n"
|
||||
|
|
@ -1701,7 +1690,7 @@ static CURLcode cookie_output(struct Curl_easy *data,
|
|||
if(!use_stdout) {
|
||||
fclose(out);
|
||||
out = NULL;
|
||||
if(Curl_rename(tempstore, filename)) {
|
||||
if(tempstore && Curl_rename(tempstore, filename)) {
|
||||
unlink(tempstore);
|
||||
error = CURLE_WRITE_ERROR;
|
||||
goto error;
|
||||
|
|
|
|||
|
|
@ -159,6 +159,9 @@
|
|||
/* Define to 1 if you have the <assert.h> header file. */
|
||||
#cmakedefine HAVE_ASSERT_H 1
|
||||
|
||||
/* Define to 1 if you have the `fchmod' function. */
|
||||
#cmakedefine HAVE_FCHMOD 1
|
||||
|
||||
/* Define to 1 if you have the `basename' function. */
|
||||
#cmakedefine HAVE_BASENAME 1
|
||||
|
||||
|
|
|
|||
113
lib/fopen.c
Normal file
113
lib/fopen.c
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "curl_setup.h"
|
||||
|
||||
#if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_ALTSVC) || \
|
||||
!defined(CURL_DISABLE_HSTS)
|
||||
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "urldata.h"
|
||||
#include "rand.h"
|
||||
#include "fopen.h"
|
||||
/* The last 3 #include files should be in this order */
|
||||
#include "curl_printf.h"
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
/*
|
||||
* Curl_fopen() opens a file for writing with a temp name, to be renamed
|
||||
* to the final name when completed. If there is an existing file using this
|
||||
* name at the time of the open, this function will clone the mode from that
|
||||
* file. if 'tempname' is non-NULL, it needs a rename after the file is
|
||||
* written.
|
||||
*/
|
||||
CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
|
||||
FILE **fh, char **tempname)
|
||||
{
|
||||
CURLcode result = CURLE_WRITE_ERROR;
|
||||
unsigned char randsuffix[9];
|
||||
char *tempstore = NULL;
|
||||
struct_stat sb;
|
||||
int fd = -1;
|
||||
*tempname = NULL;
|
||||
|
||||
if(stat(filename, &sb) == -1 || !S_ISREG(sb.st_mode)) {
|
||||
/* a non-regular file, fallback to direct fopen() */
|
||||
*fh = fopen(filename, FOPEN_WRITETEXT);
|
||||
if(*fh)
|
||||
return CURLE_OK;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
result = Curl_rand_hex(data, randsuffix, sizeof(randsuffix));
|
||||
if(result)
|
||||
goto fail;
|
||||
|
||||
tempstore = aprintf("%s.%s.tmp", filename, randsuffix);
|
||||
if(!tempstore) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
result = CURLE_WRITE_ERROR;
|
||||
fd = open(tempstore, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
if(fd == -1)
|
||||
goto fail;
|
||||
|
||||
#ifdef HAVE_FCHMOD
|
||||
{
|
||||
struct_stat nsb;
|
||||
if((fstat(fd, &nsb) != -1) &&
|
||||
(nsb.st_uid == sb.st_uid) && (nsb.st_gid == sb.st_gid)) {
|
||||
/* if the user and group are the same, clone the original mode */
|
||||
if(fchmod(fd, sb.st_mode) == -1)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
*fh = fdopen(fd, FOPEN_WRITETEXT);
|
||||
if(!*fh)
|
||||
goto fail;
|
||||
|
||||
*tempname = tempstore;
|
||||
return CURLE_OK;
|
||||
|
||||
fail:
|
||||
if(fd != -1) {
|
||||
close(fd);
|
||||
unlink(tempstore);
|
||||
}
|
||||
|
||||
free(tempstore);
|
||||
|
||||
*tempname = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* ! disabled */
|
||||
30
lib/fopen.h
Normal file
30
lib/fopen.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef HEADER_CURL_FOPEN_H
|
||||
#define HEADER_CURL_FOPEN_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
|
||||
FILE **fh, char **tempname);
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue