Hello,

I think it's a bad idea to patch extension for flaws not in PHP itself.
Furthermore, this adds a performance loss to every query. Did you do any
benchmarks with it? Anyway... I still think it's a bad idea, and from what
I've heard Zak is talking with MySQL about this.

Derick

On Wed, 27 Feb 2002, Jim Segrave wrote:

> On Tue 26 Feb 2002 (21:58 +0100), Jim Segrave wrote:
> >
> > I was looking at the posting from "James E. Flemer" <[EMAIL PROTECTED]>
> > and decided to try adding a bit more to it.
> >
> > ** This code is compiled, but not tested **
>
> I now have a patch against
> /* $Id: php_mysql.c,v 1.97.2.3 2001/12/09 13:53:56 zeev Exp $ */
> which appears to do what's needed. Initial testing indicates that it
> blocks the exploit, and only allows load data local infile 'path'
> queries where the path is valid for the php script owner (and I know a
> bit more about the regex library). The same caveats still apply for a
> threaded environment - the compile of the regex takes place on the
> first query processed, so it would need mutex'ing if threaded.
>
> Unified diff of a workding version follows:
> ========================================
> --- php_mysql.c.save  Wed Feb 27 13:22:35 2002
> +++ php_mysql.c       Wed Feb 27 12:16:00 2002
> @@ -55,6 +55,9 @@
>
>  #include "php_ini.h"
>
> +#include <regex.h>
> +#include <syslog.h>
> +
>  #if HAVE_MYSQL_MYSQL_H
>  # include <mysql/mysql.h>
>  #else
> @@ -211,9 +214,122 @@
>
>  #define CHECK_LINK(link) { if (link==-1) { php_error(E_WARNING, "MySQL:  A link to 
>the server could not be established"); RETURN_FALSE; } }
>
> +/* see if a file in a query includedes
> + * LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE "path"
> + * if so, see if we should allow it to be run (is the file specified by path
> + * valid for php
> + */
> +
> +static int php_mysql_safety_check(const char *p, int len);
> +
> +static volatile int regex_is_ready = 0;
> +
> +/* regex for mysql queries we want to be careful with. Note that the
> + * file path we're looking for is any file name beginning with a
> + * single or double quote and assumed to end with either quote type. This
> + * will fail for file names containing one or the other quote types. File
> + * names like this won't be protected from the exploit, but the risk is
> + * small IMHO
> + */
> +
> +static char* query_regex = 
>".*[[:<:]]LOAD[[:>:]].*[[:<:]]DATA[[:>:]].*[[:<:]]LOCAL[[:>:]].*[[:<:]]INFILE[[:>:]][^'\"]*['\"]([^'\"]*).*";
> +
> +
> +static regex_t preg;
> +
> +/* compile this regex on the first SQL query seen */
> +static int init_regex (void)
> +{
> +     int res;
> +
> +     /*
> +      * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
> +      * FIXME
> +      * In a threaded environment, this would need a mutex and all
> +      * sorts of other frippery. Then the result could be made
> +      * available to all other threads.
> +      */
> +
> +     res = regcomp (&preg, query_regex, REG_EXTENDED | REG_ICASE);
> +     if (res != 0) {
> +             syslog (LOG_ERR, "init_regex: regcomp returned %d", res);
> +             return 0;
> +     }
> +
> +     regex_is_ready = 1;
> +}
> +
> +/* look for mysql queries in the form LOAD DATA LOCAL INFILE 'path'
> + * if found, accept them (return 1) if a php script would be allowed
> + * to read the file
> + */
> +static int php_mysql_safety_check(const char *query, int len)
> +{
> +     int     res;
> +     char *copy;
> +     regmatch_t pmatch[2];   /* 0 = string, 1 = path */
> +     char *path;
> +
> +     /* only compile the regex once */
> +     if (!regex_is_ready) {
> +             if (init_regex () == 0) {
> +                     /* didn't compile - don't accept query - that encourages
> +                        fixing things */
> +                     return 0;
> +             }
> +     }
> +
> +     /* dunno if I can trust the query to be null terminated. If I can,
> +        why is there a length?
> +      */
> +     if ((copy = emalloc (len + 1)) == 0) {
> +             syslog (LOG_ERR, "php_mysql_safety_check: Can't malloc query space");
> +
> +     }
> +
> +     strncpy (copy, query, len);
> +
> +     /* don't allow queries with embedded nulls - to catch a potential
> +      * nasty hiding of paths
> +      */
> +     if ((len - strlen (copy)) > 1)
> +             return 0;
> +
> +     res = regexec (&preg, query, 2, pmatch, 0);
> +
> +     /* it's not one of the dangerous queries - let it pass */
> +     if (res == REG_NOMATCH) {
> +             efree (copy);
> +             return 1;
> +     }
> +
> +     /* regexec didn't like the query, so we don't either */
> +     if (res != 0) {
> +             efree (copy);
> +             return 0;
> +     }
> +
> +     /* it matched, pmatch[1].rm_so is the offset of the start of the path
> +        and pmatch[1].rm_eo is the offset of the end of the path
> +     */
> +     path = copy + pmatch[1].rm_so;
> +     *(copy + pmatch[1].rm_eo) = 0;
> +
> +     /* path is the file path that the LOAD DATA... will use */
> +     res = php_checkuid (path, "r", 0);
> +
> +     /* php_checkuid returns 0 if it's forbidden */
> +     if (res == 0) {
> +             syslog (LOG_ERR, "php_mysql_safety_check: suspect query for %s", path);
> +     }
> +
> +     efree (copy);
> +     return res;
> +}
> +
>  /* {{{ _free_mysql_result
>   * This wrapper is required since mysql_free_result() returns an integer, and
> - * thus, cannot be used directly
> + * thus, cannot be used directly
>   */
>  static void _free_mysql_result(zend_rsrc_list_entry *rsrc TSRMLS_DC)
>  {
> @@ -1005,6 +1121,15 @@
>       } while(0);
>
>       convert_to_string_ex(query);
> +
> +     /* disallow LOAD DATA LOCAL INFILE if safe_mode on */
> +     if (PG(safe_mode)) {
> +             if (!php_mysql_safety_check(Z_STRVAL_PP(query), Z_STRLEN_PP(query))) {
> +                     php_error(E_WARNING, "MySQL: Statement failed safe mode 
>checks");
> +                     RETURN_FALSE;
> +             }
> +     }
> +
>       /* mysql_query is binary unsafe, use mysql_real_query */
>  #if MYSQL_VERSION_ID > 32199
>       if (mysql_real_query(&mysql->conn, Z_STRVAL_PP(query), Z_STRLEN_PP(query))!=0) 
>{
>
> ========================================
>
> --
> Jim Segrave           [EMAIL PROTECTED]
>
> --
> PHP Development Mailing List <http://www.php.net/>
> To unsubscribe, visit: http://www.php.net/unsub.php
>


-- 
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to