mirror of
https://github.com/morgan9e/macos-stats
synced 2026-04-14 00:04:15 +09:00
feat: added certificate verification to the helper app. It will verify the incoming connection certificate if it's Stats. If not the connection will not be opened. It prevents abusing the helper app by 3d party applications to access the helper interface. Thanks @senzee1984 for finding and helping solve that problem. This commit will force the update of the helper app and will require a password for users who have installed the helper.
This commit is contained in:
@@ -7,9 +7,9 @@
|
||||
<key>CFBundleName</key>
|
||||
<string>eu.exelban.Stats.SMC.Helper</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
<string>1.0.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<string>2</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>SMAuthorizedClients</key>
|
||||
|
||||
@@ -48,11 +48,22 @@ class Helper: NSObject, NSXPCListenerDelegate, HelperProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
func listener(_ listener: NSXPCListener, shouldAcceptNewConnection connection: NSXPCConnection) -> Bool {
|
||||
connection.exportedInterface = NSXPCInterface(with: HelperProtocol.self)
|
||||
connection.exportedObject = self
|
||||
connection.invalidationHandler = {
|
||||
if let connectionIndex = self.connections.firstIndex(of: connection) {
|
||||
func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {
|
||||
do {
|
||||
let isValid = try CodesignCheck.codeSigningMatches(pid: newConnection.processIdentifier)
|
||||
if !isValid {
|
||||
NSLog("invalid connection, dropping")
|
||||
return false
|
||||
}
|
||||
} catch {
|
||||
NSLog("error checking code signing: \(error)")
|
||||
return false
|
||||
}
|
||||
|
||||
newConnection.exportedInterface = NSXPCInterface(with: HelperProtocol.self)
|
||||
newConnection.exportedObject = self
|
||||
newConnection.invalidationHandler = {
|
||||
if let connectionIndex = self.connections.firstIndex(of: newConnection) {
|
||||
self.connections.remove(at: connectionIndex)
|
||||
}
|
||||
if self.connections.isEmpty {
|
||||
@@ -60,8 +71,8 @@ class Helper: NSObject, NSXPCListenerDelegate, HelperProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
self.connections.append(connection)
|
||||
connection.resume()
|
||||
self.connections.append(newConnection)
|
||||
newConnection.resume()
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -185,3 +196,81 @@ extension Helper {
|
||||
exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/duanefields/VirtualKVM/blob/master/VirtualKVM/CodesignCheck.swift
|
||||
let kSecCSDefaultFlags = 0
|
||||
|
||||
enum CodesignCheckError: Error {
|
||||
case message(String)
|
||||
}
|
||||
|
||||
struct CodesignCheck {
|
||||
public static func codeSigningMatches(pid: pid_t) throws -> Bool {
|
||||
return try self.codeSigningCertificatesForSelf() == self.codeSigningCertificates(forPID: pid)
|
||||
}
|
||||
|
||||
private static func codeSigningCertificatesForSelf() throws -> [SecCertificate] {
|
||||
guard let secStaticCode = try secStaticCodeSelf() else { return [] }
|
||||
return try codeSigningCertificates(forStaticCode: secStaticCode)
|
||||
}
|
||||
|
||||
private static func codeSigningCertificates(forPID pid: pid_t) throws -> [SecCertificate] {
|
||||
guard let secStaticCode = try secStaticCode(forPID: pid) else { return [] }
|
||||
return try codeSigningCertificates(forStaticCode: secStaticCode)
|
||||
}
|
||||
|
||||
private static func executeSecFunction(_ secFunction: () -> (OSStatus) ) throws {
|
||||
let osStatus = secFunction()
|
||||
guard osStatus == errSecSuccess else {
|
||||
throw CodesignCheckError.message(String(describing: SecCopyErrorMessageString(osStatus, nil)))
|
||||
}
|
||||
}
|
||||
|
||||
private static func secStaticCodeSelf() throws -> SecStaticCode? {
|
||||
var secCodeSelf: SecCode?
|
||||
try executeSecFunction { SecCodeCopySelf(SecCSFlags(rawValue: 0), &secCodeSelf) }
|
||||
guard let secCode = secCodeSelf else {
|
||||
throw CodesignCheckError.message("SecCode returned empty from SecCodeCopySelf")
|
||||
}
|
||||
return try secStaticCode(forSecCode: secCode)
|
||||
}
|
||||
|
||||
private static func secStaticCode(forPID pid: pid_t) throws -> SecStaticCode? {
|
||||
var secCodePID: SecCode?
|
||||
try executeSecFunction { SecCodeCopyGuestWithAttributes(nil, [kSecGuestAttributePid: pid] as CFDictionary, [], &secCodePID) }
|
||||
guard let secCode = secCodePID else {
|
||||
throw CodesignCheckError.message("SecCode returned empty from SecCodeCopyGuestWithAttributes")
|
||||
}
|
||||
return try secStaticCode(forSecCode: secCode)
|
||||
}
|
||||
|
||||
private static func secStaticCode(forSecCode secCode: SecCode) throws -> SecStaticCode? {
|
||||
var secStaticCodeCopy: SecStaticCode?
|
||||
try executeSecFunction { SecCodeCopyStaticCode(secCode, [], &secStaticCodeCopy) }
|
||||
guard let secStaticCode = secStaticCodeCopy else {
|
||||
throw CodesignCheckError.message("SecStaticCode returned empty from SecCodeCopyStaticCode")
|
||||
}
|
||||
return secStaticCode
|
||||
}
|
||||
|
||||
private static func isValid(secStaticCode: SecStaticCode) throws {
|
||||
try executeSecFunction { SecStaticCodeCheckValidity(secStaticCode, SecCSFlags(rawValue: kSecCSDoNotValidateResources | kSecCSCheckNestedCode), nil) }
|
||||
}
|
||||
|
||||
private static func secCodeInfo(forStaticCode secStaticCode: SecStaticCode) throws -> [String: Any]? {
|
||||
try isValid(secStaticCode: secStaticCode)
|
||||
var secCodeInfoCFDict: CFDictionary?
|
||||
try executeSecFunction { SecCodeCopySigningInformation(secStaticCode, SecCSFlags(rawValue: kSecCSSigningInformation), &secCodeInfoCFDict) }
|
||||
guard let secCodeInfo = secCodeInfoCFDict as? [String: Any] else {
|
||||
throw CodesignCheckError.message("CFDictionary returned empty from SecCodeCopySigningInformation")
|
||||
}
|
||||
return secCodeInfo
|
||||
}
|
||||
|
||||
private static func codeSigningCertificates(forStaticCode secStaticCode: SecStaticCode) throws -> [SecCertificate] {
|
||||
guard
|
||||
let secCodeInfo = try secCodeInfo(forStaticCode: secStaticCode),
|
||||
let secCertificates = secCodeInfo[kSecCodeInfoCertificates as String] as? [SecCertificate] else { return [] }
|
||||
return secCertificates
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1600"
|
||||
LastUpgradeVersion = "1610"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1600"
|
||||
LastUpgradeVersion = "1610"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1600"
|
||||
LastUpgradeVersion = "1610"
|
||||
wasCreatedForAppExtension = "YES"
|
||||
version = "2.0">
|
||||
<BuildAction
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>639</string>
|
||||
<string>640</string>
|
||||
<key>Description</key>
|
||||
<string>Simple macOS system monitor in your menu bar</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.11.20</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>639</string>
|
||||
<string>640</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
|
||||
Reference in New Issue
Block a user