ããã«ã¡ã¯ãããã«ïŒ ä»æ¥ã¯ãmacOS ã§æ»æè ã«ããæ»æããããã»ã¹ãä¿è·ããæ¹æ³ã«ã€ããŠè©±ããããšæããŸãã ããšãã°ãç¹ã« macOS ã§ã¯ããã»ã¹ãã匷å¶çµäºãããæ¹æ³ãããã€ããããããããã¯ãŠã€ã«ã¹å¯Ÿçã·ã¹ãã ãããã¯ã¢ãã ã·ã¹ãã ã«åœ¹ç«ã¡ãŸãã ãããšã«ããäžã®ä¿è·æ¹æ³ã«ã€ããŠãèªã¿ãã ããã
ããã»ã¹ãã匷å¶çµäºãããå€å žçãªæ¹æ³
ããã»ã¹ãã匷å¶çµäºãããããç¥ãããæ¹æ³ã¯ãããã»ã¹ã« SIGKILL ã·ã°ãã«ãéä¿¡ããããšã§ãã bash ã䜿çšãããšãæšæºã®ãkill -SIGKILL PIDããŸãã¯ãpkill -9 NAMEããåŒã³åºã㊠kill ã§ããŸãã ãkillãã³ãã³ã㯠UNIX ã®æ代ããç¥ãããŠãããmacOS ã ãã§ãªãä»ã® UNIX ç³»ã·ã¹ãã ã§ã䜿çšã§ããŸãã
UNIX ç³»ã·ã¹ãã ãšåæ§ã«ãmacOS ã§ã¯ SIGKILL ãš SIGSTOP ã® XNUMX ã€ãé€ãããã»ã¹ãžã®ã·ã°ãã«ãã€ã³ã¿ãŒã»ããã§ããŸãã ãã®èšäºã§ã¯ãããã»ã¹ã匷å¶çµäºãããã·ã°ãã«ãšããŠã® SIGKILL ã·ã°ãã«ã«äž»ã«çŠç¹ãåœãŠãŸãã
macOSã®ä»æ§
macOS ã§ã¯ãXNU ã«ãŒãã«ã® kill ã·ã¹ãã ã³ãŒã«ã¯ pssignal(SIGKILL,...) é¢æ°ãåŒã³åºããŸãã ãŠãŒã¶ãŒç©ºéå ã®ä»ã®ãŠãŒã¶ãŒ ã¢ã¯ã·ã§ã³ã pssignal é¢æ°ã«ãã£ãŠåŒã³åºãããã©ãããèŠãŠã¿ãŸãããã ã«ãŒãã«ã®å éšã¡ã«ããºã ã«ãã pssignal é¢æ°ãžã®åŒã³åºããåãé€ããŸããã (éèŠã§ã¯ãªããããããŸãããããããã¯å¥ã®èšäºã«æ®ããŠãããŸã ð - 眲åæ€èšŒãã¡ã¢ãª ãšã©ãŒãçµäº/çµäºåŠçããã¡ã€ã«ä¿è·éåãªã©) ã
é¢æ°ãšå¯Ÿå¿ããã·ã¹ãã ã³ãŒã«ããã¬ãã¥ãŒãå§ããŸããã
static int
terminate_with_payload_internal(struct proc *cur_proc, int target_pid, uint32_t reason_namespace,
uint64_t reason_code, user_addr_t payload, uint32_t payload_size,
user_addr_t reason_string, uint64_t reason_flags)
{
...
target_proc = proc_find(target_pid);
...
if (!cansignal(cur_proc, cur_cred, target_proc, SIGKILL)) {
proc_rele(target_proc);
return EPERM;
}
...
if (target_pid == cur_proc->p_pid) {
/*
* psignal_thread_with_reason() will pend a SIGKILL on the specified thread or
* return if the thread and/or task are already terminating. Either way, the
* current thread won't return to userspace.
*/
psignal_thread_with_reason(target_proc, current_thread(), SIGKILL, signal_reason);
} else {
psignal_with_reason(target_proc, SIGKILL, signal_reason);
}
...
}
æã¡äžã
ã·ã¹ãã èµ·åæã«ããŒã¢ã³ãäœæãããã®æå¹æéãå¶åŸ¡ããæšæºçãªæ¹æ³ã¯ launchd ã§ãã ãœãŒã¹ã¯ macOS 10.10 ãŸã§ã®å€ãããŒãžã§ã³ã® launchctl çšã§ãããã³ãŒãäŸã¯èª¬æã®ããã«æäŸãããŠããããšã«æ³šæããŠãã ããã ææ°ã® launchctl 㯠XPC çµç±ã§ launchd ã·ã°ãã«ãéä¿¡ããlaunchctl ããžãã¯ã¯ XPC ã«ç§»åãããŸããã
ã¢ããªã±ãŒã·ã§ã³ãã©ã®ããã«æ£ç¢ºã«åæ¢ãããããèŠãŠã¿ãŸãããã SIGTERM ã·ã°ãã«ãéä¿¡ããåã«ããproc_terminateãã·ã¹ãã ã³ãŒã«ã䜿çšããŠã¢ããªã±ãŒã·ã§ã³ã®åæ¢ãè©Šè¡ãããŸãã
<launchctl src/core.c>
...
error = proc_terminate(j->p, &sig);
if (error) {
job_log(j, LOG_ERR | LOG_CONSOLE, "Could not terminate job: %d: %s", error, strerror(error));
job_log(j, LOG_NOTICE | LOG_CONSOLE, "Using fallback option to terminate job...");
error = kill2(j->p, SIGTERM);
if (error) {
job_log(j, LOG_ERR, "Could not signal job: %d: %s", error, strerror(error));
}
...
<>
å éšã§ã¯ãproc_terminate ã¯ãã®ååã«åããŠãSIGTERM ã䜿çšã㊠psignal ã ãã§ãªã SIGKILL ãéä¿¡ã§ããŸãã
éæ¥ãã« - ãªãœãŒã¹å¶é
ããã«èå³æ·±ãã±ãŒã¹ã¯ãå¥ã®ã·ã¹ãã ã³ãŒã«ã§èŠãããšãã§ããŸãã
ãã®ã·ã¹ãã ã³ãŒã«ã¯ããã»ã¹ã匷å¶çµäºããå¯èœæ§ããããŸãããã·ã¹ãã ã¯ã·ã¹ãã ã³ãŒã«ãåŒã³åºãããã»ã¹ã®æš©éãé©åã«ãã§ãã¯ããŸããã§ããã å®éã«ç¢ºèªããŠã¿ã
ãããã£ãŠãã¢ããªã±ãŒã·ã§ã³ã® CPU 䜿çšéã¯ã©ãŒã¿ããå¶éããããš (ããšãã°ã1 ns ã®ã¿ã®å®è¡ãèš±å¯ãããªã©)ãã·ã¹ãã å ã®ä»»æã®ããã»ã¹ã匷å¶çµäºã§ããŸãã ãããã£ãŠããã«ãŠã§ã¢ã¯ãŠã€ã«ã¹å¯Ÿçããã»ã¹ãå«ãã·ã¹ãã äžã®ããããããã»ã¹ã匷å¶çµäºããå¯èœæ§ããããŸãã ãŸããèå³æ·±ãã®ã¯ãpid 1 ã®ããã»ã¹ (launchctl) ã匷å¶çµäºãããšãã«çºçãã圱é¿ã§ããã€ãŸããSIGKILL ã·ã°ãã«ãåŠçããããšãããšã«ãŒãã« ãããã¯ãçºçããŸã:)
åé¡ã解決ããæ¹æ³ã¯ïŒ
ããã»ã¹ã匷å¶çµäºãããã®ãé²ãæãç°¡åãªæ¹æ³ã¯ãã·ã¹ãã ã³ãŒã« ããŒãã«å ã®é¢æ°ãã€ã³ã¿ã眮ãæããããšã§ãã æ®å¿µãªããããã®æ¹æ³ã¯å€ãã®çç±ããç°¡åã§ã¯ãããŸããã
ãŸããsysent ã®ã¡ã¢ãªäœçœ®ãå¶åŸ¡ããã·ã³ãã«ã¯ XNU ã«ãŒãã« ã·ã³ãã«ã«ãã©ã€ããŒãã§ããã ãã§ãªããã«ãŒãã« ã·ã³ãã«å ã§ã¯èŠã€ããããšãã§ããŸããã é¢æ°ãåçã«éã¢ã»ã³ãã«ããŠé¢æ°å ã®ãã€ã³ã¿ãŒãæ€çŽ¢ãããªã©ããã¥ãŒãªã¹ãã£ãã¯ãªæ€çŽ¢æ¹æ³ã䜿çšããå¿ èŠããããŸãã
次ã«ãããŒãã«å
ã®ãšã³ããªã®æ§é ã¯ãã«ãŒãã«ã®ã³ã³ãã€ã«ã«äœ¿çšããããã©ã°ã«äŸåããŸãã CONFIG_REQUIRES_U32_MUNGING ãã©ã°ã宣èšãããŠããå Žåãæ§é äœã®ãµã€ãºãå€æŽãããè¿œå ãã£ãŒã«ããè¿œå ãããŸãã
struct sysent { /* system call table */
sy_call_t *sy_call; /* implementing function */
#if CONFIG_REQUIRES_U32_MUNGING || (__arm__ && (__BIGGEST_ALIGNMENT__ > 4))
sy_munge_t *sy_arg_munge32; /* system call arguments munger for 32-bit process */
#endif
int32_t sy_return_type; /* system call return types */
int16_t sy_narg; /* number of args */
uint16_t sy_arg_bytes; /* Total size of arguments in bytes for
* 32-bit system calls
*/
};
幞ããªããšã«ãmacOS ã®ææ°ããŒãžã§ã³ã§ã¯ãApple ãããã»ã¹ãæäœããããã®æ°ãã API ãæäŸããŠããŸãã Endpoint Security API ã䜿çšãããšãã¯ã©ã€ã¢ã³ãã¯ä»ã®ããã»ã¹ãžã®å€ãã®ãªã¯ãšã¹ããæ¿èªã§ããŸãã ãããã£ãŠãäžèšã® API ã䜿çšããŠãSIGKILL ã·ã°ãã«ãå«ãããã»ã¹ãžã®ã·ã°ãã«ããããã¯ã§ããŸãã
#include <bsm/libbsm.h>
#include <EndpointSecurity/EndpointSecurity.h>
#include <unistd.h>
int main(int argc, const char * argv[]) {
es_client_t* cli = nullptr;
{
auto res = es_new_client(&cli, ^(es_client_t * client, const es_message_t * message) {
switch (message->event_type) {
case ES_EVENT_TYPE_AUTH_SIGNAL:
{
auto& msg = message->event.signal;
auto target = msg.target;
auto& token = target->audit_token;
auto pid = audit_token_to_pid(token);
printf("signal '%d' sent to pid '%d'n", msg.sig, pid);
es_respond_auth_result(client, message, pid == getpid() ? ES_AUTH_RESULT_DENY : ES_AUTH_RESULT_ALLOW, false);
}
break;
default:
break;
}
});
}
{
es_event_type_t evs[] = { ES_EVENT_TYPE_AUTH_SIGNAL };
es_subscribe(cli, evs, sizeof(evs) / sizeof(*evs));
}
printf("%dn", getpid());
sleep(60); // could be replaced with other waiting primitive
es_unsubscribe_all(cli);
es_delete_client(cli);
return 0;
}
åæ§ã«ãã·ã°ãã«ä¿è·ã¡ãœãã (ããªã·ãŒ proc_check_signal) ãæäŸãã MAC ããªã·ãŒãã«ãŒãã«ã«ç»é²ã§ããŸãããAPI ã¯æ£åŒã«ãµããŒããããŠããŸããã
ã«ãŒãã«æ¡åŒµæ©èœã®ä¿è·
ã·ã¹ãã å ã®ããã»ã¹ãä¿è·ããããšã«å ããŠãã«ãŒãã«æ¡åŒµæ©èœèªäœ (kext) ãä¿è·ããããšãå¿ èŠã§ãã macOS ã¯ãéçºè ã IOKit ããã€ã¹ ãã©ã€ããŒãç°¡åã«éçºã§ãããã¬ãŒã ã¯ãŒã¯ãæäŸããŸãã IOKit ã¯ãããã€ã¹ãæäœããããã®ããŒã«ãæäŸããã ãã§ãªããC++ ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ã䜿çšããŠãã©ã€ããŒãã¹ã¿ããã³ã°ããããã®ã¡ãœãããæäŸããŸãã ãŠãŒã¶ãŒç©ºéå ã®ã¢ããªã±ãŒã·ã§ã³ã¯ãã¯ã©ã¹ã®ç»é²æžã¿ã€ã³ã¹ã¿ã³ã¹ããæ€çŽ¢ãããŠãã«ãŒãã«ãšãŠãŒã¶ãŒç©ºéã®é¢ä¿ã確ç«ã§ããŸãã
ã·ã¹ãã å ã®ã¯ã©ã¹ ã€ã³ã¹ã¿ã³ã¹ã®æ°ãæ€åºããã«ã¯ãioclasscount ãŠãŒãã£ãªãã£ããããŸãã
my_kext_ioservice = 1
my_kext_iouserclient = 1
ãã©ã€ã㌠ã¹ã¿ãã¯ã«ç»é²ããã«ãŒãã«æ¡åŒµæ©èœã¯ãIOService ããç¶æ¿ããã¯ã©ã¹ã宣èšããå¿ èŠããããŸã (ãã®å Žå㯠my_kext_ioservice ãªã©)ããŠãŒã¶ãŒ ã¢ããªã±ãŒã·ã§ã³ã«æ¥ç¶ãããšãIOUserClient (äŸã§ã¯ my_kext_iouserclient) ããç¶æ¿ããã¯ã©ã¹ã®æ°ããã€ã³ã¹ã¿ã³ã¹ãäœæãããŸãã
ã·ã¹ãã ãããã©ã€ããŒãã¢ã³ããŒãããããšãããš (kextunload ã³ãã³ã)ãä»®æ³é¢æ°ãbool terminate(IOOptionBits options)ããåŒã³åºãããŸãã kextunload ãç¡å¹ã«ããããã«ã¢ã³ããŒãããããšãããšãã«çµäºããã«ã¯ãåŒã³åºã㧠false ãè¿ãã ãã§ååã§ãã
bool Kext::terminate(IOOptionBits options)
{
if (!IsUnloadAllowed)
{
// Unload is not allowed, returning false
return false;
}
return super::terminate(options);
}
IsUnloadAllowed ãã©ã°ã¯ãããŒãæã« IOUserClient ã«ãã£ãŠèšå®ã§ããŸãã ããŠã³ããŒãå¶éãããå Žåãkextunload ã³ãã³ãã¯æ¬¡ã®åºåãè¿ããŸãã
admin@admins-Mac drivermanager % sudo kextunload ./test.kext
Password:
(kernel) Can't remove kext my.kext.test; services failed to terminate - 0xe00002c7.
Failed to unload my.kext.test - (iokit/common) unsupported function.
IOUserClient ã«å¯ŸããŠãåæ§ã®ä¿è·ãè¡ãå¿ èŠããããŸãã ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ã¯ãIOKitLib ãŠãŒã¶ãŒç©ºéé¢æ°ãIOCatalogueTerminate(mach_port_t, uint32_t flag, io_name_t description);ãã䜿çšããŠã¢ã³ããŒãã§ããŸãã ãŠãŒã¶ãŒç©ºéã¢ããªã±ãŒã·ã§ã³ããçµäºããããŸã§ãã€ãŸããclientDiedãé¢æ°ãåŒã³åºãããªããªããŸã§ã¯ããterminateãã³ãã³ããåŒã³åºããšãã« false ãè¿ãããšãã§ããŸãã
ãã¡ã€ã«ä¿è·
ãã¡ã€ã«ãä¿è·ããã«ã¯ããã¡ã€ã«ãžã®ã¢ã¯ã»ã¹ãå¶éã§ãã Kauth API ã䜿çšããã ãã§ååã§ãã Apple ã¯ã¹ã³ãŒãå ã®ããŸããŸãªã€ãã³ãã«é¢ããéç¥ãéçºè ã«æäŸããŸããç§ãã¡ã«ãšã£ãŠãKAUTH_VNODE_DELETEãKAUTH_VNODE_WRITE_DATAãããã³ KAUTH_VNODE_DELETE_CHILD ã®æäœã¯éèŠã§ãã ãã¡ã€ã«ãžã®ã¢ã¯ã»ã¹ãå¶éããæãç°¡åãªæ¹æ³ã¯ãã¹ã«ãã£ãŠã§ãããvn_getpathãAPI ã䜿çšããŠãã¡ã€ã«ãžã®ãã¹ãååŸãããã¹ã®ãã¬ãã£ãã¯ã¹ãæ¯èŒããŸãã ãã¡ã€ã« ãã©ã«ã㌠ãã¹ã®ååå€æŽãæé©åããããã«ãã·ã¹ãã ã¯åãã¡ã€ã«ãžã®ã¢ã¯ã»ã¹ãèš±å¯ãããååãå€æŽããããã©ã«ããŒèªäœãžã®ã¢ã¯ã»ã¹ã®ã¿ãèš±å¯ããããšã«æ³šæããŠãã ããã 芪ãã¹ãæ¯èŒããKAUTH_VNODE_DELETEãå¶éããå¿ èŠããããŸãã
ãã®ã¢ãããŒãã®æ¬ ç¹ã¯ããã¬ãã£ãã¯ã¹ã®æ°ãå¢ãããšããã©ãŒãã³ã¹ãäœäžããå¯èœæ§ãããããšã§ãã æ¯èŒã O(prefix*length) (prefix ã¯ãã¬ãã£ãã¯ã¹ã®æ°ãlength ã¯æååã®é·ã) ãšçãããªãããšã確èªããã«ã¯ããã¬ãã£ãã¯ã¹ã«ãã£ãŠæ§ç¯ããã決å®è«çæéãªãŒãããã³ (DFA) ã䜿çšã§ããŸãã
äžãããããã¬ãã£ãã¯ã¹ã®ã»ããã«å¯Ÿã㊠DFA ãæ§ç¯ããæ¹æ³ãèããŠã¿ãŸãããã åãã¬ãã£ãã¯ã¹ã®å é ã§ã«ãŒãœã«ãåæåããŸãã ãã¹ãŠã®ã«ãŒãœã«ãåãæåãæããŠããå Žåã¯ãåã«ãŒãœã«ã XNUMX æåãã€å¢ãããåãè¡ã®é·ãã XNUMX ã€å¢ããããšã«æ³šæããŠãã ããã ç°ãªãã·ã³ãã«ãæ〠XNUMX ã€ã®ã«ãŒãœã«ãããå Žåã¯ãã«ãŒãœã«ãæãã·ã³ãã«ã«åŸã£ãŠã«ãŒãœã«ãã°ã«ãŒãã«åå²ããã°ã«ãŒãããšã«ã¢ã«ãŽãªãºã ãç¹°ãè¿ããŸãã
æåã®ã±ãŒã¹ (ã«ãŒãœã«ã®äžã«ãããã¹ãŠã®æåãåã) ã§ã¯ãåãè¡ã«æ²¿ã£ãé·ç§»ã 256 ã€ã ããã DFA ç¶æ ãåŸãããŸãã XNUMX çªç®ã®ã±ãŒã¹ã§ã¯ãé¢æ°ãååž°çã«åŒã³åºãããšã«ãã£ãŠååŸããããåŸç¶ã®ç¶æ ãžã®ãµã€ãº XNUMX (æåæ°ãšã°ã«ãŒãã®æ倧æ°) ã®é·ç§»ããŒãã«ãååŸããŸãã
äŸãèŠãŠã¿ãŸãããã ãã¬ãã£ãã¯ã¹ã®ã»ãã (ã/foo/bar/tmp/ããã/var/db/foo/ããã/foo/bar/aba/ãããfoo/bar/aac/ã) ã«ã€ããŠã¯ã次ã®ããã«ååŸã§ããŸãã DFAã ãã®å³ã¯ãä»ã®ç¶æ ã«è³ãé·ç§»ã®ã¿ã瀺ããŠãããä»ã®é·ç§»ã¯æçµçãªãã®ã§ã¯ãããŸããã
DKA å·ãééããå Žåã3 ã€ã®ã±ãŒã¹ãèããããŸãã
- æçµç¶æ ã«éããŸãã - ãã¹ã¯ä¿è·ãããŠãããæäœ KAUTH_VNODE_DELETEãKAUTH_VNODE_WRITE_DATAãããã³ KAUTH_VNODE_DELETE_CHILD ãå¶éãããŠããŸãã
- æçµç¶æ ã«ã¯å°éããŸããã§ãããããã¹ã¯ãçµäºãããŸãã (null ã¿ãŒãããŒã¿ã«å°éããŸãã) - ãã¹ã¯èŠªã§ãããããKAUTH_VNODE_DELETE ãå¶éããå¿ èŠããããŸãã vnode ããã©ã«ããŒã®å Žåã¯ãæåŸã«ã/ããè¿œå ããå¿ èŠãããããšã«æ³šæããŠãã ãããããããªããšããã¡ã€ã«ã/foor/bar/tãã«å¶éãããå¯èœæ§ããããŸãããããã¯æ£ãããããŸããã
- æçµç¶æ ã«å°éããããã¹ãçµäºããŸããã§ããã ã©ã®ãã¬ãã£ãã¯ã¹ãããã«äžèŽããªããããå¶éã¯å°å ¥ããŸããã
ãŸãšã
éçºäžã®ã»ãã¥ãªã㣠ãœãªã¥ãŒã·ã§ã³ã®ç®æšã¯ããŠãŒã¶ãŒãšãã®ããŒã¿ã®ã»ãã¥ãªã㣠ã¬ãã«ãé«ããããšã§ãã äžæ¹ã§ããã®ç®æšã¯ããªãã¬ãŒãã£ã³ã° ã·ã¹ãã èªäœãã匱ããè匱æ§ã解決ãã Acronis ãœãããŠã§ã¢è£œåã®éçºã«ãã£ãŠéæãããŸãã äžæ¹ã§ãOSåŽã§æ¹åã§ããã»ãã¥ãªãã£é¢ã®åŒ·åãæ ã£ãŠã¯ãããŸãããç¹ã«è匱æ§ã解æ¶ããããšã§è£œåãšããŠã®å®å®æ§ãé«ãŸããŸãã ãã®è匱æ§ã¯ Apple 補åã»ãã¥ãªã㣠ããŒã ã«å ±åãããmacOS 10.14.5 (https://support.apple.com/en-gb/HT210119) ã§ä¿®æ£ãããŸããã
ããããã¹ãŠã¯ããŠãŒãã£ãªãã£ãã«ãŒãã«ã«æ£åŒã«ã€ã³ã¹ããŒã«ãããŠããå Žåã«ã®ã¿å®è¡ã§ããŸãã ã€ãŸããå€éšã®æãŸãããªããœãããŠã§ã¢ã«å¯Ÿãããã®ãããªæãç©Žã¯ãããŸããã ãã ããã芧ã®ãšããããŠã€ã«ã¹å¯Ÿçã·ã¹ãã ãããã¯ã¢ãã ã·ã¹ãã ãªã©ã®æ£èŠã®ããã°ã©ã ãä¿è·ããå Žåã§ãäœæ¥ãå¿
èŠã§ãã ããããmacOS çšã®æ°ãã Acronis 補åã«ã¯ãã·ã¹ãã ããã®ã¢ã³ããŒãã«å¯Ÿããè¿œå ã®ä¿è·æ©èœãè¿œå ãããŸããã
åºæïŒ habr.com