Project

General

Profile

Bug #2793

1.4.40 regression: broken redirect (using Location) between url.rewrite-once URLs

Added by rmilecki 9 months ago. Updated 9 months ago.

Status:
Fixed
Priority:
Normal
Assignee:
-
Category:
mod_cgi
Target version:
Start date:
2017-02-20
Due date:
% Done:

100%

Estimated time:
Missing in 1.5.x:

Description

Hi, I use Lighttpd with following mod_rewrite rules:

url.rewrite-once = (
    "^/(foo)" => "/foo.php",
    "^/(bar)" => "/bar.txt" 
)

My foo.php is a trivial file:
<?php
header('Location: /bar');
die('Redirected to the bar');

My bar.txt is just a dummy:
Bar!


My use case is sending GET /foo request. It used to work with all old Lighttps versions including 1.4.39. It stopped working with 1.4.40.

1.4.39
> curl -v http://192.168.1.1/foo
*   Trying 192.168.1.1...
* Connected to 192.168.1.1 (192.168.1.1) port 80 (#0)
> GET /foo HTTP/1.1
> Host: 192.168.1.1
> User-Agent: curl/7.42.1
> Accept: */*
> 
< HTTP/1.1 302 Found
< Status: 302 Found
< X-Powered-By: PHP/7.1.1
< Location: /bar
< Content-type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Date: Wed, 15 Feb 2017 10:49:45 GMT
< Server: lighttpd/1.4.39
< 
Redirected to the bar
* Connection #0 to host 192.168.1.1 left intact

> curl -v http://192.168.1.1/bar
*   Trying 192.168.1.1...
* Connected to 192.168.1.1 (192.168.1.1) port 80 (#0)
> GET /bar HTTP/1.1
> Host: 192.168.1.1
> User-Agent: curl/7.42.1
> Accept: */*
> 
< HTTP/1.1 200 OK
< Content-Type: text/plain; charset=utf-8
< Accept-Ranges: bytes
< ETag: "1794762551" 
< Last-Modified: Wed, 15 Feb 2017 10:48:10 GMT
< Content-Length: 6
< Date: Wed, 15 Feb 2017 10:49:49 GMT
< Server: lighttpd/1.4.39
< 
Bar!

* Connection #0 to host 192.168.1.1 left intact

1.4.40
> curl -v http://192.168.1.1/foo
*   Trying 192.168.1.1...
* Connected to 192.168.1.1 (192.168.1.1) port 80 (#0)
> GET /foo HTTP/1.1
> Host: 192.168.1.1
> User-Agent: curl/7.42.1
> Accept: */*
> 
< HTTP/1.1 404 Not Found
< Content-Type: text/html
< Content-Length: 345
< Date: Wed, 15 Feb 2017 10:48:30 GMT
< Server: lighttpd/1.4.40
< 
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 <head>
  <title>404 - Not Found</title>
 </head>
 <body>
  <h1>404 - Not Found</h1>
 </body>
</html>
* Connection #0 to host 192.168.1.1 left intact

tmp.diff (3.37 KB) tmp.diff Fix using a new plugin slot rmilecki, 2017-02-20 20:09

Related issues

Related to Bug #2108: CGI local redirect not implemented correctlyFixed2009-11-26

Associated revisions

Revision ab85841b (diff)
Added by gstrauss 9 months ago

[mod_cgi] fix CGI local-redir w/ url.rewrite-once (fixes #2793)

x-ref:
"1.4.40 regression: broken redirect (using Location) between url.rewrite-once URLs"
https://redmine.lighttpd.net/issues/2793

Revision 57ab20ac (diff)
Added by gstrauss 9 months ago

[mod_cgi] cgi.local-redir = [enable|disable] (#2108, #2793)

new directive cgi.local-redir = [enable|disable]

disable RFC3875 6.2.2 local-redir by default.
(behavior change from when local-redir support added in lighttpd 1.4.40)

The reason for this behavior change is that CGI local-redir support
(RFC3875 6.2.2) is an optimization. Absence of support may result in
additional latency in servicing a request due the additional round-trip
to the client, but that was the prior behavior (before lighttpd 1.4.40)
and is the behavior of web servers which do not support CGI local-redir.

However, enabling CGI local-redir by default may result in broken links
in the case where a user config (unaware of CGI local-redir behavior)
returns HTML pages containing relative paths (not root-relative paths)
which are relative to the location of the local-redir target document,
and the local-redir target document is located at a different URL-path
from the original CGI request.

x-ref:
RFC3875 CGI 1.1 specification section 6.2.2 Local Redirect Response
http://www.ietf.org/rfc/rfc3875
"CGI local redirect not implemented correctly"
https://redmine.lighttpd.net/issues/2108
"1.4.40 regression: broken redirect (using Location) between url.rewrite-once URLs"
https://redmine.lighttpd.net/issues/2793

History

#1

Updated by stbuehler 9 months ago

  • Related to Bug #2108: CGI local redirect not implemented correctly added
#2

Updated by gstrauss 9 months ago

  • Category set to mod_cgi
  • Target version changed from 1.4.x to 1.4.46

stbuehler: thx for cross-reference.

Seems like a bad interaction between CGI local-redir feature (added in lighttpd 1.4.40) and the url.rewrite-once state, which does not rewrite the resulting /bar to /bar.txt after CGI local-redir.

#3

Updated by gstrauss 9 months ago

  • Status changed from New to Patch Pending

This might work (still needs to be tested):

--- a/src/mod_cgi.c
+++ b/src/mod_cgi.c
@@ -590,6 +590,7 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) {
                                                        }

                                                        connection_response_reset(srv, con); /*(includes con->http_status = 0)*/
+                                                       plugins_call_connection_reset(srv, con);

                                                        con->mode = DIRECT;
                                                        return FDEVENT_HANDLED_COMEBACK;
#4

Updated by rmilecki 9 months ago

gstrauss wrote:

This might work (still needs to be tested):

[...]

It doesn't (tried on top of 1.4.45). Server crashes when processing the first request

# /usr/sbin/lighttpd -f /etc/lighttpd/lighttpd.conf -D
2017-02-15 11:10:19: (log.c.217) server started 
Segmentation fault

#5

Updated by rmilecki 9 months ago

I managed to fix it by adding a new plugin slot and calling it from the mod_cgi.c.

It works, but is requires new handler. Maybe there is simpler solution?

#6

Updated by rmilecki 9 months ago

rmilecki wrote:

gstrauss wrote:

This might work (still needs to be tested):

[...]

It doesn't (tried on top of 1.4.45). Server crashes when processing the first request
[...]

I used gdb to check why lighttpd crashes with your diff applied:

(gdb) run -f lighttpd.conf -D
Starting program: /usr/local/sbin/lighttpd -f lighttpd.conf -D
Missing separate debuginfo for /lib64/ld-linux-x86-64.so.2
Try: zypper install -C "debuginfo(build-id)=afa98667969782208459e394f8c8f87ac7510710" 
Missing separate debuginfo for /usr/lib64/libpcre.so.1
Try: zypper install -C "debuginfo(build-id)=fef485da4e84bae0a0245b782cb2c575bd244a88" 
Missing separate debuginfo for /lib64/libdl.so.2
Try: zypper install -C "debuginfo(build-id)=666913ec064c25fde1720db77b1f57bdeb5d9b3a" 
Missing separate debuginfo for /lib64/libc.so.6
Try: zypper install -C "debuginfo(build-id)=d21e5369d55e688fb863ceade4984189ab3f7ae7" 
Missing separate debuginfo for /lib64/libpthread.so.0
Try: zypper install -C "debuginfo(build-id)=24a941b6c85e244bd2e4906928dc17ab63b0a38a" 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".

Detaching after fork from child process 25789.
*** Error in `/usr/local/sbin/lighttpd': double free or corruption (out): 0x00000000006dcda0 ***

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7636fc2 in malloc_consolidate () from /lib64/libc.so.6
(gdb) 
(gdb) bt
#0  0x00007ffff7636fc2 in malloc_consolidate () from /lib64/libc.so.6
#1  0x00007ffff7638218 in _int_malloc () from /lib64/libc.so.6
#2  0x00007ffff763aed3 in calloc () from /lib64/libc.so.6
#3  0x00007ffff7de776f in _dl_new_object () from /lib64/ld-linux-x86-64.so.2
#4  0x00007ffff7de31b4 in _dl_map_object_from_fd () from /lib64/ld-linux-x86-64.so.2
#5  0x00007ffff7de4ff5 in _dl_map_object () from /lib64/ld-linux-x86-64.so.2
#6  0x00007ffff7def887 in dl_open_worker () from /lib64/ld-linux-x86-64.so.2
#7  0x00007ffff7deb6e4 in _dl_catch_error () from /lib64/ld-linux-x86-64.so.2
#8  0x00007ffff7def29b in _dl_open () from /lib64/ld-linux-x86-64.so.2
#9  0x00007ffff76db722 in do_dlopen () from /lib64/libc.so.6
#10 0x00007ffff7deb6e4 in _dl_catch_error () from /lib64/ld-linux-x86-64.so.2
#11 0x00007ffff76db7bf in dlerror_run () from /lib64/libc.so.6
#12 0x00007ffff76db831 in __libc_dlopen_mode () from /lib64/libc.so.6
#13 0x00007ffff76b2135 in init () from /lib64/libc.so.6
#14 0x00007ffff73ad470 in pthread_once () from /lib64/libpthread.so.0
#15 0x00007ffff76b224c in backtrace () from /lib64/libc.so.6
#16 0x00007ffff75dde36 in backtrace_and_maps () from /lib64/libc.so.6
#17 0x00007ffff763164f in __libc_message () from /lib64/libc.so.6
#18 0x00007ffff7636eae in malloc_printerr () from /lib64/libc.so.6
#19 0x00007ffff7637b87 in _int_free () from /lib64/libc.so.6
#20 0x0000000000415da1 in buffer_free (b=0x6dcdd0) at buffer.c:47
#21 0x00007ffff6f98965 in cgi_handler_ctx_free (hctx=0x6dcd70) at mod_cgi.c:102
#22 cgi_connection_close (srv=srv@entry=0x633010, hctx=hctx@entry=0x6dcd70) at mod_cgi.c:656
#23 0x00007ffff6f99553 in cgi_recv_response (srv=0x633010, hctx=<optimized out>) at mod_cgi.c:782
#24 0x00007ffff6f9967b in cgi_handle_fdevent (srv=srv@entry=0x633010, ctx=0x6dcd70, revents=revents@entry=1) at mod_cgi.c:802
#25 0x00000000004085e2 in main (argc=<optimized out>, argv=<optimized out>) at server.c:1798

Calling plugins_call_connection_reset results in calling cgi_connection_close_callback and this probably frees handler_ctx *hctx that we try to access later.

#7

Updated by gstrauss 9 months ago

Thanks for testing. Yes, you are correct that the hctx has already been cleaned up. Here is an additional patch to make it work.

@@ -810,7 +809,7 @@ static int cgi_recv_response(server *srv, handler_ctx *hctx) {
                        /* if we get a IN|HUP and have read everything don't exec the close twice */
                        return HANDLER_FINISHED;
                case FDEVENT_HANDLED_COMEBACK:
-                       cgi_connection_close(srv, hctx);
+                       /*cgi_connection_close(srv, hctx);*//*(already cleaned up)*/
                        return HANDLER_COMEBACK;
                case FDEVENT_HANDLED_ERROR:
                        log_error_write(srv, __FILE__, __LINE__, "s", "demuxer failed: ");

#8

Updated by rmilecki 9 months ago

gstrauss wrote:

Thanks for testing. Yes, you are correct that the hctx has already been cleaned up. Here is an additional patch to make it work.
[...]

Hooray, applying both your diffs resolves the problem, thank you!

#9

Updated by gstrauss 9 months ago

  • Status changed from Patch Pending to Fixed
  • % Done changed from 0 to 100

Also available in: Atom