commit 3b80b34de19ba6121c0b8b48bae7b78c1b092242 Author: Daniel Stenberg Date: Wed May 25 10:09:53 2022 +0200 [Backport] fopen: add Curl_fopen() for better overwriting of files Offering: RTOS CVE: CVE-2022-32207 Reference: upstream_commit_id=20f9dd6bae50b7223171b17ba7798946e74f877f DTS/AR: DTS2022062910035 type: LTS reason: fix CVE-2022-32207 for curl. weblink:https://github.com/curl/curl/commit/20f9dd6bae50b7223171b17ba7798946e74f877f Bug: https://curl.se/docs/CVE-2022-32207.html CVE-2022-32207 Reported-by: Harry Sintonen Closes #9050 Signed-off-by: laiyuanyuan diff --git a/CMakeLists.txt b/CMakeLists.txt index c85295e11..eeace1b02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -991,6 +991,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) diff --git a/configure.ac b/configure.ac index dc8e416e4..ea282b537 100644 --- a/configure.ac +++ b/configure.ac @@ -3272,6 +3272,7 @@ AC_CHECK_DECLS([getpwuid_r], [], [AC_DEFINE(HAVE_DECL_GETPWUID_R_MISSING, 1, "Se AC_CHECK_FUNCS([fnmatch \ + fchmod \ geteuid \ getpass_r \ getppid \ diff --git a/lib/Makefile.inc b/lib/Makefile.inc index 3e9ddec12..1ba733590 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -131,6 +131,7 @@ LIB_CFILES = \ escape.c \ file.c \ fileinfo.c \ + fopen.c \ formdata.c \ ftp.c \ ftplistparser.c \ @@ -263,6 +264,7 @@ LIB_HFILES = \ escape.h \ file.h \ fileinfo.h \ + fopen.h \ formdata.h \ ftp.h \ ftplistparser.h \ diff --git a/lib/cookie.c b/lib/cookie.c index b7531f742..ee0b43484 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -96,8 +96,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" @@ -1602,20 +1602,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" @@ -1662,7 +1651,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; diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake index fa4f19c74..2141884f9 100644 --- a/lib/curl_config.h.cmake +++ b/lib/curl_config.h.cmake @@ -127,6 +127,9 @@ /* Define to 1 if you have the 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 diff --git a/lib/fopen.c b/lib/fopen.c new file mode 100644 index 000000000..ad3691ba9 --- /dev/null +++ b/lib/fopen.c @@ -0,0 +1,113 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, , 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 +#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 */ diff --git a/lib/fopen.h b/lib/fopen.h new file mode 100644 index 000000000..289e55f2a --- /dev/null +++ b/lib/fopen.h @@ -0,0 +1,30 @@ +#ifndef HEADER_CURL_FOPEN_H +#define HEADER_CURL_FOPEN_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, , 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