From: Daniel Stenberg Date: Sun, 21 Dec 2025 22:40:24 +0000 (+0100) Subject: curlx: curlx_strcopy() instead of strcpy() X-Git-Tag: rc-8_18_0-3~20 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a535be4ea0960cfaeeaf744128a3acb4b7e8b67a;p=thirdparty%2Fcurl.git curlx: curlx_strcopy() instead of strcpy() This function REQUIRES the size of the target buffer as well as the length of the source string. Meant to make it harder to do a bad strcpy(). Removes 23 calls to strcpy(). Closes #20067 --- diff --git a/lib/Makefile.inc b/lib/Makefile.inc index 47358a1f87..402a5be229 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -31,6 +31,7 @@ LIB_CURLX_CFILES = \ curlx/inet_pton.c \ curlx/multibyte.c \ curlx/nonblock.c \ + curlx/strcopy.c \ curlx/strerr.c \ curlx/strparse.c \ curlx/timediff.c \ @@ -51,6 +52,7 @@ LIB_CURLX_HFILES = \ curlx/multibyte.h \ curlx/nonblock.h \ curlx/snprintf.h \ + curlx/strcopy.h \ curlx/strerr.h \ curlx/strparse.h \ curlx/timediff.h \ diff --git a/lib/curl_gethostname.c b/lib/curl_gethostname.c index e339e60798..4d772cb491 100644 --- a/lib/curl_gethostname.c +++ b/lib/curl_gethostname.c @@ -23,8 +23,8 @@ ***************************************************************************/ #include "curl_setup.h" - #include "curl_gethostname.h" +#include "curlx/strcopy.h" /* * Curl_gethostname() is a wrapper around gethostname() which allows @@ -60,7 +60,7 @@ int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen) const char *force_hostname = getenv("CURL_GETHOSTNAME"); if(force_hostname) { if(strlen(force_hostname) < (size_t)namelen) - strcpy(name, force_hostname); + curlx_strcopy(name, namelen, force_hostname, strlen(force_hostname)); else return 1; /* cannot do it */ err = 0; diff --git a/lib/curl_gssapi.c b/lib/curl_gssapi.c index efd293f15e..2145b42686 100644 --- a/lib/curl_gssapi.c +++ b/lib/curl_gssapi.c @@ -28,6 +28,7 @@ #include "curl_gssapi.h" #include "curl_trc.h" +#include "curlx/strcopy.h" #ifdef DEBUGBUILD #if defined(HAVE_GSSGNU) || !defined(_WIN32) @@ -224,7 +225,7 @@ stub_gss_init_sec_context(OM_uint32 *min, return GSS_S_FAILURE; } - strcpy(ctx->creds, creds); + curlx_strcopy(ctx->creds, sizeof(ctx->creds), creds, strlen(creds)); ctx->flags = req_flags; } diff --git a/lib/curl_trc.c b/lib/curl_trc.c index 97a4c23960..fd80a76ee5 100644 --- a/lib/curl_trc.c +++ b/lib/curl_trc.c @@ -43,6 +43,7 @@ #include "curlx/strparse.h" #include "vtls/vtls.h" #include "vquic/vquic.h" +#include "curlx/strcopy.h" static void trc_write(struct Curl_easy *data, curl_infotype type, const char *ptr, size_t size) @@ -184,7 +185,7 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...) len = curl_mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap); if(data->set.errorbuffer && !data->state.errorbuf) { - strcpy(data->set.errorbuffer, error); + curlx_strcopy(data->set.errorbuffer, CURL_ERROR_SIZE, error, len); data->state.errorbuf = TRUE; /* wrote error string */ } error[len++] = '\n'; diff --git a/lib/curlx/curlx.h b/lib/curlx/curlx.h index 67219603f9..817acb07cd 100644 --- a/lib/curlx/curlx.h +++ b/lib/curlx/curlx.h @@ -55,6 +55,9 @@ #include "strparse.h" /* The curlx_str_* parsing functions */ +#include "strcopy.h" +/* curlx_strcopy */ + #include "dynbuf.h" /* The curlx_dyn_* functions */ diff --git a/lib/curlx/inet_ntop.c b/lib/curlx/inet_ntop.c index 96c58273e2..e3dfdc93d1 100644 --- a/lib/curlx/inet_ntop.c +++ b/lib/curlx/inet_ntop.c @@ -33,6 +33,7 @@ #include "inet_ntop.h" #include "snprintf.h" +#include "strcopy.h" #define IN6ADDRSZ 16 /* #define INADDRSZ 4 */ @@ -78,7 +79,7 @@ static char *inet_ntop4(const unsigned char *src, char *dst, size_t size) #endif return NULL; } - strcpy(dst, tmp); + curlx_strcopy(dst, size, tmp, len); return dst; } @@ -183,8 +184,7 @@ static char *inet_ntop6(const unsigned char *src, char *dst, size_t size) *tp++ = ':'; *tp++ = '\0'; - /* Check for overflow, copy, and we are done. - */ + /* Check for overflow, copy, and we are done. */ if((size_t)(tp - tmp) > size) { #ifdef USE_WINSOCK errno = WSAEINVAL; @@ -193,7 +193,8 @@ static char *inet_ntop6(const unsigned char *src, char *dst, size_t size) #endif return NULL; } - strcpy(dst, tmp); + + curlx_strcopy(dst, size, tmp, strlen(tmp)); return dst; } diff --git a/lib/curlx/strcopy.c b/lib/curlx/strcopy.c new file mode 100644 index 0000000000..7ca1b9a057 --- /dev/null +++ b/lib/curlx/strcopy.c @@ -0,0 +1,49 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 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" +#include "strcopy.h" + +/* + * curlx_strcopy() is a replacement for strcpy(). + * + * Provide the target buffer @dest and size of the target buffer @dsize, If + * the source string @src with its *string length* @slen fits in the target + * buffer it will be copied there - including storing a null terminator. + * + * If the target buffer is too small, the copy is not performed but if the + * target buffer has a non-zero size it will get a null terminator stored. + */ +void curlx_strcopy(char *dest, /* destination buffer */ + size_t dsize, /* size of target buffer */ + const char *src, /* source string */ + size_t slen) /* length of source string to copy */ +{ + DEBUGASSERT(slen < dsize); + if(slen < dsize) { + memcpy(dest, src, slen); + dest[slen] = 0; + } + else if(dsize) + dest[0] = 0; +} diff --git a/lib/curlx/strcopy.h b/lib/curlx/strcopy.h new file mode 100644 index 0000000000..d671149cb8 --- /dev/null +++ b/lib/curlx/strcopy.h @@ -0,0 +1,32 @@ +#ifndef HEADER_CURLX_STRCOPY_H +#define HEADER_CURLX_STRCOPY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 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 + * + ***************************************************************************/ + +void curlx_strcopy(char *dest, + size_t dsize, /* size of target buffer */ + const char *src, + size_t slen); /* length of string to copy */ + +#endif /* HEADER_CURLX_STRCOPY_H */ diff --git a/lib/curlx/strerr.c b/lib/curlx/strerr.c index a971875a69..addafd2897 100644 --- a/lib/curlx/strerr.c +++ b/lib/curlx/strerr.c @@ -35,6 +35,7 @@ #include "winapi.h" #include "snprintf.h" #include "strerr.h" +#include "strcopy.h" #ifdef USE_WINSOCK /* This is a helper function for curlx_strerror that converts Winsock error @@ -224,8 +225,7 @@ static const char *get_winsock_error(int err, char *buf, size_t len) return NULL; } alen = strlen(p); - if(alen < len) - strcpy(buf, p); + curlx_strcopy(buf, len, p, alen); return buf; #endif } diff --git a/lib/curlx/winapi.c b/lib/curlx/winapi.c index 3243f7cb4a..b46a5bf0dd 100644 --- a/lib/curlx/winapi.c +++ b/lib/curlx/winapi.c @@ -30,6 +30,7 @@ #ifdef _WIN32 #include "winapi.h" #include "snprintf.h" +#include "strcopy.h" /* This is a helper function for curlx_strerror that converts Windows API error * codes (GetLastError) to error messages. @@ -93,8 +94,7 @@ const char *curlx_winapi_strerror(DWORD err, char *buf, size_t buflen) #else { const char *txt = (err == ERROR_SUCCESS) ? "No error" : "Error"; - if(strlen(txt) < buflen) - strcpy(buf, txt); + curlx_strcopy(buf, buflen, txt, strlen(txt)); } #endif diff --git a/lib/hostip.c b/lib/hostip.c index 2cf8d4bb1e..aba12ef791 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -60,6 +60,7 @@ #include "select.h" #include "strcase.h" #include "easy_lock.h" +#include "curlx/strcopy.h" #include "curlx/strparse.h" #if defined(CURLRES_SYNCH) && \ @@ -622,7 +623,7 @@ static struct Curl_addrinfo *get_localhost6(int port, const char *name) ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo)); memcpy(ca->ai_addr, &sa6, ss_size); ca->ai_canonname = (char *)ca->ai_addr + ss_size; - strcpy(ca->ai_canonname, name); + curlx_strcopy(ca->ai_canonname, hostlen + 1, name, hostlen); return ca; } #else @@ -659,7 +660,7 @@ static struct Curl_addrinfo *get_localhost(int port, const char *name) ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo)); memcpy(ca->ai_addr, &sa, ss_size); ca->ai_canonname = (char *)ca->ai_addr + ss_size; - strcpy(ca->ai_canonname, name); + curlx_strcopy(ca->ai_canonname, hostlen + 1, name, hostlen); ca6 = get_localhost6(port, name); if(!ca6) diff --git a/lib/hsts.c b/lib/hsts.c index 393572a6c2..a4e233e61e 100644 --- a/lib/hsts.c +++ b/lib/hsts.c @@ -37,6 +37,7 @@ #include "curl_share.h" #include "curlx/strparse.h" #include "curlx/timeval.h" +#include "curlx/strcopy.h" #define MAX_HSTS_LINE 4095 #define MAX_HSTS_HOSTLEN 2048 @@ -294,7 +295,7 @@ static CURLcode hsts_push(struct Curl_easy *data, stamp.tm_hour, stamp.tm_min, stamp.tm_sec); } else - strcpy(e.expire, UNLIMITED); + curlx_strcopy(e.expire, sizeof(e.expire), UNLIMITED, strlen(UNLIMITED)); sc = data->set.hsts_write(data, &e, i, data->set.hsts_write_userp); *stop = (sc != CURLSTS_OK); diff --git a/lib/imap.c b/lib/imap.c index 20455a957a..c5da40c4e4 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -73,7 +73,7 @@ #include "url.h" #include "bufref.h" #include "curl_sasl.h" - +#include "curlx/strcopy.h" /* meta key for storing protocol meta at easy handle */ #define CURL_META_IMAP_EASY "meta:proto:imap:easy" @@ -1679,7 +1679,7 @@ static CURLcode imap_connect(struct Curl_easy *data, bool *done) imap_state(data, imapc, IMAP_SERVERGREET); /* Start off with an response id of '*' */ - strcpy(imapc->resptag, "*"); + curlx_strcopy(imapc->resptag, sizeof(imapc->resptag), "*", 1); result = imap_multi_statemach(data, done); diff --git a/lib/mime.c b/lib/mime.c index b6b64fd10f..011201a7cb 100644 --- a/lib/mime.c +++ b/lib/mime.c @@ -32,6 +32,7 @@ struct Curl_easy; #include "curl_trc.h" #include "transfer.h" #include "strdup.h" +#include "curlx/strcopy.h" #include "curlx/fopen.h" #include "curlx/base64.h" @@ -602,7 +603,7 @@ static size_t encoder_qp_read(char *buffer, size_t size, bool ateof, } } if(softlinebreak) { - strcpy(buf, "\x3D\x0D\x0A"); /* "=\r\n" */ + curlx_strcopy(buf, sizeof(buf), "\x3D\x0D\x0A", 3); /* "=\r\n" */ len = 3; consumed = 0; } diff --git a/lib/progress.c b/lib/progress.c index 18dde19163..fc0164c172 100644 --- a/lib/progress.c +++ b/lib/progress.c @@ -30,6 +30,7 @@ #include "progress.h" #include "transfer.h" #include "curlx/timeval.h" +#include "curlx/strcopy.h" /* check rate limits within this many recent milliseconds, at minimum. */ #define MIN_RATE_LIMIT_PERIOD 3000 @@ -37,18 +38,18 @@ #ifndef CURL_DISABLE_PROGRESS_METER /* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero byte) */ -static void time2str(char *r, curl_off_t seconds) +static void time2str(char *r, size_t rsize, curl_off_t seconds) { curl_off_t h; if(seconds <= 0) { - strcpy(r, "--:--:--"); + curlx_strcopy(r, rsize, "--:--:--", 8); return; } h = seconds / 3600; if(h <= 99) { curl_off_t m = (seconds - (h * 3600)) / 60; curl_off_t s = (seconds - (h * 3600)) - (m * 60); - curl_msnprintf(r, 9, "%2" FMT_OFF_T ":%02" FMT_OFF_T ":%02" FMT_OFF_T, + curl_msnprintf(r, rsize, "%2" FMT_OFF_T ":%02" FMT_OFF_T ":%02" FMT_OFF_T, h, m, s); } else { @@ -57,21 +58,21 @@ static void time2str(char *r, curl_off_t seconds) curl_off_t d = seconds / 86400; h = (seconds - (d * 86400)) / 3600; if(d <= 999) - curl_msnprintf(r, 9, "%3" FMT_OFF_T "d %02" FMT_OFF_T "h", d, h); + curl_msnprintf(r, rsize, "%3" FMT_OFF_T "d %02" FMT_OFF_T "h", d, h); else - curl_msnprintf(r, 9, "%7" FMT_OFF_T "d", d); + curl_msnprintf(r, rsize, "%7" FMT_OFF_T "d", d); } } /* The point of this function would be to return a string of the input data, but never longer than 6 columns (+ one zero byte). Add suffix k, M, G when suitable... */ -static char *max6data(curl_off_t bytes, char *max6) +static char *max6out(curl_off_t bytes, char *max6, size_t mlen) { /* a signed 64-bit value is 8192 petabytes maximum, shown as 8.0E (exabytes)*/ if(bytes < 100000) - curl_msnprintf(max6, 7, "%6" CURL_FORMAT_CURL_OFF_T, bytes); + curl_msnprintf(max6, mlen, "%6" CURL_FORMAT_CURL_OFF_T, bytes); else { const char unit[] = { 'k', 'M', 'G', 'T', 'P', 'E', 0 }; int k = 0; @@ -85,7 +86,7 @@ static char *max6data(curl_off_t bytes, char *max6) DEBUGASSERT(unit[k]); } while(unit[k]); /* xxx.yU */ - curl_msnprintf(max6, 7, "%3" CURL_FORMAT_CURL_OFF_T + curl_msnprintf(max6, mlen, "%3" CURL_FORMAT_CURL_OFF_T ".%" CURL_FORMAT_CURL_OFF_T "%c", nbytes, (bytes % 1024) / (1024 / 10), unit[k]); } @@ -528,9 +529,10 @@ static void progress_meter(struct Curl_easy *data) /* Since both happen at the same time, total expected duration is max. */ total_estm.secs = CURLMAX(ul_estm.secs, dl_estm.secs); /* create the three time strings */ - time2str(time_left, total_estm.secs > 0 ? (total_estm.secs - cur_secs) : 0); - time2str(time_total, total_estm.secs); - time2str(time_spent, cur_secs); + time2str(time_left, sizeof(time_left), + total_estm.secs > 0 ? (total_estm.secs - cur_secs) : 0); + time2str(time_total, sizeof(time_total), total_estm.secs); + time2str(time_spent, sizeof(time_spent), cur_secs); /* Get the total amount of data expected to get transferred */ total_expected_size = p->ul_size_known ? p->ul.total_size : p->ul.cur_size; @@ -554,18 +556,24 @@ static void progress_meter(struct Curl_easy *data) "%3" FMT_OFF_T " %s " "%3" FMT_OFF_T " %s " "%3" FMT_OFF_T " %s %s %s %s %s %s %s", - total_estm.percent, /* 3 letters */ /* total % */ - max6data(total_expected_size, max6[2]), /* total size */ - dl_estm.percent, /* 3 letters */ /* rcvd % */ - max6data(p->dl.cur_size, max6[0]), /* rcvd size */ - ul_estm.percent, /* 3 letters */ /* xfer % */ - max6data(p->ul.cur_size, max6[1]), /* xfer size */ - max6data(p->dl.speed, max6[3]), /* avrg dl speed */ - max6data(p->ul.speed, max6[4]), /* avrg ul speed */ - time_total, /* 8 letters */ /* total time */ - time_spent, /* 8 letters */ /* time spent */ - time_left, /* 8 letters */ /* time left */ - max6data(p->current_speed, max6[5]) + total_estm.percent, /* 3 letters */ /* total % */ + max6out(total_expected_size, max6[2], + sizeof(max6[2])), /* total size */ + dl_estm.percent, /* 3 letters */ /* rcvd % */ + max6out(p->dl.cur_size, max6[0], + sizeof(max6[0])), /* rcvd size */ + ul_estm.percent, /* 3 letters */ /* xfer % */ + max6out(p->ul.cur_size, max6[1], + sizeof(max6[1])), /* xfer size */ + max6out(p->dl.speed, max6[3], + sizeof(max6[3])), /* avrg dl speed */ + max6out(p->ul.speed, max6[4], + sizeof(max6[4])), /* avrg ul speed */ + time_total, /* 8 letters */ /* total time */ + time_spent, /* 8 letters */ /* time spent */ + time_left, /* 8 letters */ /* time left */ + max6out(p->current_speed, max6[5], + sizeof(max6[5])) /* current speed */ ); /* we flush the output stream to make it appear as soon as possible */ diff --git a/lib/smb.c b/lib/smb.c index d9eeec83a5..5f3e419a42 100644 --- a/lib/smb.c +++ b/lib/smb.c @@ -40,7 +40,7 @@ #include "curl_ntlm_core.h" #include "escape.h" #include "curl_endian.h" - +#include "curlx/strcopy.h" /* meta key for storing protocol meta at easy handle */ #define CURL_META_SMB_EASY "meta:proto:smb:easy" @@ -790,7 +790,7 @@ static CURLcode smb_send_open(struct Curl_easy *data, msg.create_disposition = smb_swap32(SMB_FILE_OPEN); } msg.byte_count = smb_swap16((unsigned short)byte_count); - strcpy(msg.bytes, req->path); + curlx_strcopy(msg.bytes, sizeof(msg.bytes), req->path, byte_count - 1); return smb_send_message(data, smbc, req, SMB_COM_NT_CREATE_ANDX, &msg, sizeof(msg) - sizeof(msg.bytes) + byte_count); diff --git a/lib/strdup.h b/lib/strdup.h index 22ade4d7ff..cd01ffbdb8 100644 --- a/lib/strdup.h +++ b/lib/strdup.h @@ -34,5 +34,4 @@ wchar_t *Curl_wcsdup(const wchar_t *src); void *Curl_memdup(const void *src, size_t buffer_length); void *Curl_saferealloc(void *ptr, size_t size); void *Curl_memdup0(const char *src, size_t length); - #endif /* HEADER_CURL_STRDUP_H */ diff --git a/lib/strerror.c b/lib/strerror.c index a15a8d01b4..6c655f4fe6 100644 --- a/lib/strerror.c +++ b/lib/strerror.c @@ -30,6 +30,7 @@ #include "curlx/winapi.h" #include "strerror.h" +#include "curlx/strcopy.h" const char *curl_easy_strerror(CURLcode error) { @@ -663,8 +664,7 @@ const char *Curl_sspi_strerror(SECURITY_STATUS err, char *buf, size_t buflen) txt = "No error"; else txt = "Error"; - if(buflen > strlen(txt)) - strcpy(buf, txt); + curlx_strcopy(buf, buflen, txt, strlen(txt)); #endif if(errno != old_errno) diff --git a/lib/tftp.c b/lib/tftp.c index d457611662..0e03933ab9 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -62,6 +62,7 @@ #include "escape.h" #include "curlx/strerr.h" #include "curlx/strparse.h" +#include "curlx/strcopy.h" /* RFC2348 allows the block size to be negotiated */ #define TFTP_BLKSIZE_DEFAULT 512 @@ -369,12 +370,17 @@ static CURLcode tftp_parse_option_ack(struct tftp_conn *state, } static CURLcode tftp_option_add(struct tftp_conn *state, size_t *csize, - char *buf, const char *option) + size_t index, const char *option) { - if((strlen(option) + *csize + 1) > (size_t)state->blksize) + char *buf = (char *)&state->spacket.data[index]; + size_t oplen = strlen(option); + size_t blen; + if((state->blksize <= index) || + (oplen + 1) > (size_t)(state->blksize - index)) return CURLE_TFTP_ILLEGAL; - strcpy(buf, option); - *csize += strlen(option) + 1; + blen = state->blksize - index; + curlx_strcopy(buf, blen, option, oplen); + *csize += oplen + 1; return CURLE_OK; } @@ -479,32 +485,23 @@ static CURLcode tftp_send_first(struct tftp_conn *state, data->state.upload && (data->state.infilesize != -1) ? data->state.infilesize : 0); - result = tftp_option_add(state, &sbytes, - (char *)state->spacket.data + sbytes, - TFTP_OPTION_TSIZE); + result = tftp_option_add(state, &sbytes, sbytes, TFTP_OPTION_TSIZE); if(result == CURLE_OK) - result = tftp_option_add(state, &sbytes, - (char *)state->spacket.data + sbytes, buf); + result = tftp_option_add(state, &sbytes, sbytes, buf); /* add blksize option */ curl_msnprintf(buf, sizeof(buf), "%d", state->requested_blksize); if(result == CURLE_OK) - result = tftp_option_add(state, &sbytes, - (char *)state->spacket.data + sbytes, - TFTP_OPTION_BLKSIZE); + result = tftp_option_add(state, &sbytes, sbytes, TFTP_OPTION_BLKSIZE); if(result == CURLE_OK) - result = tftp_option_add(state, &sbytes, - (char *)state->spacket.data + sbytes, buf); + result = tftp_option_add(state, &sbytes, sbytes, buf); /* add timeout option */ curl_msnprintf(buf, sizeof(buf), "%d", state->retry_time); if(result == CURLE_OK) - result = tftp_option_add(state, &sbytes, - (char *)state->spacket.data + sbytes, - TFTP_OPTION_INTERVAL); + result = tftp_option_add(state, &sbytes, sbytes, TFTP_OPTION_INTERVAL); if(result == CURLE_OK) - result = tftp_option_add(state, &sbytes, - (char *)state->spacket.data + sbytes, buf); + result = tftp_option_add(state, &sbytes, sbytes, buf); if(result != CURLE_OK) { failf(data, "TFTP buffer too small for options"); diff --git a/lib/urlapi.c b/lib/urlapi.c index f84ee2ed09..747ac814ba 100644 --- a/lib/urlapi.c +++ b/lib/urlapi.c @@ -509,7 +509,7 @@ static CURLUcode ipv6_parse(struct Curl_URL *u, char *hostname, hostname[hlen] = 0; /* end the address there */ if(curlx_inet_pton(AF_INET6, hostname, dest) != 1) return CURLUE_BAD_IPV6; - if(curlx_inet_ntop(AF_INET6, dest, hostname, hlen)) { + if(curlx_inet_ntop(AF_INET6, dest, hostname, hlen + 1)) { hlen = strlen(hostname); /* might be shorter now */ hostname[hlen + 1] = 0; } diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index b2394d287c..cffe61a402 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -53,6 +53,7 @@ #include "../url.h" #include "../bufref.h" #include "../curlx/strerr.h" +#include "../curlx/strcopy.h" /* A stream window is the maximum amount we need to buffer for * each active transfer. We use HTTP/3 flow control and only ACK @@ -141,7 +142,7 @@ static char *osslq_strerror(unsigned long error, char *buf, size_t size) if(!*buf) { const char *msg = error ? "Unknown error" : "No error"; if(strlen(msg) < size) - strcpy(buf, msg); + curlx_strcopy(buf, size, msg, strlen(msg)); } return buf; diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 99ee20974c..dcc76a9299 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -61,6 +61,7 @@ #include "../multiif.h" #include "../curlx/strerr.h" #include "../curlx/strparse.h" +#include "../curlx/strcopy.h" #include "../strdup.h" #include "apple.h" @@ -773,8 +774,7 @@ static char *ossl_strerror(unsigned long error, char *buf, size_t size) if(!*buf) { const char *msg = error ? "Unknown error" : "No error"; - if(strlen(msg) < size) - strcpy(buf, msg); + curlx_strcopy(buf, size, msg, strlen(msg)); } return buf; diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index ed63842b36..78f17ea132 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -72,6 +72,7 @@ #include "../select.h" #include "../setopt.h" #include "../strdup.h" +#include "../curlx/strcopy.h" #ifdef USE_APPLE_SECTRUST #include @@ -1082,10 +1083,7 @@ static size_t multissl_version(char *buffer, size_t size) } if(size) { - if(backends_len < size) - strcpy(buffer, backends); - else - *buffer = 0; /* did not fit */ + curlx_strcopy(buffer, size, backends, backends_len); } return 0; } diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index 9f75b54df3..3ccd0917a4 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -62,6 +62,7 @@ #include "../connect.h" /* for the connect timeout */ #include "../progress.h" #include "../strdup.h" +#include "../curlx/strcopy.h" #include "x509asn1.h" #include @@ -1542,8 +1543,7 @@ static char *wssl_strerror(unsigned long error, char *buf, unsigned long size) if(!*buf) { const char *msg = error ? "Unknown error" : "No error"; - /* the string fits because the assert above assures this */ - strcpy(buf, msg); + curlx_strcopy(buf, size, msg, strlen(msg)); } return buf; diff --git a/lib/ws.c b/lib/ws.c index c97586ec02..0f60d44213 100644 --- a/lib/ws.c +++ b/lib/ws.c @@ -40,6 +40,7 @@ #include "transfer.h" #include "select.h" #include "curlx/strparse.h" +#include "curlx/strcopy.h" /*** RFC 6455 Section 5.2 @@ -1274,7 +1275,7 @@ CURLcode Curl_ws_request(struct Curl_easy *data, struct dynbuf *req) curlx_free(randstr); return CURLE_FAILED_INIT; } - strcpy(keyval, randstr); + curlx_strcopy(keyval, sizeof(keyval), randstr, randlen); curlx_free(randstr); for(i = 0; !result && (i < CURL_ARRAYSIZE(heads)); i++) { if(!Curl_checkheaders(data, heads[i].name, strlen(heads[i].name))) { diff --git a/src/Makefile.inc b/src/Makefile.inc index 82c3817ce9..4e8efdd926 100644 --- a/src/Makefile.inc +++ b/src/Makefile.inc @@ -38,6 +38,7 @@ CURLX_CFILES = \ ../lib/curlx/fopen.c \ ../lib/curlx/multibyte.c \ ../lib/curlx/nonblock.c \ + ../lib/curlx/strcopy.c \ ../lib/curlx/strerr.c \ ../lib/curlx/strparse.c \ ../lib/curlx/timediff.c \ @@ -55,6 +56,7 @@ CURLX_HFILES = \ ../lib/curlx/multibyte.h \ ../lib/curlx/nonblock.h \ ../lib/curlx/snprintf.h \ + ../lib/curlx/strcopy.h \ ../lib/curlx/strerr.h \ ../lib/curlx/strparse.h \ ../lib/curlx/timediff.h \ diff --git a/src/tool_main.c b/src/tool_main.c index 3784f280f6..e4a5467de7 100644 --- a/src/tool_main.c +++ b/src/tool_main.c @@ -108,9 +108,7 @@ static void memory_tracking_init(void) if(env) { /* use the value as filename */ char fname[512]; - if(strlen(env) >= sizeof(fname)) - env[sizeof(fname) - 1] = '\0'; - strcpy(fname, env); + curlx_strcopy(fname, sizeof(fname), env, strlen(env)); curl_free(env); curl_dbg_memdebug(fname); /* this weird stuff here is to make curl_free() get called before diff --git a/src/tool_progress.c b/src/tool_progress.c index 53ed9bcb3c..5ed038917e 100644 --- a/src/tool_progress.c +++ b/src/tool_progress.c @@ -29,13 +29,13 @@ /* The point of this function would be to return a string of the input data, but never longer than 5 columns (+ one zero byte). Add suffix k, M, G when suitable... */ -static char *max5data(curl_off_t bytes, char *max5) +static char *max5data(curl_off_t bytes, char *max5, size_t mlen) { /* a signed 64-bit value is 8192 petabytes maximum */ - const char unit[] = { 'k', 'M', 'G', 'T', 'P', 0 }; + const char unit[] = { 'k', 'M', 'G', 'T', 'P', 'E', 0 }; int k = 0; if(bytes < 100000) { - curl_msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes); + curl_msnprintf(max5, mlen, "%5" CURL_FORMAT_CURL_OFF_T, bytes); return max5; } @@ -43,14 +43,14 @@ static char *max5data(curl_off_t bytes, char *max5) curl_off_t nbytes = bytes / 1024; if(nbytes < 100) { /* display with a decimal */ - curl_msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" + curl_msnprintf(max5, mlen, "%2" CURL_FORMAT_CURL_OFF_T ".%0" CURL_FORMAT_CURL_OFF_T "%c", bytes / 1024, (bytes % 1024) / (1024 / 10), unit[k]); break; } else if(nbytes < 10000) { /* no decimals */ - curl_msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "%c", nbytes, + curl_msnprintf(max5, mlen, "%4" CURL_FORMAT_CURL_OFF_T "%c", nbytes, unit[k]); break; } @@ -87,18 +87,18 @@ int xferinfo_cb(void *clientp, /* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero byte) */ -static void time2str(char *r, curl_off_t seconds) +static void time2str(char *r, size_t rlen, curl_off_t seconds) { curl_off_t h; if(seconds <= 0) { - strcpy(r, "--:--:--"); + curlx_strcopy(r, rlen, "--:--:--", 8); return; } h = seconds / 3600; if(h <= 99) { curl_off_t m = (seconds - (h * 3600)) / 60; curl_off_t s = (seconds - (h * 3600)) - (m * 60); - curl_msnprintf(r, 9, "%2" CURL_FORMAT_CURL_OFF_T + curl_msnprintf(r, rlen, "%2" CURL_FORMAT_CURL_OFF_T ":%02" CURL_FORMAT_CURL_OFF_T ":%02" CURL_FORMAT_CURL_OFF_T, h, m, s); } @@ -108,10 +108,10 @@ static void time2str(char *r, curl_off_t seconds) curl_off_t d = seconds / 86400; h = (seconds - (d * 86400)) / 3600; if(d <= 999) - curl_msnprintf(r, 9, "%3" CURL_FORMAT_CURL_OFF_T + curl_msnprintf(r, rlen, "%3" CURL_FORMAT_CURL_OFF_T "d %02" CURL_FORMAT_CURL_OFF_T "h", d, h); else - curl_msnprintf(r, 9, "%7" CURL_FORMAT_CURL_OFF_T "d", d); + curl_msnprintf(r, rlen, "%7" CURL_FORMAT_CURL_OFF_T "d", d); } } @@ -254,14 +254,14 @@ bool progress_meter(CURLM *multi, struct curltime *start, bool final) if(dlknown && speed) { curl_off_t est = all_dltotal / speed; curl_off_t left = (all_dltotal - all_dlnow) / speed; - time2str(time_left, left); - time2str(time_total, est); + time2str(time_left, sizeof(time_left), left); + time2str(time_total, sizeof(time_total), est); } else { - time2str(time_left, 0); - time2str(time_total, 0); + time2str(time_left, sizeof(time_left), 0); + time2str(time_total, sizeof(time_total), 0); } - time2str(time_spent, spent); + time2str(time_spent, sizeof(time_spent), spent); (void)curl_multi_get_offt(multi, CURLMINFO_XFERS_ADDED, &xfers_added); (void)curl_multi_get_offt(multi, CURLMINFO_XFERS_RUNNING, &xfers_running); @@ -281,14 +281,14 @@ bool progress_meter(CURLM *multi, struct curltime *start, bool final) dlpercen, /* 3 letters */ ulpercen, /* 3 letters */ - max5data(all_dlnow, buffer[0]), - max5data(all_ulnow, buffer[1]), + max5data(all_dlnow, buffer[0], sizeof(buffer[0])), + max5data(all_ulnow, buffer[1], sizeof(buffer[1])), xfers_added, xfers_running, time_total, time_spent, time_left, - max5data(speed, buffer[2]), /* speed */ + max5data(speed, buffer[2], sizeof(buffer[2])), /* speed */ final ? "\n" : ""); return TRUE; } diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc index ab616ca67a..e365e4e6f9 100644 --- a/tests/libtest/Makefile.inc +++ b/tests/libtest/Makefile.inc @@ -37,6 +37,7 @@ CURLX_C = \ ../../lib/curl_threads.c \ ../../lib/curlx/fopen.c \ ../../lib/curlx/multibyte.c \ + ../../lib/curlx/strcopy.c \ ../../lib/curlx/strerr.c \ ../../lib/curlx/strparse.c \ ../../lib/curlx/timediff.c \ diff --git a/tests/server/Makefile.inc b/tests/server/Makefile.inc index eb81a34949..96da26d643 100644 --- a/tests/server/Makefile.inc +++ b/tests/server/Makefile.inc @@ -40,6 +40,7 @@ CURLX_C = \ ../../lib/curlx/inet_pton.c \ ../../lib/curlx/multibyte.c \ ../../lib/curlx/nonblock.c \ + ../../lib/curlx/strcopy.c \ ../../lib/curlx/strerr.c \ ../../lib/curlx/strparse.c \ ../../lib/curlx/timediff.c \