lightpanda-io / browser

The open-source browser made for headless usage
https://lightpanda.io
GNU Affero General Public License v3.0
117 stars 0 forks source link

xhr: closing connection can panic with TLS #261

Closed krichprollsch closed 2 months ago

krichprollsch commented 2 months ago
$ zig build get -- https://httpbin.tch.re/xhr/index.html --dump                                                                              
debug(browser): starting GET https://httpbin.tch.re/xhr/index.html                                                                           
info(browser): GET https://httpbin.tch.re/xhr/index.html http.Status.ok                                                                                                                                                                                                                   
debug(browser): header content-type: text/html; charset=utf-8                                                                                
debug(browser): parse html with charset utf-8                         
debug(browser): start js env                                                                                                                 
debug(browser): setup global env                                                                                                             
debug(xhr): http.Method.GET https://httpbin.tch.re/get.json                                                                                  
debug(browser): eval inline: undefined                                                                                                       
info(xhr): http.Method.GET https://httpbin.tch.re/get.json http.Status.ok                                                                    
debug(xhr): dispatch progress event: loadstart                        
debug(xhr): dispatch progress event: progress                         
debug(xhr): dispatch progress event: load                                                                                                    
debug(xhr): dispatch progress event: loadend
debug(browser): wait:                                                 
<!DOCTYPE html>                                                       
<html><head>                                                          
  </head>                                                             
  <body>                                                              
  <pre id="response">{                                                
  "args": {},                                                         
  "headers": {                                                        
    "Accept": [                                                       
      "*/*"                                                           
    ],                                                                
    "Host": [                                                         
      "httpbin.io"                                                    
    ],                                                                
    "User-Agent": [                                                   
      "curl/8.5.0"                                                    
    ]                                                                 
  },                                                                  
  "origin": "213.41.108.198:57515",
  "url": "http://httpbin.io/get"                                      
}                                                                     
</pre>                                                                
  <script type="text/javascript">                                     
      const xhr = new XMLHttpRequest();

      xhr.onload = function () {                                      
          if (xhr.status >= 200 && xhr.status < 300) {
              document.getElementById('response').textContent = xhr.responseText;                                                            
          } else {                                                    
              console.log('The request failed!');
          }                                                           
      };                                                              

      xhr.onerror = function () {                                     
          console.log('There was an error!');
      };                                                              

      xhr.open('GET', 'https://httpbin.tch.re/get.json');
      xhr.send();                                                     
  </script>                                                           

</body></html>
Segmentation fault at address 0x7f4695485000
/usr/local/zig-0.12.1/lib/std/os/linux/IoUring.zig:136:42: 0x1a080dc in get_sqe (browsercore-get)                                            
    const head = @atomicLoad(u32, self.sq.head, .acquire);
                                         ^
/home/pierre/wrk/browser/vendor/zig-js-runtime/vendor/tigerbeetle-io/io/linux.zig:181:38: 0x19b0b6e in enqueue (browsercore-get)             
        const sqe = self.ring.get_sqe() catch |err| switch (err) {
                                     ^
/home/pierre/wrk/browser/vendor/zig-js-runtime/vendor/tigerbeetle-io/io/linux.zig:793:21: 0x1f9f875 in send__anon_30711 (browsercore-get)    
        self.enqueue(completion);                                     
                    ^                                                 
/home/pierre/wrk/browser/vendor/zig-js-runtime/src/loop.zig:236:34: 0x1ef6d01 in send (browsercore-get)                                      
                self.loop.io.send(*NetworkImpl, self, NetworkImpl.sendCbk, &self.completion, socket, buffer);                                
                                 ^                                    
/home/pierre/wrk/browser/src/async/tcp.zig:70:22: 0x1ef6a99 in send (browsercore-get)                                                        
        cmd.impl.send(&cmd, socket, buffer);
                     ^                                                
/home/pierre/wrk/browser/src/async/stream.zig:89:30: 0x1c8fafb in write (browsercore-get)                                                    
        return self.conn.send(self.handle, buffer) catch |err| switch (err) {                                                                
                             ^                                        
/home/pierre/wrk/browser/src/async/stream.zig:111:30: 0x1baeff1 in writev (browsercore-get)                                                  
        return try self.write(first_buffer);
                             ^                                        
/usr/local/zig-0.12.1/lib/std/crypto/tls/Client.zig:778:36: 0x1bae9d8 in writeEnd__anon_25655 (browsercore-get)                              
        var amt = try stream.writev(iovecs_buf[i..iovec_end]);
                                   ^
/home/pierre/wrk/browser/src/async/Client.zig:415:41: 0x1b2ab1c in close (browsercore-get)                                                   
            _ = conn.tls_client.writeEnd(conn.stream, "", true) catch {};                                                                    
                                        ^
/home/pierre/wrk/browser/src/async/Client.zig:201:28: 0x1a3bae4 in deinit (browsercore-get)                                                  
            node.data.close(allocator);
                           ^                                          
/home/pierre/wrk/browser/src/async/Client.zig:1234:34: 0x19f7163 in deinit (browsercore-get)                                                 
    client.connection_pool.deinit(client.allocator);
                                 ^                                    
/home/pierre/wrk/browser/src/browser/browser.zig:131:31: 0x19a13a0 in deinit (browsercore-get)                                               
        self.httpClient.deinit();                                     
                              ^                                       
/home/pierre/wrk/browser/src/browser/browser.zig:65:28: 0x19813c8 in deinit (browsercore-get)                                                
        self.session.deinit();                                        
                           ^                                          
/home/pierre/wrk/browser/src/main_get.zig:84:25: 0x1980d2f in main (browsercore-get)                                                         
    defer browser.deinit();                                           
                        ^                                             
/usr/local/zig-0.12.1/lib/std/start.zig:511:37: 0x198189e in main (browsercore-get)                                                          
            const result = root.main() catch |err| {
                                    ^
../sysdeps/nptl/libc_start_call_main.h:58:16: 0x7f46951d3c89 in __libc_start_call_main (../sysdeps/x86/libc-start.c)                         
../csu/libc-start.c:360:3: 0x7f46951d3d44 in __libc_start_main_impl (../sysdeps/x86/libc-start.c)                                            
???:?:?: 0x195d020 in ??? (???)                                       
???:?:?: 0x0 in ??? (???)                                             
get                                                                   
└─ run browsercore-get failure                                        
error: the following command terminated unexpectedly:
/home/pierre/wrk/browser/zig-cache/o/353e63a608a1062810eb3d006d78545b/browsercore-get https://httpbin.tch.re/xhr/index.html --dump           
Build Summary: 2/4 steps succeeded; 1 failed (disable with --summary none)                                                                   
get transitive failure                                                
└─ run browsercore-get failure                                        
error: the following build command failed with exit code 1:
/home/pierre/wrk/browser/zig-cache/o/5e9571f7bb5fe714ee754cb1e604faae/build /usr/local/zig-0.12.1/zig /home/pierre/wrk/browser /home/pierre/wrk/browser/zig-cache /home/pierre/.cache/zig --seed 0xce65313b -Z6d2619c91cef63fc get -- https://httpbin.tch.re/xhr/index.html --dump
krichprollsch commented 2 months ago

The issue happens only with a xhr conn via TLS. w/o TLS, the same code doesn't panic.

$ zig build get -- http://127.0.0.1:1234/xhr/index.html --dump
debug(browser): starting GET http://127.0.0.1:1234/xhr/index.html
info(browser): GET http://127.0.0.1:1234/xhr/index.html http.Status.ok
debug(browser): header content-type: text/html; charset=utf-8
debug(browser): parse html with charset utf-8
debug(browser): start js env
debug(browser): setup global env
debug(xhr): http.Method.GET http://127.0.0.1:1234/get.json
debug(browser): eval inline undefined
info(xhr): http.Method.GET http://127.0.0.1:1234/get.json http.Status.ok
debug(xhr): dispatch progress event: loadstart
debug(xhr): dispatch progress event: progress
debug(xhr): dispatch progress event: load
debug(xhr): dispatch progress event: loadend
debug(browser): wait: OK
<!DOCTYPE html>
<html><head>
  </head>
  <body>
  <pre id="response">{
  "args": {},
  "headers": {
    "Accept": [
      "*/*"
    ],
    "Host": [
      "httpbin.io"
    ],
    "User-Agent": [
      "curl/8.5.0"
    ]
  },
  "origin": "213.41.108.198:57515",
  "url": "http://httpbin.io/get"
}
</pre>
  <script type="text/javascript">
      const xhr = new XMLHttpRequest();

      xhr.onload = function () {
          if (xhr.status >= 200 && xhr.status < 300) {
              document.getElementById('response').textContent = xhr.responseText;
          } else {
              console.log('The request failed!');
          }
      };

      xhr.onerror = function () {
          console.log('There was an error!');
      };

      xhr.open('GET', 'http://127.0.0.1:1234/get.json');
      xhr.send();
  </script>

</body></html>