Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Enhance the db_prepare() and db_static_prepare() utility routines so that they throw an error if handed more than one SQL statement. This might help prevent SQL injection attacks. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | sec2020 |
| Files: | files | file ages | folders |
| SHA3-256: |
be0d95adedbc7ce63ec12a7774903f41 |
| User & Date: | drh 2020-08-17 18:57:42.876 |
Context
|
2020-08-17
| ||
| 19:59 | Every database connection now has a default authorizer, which calls out to an operation-specific authorizer if needed. check-in: f98ef3c103 user: drh tags: sec2020 | |
| 18:57 | Enhance the db_prepare() and db_static_prepare() utility routines so that they throw an error if handed more than one SQL statement. This might help prevent SQL injection attacks. check-in: be0d95aded user: drh tags: sec2020 | |
| 18:20 | Merge in reject-ckout-db branch. check-in: 8c16884aa2 user: stephan tags: sec2020 | |
Changes
Changes to src/db.c.
| ︙ | ︙ | |||
67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
*/
#define empty_Stmt_m {BLOB_INITIALIZER,NULL, NULL, NULL, 0, 0}
#endif /* INTERFACE */
const struct Stmt empty_Stmt = empty_Stmt_m;
/*
** Call this routine when a database error occurs.
*/
static void db_err(const char *zFormat, ...){
va_list ap;
char *z;
va_start(ap, zFormat);
z = vmprintf(zFormat, ap);
va_end(ap);
| > | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
*/
#define empty_Stmt_m {BLOB_INITIALIZER,NULL, NULL, NULL, 0, 0}
#endif /* INTERFACE */
const struct Stmt empty_Stmt = empty_Stmt_m;
/*
** Call this routine when a database error occurs.
** This routine throws a fatal error. It does not return.
*/
static void db_err(const char *zFormat, ...){
va_list ap;
char *z;
va_start(ap, zFormat);
z = vmprintf(zFormat, ap);
va_end(ap);
|
| ︙ | ︙ | |||
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
** If the input string contains multiple SQL statements, only the first
** one is processed. All statements beyond the first are silently ignored.
*/
int db_vprepare(Stmt *pStmt, int flags, const char *zFormat, va_list ap){
int rc;
int prepFlags = 0;
char *zSql;
blob_zero(&pStmt->sql);
blob_vappendf(&pStmt->sql, zFormat, ap);
va_end(ap);
zSql = blob_str(&pStmt->sql);
db.nPrepare++;
if( flags & DB_PREPARE_PERSISTENT ){
prepFlags = SQLITE_PREPARE_PERSISTENT;
}
| > | > > | 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 |
** If the input string contains multiple SQL statements, only the first
** one is processed. All statements beyond the first are silently ignored.
*/
int db_vprepare(Stmt *pStmt, int flags, const char *zFormat, va_list ap){
int rc;
int prepFlags = 0;
char *zSql;
const char *zExtra = 0;
blob_zero(&pStmt->sql);
blob_vappendf(&pStmt->sql, zFormat, ap);
va_end(ap);
zSql = blob_str(&pStmt->sql);
db.nPrepare++;
if( flags & DB_PREPARE_PERSISTENT ){
prepFlags = SQLITE_PREPARE_PERSISTENT;
}
rc = sqlite3_prepare_v3(g.db, zSql, -1, prepFlags, &pStmt->pStmt, &zExtra);
if( rc!=0 && (flags & DB_PREPARE_IGNORE_ERROR)==0 ){
db_err("%s\n%s", sqlite3_errmsg(g.db), zSql);
}else if( zExtra && !fossil_all_whitespace(zExtra) ){
db_err("surplus text follows SQL: \"%s\"", zExtra);
}
pStmt->pNext = db.pAllStmt;
pStmt->pPrev = 0;
if( db.pAllStmt ) db.pAllStmt->pPrev = pStmt;
db.pAllStmt = pStmt;
pStmt->nStep = 0;
pStmt->rc = rc;
|
| ︙ | ︙ | |||
638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 |
rc = db_reset(pStmt);
db_check_result(rc, pStmt);
return rc;
}
/*
** COMMAND: test-db-exec-error
**
** Invoke the db_exec() interface with an erroneous SQL statement
** in order to verify the error handling logic.
*/
void db_test_db_exec_cmd(void){
Stmt err;
db_find_and_open_repository(0,0);
db_prepare(&err, "INSERT INTO repository.config(name) VALUES(NULL);");
db_exec(&err);
}
/*
** Print the output of one or more SQL queries on standard output.
** This routine is used for debugging purposes only.
*/
int db_debug(const char *zSql, ...){
Blob sql;
| > > > > > > > > > > > > > > > > > > | 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 |
rc = db_reset(pStmt);
db_check_result(rc, pStmt);
return rc;
}
/*
** COMMAND: test-db-exec-error
** Usage: %fossil test-db-exec-error
**
** Invoke the db_exec() interface with an erroneous SQL statement
** in order to verify the error handling logic.
*/
void db_test_db_exec_cmd(void){
Stmt err;
db_find_and_open_repository(0,0);
db_prepare(&err, "INSERT INTO repository.config(name) VALUES(NULL);");
db_exec(&err);
}
/*
** COMMAND: test-db-prepare
** Usage: %fossil test-db-prepare ?OPTIONS? SQL
**
** Invoke db_prepare() on the SQL input. Report any errors encountered.
** This command is used to verify error detection logic in the db_prepare()
** utility routine.
*/
void db_test_db_prepare(void){
Stmt err;
db_find_and_open_repository(0,0);
verify_all_options();
if( g.argc!=3 ) usage("?OPTIONS? SQL");
db_prepare(&err, "%s", g.argv[2]/*safe-for-%s*/);
db_finalize(&err);
}
/*
** Print the output of one or more SQL queries on standard output.
** This routine is used for debugging purposes only.
*/
int db_debug(const char *zSql, ...){
Blob sql;
|
| ︙ | ︙ |