Skip to content

feat: safe sscanf #108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ psqlodbca_la_SOURCES = \
statement.c tuple.c dlg_specific.c \
multibyte.c odbcapi.c descriptor.c \
odbcapi30.c pgapi30.c mylog.c \
secure_sscanf.c \
\
bind.h catfunc.h columninfo.h connection.h convert.h \
descriptor.h dlg_specific.h environ.h unicode_support.h \
lobj.h misc.h multibyte.h pgapifunc.h pgtypes.h \
psqlodbc.h qresult.h resource.h statement.h tuple.h \
version.h pgenlist.h mylog.h xalibname.h
version.h pgenlist.h mylog.h xalibname.h \
secure_sscanf.h

psqlodbcw_la_SOURCES = $(psqlodbca_la_SOURCES) \
odbcapi30w.c odbcapiw.c win_unicode.c
Expand Down
88 changes: 65 additions & 23 deletions convert.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
#include "catfunc.h"
#include "pgapifunc.h"

#include "secure_sscanf.h"

CSTR NAN_STRING = "NaN";
CSTR INFINITY_STRING = "Infinity";
CSTR MINFINITY_STRING = "-Infinity";
Expand Down Expand Up @@ -255,14 +257,16 @@ static SQLLEN pg_bin2whex(const char *src, SQLWCHAR *dst, SQLLEN length);
#else
static ODBCINT64 ATOI64(const char *val)
{
int status;
ODBCINT64 ll;
sscanf(val, "%lld", &ll);
secure_sscanf(val, &status, "%lld", ARG_LLONG(&ll));
return ll;
}
static unsigned ODBCINT64 ATOI64U(const char *val)
{
int status;
unsigned ODBCINT64 ll;
sscanf(val, "%llu", &ll);
secure_sscanf(val, &status, "%llu", ARG_ULLONG(&ll));
return ll;
}
#endif /* HAVE_STRTOLL */
Expand All @@ -283,6 +287,7 @@ timestamp2stime(const char *str, SIMPLE_TIME *st, BOOL *bZone, int *zone)
char rest[64], bc[16],
*ptr;
int scnt,
status,
i;
int y, m, d, hh, mm, ss;
#ifdef TIMEZONE_GLOBAL
Expand All @@ -296,7 +301,10 @@ timestamp2stime(const char *str, SIMPLE_TIME *st, BOOL *bZone, int *zone)
st->infinity = 0;
rest[0] = '\0';
bc[0] = '\0';
if ((scnt = sscanf(str, "%4d-%2d-%2d %2d:%2d:%2d%31s %15s", &y, &m, &d, &hh, &mm, &ss, rest, bc)) < 6)
if ((scnt = secure_sscanf(str, &status, "%4d-%2d-%2d %2d:%2d:%2d%31s %15s",
ARG_INT(&y), ARG_INT(&m), ARG_INT(&d),
ARG_INT(&hh), ARG_INT(&mm), ARG_INT(&ss),
ARG_STR(&rest, sizeof(rest)), ARG_STR(&bc, sizeof(bc)))) < 6)
{
if (scnt == 3) /* date */
{
Expand All @@ -308,7 +316,9 @@ timestamp2stime(const char *str, SIMPLE_TIME *st, BOOL *bZone, int *zone)
st->ss = 0;
return TRUE;
}
if ((scnt = sscanf(str, "%2d:%2d:%2d%31s %15s", &hh, &mm, &ss, rest, bc)) < 3)
if ((scnt = secure_sscanf(str, &status, "%2d:%2d:%2d%31s %15s",
ARG_INT(&hh), ARG_INT(&mm), ARG_INT(&ss),
ARG_STR(&rest, sizeof(rest)), ARG_STR(&bc, sizeof(bc)))) < 3)
return FALSE;
else
{
Expand Down Expand Up @@ -573,9 +583,11 @@ interval2istruct(SQLSMALLINT ctype, int precision, const char *str, SQL_INTERVAL
int scnt, years, mons, days, hours, minutes, seconds;
BOOL sign;
SQLINTERVAL itype = interval2itype(ctype);
int status = 0;

pg_memset(st, 0, sizeof(SQL_INTERVAL_STRUCT));
if ((scnt = sscanf(str, "%d-%d", &years, &mons)) >=2)
if ((scnt = secure_sscanf(str, &status, "%d-%d",
ARG_INT(&years), ARG_INT(&mons))) >=2)
{
if (SQL_IS_YEAR_TO_MONTH == itype)
{
Expand All @@ -588,7 +600,11 @@ interval2istruct(SQLSMALLINT ctype, int precision, const char *str, SQL_INTERVAL
}
return FALSE;
}
else if (scnt = sscanf(str, "%d %02d:%02d:%02d.%09s", &days, &hours, &minutes, &seconds, lit2), 5 == scnt || 4 == scnt)
else if (scnt = secure_sscanf(str, &status, "%d %02d:%02d:%02d.%09s",
ARG_INT(&days), ARG_INT(&hours),
ARG_INT(&minutes), ARG_INT(&seconds),
ARG_STR(&lit2, sizeof(lit2))
), 5 == scnt || 4 == scnt)
{
sign = days < 0 ? SQL_TRUE : SQL_FALSE;
st->interval_type = itype;
Expand All @@ -601,7 +617,9 @@ interval2istruct(SQLSMALLINT ctype, int precision, const char *str, SQL_INTERVAL
st->intval.day_second.fraction = getPrecisionPart(precision, lit2);
return TRUE;
}
else if ((scnt = sscanf(str, "%d %10s %d %10s", &years, lit1, &mons, lit2)) >=4)
else if ((scnt = secure_sscanf(str, &status, "%d %10s %d %10s",
ARG_INT(&years), ARG_STR(&lit1, sizeof(lit1)),
ARG_INT(&mons), ARG_STR(&lit2, sizeof(lit2)))) >=4)
{
if (strnicmp(lit1, "year", 4) == 0 &&
strnicmp(lit2, "mon", 2) == 0 &&
Expand All @@ -617,7 +635,9 @@ interval2istruct(SQLSMALLINT ctype, int precision, const char *str, SQL_INTERVAL
}
return FALSE;
}
if ((scnt = sscanf(str, "%d %10s %d", &years, lit1, &days)) == 2)
if ((scnt = secure_sscanf(str, &status, "%d %10s %d",
ARG_INT(&years), ARG_STR(&lit1, sizeof(lit1)),
ARG_INT(&days))) == 2)
{
sign = years < 0 ? SQL_TRUE : SQL_FALSE;
if (SQL_IS_YEAR == itype &&
Expand Down Expand Up @@ -654,7 +674,10 @@ interval2istruct(SQLSMALLINT ctype, int precision, const char *str, SQL_INTERVAL
/* these formats should've been handled above already */
return FALSE;
}
scnt = sscanf(str, "%d %10s %02d:%02d:%02d.%09s", &days, lit1, &hours, &minutes, &seconds, lit2);
scnt = secure_sscanf(str, &status, "%d %10s %02d:%02d:%02d.%09s",
ARG_INT(&days), ARG_STR(&lit1, sizeof(lit1)),
ARG_INT(&hours), ARG_INT(&minutes), ARG_INT(&seconds),
ARG_STR(&lit2, sizeof(lit2)));
if (scnt == 5 || scnt == 6)
{
if (strnicmp(lit1, "day", 3) != 0)
Expand All @@ -671,7 +694,9 @@ interval2istruct(SQLSMALLINT ctype, int precision, const char *str, SQL_INTERVAL
st->intval.day_second.fraction = getPrecisionPart(precision, lit2);
return TRUE;
}
scnt = sscanf(str, "%02d:%02d:%02d.%09s", &hours, &minutes, &seconds, lit2);
scnt = secure_sscanf(str, &status, "%02d:%02d:%02d.%09s",
ARG_INT(&hours), ARG_INT(&minutes), ARG_INT(&seconds),
ARG_STR(&lit2, sizeof(lit2)));
if (scnt == 3 || scnt == 4)
{
sign = hours < 0 ? SQL_TRUE : SQL_FALSE;
Expand Down Expand Up @@ -860,12 +885,15 @@ static int char2guid(const char *str, SQLGUID *g)
* "unsigned int", so use a temporary variable for it.
*/
unsigned int Data1;
if (sscanf(str,
int status = 0;
if (secure_sscanf(str, &status,
"%08X-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX",
&Data1,
&g->Data2, &g->Data3,
&g->Data4[0], &g->Data4[1], &g->Data4[2], &g->Data4[3],
&g->Data4[4], &g->Data4[5], &g->Data4[6], &g->Data4[7]) < 11)
ARG_UINT(&Data1),
ARG_USHORT(&g->Data2), ARG_USHORT(&g->Data3),
ARG_UCHAR(&g->Data4[0]), ARG_UCHAR(&g->Data4[1]),
ARG_UCHAR(&g->Data4[2]), ARG_UCHAR(&g->Data4[3]),
ARG_UCHAR(&g->Data4[4]), ARG_UCHAR(&g->Data4[5]),
ARG_UCHAR(&g->Data4[6]), ARG_UCHAR(&g->Data4[7])) < 11)
return COPY_GENERAL_ERROR;
g->Data1 = Data1;
return COPY_OK;
Expand Down Expand Up @@ -1416,7 +1444,11 @@ MYLOG(0, "null_cvt_date_string=%d\n", conn->connInfo.cvt_null_date_string);
* PG_TYPE_CHAR,VARCHAR $$$
*/
case PG_TYPE_DATE:
sscanf(value, "%4d-%2d-%2d", &std_time.y, &std_time.m, &std_time.d);
{
int status = 0;
secure_sscanf(value, &status, "%4d-%2d-%2d",
ARG_INT(&std_time.y), ARG_INT(&std_time.m), ARG_INT(&std_time.d));
}
break;

case PG_TYPE_TIME:
Expand Down Expand Up @@ -1530,7 +1562,8 @@ MYLOG(DETAIL_LOG_LEVEL, "2stime fr=%d\n", std_time.fr);
MYLOG(0, "index=(");
for (i = 0;; i++)
{
if (sscanf(vp, "%hi", &shortv) != 1)
int status = 0;
if (secure_sscanf(vp, &status, "%hi", ARG_SHORT(&shortv)) != 1)
break;
MYPRINTF(0, " %hi", shortv);
nval++;
Expand Down Expand Up @@ -5555,7 +5588,8 @@ convert_escape(QueryParse *qp, QueryBuild *qb)
while (isspace((UCHAR) qp->statement[++qp->opos]));
}

sscanf(F_OldPtr(qp), "%32s", key);
int status = 0;
secure_sscanf(F_OldPtr(qp), &status, "%32s", ARG_STR(&key, sizeof(key)));
while ((ucv = F_OldChar(qp)) != '\0' && (IS_NOT_SPACE(ucv)))
F_OldNext(qp);
while ((ucv = F_OldChar(qp)) != '\0' && isspace(ucv))
Expand Down Expand Up @@ -5970,6 +6004,7 @@ parse_datetime(const char *buf, SIMPLE_TIME *st)
mm,
ss;
int nf;
int status = 0;
BOOL bZone; int zone;

y = m = d = hh = mm = ss = 0;
Expand All @@ -5993,9 +6028,13 @@ parse_datetime(const char *buf, SIMPLE_TIME *st)
if (timestamp2stime(buf, st, &bZone, &zone))
return TRUE;
if (buf[4] == '-') /* year first */
nf = sscanf(buf, "%4d-%2d-%2d %2d:%2d:%2d", &y, &m, &d, &hh, &mm, &ss);
nf = secure_sscanf(buf, &status, "%4d-%2d-%2d %2d:%2d:%2d",
ARG_INT(&y), ARG_INT(&m), ARG_INT(&d),
ARG_INT(&hh), ARG_INT(&mm), ARG_INT(&ss));
else
nf = sscanf(buf, "%2d-%2d-%4d %2d:%2d:%2d", &m, &d, &y, &hh, &mm, &ss);
nf = secure_sscanf(buf, &status, "%2d-%2d-%4d %2d:%2d:%2d",
ARG_INT(&m), ARG_INT(&d), ARG_INT(&y),
ARG_INT(&hh), ARG_INT(&mm), ARG_INT(&ss));

if (nf == 5 || nf == 6)
{
Expand All @@ -6010,9 +6049,11 @@ parse_datetime(const char *buf, SIMPLE_TIME *st)
}

if (buf[4] == '-') /* year first */
nf = sscanf(buf, "%4d-%2d-%2d", &y, &m, &d);
nf = secure_sscanf(buf, &status, "%4d-%2d-%2d",
ARG_INT(&y), ARG_INT(&m), ARG_INT(&d));
else
nf = sscanf(buf, "%2d-%2d-%4d", &m, &d, &y);
nf = secure_sscanf(buf, &status, "%2d-%2d-%4d",
ARG_INT(&m), ARG_INT(&d), ARG_INT(&y));

if (nf == 3)
{
Expand All @@ -6023,7 +6064,8 @@ parse_datetime(const char *buf, SIMPLE_TIME *st)
return TRUE;
}

nf = sscanf(buf, "%2d:%2d:%2d", &hh, &mm, &ss);
nf = secure_sscanf(buf, &status, "%2d:%2d:%2d",
ARG_INT(&hh), ARG_INT(&mm), ARG_INT(&ss));
if (nf == 2 || nf == 3)
{
st->hh = hh;
Expand Down
22 changes: 15 additions & 7 deletions dlg_specific.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

#include "pgapifunc.h"

#include "secure_sscanf.h"

#define NULL_IF_NULL(a) ((a) ? ((const char *)(a)) : "(null)")
CSTR ENTRY_TEST = " @@@ ";

Expand Down Expand Up @@ -103,6 +105,7 @@ BOOL setExtraOptions(ConnInfo *ci, const char *optstr, const char *format)
{
UInt4 flag = 0, cnt;
char dummy[2];
int status = 0;

if (!format)
{
Expand All @@ -127,7 +130,8 @@ BOOL setExtraOptions(ConnInfo *ci, const char *optstr, const char *format)
format = dec_format;
}

if (cnt = sscanf(optstr, format, &flag, dummy), cnt < 1) // format error
if (cnt = secure_sscanf(optstr, &status, format,
ARG_UINT(&flag), ARG_STR(&dummy, sizeof(dummy))), cnt < 1) // format error
return FALSE;
else if (cnt > 1) // format error
return FALSE;
Expand Down Expand Up @@ -551,19 +555,20 @@ unfoldCXAttribute(ConnInfo *ci, const char *value)
{
int count;
UInt4 flag;
int status = 0;

if (strlen(value) < 2)
{
count = 3;
sscanf(value, "%x", &flag);
secure_sscanf(value, &status, "%x", ARG_UINT(&flag));
}
else
{
char cnt[8];
memcpy(cnt, value, 2);
cnt[2] = '\0';
sscanf(cnt, "%x", &count);
sscanf(value + 2, "%x", &flag);
secure_sscanf(cnt, &status, "%x", ARG_UINT(&count));
secure_sscanf(value + 2, &status, "%x", ARG_UINT(&flag));
}
ci->allow_keyset = (char)((flag & BIT_UPDATABLECURSORS) != 0);
ci->lf_conversion = (char)((flag & BIT_LFCONVERSION) != 0);
Expand Down Expand Up @@ -756,15 +761,17 @@ copyConnAttributes(ConnInfo *ci, const char *attribute, const char *value)
else if (stricmp(attribute, INI_EXTRAOPTIONS) == 0)
{
UInt4 val1 = 0, val2 = 0;
int status = 0;

if ('+' == value[0])
{
sscanf(value + 1, "%x-%x", &val1, &val2);
secure_sscanf(value + 1, &status, "%x-%x",
ARG_UINT(&val1), ARG_UINT(&val2));
add_removeExtraOptions(ci, val1, val2);
}
else if ('-' == value[0])
{
sscanf(value + 1, "%x", &val2);
secure_sscanf(value + 1, &status, "%x", ARG_UINT(&val2));
add_removeExtraOptions(ci, 0, val2);
}
else
Expand Down Expand Up @@ -1112,8 +1119,9 @@ MYLOG(0, "drivername=%s\n", drivername);
temp, sizeof(temp), ODBC_INI) > 0)
{
UInt4 val = 0;
int status = 0;

sscanf(temp, "%x", &val);
secure_sscanf(temp, &status, "%x", ARG_UINT(&val));
replaceExtraOptions(ci, val, TRUE);
MYLOG(0, "force_abbrev=%d bde=%d cvt_null_date=%d\n", ci->force_abbrev_connstr, ci->bde_environment, ci->cvt_null_date_string);
}
Expand Down
9 changes: 6 additions & 3 deletions execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
#include "lobj.h"
#include "pgapifunc.h"

#include "secure_sscanf.h"

/**
* @brief Perform a Prepare on the SQL statement
*
Expand Down Expand Up @@ -643,11 +645,12 @@ MYLOG(0, "count_of_deffered=%d has_notice=%d\n", count_of_deferred, stmt->has_no
NULL != env &&
EN_is_odbc3(env))
{
int count;
int count;
int status = 0;

if (sscanf(cmd , "UPDATE %d", &count) == 1)
if (secure_sscanf(cmd, &status, "UPDATE %d", ARG_INT(&count)) == 1)
;
else if (sscanf(cmd , "DELETE %d", &count) == 1)
else if (secure_sscanf(cmd, &status, "DELETE %d", ARG_INT(&count)) == 1)
;
else
count = -1;
Expand Down
5 changes: 4 additions & 1 deletion info.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
#include "multibyte.h"
#include "catfunc.h"

#include "secure_sscanf.h"

/* Trigger related stuff for SQLForeign Keys */
#define TRIGGER_SHIFT 3
#define TRIGGER_MASK 0x03
Expand Down Expand Up @@ -5367,7 +5369,8 @@ MYLOG(0, "atttypid=%s\n", atttypid ? atttypid : "(null)");
params = NULL;
else
{
sscanf(params, "%u", &pgtype);
int status = 0;
secure_sscanf(params, &status, "%u", ARG_UINT(&pgtype));
while (isdigit((unsigned char) *params))
params++;
}
Expand Down
Loading