Reboot caused by my AppProxy handling UDPFlows

I'm writing an app handling flows of target apps, and I'm testing it with Wechat - which is an app supporting audio chat.

I learned how to use PerAppProxy from sample code SimpleTunnel, and because my server should be on Ubuntu, I used SOCKS5 as my PacketTunnel server.

Everything just goes fine with TCP flows. I can send and receive text messages, vedios, and browse webpages.

But when it comes to UDP flows, which are used for vedio or audio chatting, my iPhone starts rebooting, with no error message.


I used CocoaAsyncUDPSocket for UDP flows. Whenever a new UDP flow comes, I'll start a new udpSocket, receiving udp datagrams and writing those datagrams back to app by UDPFlow.writeDatagrams(), and sending those datagrams read from UDPFlow.


I'm quite confused with my problem. Could anyone tell me on what condition will problems like mine appear? And any suggestions for my problem will be appreciated.


I will paste my code if you want to view my code handling UDP flows.

Accepted Reply

For those reading along at home, I just want to fill in some details here. It seems that the phone reboot seen by Ainassine is actually a kernel panic, one that we’re tracking with the bug number they mentioned earlier (r. 44974555). We believe that this is fixed in the iOS 12.1.1 beta 2 (16C5043b) build that we’re currently seeding.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Replies

But when it comes to UDP flows, which are used for vedio or audio chatting, my iPhone starts rebooting, with no error message.

Yikes! An app proxy provider shouldn’t be able to trigger a reboot, so the fact that this is happening is automatically bugworthy. Please trigger a sysdiagnose log immediately after the device has rebooted and then include that in a bug report. I’d appreciate you posting your bug number, just for the record.

You can learn more about sysdiagnose logs on our Bug Reporting > Profiles and Logs page.

What OS releases have you seen this on?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I encountered this wired problem on both my iPhone 5s and iPhone 8, and both of them have iOS 12.0 installed.

I'll look into materials you've just given to me, and let you know if I get some new progress.


BTW, I've been trying to fix this problem for days and got no progress, which really makes me crazy : (

Really glad to hear from you!

Issue reported.

Bug Number: 45942938

Reply from Apple Developer Support says that my bug report is DUPLICATE OF 44974555.


And I'm still working on my code to see if there could be any breakthrough, and I do find something out of my expectation.

NEAppProxyUDPFlow should be opened before being used. I set up a UDP socket, and bind this UDP socket to a local address so that this socket can have its own ip address and port number, before opening the corresponding UDPFlow. After having a UDP socket, I open the UDPFlow with localAddress of this socket, and I printed localEnpoint information of UDPFlow before and after calling open( withEndpoint) method. From information printed, I find that sometimes, UDPFlow does not have a valid UDP port after open method is called, and its invalid UDP port is 0. And error in completion handler is nil, so there was no error happened while opening that UDPFlow.


Could you give me some explanations?

Thank you!


Part of my code opening UDPFlow:



              else if let UDPFlow = flows[sock] as? NEAppProxyUDPFlow {
                // open up a new UDP socket
                let udpsock = GCDAsyncUdpSocket()
                udpsock.setDelegate(self)
                udpsock.setDelegateQueue(DispatchQueue.main)
                //udpsock.setDelegateQueue(DispatchQueue.init(label: "UDP"))
                
                udpSocks[sock] = udpsock
                utSocks[udpsock] = sock
                udpflows[udpsock] = UDPFlow
                
                
                // bind UDP socket with local ip
                do {
                    var sa = sockaddr_in()
                    sa.sin_len = UInt8(MemoryLayout.size(ofValue: sa))
                    sa.sin_family = sa_family_t(AF_INET)
                    sa.sin_addr.s_addr = inet_addr(sock.localHost!)
                    try udpsock.bind(toAddress: NSData.init(bytes: &sa, length: MemoryLayout<sockaddr_in>.size) as Data)
                    
                    let localAddress = NWHostEndpoint(hostname: udpsock.localHost()!, port: "\(udpsock.localPort())")
                    
                    testVPNLog("################+NEAppProxyUDPFlow is going to open with local endpoint: \(localAddress), before that, I tried to get its localEnpoint property: \(UDPFlow.localEndpoint)")
                    UDPFlow.open(withLocalEndpoint: localAddress){ error in
                        testVPNLog("################-NEAppProxyUDPFlow is going to open with local endpoint: \(localAddress), after that, I tried to get its localEnpoint property: \(UDPFlow.localEndpoint)\n\(error)")
                        if error != nil {
                            testVPNLog(self.TAG + "Error happened while opening UDP flow: \(error)")
                            self.closeSock(self.utSocks[udpsock]!, forFlow: UDPFlow, reason: "Error happened while opening UDP flow: \(error)")
                            return
                        }
                        
                        do {
                            try udpsock.beginReceiving()
                        }
                        catch let receiveError as NSError {
                            testVPNLog(self.TAG + "Error happened when UDP socket begin receiving. \(receiveError)")
                            self.closeSock(sock, forFlow: self.flows[sock]!, reason: "Error happened when UDP socket begin receiving. \(receiveError)")
                            return
                        }
                        
                        var UDP_ASSOCIATE_REQ = [UInt8]()
                        UDP_ASSOCIATE_REQ += [SOCKS5_VER, SOCKS5_CMD.UDP_ASSOCIATE.rawValue, SOCKS5_RSV, SOCKS5_ATYP.IPV4.rawValue]
                        UDP_ASSOCIATE_REQ += string2Hex(input: "0.0.0.0", mod: "ip")
                        UDP_ASSOCIATE_REQ += string2Hex(input: "\(udpsock.localPort())", mod: "port")
                        
                        testVPNLog(self.TAG + "write UDP ASSOCIATE REQUEST: \(NSMutableData.init(data: Data.init(bytes: UDP_ASSOCIATE_REQ)))")
                        sock.write(Data.init(bytes: UDP_ASSOCIATE_REQ), withTimeout: TimeInterval(-1), tag: SOCK_TAG.UDP_ASSOCIATE.rawValue)
                        sock.readData(withTimeout: TimeInterval(-1), tag: 0)
                    }
                }
                catch let error as NSError {
                    testVPNLog(self.TAG + "Error happened when bind UDP socket to local address. \(error)")
                    closeSock(sock, forFlow: flows[sock]!, reason: "Error happened when bind UDP socket to local address. \(error)")
                    return
                }
            }

I’ll follow up via a private channel later today .

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
(s. 703526457)

For those reading along at home, I just want to fill in some details here. It seems that the phone reboot seen by Ainassine is actually a kernel panic, one that we’re tracking with the bug number they mentioned earlier (r. 44974555). We believe that this is fixed in the iOS 12.1.1 beta 2 (16C5043b) build that we’re currently seeding.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hi @Eskimo, We are observing the same kernel panic's for Mac version of our app proxy. The kernel panic report points to the same API as mentioned by Ainassine.

Below is a snippet of stack trace from kernel report.

If you look closely, the panic seems to have been caused by below API.

-[NEAppProxyUDPFlow writeDatagrams:sentByEndpoints:completionHandler:] + 1013 (NetworkExtension + 183908) [0x7fff57e37e64] 1


Since you mentioned that this issue is already fixed for iOS 12.1.1 beta, did we fix a similar issue for MacOS?

We are running MacOS 10.14.3 (Mojave)

These crashes are very frequently reported from the field and we will appreciate any help regarding this.


Thanks,

Surender


Thread 0x49f50 1 sample (1) priority 37 (base 37)

<thread QoS user initiated (requested user interactive), process unclamped, IO tier 0>

1 ??? [0x7fd89964d630] 1

1 start_wqthread + 13 (libsystem_pthread.dylib + 9221) [0x7fff7f024405] 1

1 _pthread_wqthread + 409 (libsystem_pthread.dylib + 9739) [0x7fff7f02460b] 1

1 _dispatch_workloop_worker_thread + 603 (libdispatch.dylib + 77968) [0x7fff7edf3090] 1

1 _dispatch_lane_invoke + 388 (libdispatch.dylib + 43996) [0x7fff7edeabdc] 1

1 _dispatch_lane_serial_drain + 618 (libdispatch.dylib + 41252) [0x7fff7edea124] 1

1 _dispatch_client_callout + 8 (libdispatch.dylib + 15823) [0x7fff7ede3dcf] 1

1 _dispatch_call_block_and_release + 12 (libdispatch.dylib + 11603) [0x7fff7ede2d53] 1

1 __flow_call_dgram_read_handler_block_invoke + 28 (NetworkExtension + 1221642) [0x7fff57f3540a] 1

1 __56-[NEAppProxyUDPFlow readDatagramsWithCompletionHandler:]_block_invoke + 271 (NetworkExtension + 182702) [0x7fff57e379ae] 1

1 ??? (MobileIron Proxy + 54425) [0x104a5d499] 1

1 ??? (MobileIron Proxy + 55571) [0x104a5d913] 1

1 ??? (MobileIron Proxy + 55886) [0x104a5da4e] 1

1 -[NEAppProxyUDPFlow writeDatagrams:sentByEndpoints:completionHandler:] + 1013 (NetworkExtension + 183908) [0x7fff57e37e64] 1

1 NEFlowWrite + 355 (NetworkExtension + 1204422) [0x7fff57f310c6] 1

1 flow_write_range_of_cfdata + 111 (NetworkExtension + 1205203) [0x7fff57f313d3] 1

1 flow_director_send_cfdata + 215 (NetworkExtension + 1221927) [0x7fff57f35527] 1

1 __sendmsg + 10 (libsystem_kernel.dylib + 26342) [0x7fff7ef706e6] 1

*1 ??? (<1970B070-E53F-3178-83F3-1B95FA340695> + 1426534) [0xffffff800035c466] 1

*1 ??? (<1970B070-E53F-3178-83F3-1B95FA340695> + 8086203) [0xffffff80009b62bb] 1

*1 ??? (<1970B070-E53F-3178-83F3-1B95FA340695> + 7548761) [0xffffff8000932f59] 1

*1 ??? (<1970B070-E53F-3178-83F3-1B95FA340695> + 7547468) [0xffffff8000932a4c] 1

*1 ??? (<1970B070-E53F-3178-83F3-1B95FA340695> + 7476988) [0xffffff80009216fc] 1

*1 ??? (<1970B070-E53F-3178-83F3-1B95FA340695> + 6997140) [0xffffff80008ac494] 1

*1 ??? (<1970B070-E53F-3178-83F3-1B95FA340695> + 6062376) [0xffffff80007c8128] 1

*1 ??? (<1970B070-E53F-3178-83F3-1B95FA340695> + 1424544) [0xffffff800035bca0] 1

*1 ??? (<1970B070-E53F-3178-83F3-1B95FA340695> + 2990749) [0xffffff80004da29d] 1

*1 ??? (<1970B070-E53F-3178-83F3-1B95FA340695> + 1762163) [0xffffff80003ae373] 1

*1 ??? (<1970B070-E53F-3178-83F3-1B95FA340695> + 1762599) [0xffffff80003ae527] (running) 1