Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:42796 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 62493 invoked from network); 23 Jan 2009 07:24:06 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 23 Jan 2009 07:24:06 -0000 Authentication-Results: pb1.pair.com header.from=seanius@debian.org; sender-id=unknown Authentication-Results: pb1.pair.com smtp.mail=sean@seanius.net; spf=permerror; sender-id=unknown Received-SPF: error (pb1.pair.com: domain seanius.net from 66.93.22.232 cause and error) X-PHP-List-Original-Sender: sean@seanius.net X-Host-Fingerprint: 66.93.22.232 cobija.connexer.com Received: from [66.93.22.232] ([66.93.22.232:43453] helo=cobija.connexer.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id D5/61-45130-49079794 for ; Fri, 23 Jan 2009 02:24:05 -0500 Received: from rangda.stickybit.se (h-234-204.A189.priv.bahnhof.se [81.170.234.204]) by cobija.connexer.com (Postfix) with ESMTP id 2FBC817C1BD; Fri, 23 Jan 2009 02:24:01 -0500 (EST) Received: by rangda.stickybit.se (Postfix, from userid 1000) id D8F9010501; Fri, 23 Jan 2009 08:23:59 +0100 (CET) Date: Fri, 23 Jan 2009 08:23:59 +0100 To: Pierre Joye Cc: PHP internals , Debian PHP Maintainers , Stefan Esser Message-ID: <20090123072359.GB28562@rangda.stickybit.se> References: <20090121215750.GC15208@rangda.stickybit.se> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="gr/z0/N6AeWAPJVB" Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.18 (2008-05-17) Subject: Re: [PHP-DEV] CVE-2008-5658 unfixed or new problem with Zip::extractTo in 5.2.x? From: seanius@debian.org (sean finney) --gr/z0/N6AeWAPJVB Content-Type: multipart/mixed; boundary="IrhDeMKUP4DT/M7F" Content-Disposition: inline --IrhDeMKUP4DT/M7F Content-Type: text/plain; charset=us-ascii Content-Disposition: inline hi pierre, i've tested the patch that you proposed via IRC (attached) and it seems to work for me against 5.2.8. passes valgrind too, without any detected errors or leaks. it's unfortunate that there isn't a more surgical fix (301 insertions!), but i'll take your word for it that it would be too complicated/dangerous to try and modify virtual_file_ex() directly. thanks! sean --IrhDeMKUP4DT/M7F Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="m7a89d6fa.txt" Content-Transfer-Encoding: quoted-printable Index: php_zip.c=0D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0D RCS file: /repository/php-src/ext/zip/php_zip.c,v=0D retrieving revision 1.1.2.44=0D diff -u -r1.1.2.44 php_zip.c=0D --- php_zip.c 23 Oct 2008 16:13:50 -0000 1.1.2.44=0D +++ php_zip.c 22 Jan 2009 09:15:48 -0000=0D @@ -86,6 +86,304 @@=0D # define add_ascii_assoc_long add_assoc_long=0D #endif=0D =0D +static int php_zip_realpath_r(char *path, int start, int len, int *ll, tim= e_t *t, int use_realpath, int is_dir, int *link_is_dir TSRMLS_DC) /* {{{ */= =0D +{=0D + int i, j;=0D + int directory =3D 0;=0D +#ifdef PHP_WIN32=0D + WIN32_FIND_DATA data;=0D + HANDLE hFind;=0D +#else=0D + struct stat st;=0D +#endif=0D + realpath_cache_bucket *bucket;=0D + char *tmp;=0D +=0D + while (1) {=0D + if (len <=3D start) {=0D + return start;=0D + }=0D +=0D + i =3D len;=0D + while (i > start && !IS_SLASH(path[i-1])) {=0D + i--;=0D + }=0D +=0D + if (i =3D=3D len ||=0D + (i =3D=3D len - 1 && path[i] =3D=3D '.')) {=0D + /* remove double slashes and '.' */=0D + len =3D i - 1;=0D + is_dir =3D 1;=0D + continue;=0D + } else if (i =3D=3D len - 2 && path[i] =3D=3D '.' && path[i+1] =3D=3D '.= ') {=0D + /* remove '..' and previous directory */=0D + if (i - 1 <=3D start) {=0D + return start ? start : len;=0D + }=0D + j =3D php_zip_realpath_r(path, start, i-1, ll, t, use_realpath, 1, NULL= TSRMLS_CC);=0D + if (j > start) {=0D + j--;=0D + while (j > start && !IS_SLASH(path[j])) {=0D + j--;=0D + }=0D + if (!start) {=0D + /* leading '..' must not be removed in case of relative path */=0D + if (j =3D=3D 0 && path[0] =3D=3D '.' && path[1] =3D=3D '.' &&=0D + IS_SLASH(path[2])) {=0D + path[3] =3D '.';=0D + path[4] =3D '.';=0D + path[5] =3D DEFAULT_SLASH;=0D + j =3D 5;=0D + } else if (j > 0 && =0D + path[j+1] =3D=3D '.' && path[j+2] =3D=3D '.' &&=0D + IS_SLASH(path[j+3])) {=0D + j +=3D 4;=0D + path[j++] =3D '.';=0D + path[j++] =3D '.';=0D + path[j] =3D DEFAULT_SLASH;=0D + }=0D + }=0D + } else if (!start && !j) {=0D + /* leading '..' must not be removed in case of relative path */=0D + path[0] =3D '.';=0D + path[1] =3D '.';=0D + path[2] =3D DEFAULT_SLASH;=0D + j =3D 2;=0D + }=0D + return j;=0D + }=0D + =0D + path[len] =3D 0;=0D +=0D +#ifdef PHP_WIN32=0D + tmp =3D tsrm_do_alloca(len+1);=0D + memcpy(tmp, path, len+1);=0D +#elif defined(NETWARE)=0D +=0D + tmp =3D tsrm_do_alloca(len+1);=0D + memcpy(tmp, path, len+1);=0D +#else=0D + tmp =3D tsrm_do_alloca(len+1);=0D + memcpy(tmp, path, len+1);=0D +=0D + {=0D +#endif=0D + if (i - 1 <=3D start) {=0D + j =3D start;=0D + } else {=0D + /* some leading directories may be unaccessable */=0D + j =3D php_zip_realpath_r(path, start, i-1, ll, t, use_realpath, 1, NUL= L TSRMLS_CC);=0D + if (j > start) {=0D + path[j++] =3D DEFAULT_SLASH;=0D + }=0D + }=0D +#ifdef PHP_WIN32=0D + if (j < 0 || j + len - i >=3D MAXPATHLEN-1) {=0D + tsrm_free_alloca(tmp);=0D +=0D + return -1;=0D + }=0D + {=0D + /* use the original file or directory name as it wasn't found */=0D + memcpy(path+j, tmp+i, len-i+1);=0D + j +=3D (len-i);=0D + }=0D +#else=0D + if (j < 0 || j + len - i >=3D MAXPATHLEN-1) {=0D + tsrm_free_alloca(tmp);=0D + return -1;=0D + }=0D + memcpy(path+j, tmp+i, len-i+1);=0D + j +=3D (len-i);=0D + }=0D +#endif=0D +=0D + tsrm_free_alloca(tmp);=0D + return j;=0D + }=0D +}=0D +/* }}} */=0D +=0D +#define CWD_STATE_FREE(s) \=0D + free((s)->cwd);=0D +=0D +=0D +#define CWD_STATE_COPY(d, s) \=0D + (d)->cwd_length =3D (s)->cwd_length; \=0D + (d)->cwd =3D (char *) malloc((s)->cwd_length+1); \=0D + memcpy((d)->cwd, (s)->cwd, (s)->cwd_length+1);=0D +=0D +/* Resolve path relatively to state and put the real path into state */=0D +/* returns 0 for ok, 1 for error */=0D +int php_zip_virtual_file_ex(cwd_state *state, const char *path, verify_pat= h_func verify_path, int use_realpath) /* {{{ */=0D +{=0D + int path_length =3D strlen(path);=0D + char resolved_path[MAXPATHLEN];=0D + int start =3D 1;=0D + int ll =3D 0;=0D + time_t t;=0D + int ret;=0D + int add_slash;=0D + TSRMLS_FETCH();=0D +=0D + if (path_length =3D=3D 0 || path_length >=3D MAXPATHLEN-1) {=0D + return 1;=0D + }=0D +=0D + /* cwd_length can be 0 when getcwd() fails.=0D + * This can happen under solaris when a dir does not have read permission= s=0D + * but *does* have execute permissions */=0D + if (!IS_ABSOLUTE_PATH(path, path_length)) {=0D + if (state->cwd_length =3D=3D 0) {=0D + /* resolve relative path */=0D + start =3D 0;=0D + memcpy(resolved_path , path, path_length + 1);=0D + } else {=0D + int state_cwd_length =3D state->cwd_length;=0D +=0D +#ifdef PHP_WIN32=0D + if (IS_SLASH(path[0])) {=0D + if (state->cwd[1] =3D=3D ':') {=0D + /* Copy only the drive name */=0D + state_cwd_length =3D 2;=0D + } else if (IS_UNC_PATH(state->cwd, state->cwd_length)) {=0D + /* Copy only the share name */=0D + state_cwd_length =3D 2;=0D + while (IS_SLASH(state->cwd[state_cwd_length])) {=0D + state_cwd_length++;=0D + } =0D + while (state->cwd[state_cwd_length] &&=0D + !IS_SLASH(state->cwd[state_cwd_length])) {=0D + state_cwd_length++;=0D + } =0D + while (IS_SLASH(state->cwd[state_cwd_length])) {=0D + state_cwd_length++;=0D + } =0D + while (state->cwd[state_cwd_length] &&=0D + !IS_SLASH(state->cwd[state_cwd_length])) {=0D + state_cwd_length++;=0D + } =0D + }=0D + }=0D +#endif=0D + if (path_length + state_cwd_length + 1 >=3D MAXPATHLEN-1) {=0D + return 1;=0D + }=0D + memcpy(resolved_path, state->cwd, state_cwd_length);=0D + resolved_path[state_cwd_length] =3D DEFAULT_SLASH;=0D + memcpy(resolved_path + state_cwd_length + 1, path, path_length + 1);=0D + path_length +=3D state_cwd_length + 1;=0D + }=0D + } else { =0D +#ifdef PHP_WIN32=0D + if (path_length > 2 && path[1] =3D=3D ':' && !IS_SLASH(path[2])) {=0D + resolved_path[0] =3D path[0];=0D + resolved_path[1] =3D ':';=0D + resolved_path[2] =3D DEFAULT_SLASH;=0D + memcpy(resolved_path + 3, path + 2, path_length - 1);=0D + path_length++;=0D + } else=0D +#endif=0D + memcpy(resolved_path, path, path_length + 1);=0D + } =0D +=0D +#ifdef PHP_WIN32=0D + if (memchr(resolved_path, '*', path_length) ||=0D + memchr(resolved_path, '?', path_length)) {=0D + return 1;=0D + }=0D +#endif=0D +=0D +#ifdef PHP_WIN32=0D + if (IS_UNC_PATH(resolved_path, path_length)) {=0D + /* skip UNC name */=0D + resolved_path[0] =3D DEFAULT_SLASH;=0D + resolved_path[1] =3D DEFAULT_SLASH;=0D + start =3D 2;=0D + while (!IS_SLASH(resolved_path[start])) {=0D + if (resolved_path[start] =3D=3D 0) {=0D + goto verify;=0D + }=0D + resolved_path[start] =3D toupper(resolved_path[start]);=0D + start++;=0D + }=0D + resolved_path[start++] =3D DEFAULT_SLASH;=0D + while (!IS_SLASH(resolved_path[start])) {=0D + if (resolved_path[start] =3D=3D 0) {=0D + goto verify;=0D + }=0D + resolved_path[start] =3D toupper(resolved_path[start]);=0D + start++;=0D + }=0D + resolved_path[start++] =3D DEFAULT_SLASH;=0D + } else if (IS_ABSOLUTE_PATH(resolved_path, path_length)) {=0D + /* skip DRIVE name */=0D + resolved_path[0] =3D toupper(resolved_path[0]);=0D + resolved_path[2] =3D DEFAULT_SLASH;=0D + start =3D 3;=0D + }=0D +#elif defined(NETWARE)=0D + if (IS_ABSOLUTE_PATH(resolved_path, path_length)) {=0D + /* skip VOLUME name */=0D + start =3D 0;=0D + while (start !=3D ':') {=0D + if (resolved_path[start] =3D=3D 0) return -1;=0D + start++;=0D + }=0D + start++;=0D + if (!IS_SLASH(resolved_path[start])) return -1;=0D + resolved_path[start++] =3D DEFAULT_SLASH;=0D + }=0D +#endif=0D +=0D + add_slash =3D (use_realpath !=3D CWD_REALPATH) && path_length > 0 && IS_S= LASH(resolved_path[path_length-1]);=0D + t =3D CWDG(realpath_cache_ttl) ? 0 : -1;=0D + path_length =3D php_zip_realpath_r(resolved_path, start, path_length, &ll= , &t, use_realpath, 0, NULL TSRMLS_CC);=0D +=0D + if (path_length < 0) {=0D + errno =3D ENOENT;=0D + return 1;=0D + }=0D + =0D + if (!start && !path_length) {=0D + resolved_path[path_length++] =3D '.';=0D + }=0D + if (add_slash && path_length && !IS_SLASH(resolved_path[path_length-1])) = {=0D + if (path_length >=3D MAXPATHLEN-1) {=0D + return -1;=0D + }=0D + resolved_path[path_length++] =3D DEFAULT_SLASH;=0D + }=0D + resolved_path[path_length] =3D 0;=0D +=0D +#ifdef PHP_WIN32=0D +verify:=0D +#endif=0D + if (verify_path) {=0D + cwd_state old_state;=0D +=0D + CWD_STATE_COPY(&old_state, state);=0D + state->cwd_length =3D path_length;=0D + state->cwd =3D (char *) realloc(state->cwd, state->cwd_length+1);=0D + memcpy(state->cwd, resolved_path, state->cwd_length+1);=0D + if (verify_path(state)) {=0D + CWD_STATE_FREE(state);=0D + *state =3D old_state;=0D + ret =3D 1;=0D + } else {=0D + CWD_STATE_FREE(&old_state);=0D + ret =3D 0;=0D + }=0D + } else {=0D + state->cwd_length =3D path_length;=0D + state->cwd =3D (char *) realloc(state->cwd, state->cwd_length+1);=0D + memcpy(state->cwd, resolved_path, state->cwd_length+1);=0D + ret =3D 0;=0D + }=0D + return (ret);=0D +}=0D +/* }}} */=0D +=0D /* Flatten a path by creating a relative path (to .) */=0D static char * php_zip_make_relative_path(char *path, int path_len) /* {{{ = */=0D {=0D @@ -153,7 +451,9 @@=0D /* Clean/normlize the path and then transform any path (absolute or relat= ive)=0D to a path relative to cwd (../../mydir/foo.txt > mydir/foo.txt)=0D */=0D - virtual_file_ex(&new_state, file, NULL, CWD_EXPAND);=0D + if (php_zip_virtual_file_ex(&new_state, file, NULL, CWD_EXPAND) =3D=3D 1)= {=0D + return 0;=0D + }=0D path_cleaned =3D php_zip_make_relative_path(new_state.cwd, new_state.cwd= _length);=0D path_cleaned_len =3D strlen(path_cleaned);=0D =0D =0D --IrhDeMKUP4DT/M7F-- --gr/z0/N6AeWAPJVB Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Digital signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux) iD8DBQFJeXCPynjLPm522B0RAgpqAJ9rSc1n8qUTS9YqoZdO/uKQbQAR1ACfdllh yoeHrp4nBPjQ3r+/6B/OuQI= =KaXu -----END PGP SIGNATURE----- --gr/z0/N6AeWAPJVB--