Changeset: 3db848b50ce4 for MonetDB URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=3db848b50ce4 Modified Files: sql/ChangeLog.Oct2010 sql/src/server/rel_updates.mx Branch: Oct2010 Log Message:
COPY INTO: take security measures when using paths As reported by Stefan de Konink, COPY INTO can be used to read and write files in any location on the host the database is running at. To prevent people from doing damage, the usage of COPY INTO is restricted in a number of ways: - COPY INTO with a path may only be used by the super-user, normal users can use STDIN and STDOUT to let their client handle the reading and writing of data - paths used with COPY INTO may only be absolute - paths used with COPY INTO may not be within the dbfarm - when COPY INTO is used to write to a file, this file may not already exist to prevent files being overwritten diffs (106 lines): diff -r a45da51ff57e -r 3db848b50ce4 sql/ChangeLog.Oct2010 --- a/sql/ChangeLog.Oct2010 Mon Dec 13 07:59:39 2010 +0100 +++ b/sql/ChangeLog.Oct2010 Mon Dec 13 18:07:05 2010 +0100 @@ -1,3 +1,12 @@ # ChangeLog file for sql # This file is updated with Maddlog +* Mon Dec 13 2010 Fabian Groffen <fab...@cwi.nl> +- Security related fixes to the COPY INTO commands: 1) binary COPY INTO + is disallowed for non-administrator users, 2) COPY INTO using a path + both for reading and writing is disallowed for non-administrator users, + 3) paths used with COPY INTO may not be relative, 4) paths used with + COPY INTO may not be descendants of the dbfarm directory (where the + database files reside) and 5) COPY INTO a file may only be writing to + a non-existing file + diff -r a45da51ff57e -r 3db848b50ce4 sql/src/server/rel_updates.mx --- a/sql/src/server/rel_updates.mx Mon Dec 13 07:59:39 2010 +0100 +++ b/sql/src/server/rel_updates.mx Mon Dec 13 18:07:05 2010 +0100 @@ -587,15 +587,34 @@ if (!t) return sql_error(sql, 02, "COPY INTO: no such table '%s'", tname); if (t->readonly) - return sql_error(sql, 02, "COPY INTO: cannot copy into read only table '%s'", tname); + return sql_error(sql, 02, "COPY INTO: cannot copy into read-only table '%s'", tname); if (t && !isTempTable(t) && STORE_READONLY(active_store_type)) - return sql_error(sql, 02, "COPY INTO: copy into table '%s' not allowed in readonly mode", tname); + return sql_error(sql, 02, "COPY INTO: database is in read-only mode"); if (files) { dnode *n = files->h; + char realdbfarm[1024]; + char realfile[1024]; + + if (sql->user_id != USER_MONETDB) + return sql_error(sql, 02, "COPY INTO: insufficient privileges: " + "COPY INTO from file(s) requires administrator rights, " + "use 'COPY INTO \"%s\" FROM STDIN' instead", tname); + + realpath(GDKgetenv("gdk_dbfarm"), realdbfarm); for (; n; n = n->next) { char *fname = n->data.sval; - sql_rel *nrel = rel_import(sql, t, tsep, rsep, ssep, ns, fname, nr, offset); + sql_rel *nrel; + + if (fname && *fname != '/') + return sql_error(sql, 02, "COPY INTO: filename must " + "have absolute path: %s", fname); + realpath(fname, realfile); + if (strncmp(realdbfarm, realfile, strlen(realdbfarm)) == 0) + return sql_error(sql, 02, "COPY INTO: file may not " + "reside in the server's dbfarm: %s", realfile); + + nrel = rel_import(sql, t, tsep, rsep, ssep, ns, fname, nr, offset); if (!rel) rel = nrel; @@ -630,6 +649,12 @@ sql_schema *sys = mvc_bind_schema(sql, "sys"); sql_subfunc *f = sql_find_func(sys, "copyfrom", 2); + if (sql->user_id != USER_MONETDB) { + (void) sql_error(sql, 02, "COPY INTO: insufficient privileges: " + "binary COPY INTO requires administrator rights"); + return NULL; + } + if (sname && !(s=mvc_bind_schema(sql, sname))) { (void) sql_error(sql, 02, "COPY INTO: no such schema '%s'", sname); return NULL; @@ -704,6 +729,8 @@ static sql_rel * copyto(mvc *sql, symbol *sq, str filename, dlist *seps, str null_string) { + char realdbfarm[1024]; + char realfile[1024]; char *tsep = seps->h->data.sval; char *rsep = seps->h->next->data.sval; char *ssep = (seps->h->next->next)?seps->h->next->next->data.sval:"\""; @@ -720,6 +747,26 @@ ssep_e = exp_atom_clob(ssep); ns_e = exp_atom_clob(ns); fname_e = filename?exp_atom_clob(filename):NULL; + + if (filename) { + struct stat fs; + if (sql->user_id != USER_MONETDB) + return sql_error(sql, 02, "COPY INTO: insufficient privileges: " + "COPY INTO file requires administrator rights, " + "use 'COPY ... INTO STDOUT' instead"); + realpath(GDKgetenv("gdk_dbfarm"), realdbfarm); + if (filename && *filename != '/') + return sql_error(sql, 02, "COPY INTO: filename must " + "have absolute path: %s", filename); + realpath(filename, realfile); + if (strncmp(realdbfarm, realfile, strlen(realdbfarm)) == 0) + return sql_error(sql, 02, "COPY INTO: file may not " + "reside in the server's dbfarm: %s", realfile); + if (lstat(realfile, &fs) == 0) + return sql_error(sql, 02, "COPY INTO: file already " + "exists: %s", realfile); + } + return rel_output(r, tsep_e, rsep_e, ssep_e, ns_e, fname_e); } _______________________________________________ Checkin-list mailing list Checkin-list@monetdb.org http://mail.monetdb.org/mailman/listinfo/checkin-list