Skip to content
Closed
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
17 changes: 13 additions & 4 deletions ext/pgsql/pgsql.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,8 @@ static void pgsql_lob_free_obj(zend_object *obj)

/* Compatibility definitions */

static inline zend_result build_tablename(smart_str *querystr, PGconn *pg_link, const zend_string *table);

static zend_string *_php_pgsql_trim_message(const char *message)
{
size_t i = strlen(message);
Expand Down Expand Up @@ -3464,7 +3466,6 @@ PHP_FUNCTION(pg_copy_from)
zend_string *pg_delimiter = NULL;
char *pg_null_as = "\\\\N";
size_t pg_null_as_len;
char *query;
PGconn *pgsql;
PGresult *pgsql_result;
ExecStatusType status;
Expand All @@ -3489,13 +3490,21 @@ PHP_FUNCTION(pg_copy_from)
RETURN_THROWS();
}

spprintf(&query, 0, "COPY %s FROM STDIN DELIMITER E'%c' NULL AS E'%s'", ZSTR_VAL(table_name), *ZSTR_VAL(pg_delimiter), pg_null_as);
smart_str querystr = {0};
smart_str_appends(&querystr, "COPY ");
if (build_tablename(&querystr, pgsql, table_name) == FAILURE) {
smart_str_free(&querystr);
RETURN_FALSE;
}
smart_str_append_printf(&querystr, " FROM STDIN DELIMITER E'%c' NULL AS E'%s'", *ZSTR_VAL(pg_delimiter), pg_null_as);
smart_str_0(&querystr);

while ((pgsql_result = PQgetResult(pgsql))) {
PQclear(pgsql_result);
}
pgsql_result = PQexec(pgsql, query);
pgsql_result = PQexec(pgsql, ZSTR_VAL(querystr.s));

efree(query);
smart_str_free(&querystr);

if (pgsql_result) {
status = PQresultStatus(pgsql_result);
Expand Down
36 changes: 36 additions & 0 deletions ext/pgsql/tests/pg_copy_from_table_name_escape.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
--TEST--
pg_copy_from() escapes the table name argument
--EXTENSIONS--
pgsql
--SKIPIF--
<?php include("inc/skipif.inc"); ?>
--FILE--
<?php

include('inc/config.inc');

$db = pg_connect($conn_str);
pg_query($db, 'DROP TABLE IF EXISTS pg_copy_from_target');
pg_query($db, 'CREATE TABLE pg_copy_from_target (v text)');
pg_query($db, 'DROP TABLE IF EXISTS pg_copy_from_other');
pg_query($db, 'CREATE TABLE pg_copy_from_other (v text)');

$evil = "pg_copy_from_other FROM STDIN --";
var_dump(pg_copy_from($db, $evil, ["redirected\n"]));

$rows = pg_fetch_all(pg_query($db, 'SELECT v FROM pg_copy_from_other')) ?: [];
var_dump($rows);

?>
--CLEAN--
<?php
include('inc/config.inc');
$db = pg_connect($conn_str);
pg_query($db, 'DROP TABLE IF EXISTS pg_copy_from_target');
pg_query($db, 'DROP TABLE IF EXISTS pg_copy_from_other');
?>
--EXPECTF--
Warning: pg_copy_from(): %s in %s on line %d
bool(false)
array(0) {
}
Loading