@@ -4200,6 +4200,9 @@ static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char *
4200
4200
char * fullpath ;
4201
4201
const char * slash ;
4202
4202
mode_t mode ;
4203
+ cwd_state new_state ;
4204
+ char * filename ;
4205
+ size_t filename_len ;
4203
4206
4204
4207
if (entry -> is_mounted ) {
4205
4208
/* silently ignore mounted entries */
@@ -4209,8 +4212,39 @@ static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char *
4209
4212
if (entry -> filename_len >= sizeof (".phar" )- 1 && !memcmp (entry -> filename , ".phar" , sizeof (".phar" )- 1 )) {
4210
4213
return SUCCESS ;
4211
4214
}
4215
+ /* strip .. from path and restrict it to be under dest directory */
4216
+ new_state .cwd = (char * )malloc (2 );
4217
+ new_state .cwd [0 ] = DEFAULT_SLASH ;
4218
+ new_state .cwd [1 ] = '\0' ;
4219
+ new_state .cwd_length = 1 ;
4220
+ if (virtual_file_ex (& new_state , entry -> filename , NULL , CWD_EXPAND TSRMLS_CC ) != 0 ||
4221
+ new_state .cwd_length <= 1 ) {
4222
+ if (EINVAL == errno && entry -> filename_len > 50 ) {
4223
+ char * tmp = estrndup (entry -> filename , 50 );
4224
+ spprintf (error , 4096 , "Cannot extract \"%s...\" to \"%s...\", extracted filename is too long for filesystem" , tmp , dest );
4225
+ efree (tmp );
4226
+ } else {
4227
+ spprintf (error , 4096 , "Cannot extract \"%s\", internal error" , entry -> filename );
4228
+ }
4229
+ free (new_state .cwd );
4230
+ return FAILURE ;
4231
+ }
4232
+ filename = new_state .cwd + 1 ;
4233
+ filename_len = new_state .cwd_length - 1 ;
4234
+ #ifdef PHP_WIN32
4235
+ /* unixify the path back, otherwise non zip formats might be broken */
4236
+ {
4237
+ int cnt = filename_len ;
4238
+
4239
+ do {
4240
+ if ('\\' == filename [cnt ]) {
4241
+ filename [cnt ] = '/' ;
4242
+ }
4243
+ } while (cnt -- >= 0 );
4244
+ }
4245
+ #endif
4212
4246
4213
- len = spprintf (& fullpath , 0 , "%s/%s" , dest , entry -> filename );
4247
+ len = spprintf (& fullpath , 0 , "%s/%s" , dest , filename );
4214
4248
4215
4249
if (len >= MAXPATHLEN ) {
4216
4250
char * tmp ;
@@ -4224,33 +4258,37 @@ static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char *
4224
4258
spprintf (error , 4096 , "Cannot extract \"%s\" to \"%s...\", extracted filename is too long for filesystem" , entry -> filename , fullpath );
4225
4259
}
4226
4260
efree (fullpath );
4261
+ free (new_state .cwd );
4227
4262
return FAILURE ;
4228
4263
}
4229
4264
4230
4265
if (!len ) {
4231
4266
spprintf (error , 4096 , "Cannot extract \"%s\", internal error" , entry -> filename );
4232
4267
efree (fullpath );
4268
+ free (new_state .cwd );
4233
4269
return FAILURE ;
4234
4270
}
4235
4271
4236
4272
if (PHAR_OPENBASEDIR_CHECKPATH (fullpath )) {
4237
4273
spprintf (error , 4096 , "Cannot extract \"%s\" to \"%s\", openbasedir/safe mode restrictions in effect" , entry -> filename , fullpath );
4238
4274
efree (fullpath );
4275
+ free (new_state .cwd );
4239
4276
return FAILURE ;
4240
4277
}
4241
4278
4242
4279
/* let see if the path already exists */
4243
4280
if (!overwrite && SUCCESS == php_stream_stat_path (fullpath , & ssb )) {
4244
4281
spprintf (error , 4096 , "Cannot extract \"%s\" to \"%s\", path already exists" , entry -> filename , fullpath );
4245
4282
efree (fullpath );
4283
+ free (new_state .cwd );
4246
4284
return FAILURE ;
4247
4285
}
4248
4286
4249
4287
/* perform dirname */
4250
- slash = zend_memrchr (entry -> filename , '/' , entry -> filename_len );
4288
+ slash = zend_memrchr (filename , '/' , filename_len );
4251
4289
4252
4290
if (slash ) {
4253
- fullpath [dest_len + (slash - entry -> filename ) + 1 ] = '\0' ;
4291
+ fullpath [dest_len + (slash - filename ) + 1 ] = '\0' ;
4254
4292
} else {
4255
4293
fullpath [dest_len ] = '\0' ;
4256
4294
}
@@ -4260,23 +4298,27 @@ static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char *
4260
4298
if (!php_stream_mkdir (fullpath , entry -> flags & PHAR_ENT_PERM_MASK , PHP_STREAM_MKDIR_RECURSIVE , NULL )) {
4261
4299
spprintf (error , 4096 , "Cannot extract \"%s\", could not create directory \"%s\"" , entry -> filename , fullpath );
4262
4300
efree (fullpath );
4301
+ free (new_state .cwd );
4263
4302
return FAILURE ;
4264
4303
}
4265
4304
} else {
4266
4305
if (!php_stream_mkdir (fullpath , 0777 , PHP_STREAM_MKDIR_RECURSIVE , NULL )) {
4267
4306
spprintf (error , 4096 , "Cannot extract \"%s\", could not create directory \"%s\"" , entry -> filename , fullpath );
4268
4307
efree (fullpath );
4308
+ free (new_state .cwd );
4269
4309
return FAILURE ;
4270
4310
}
4271
4311
}
4272
4312
}
4273
4313
4274
4314
if (slash ) {
4275
- fullpath [dest_len + (slash - entry -> filename ) + 1 ] = '/' ;
4315
+ fullpath [dest_len + (slash - filename ) + 1 ] = '/' ;
4276
4316
} else {
4277
4317
fullpath [dest_len ] = '/' ;
4278
4318
}
4279
4319
4320
+ filename = NULL ;
4321
+ free (new_state .cwd );
4280
4322
/* it is a standalone directory, job done */
4281
4323
if (entry -> is_dir ) {
4282
4324
efree (fullpath );
0 commit comments