Post

Replies

Boosts

Views

Activity

Reply to PKG Installer postinstall script not executing in Sonoma
After many tests I finally found a solution. Apparently the & at the end of the command is whats causing the issue in Sonoma. So I had to replace this command: /Applications/myapp.app/Contents/MacOS/myapp --load-system-extension & With this one: /usr/bin/open /Applications/myapp.app --args --load-system-extension And now it works perfectly! Im still curious about those better ways to activate an extension.
May ’24
Reply to Crash when using String(cString:)
I found a solution similar to what Quinn suggested on Google's Project Santa's github. I just ported it to swift. Here it is: let deadline = DispatchTime(uptimeNanoseconds: cMsg.pointee.deadline) - .seconds(2) let handlerSemaphore = DispatchSemaphore(value: 0) handlerSemaphore.signal() let deadlineSemaphore = DispatchSemaphore(value: 0) queue.asyncAfter(deadline: deadline) { // Check if event handler has already responded if handlerSemaphore.wait(timeout: .now()) == .timedOut { // Event handler already responded so exit return } // Deadline met, event handler still processing, default to allow self.allowMessage(cMsg) deadlineSemaphore.signal() } queue.async { // Process auth event and respond handleAuthEvent(cMsg) // Check if deadline was met if handlerSemaphore.wait(timeout: .now()) == .timedOut { // Wait for deadline block to allow the message, then free deadlineSemaphore.wait() } self.freeMessage(cMsg) }
Aug ’22
Reply to Apps/files do not open when the result is cached with es_respond_flags_result
Hi, I am having the same issue that Uddalak described. But in my case this only happens when I attach Xcode's debugger to my system extension. As soon as I do it the entire system becomes unresponsive for 30 secs until my app is killed (no crash log). It doesn't matter if I use the 0x7fffffff or 0xffffffff flags or if I cache the response or not. In my event handler block I allow all events, like this: es_respond_flags_result(client, msg, 0x7fffffff, true)
Aug ’22
Reply to Crash when using String(cString:)
As per Quinns request here is a more detailed version of my code static func handleProcessExec(_ msg: UnsafePointer<es_message_t>) {     let target = msg.pointee.event.exec.target.pointee guard msg.pointee.process.pointee.is_es_client == false else {      es_respond_auth_result(esClient.client!, msg, ES_AUTH_RESULT_ALLOW, true)       return     }     // copy message so it can be used on another thread     guard let copiedMessage = copyMessage(msg) else {       es_respond_auth_result(esClient.client!, msg, ES_AUTH_RESULT_DENY, false)       return     }     DispatchQueue.global().async { var process: ProcessDetails? = nil let deadline = DispatchTime(uptimeNanoseconds: copiedMessage.pointee.deadline - (2*NSEC_PER_SEC)) let semaphore = DispatchSemaphore(value: 0) // RuleResult contains what rule matched and if we should allow/deny var result = RuleResult() let timestamp = copiedMessage.pointee.time.tv_sec DispatchQueue.global().async { process = ProcessDetails(process: copiedMessage.pointee.event.exec.target.pointee) ESEventRulesRunner.runProcessExecRules(process: process!, &result) semaphore.signal()        }       _ = semaphore.wait(timeout: deadline)       es_respond_auth_result(esClient.client!, copiedMessage, result.verdict, false)       if result.verdict == ES_AUTH_RESULT_DENY {         // Log event to api let event = ESEvent(process: process!, timestamp: timestamp, ruleType: result.type)         Api.postEvent(event: event) }       freeMessage(copiedMessage)     }       }
Aug ’22
Reply to Crash when using String(cString:)
Ok I found out what is happening but I need help fixing it. Look at this code // Inside function that handles process exec messages     guard let copiedMessage = copyMessage(msg) else {       es_respond_auth_result(esClient.client!, msg, ES_AUTH_RESULT_ALLOW, false)        return     }     DispatchQueue.global().async { var process: ProcessDetails? = nil        let deadline = copiedMessage.pointee.deadline let semaphore = DispatchSemaphore(value: 0) DispatchQueue.global().async { // This may take some time          process = ProcessDetails(process: copiedMessage.pointee.event.exec.target.pointee) semaphore.signal()       }       _ = semaphore.wait(timeout: DispatchTime(uptimeNanoseconds: deadline - (2 * NSEC_PER_SEC)))       es_respond_auth_result(...)       freeMessage(copiedMessage)     } I am calling description inside my ProcessDetails class, the problem is that if the timeout of the semaphore runs out I will free the copiedMessage but the initialization of ProcessDetails is still going so that results in a crash. How could I kill that seconds thread before freeing the message? Or should I somehow set another semaphore and wait for that thread to finish (even though I already responded to the message) to free the message?
Aug ’22
Reply to How to handle System Extension willCompleteAfterReboot
Another question I had about the willCompleteAfterReboot is why is this called? I want to better understand this problem I am having about extensions needing a reboot to complete an upgrade. What is preventing the system from starting my extension without the need of a reboot? I am using a Network Extension, if I were to add Endpoint Security to my extension would something in the activation process change? I can't see antivirus software that uses this framework requiring a reboot for every update to their extension.
Jul ’21
Reply to Get all Domain names in macos ?
Would this work? Just accessing the NEAppProxyFlow and returning true without having to handle the flow // NEDNSProxyProvider override func handleNewFlow(_ flow: NEAppProxyFlow) -> Bool { NSLog("DNSProxyProvider: handleFlow") if let tcpFlow = flow as? NEAppProxyTCPFlow { let remoteHost = (tcpFlow.remoteEndpoint as! NWHostEndpoint).hostname let remotePort = (tcpFlow.remoteEndpoint as! NWHostEndpoint).port // Do whatever I want with this data } else if let udpFlow = flow as? NEAppProxyUDPFlow { let localHost = (udpFlow.localEndpoint as! NWHostEndpoint).hostname let localPort = (udpFlow.localEndpoint as! NWHostEndpoint).port // Do whatever I want with this data } return true }
Jun ’21
Reply to Process arguments from audit token
Ok so here is what I came up with. This works fine, the only thing I have yet to see is if it has any memory leaks. I hope this helps someone in the future :) If you have any suggestions to the func please let me know. Also, you should first convert the audit_token to pid using the function mentioned above. func getArgs(from pid: Int32) -> [NSString]? {   var arguments: [NSString] = []   var mib: [Int32] = [0, 0, 0]   var argsMax: Int = 0   mib[0] = CTL_KERN   mib[1] = KERN_ARGMAX   var size = MemoryLayout<Int>.stride(ofValue: argsMax)   if sysctl(&mib, 2, &argsMax, &size, nil, 0) == -1 {     return nil   }   let processArgs = UnsafeMutablePointer<CChar>.allocate(capacity: argsMax)   mib[0] = CTL_KERN   mib[1] = KERN_PROCARGS2   mib[2] = pid size = argsMax as size_t   // Get process arguments   if sysctl(&mib, 3, processArgs, &size, nil, 0) == -1 {     return nil   }   if size <= MemoryLayout<Int>.size {     return nil   }   var numberOfArgs: Int32 = 0   //Get number of args   memcpy(&numberOfArgs, processArgs, MemoryLayout.size(ofValue: numberOfArgs)) // Initialize the pointer to the start of args   var parser: UnsafeMutablePointer<CChar> = processArgs + MemoryLayout.size(ofValue: numberOfArgs) // Iterate until NULL terminated path   while parser < &processArgs[size] {     if 0x0 == parser.pointee {       // arrived ar argv[0]       break     }     parser += 1   }   // sanity check   if parser == &processArgs[size] {     return nil   }   while parser < &processArgs[size] {     if 0x0 != parser.pointee {       break     }     parser += 1   }   // sanity check   if parser == &processArgs[size] {     return nil   }   var argStart: UnsafeMutablePointer<CChar>? = parser   // Get all args   while parser < &processArgs[size] {     if parser.pointee == CChar(0) {       if nil != argStart {         let argument = NSString(utf8String: argStart!)         if argument != nil {           arguments.append(argument!)         }       }       argStart = parser + 1       if arguments.count == numberOfArgs {         break       }     }     parser += 1   }   // Is this free necessary?   free(processArgs)   return arguments }
Jun ’21
Reply to NEFilterSocketFlow remoteHostname property
Yes, I can get the remoteEndpoint populated guard let socketFlow = flow as? NEFilterSocketFlow,     let remoteEndpoint = socketFlow.remoteEndpoint as? NWHostEndpoint,     let localEndpoint = socketFlow.localEndpoint as? NWHostEndpoint else {      return nil }       if #available(macOS 11.0, *) { if let hostname = socketFlow.remoteHostname {      // Access hostname     } }
May ’21