From eb6b6ca394357805f2bdba989abae309f718b4d8 Mon Sep 17 00:00:00 2001 From: Apple Date: Wed, 29 Jul 2020 21:28:34 +0000 Subject: [PATCH 1/1] xnu-6153.141.1.tar.gz --- bsd/kern/kern_aio.c | 397 +- bsd/kern/kern_exec.c | 8 + bsd/kern/kern_exit.c | 29 + bsd/kern/kern_proc.c | 13 + bsd/kern/kern_sysctl.c | 2 +- bsd/kern/mach_loader.c | 9 +- bsd/kern/uipc_usrreq.c | 5 + bsd/net/content_filter.c | 4 +- bsd/net/if.c | 4 +- bsd/net/if_gif.c | 10 +- bsd/net/if_stf.c | 5 +- bsd/net/kpi_interface.c | 1 + bsd/net/necp.c | 177 +- bsd/net/necp.h | 2 + bsd/netinet/flow_divert.c | 26 +- bsd/netinet/in.c | 29 +- bsd/netinet/ip_input.c | 488 ++- bsd/netinet/ip_var.h | 4 +- bsd/netinet/kpi_ipfilter.c | 4 +- bsd/netinet6/ah_input.c | 23 +- bsd/netinet6/dest6.c | 36 +- bsd/netinet6/esp_input.c | 2 + bsd/netinet6/frag6.c | 41 +- bsd/netinet6/icmp6.c | 27 +- bsd/netinet6/in6.c | 327 +- bsd/netinet6/in6_ifattach.c | 63 +- bsd/netinet6/in6_pcb.c | 6 +- bsd/netinet6/in6_src.c | 4 +- bsd/netinet6/in6_var.h | 35 +- bsd/netinet6/ip6_input.c | 524 ++- bsd/netinet6/ip6_output.c | 4 +- bsd/netinet6/ip6_var.h | 6 +- bsd/netinet6/mld6.c | 13 +- bsd/netinet6/nd6.c | 67 +- bsd/netinet6/nd6_nbr.c | 21 +- bsd/netinet6/nd6_rtr.c | 8 +- bsd/netinet6/route6.c | 13 +- bsd/netkey/key.c | 219 +- bsd/nfs/nfs_socket.c | 26 +- bsd/sys/proc.h | 1 + bsd/sys/reason.h | 3 +- bsd/sys/vnode.h | 18 + bsd/sys/vnode_internal.h | 2 +- bsd/vfs/vfs_cache.c | 18 +- bsd/vfs/vfs_subr.c | 44 +- config/IOKit.exports | 3 + config/MasterVersion | 2 +- config/Private.exports | 1 + iokit/DriverKit/IODMACommand.iig | 191 + iokit/DriverKit/IOInterruptDispatchSource.iig | 21 + iokit/IOKit/IODMACommand.h | 3 +- iokit/IOKit/IOKitKeys.h | 3 + iokit/IOKit/IOService.h | 1 + iokit/Kernel/IOService.cpp | 2 + iokit/Kernel/IOUserServer.cpp | 281 +- iokit/conf/files | 1 + osfmk/arm/pmap.c | 13 +- osfmk/arm/status.c | 4 + osfmk/arm64/cswitch.s | 17 +- osfmk/arm64/exception_asm.h | 13 +- osfmk/arm64/locore.s | 118 +- osfmk/arm64/pcb.c | 15 +- osfmk/arm64/proc_reg.h | 14 + osfmk/arm64/sleh.c | 76 +- osfmk/arm64/status.c | 10 +- osfmk/i386/acpi.c | 4 +- osfmk/i386/bsd_i386.c | 44 +- osfmk/i386/cpuid.c | 4 + osfmk/i386/cpuid.h | 1 + osfmk/i386/fpu.c | 76 +- osfmk/i386/i386_init.c | 4 +- osfmk/i386/proc_reg.h | 2 +- osfmk/i386/ucode.c | 5 +- osfmk/i386/ucode.h | 2 +- osfmk/ipc/ipc_importance.c | 4 +- osfmk/ipc/ipc_kmsg.c | 61 +- osfmk/ipc/ipc_mqueue.c | 2 +- osfmk/ipc/mach_msg.c | 2 +- osfmk/kern/exception.c | 33 + osfmk/kern/task.c | 39 +- osfmk/kern/task.h | 14 +- osfmk/kern/thread.h | 2 +- osfmk/kern/zalloc.c | 224 +- osfmk/kern/zalloc.h | 6 +- osfmk/mach/arm/exception.h | 6 + osfmk/mach/message.h | 22 + osfmk/vm/vm_fault.c | 7 +- osfmk/vm/vm_map.c | 70 +- osfmk/vm/vm_map.h | 4 + osfmk/vm/vm_user.c | 32 +- tests/IP6_EXTHDR_CHECK_61873584.c | 83 + tests/Makefile | 2 + tests/ioc_str.h | 154 + tests/macho_size_63133398.c | 3223 +++++++++++++++++ tests/pfkey.c | 1778 +++++++++ tests/proc_info.c | 6 +- tests/sioc-if-addr-bounds.c | 662 ++++ tests/unp_connect_thread_uaf.c | 149 + tools/lldbmacros/sysreg.py | 2 +- tools/lldbmacros/zonetriage.py | 2 +- 100 files changed, 9063 insertions(+), 1225 deletions(-) create mode 100644 iokit/DriverKit/IODMACommand.iig create mode 100644 tests/IP6_EXTHDR_CHECK_61873584.c create mode 100644 tests/ioc_str.h create mode 100644 tests/macho_size_63133398.c create mode 100644 tests/pfkey.c create mode 100644 tests/sioc-if-addr-bounds.c create mode 100644 tests/unp_connect_thread_uaf.c diff --git a/bsd/kern/kern_aio.c b/bsd/kern/kern_aio.c index 3ad8a516d..4a07657cb 100644 --- a/bsd/kern/kern_aio.c +++ b/bsd/kern/kern_aio.c @@ -106,11 +106,6 @@ #define AIO_suspend_sleep 111 #define AIO_worker_thread 120 -#if 0 -#undef KERNEL_DEBUG -#define KERNEL_DEBUG KERNEL_DEBUG_CONSTANT -#endif - /* * aio requests queue up on the aio_async_workq or lio_sync_workq (for * lio_listio LIO_WAIT). Requests then move to the per process aio_activeq @@ -502,11 +497,11 @@ aio_workq_mutex(aio_workq_t wq) int aio_cancel(proc_t p, struct aio_cancel_args *uap, int *retval ) { - struct user_aiocb my_aiocb; - int result; + struct user_aiocb my_aiocb; + int result; - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_cancel)) | DBG_FUNC_START, - (int)p, (int)uap->aiocbp, 0, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_cancel) | DBG_FUNC_START, + VM_KERNEL_ADDRPERM(p), uap->uaiocbp, 0, 0, 0); /* quick check to see if there are any async IO requests queued up */ if (aio_get_all_queues_count() < 1) { @@ -562,8 +557,8 @@ aio_cancel(proc_t p, struct aio_cancel_args *uap, int *retval ) result = EBADF; ExitRoutine: - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_cancel)) | DBG_FUNC_END, - (int)p, (int)uap->aiocbp, result, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_cancel) | DBG_FUNC_END, + VM_KERNEL_ADDRPERM(p), uap->uaiocbp, result, 0, 0); return result; } /* aio_cancel */ @@ -577,15 +572,15 @@ ExitRoutine: __private_extern__ void _aio_close(proc_t p, int fd ) { - int error; + int error; /* quick check to see if there are any async IO requests queued up */ if (aio_get_all_queues_count() < 1) { return; } - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_close)) | DBG_FUNC_START, - (int)p, fd, 0, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_close) | DBG_FUNC_START, + VM_KERNEL_ADDRPERM(p), fd, 0, 0, 0); /* cancel all async IO requests on our todo queues for this file descriptor */ aio_proc_lock(p); @@ -601,8 +596,8 @@ _aio_close(proc_t p, int fd ) * when we must wait for all active aio requests. */ - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_close_sleep)) | DBG_FUNC_NONE, - (int)p, fd, 0, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_close_sleep) | DBG_FUNC_NONE, + VM_KERNEL_ADDRPERM(p), fd, 0, 0, 0); while (aio_proc_active_requests_for_file(p, fd) > 0) { msleep(&p->AIO_CLEANUP_SLEEP_CHAN, aio_proc_mutex(p), PRIBIO, "aio_close", 0 ); @@ -611,8 +606,8 @@ _aio_close(proc_t p, int fd ) aio_proc_unlock(p); - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_close)) | DBG_FUNC_END, - (int)p, fd, 0, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_close) | DBG_FUNC_END, + VM_KERNEL_ADDRPERM(p), fd, 0, 0, 0); return; } /* _aio_close */ @@ -627,11 +622,11 @@ _aio_close(proc_t p, int fd ) int aio_error(proc_t p, struct aio_error_args *uap, int *retval ) { - aio_workq_entry *entryp; - int error; + aio_workq_entry *entryp; + int error; - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_error)) | DBG_FUNC_START, - (int)p, (int)uap->aiocbp, 0, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_error) | DBG_FUNC_START, + VM_KERNEL_ADDRPERM(p), uap->uaiocbp, 0, 0, 0); /* see if there are any aios to check */ if (aio_get_all_queues_count() < 1) { @@ -649,8 +644,8 @@ aio_error(proc_t p, struct aio_error_args *uap, int *retval ) *retval = entryp->errorval; error = 0; aio_entry_unlock(entryp); - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_error_val)) | DBG_FUNC_NONE, - (int)p, (int)uap->aiocbp, *retval, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_error_val) | DBG_FUNC_NONE, + VM_KERNEL_ADDRPERM(p), uap->uaiocbp, *retval, 0, 0); goto ExitRoutine; } } @@ -661,8 +656,8 @@ aio_error(proc_t p, struct aio_error_args *uap, int *retval ) ASSERT_AIO_FROM_PROC(entryp, p); *retval = EINPROGRESS; error = 0; - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_error_activeq)) | DBG_FUNC_NONE, - (int)p, (int)uap->aiocbp, *retval, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_error_activeq) | DBG_FUNC_NONE, + VM_KERNEL_ADDRPERM(p), uap->uaiocbp, *retval, 0, 0); goto ExitRoutine; } } @@ -670,8 +665,8 @@ aio_error(proc_t p, struct aio_error_args *uap, int *retval ) error = EINVAL; ExitRoutine: - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_error)) | DBG_FUNC_END, - (int)p, (int)uap->aiocbp, error, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_error) | DBG_FUNC_END, + VM_KERNEL_ADDRPERM(p), uap->uaiocbp, error, 0, 0); aio_proc_unlock(p); return error; @@ -688,11 +683,11 @@ ExitRoutine: int aio_fsync(proc_t p, struct aio_fsync_args *uap, int *retval ) { - int error; - int fsync_kind; + int error; + int fsync_kind; - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_fsync)) | DBG_FUNC_START, - (int)p, (int)uap->aiocbp, uap->op, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_fsync) | DBG_FUNC_START, + VM_KERNEL_ADDRPERM(p), uap->uaiocbp, uap->op, 0, 0); *retval = 0; /* 0 := O_SYNC for binary backward compatibility with Panther */ @@ -712,8 +707,8 @@ aio_fsync(proc_t p, struct aio_fsync_args *uap, int *retval ) } ExitRoutine: - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_fsync)) | DBG_FUNC_END, - (int)p, (int)uap->aiocbp, error, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_fsync) | DBG_FUNC_END, + VM_KERNEL_ADDRPERM(p), uap->uaiocbp, error, 0, 0); return error; } /* aio_fsync */ @@ -726,10 +721,10 @@ ExitRoutine: int aio_read(proc_t p, struct aio_read_args *uap, int *retval ) { - int error; + int error; - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_read)) | DBG_FUNC_START, - (int)p, (int)uap->aiocbp, 0, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_read) | DBG_FUNC_START, + VM_KERNEL_ADDRPERM(p), uap->uaiocbp, 0, 0, 0); *retval = 0; @@ -738,8 +733,8 @@ aio_read(proc_t p, struct aio_read_args *uap, int *retval ) *retval = -1; } - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_read)) | DBG_FUNC_END, - (int)p, (int)uap->aiocbp, error, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_read) | DBG_FUNC_END, + VM_KERNEL_ADDRPERM(p), uap->uaiocbp, error, 0, 0); return error; } /* aio_read */ @@ -755,12 +750,12 @@ aio_read(proc_t p, struct aio_read_args *uap, int *retval ) int aio_return(proc_t p, struct aio_return_args *uap, user_ssize_t *retval ) { - aio_workq_entry *entryp; - int error; - boolean_t proc_lock_held = FALSE; + aio_workq_entry *entryp; + int error; + boolean_t proc_lock_held = FALSE; - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_return)) | DBG_FUNC_START, - (int)p, (int)uap->aiocbp, 0, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_return) | DBG_FUNC_START, + VM_KERNEL_ADDRPERM(p), uap->uaiocbp, 0, 0, 0); /* See if there are any entries to check */ if (aio_get_all_queues_count() < 1) { @@ -798,8 +793,8 @@ aio_return(proc_t p, struct aio_return_args *uap, user_ssize_t *retval ) } - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_return_val)) | DBG_FUNC_NONE, - (int)p, (int)uap->aiocbp, *retval, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_return_val) | DBG_FUNC_NONE, + VM_KERNEL_ADDRPERM(p), uap->uaiocbp, *retval, 0, 0); goto ExitRoutine; } } @@ -809,8 +804,8 @@ aio_return(proc_t p, struct aio_return_args *uap, user_ssize_t *retval ) ASSERT_AIO_FROM_PROC(entryp, p); if (entryp->uaiocbp == uap->aiocbp) { error = EINPROGRESS; - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_return_activeq)) | DBG_FUNC_NONE, - (int)p, (int)uap->aiocbp, *retval, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_return_activeq) | DBG_FUNC_NONE, + VM_KERNEL_ADDRPERM(p), uap->uaiocbp, *retval, 0, 0); goto ExitRoutine; } } @@ -821,8 +816,8 @@ ExitRoutine: if (proc_lock_held) { aio_proc_unlock(p); } - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_return)) | DBG_FUNC_END, - (int)p, (int)uap->aiocbp, error, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_return) | DBG_FUNC_END, + VM_KERNEL_ADDRPERM(p), uap->uaiocbp, error, 0, 0); return error; } /* aio_return */ @@ -838,15 +833,13 @@ ExitRoutine: __private_extern__ void _aio_exec(proc_t p ) { - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_exec)) | DBG_FUNC_START, - (int)p, 0, 0, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_exec) | DBG_FUNC_START, + VM_KERNEL_ADDRPERM(p), 0, 0, 0, 0); _aio_exit( p ); - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_exec)) | DBG_FUNC_END, - (int)p, 0, 0, 0, 0 ); - - return; + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_exec) | DBG_FUNC_END, + VM_KERNEL_ADDRPERM(p), 0, 0, 0, 0); } /* _aio_exec */ @@ -859,8 +852,8 @@ _aio_exec(proc_t p ) __private_extern__ void _aio_exit(proc_t p ) { - int error; - aio_workq_entry *entryp; + int error; + aio_workq_entry *entryp; /* quick check to see if there are any async IO requests queued up */ @@ -868,8 +861,8 @@ _aio_exit(proc_t p ) return; } - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_exit)) | DBG_FUNC_START, - (int)p, 0, 0, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_exit) | DBG_FUNC_START, + VM_KERNEL_ADDRPERM(p), 0, 0, 0, 0); aio_proc_lock(p); @@ -889,8 +882,8 @@ _aio_exit(proc_t p ) * active aio requests. */ - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_exit_sleep)) | DBG_FUNC_NONE, - (int)p, 0, 0, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_exit_sleep) | DBG_FUNC_NONE, + VM_KERNEL_ADDRPERM(p), 0, 0, 0, 0); while (p->p_aio_active_count != 0) { msleep(&p->AIO_CLEANUP_SLEEP_CHAN, aio_proc_mutex(p), PRIBIO, "aio_exit", 0 ); @@ -933,9 +926,8 @@ _aio_exit(proc_t p ) aio_proc_unlock(p); - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_exit)) | DBG_FUNC_END, - (int)p, 0, 0, 0, 0 ); - return; + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_exit) | DBG_FUNC_END, + VM_KERNEL_ADDRPERM(p), 0, 0, 0, 0); } /* _aio_exit */ @@ -1001,8 +993,9 @@ do_aio_cancel_locked(proc_t p, int fd, user_addr_t aiocbp, /* Now it's officially cancelled. Do the completion */ result = AIO_CANCELED; - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_cancel_async_workq)) | DBG_FUNC_NONE, - (int)entryp->procp, (int)entryp->uaiocbp, fd, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_cancel_async_workq) | DBG_FUNC_NONE, + VM_KERNEL_ADDRPERM(p), VM_KERNEL_ADDRPERM(entryp->uaiocbp), + fd, 0, 0); do_aio_completion(entryp); /* This will free if the aio_return() has already happened ... */ @@ -1032,8 +1025,9 @@ do_aio_cancel_locked(proc_t p, int fd, user_addr_t aiocbp, */ result = AIO_NOTCANCELED; - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_cancel_activeq)) | DBG_FUNC_NONE, - (int)entryp->procp, (int)entryp->uaiocbp, fd, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_cancel_activeq) | DBG_FUNC_NONE, + VM_KERNEL_ADDRPERM(p), VM_KERNEL_ADDRPERM(entryp->uaiocbp), + fd, 0, 0); /* Mark for waiting and such; will not take a ref if "cancelled" arg is FALSE */ aio_entry_update_for_cancel(entryp, FALSE, wait_for_completion, disable_notification); @@ -1057,8 +1051,9 @@ do_aio_cancel_locked(proc_t p, int fd, user_addr_t aiocbp, ASSERT_AIO_FROM_PROC(entryp, p); if (should_cancel(entryp, aiocbp, fd)) { result = AIO_ALLDONE; - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_cancel_doneq)) | DBG_FUNC_NONE, - (int)entryp->procp, (int)entryp->uaiocbp, fd, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_cancel_doneq) | DBG_FUNC_NONE, + VM_KERNEL_ADDRPERM(p), VM_KERNEL_ADDRPERM(entryp->uaiocbp), + fd, 0, 0); if (aiocbp != USER_ADDR_NULL) { return result; @@ -1092,15 +1087,15 @@ aio_suspend(proc_t p, struct aio_suspend_args *uap, int *retval ) int aio_suspend_nocancel(proc_t p, struct aio_suspend_nocancel_args *uap, int *retval ) { - int error; - int i, count; - uint64_t abstime; - struct user_timespec ts; - aio_workq_entry *entryp; - user_addr_t *aiocbpp; + int error; + int i, count; + uint64_t abstime; + struct user_timespec ts; + aio_workq_entry *entryp; + user_addr_t *aiocbpp; - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_suspend)) | DBG_FUNC_START, - (int)p, uap->nent, 0, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_suspend) | DBG_FUNC_START, + VM_KERNEL_ADDRPERM(p), uap->nent, 0, 0, 0); *retval = -1; abstime = 0; @@ -1178,8 +1173,8 @@ check_for_our_aiocbp: } } /* for ( ; i < uap->nent; ) */ - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_suspend_sleep)) | DBG_FUNC_NONE, - (int)p, uap->nent, 0, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_suspend_sleep) | DBG_FUNC_NONE, + VM_KERNEL_ADDRPERM(p), uap->nent, 0, 0, 0); /* * wait for an async IO to complete or a signal fires or timeout expires. @@ -1212,8 +1207,8 @@ ExitThisRoutine: FREE( aiocbpp, M_TEMP ); } - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_suspend)) | DBG_FUNC_END, - (int)p, uap->nent, error, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_suspend) | DBG_FUNC_END, + VM_KERNEL_ADDRPERM(p), uap->nent, error, 0, 0); return error; } /* aio_suspend */ @@ -1225,22 +1220,17 @@ ExitThisRoutine: */ int -aio_write(proc_t p, struct aio_write_args *uap, int *retval ) +aio_write(proc_t p, struct aio_write_args *uap, int *retval __unused) { - int error; - - *retval = 0; + int error; - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_write)) | DBG_FUNC_START, - (int)p, (int)uap->aiocbp, 0, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_write) | DBG_FUNC_START, + VM_KERNEL_ADDRPERM(p), uap->uaiocbp, 0, 0, 0); error = aio_queue_async_request( p, uap->aiocbp, AIO_WRITE ); - if (error != 0) { - *retval = -1; - } - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_write)) | DBG_FUNC_END, - (int)p, (int)uap->aiocbp, error, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_write) | DBG_FUNC_END, + VM_KERNEL_ADDRPERM(p), uap->uaiocbp, error, 0, 0); return error; } /* aio_write */ @@ -1424,6 +1414,13 @@ aio_enqueue_work( proc_t procp, aio_workq_entry *entryp, int proc_locked) THREAD_AWAKENED, WAITQ_ALL_PRIORITIES); aio_workq_unlock(queue); + + KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_AIO, AIO_work_queued) | DBG_FUNC_START, + VM_KERNEL_ADDRPERM(procp), VM_KERNEL_ADDRPERM(entryp->uaiocbp), + entryp->flags, entryp->aiocb.aio_fildes, 0 ); + KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_AIO, AIO_work_queued) | DBG_FUNC_END, + entryp->aiocb.aio_offset, 0, entryp->aiocb.aio_nbytes, 0, 0); + if (proc_locked == 0) { aio_proc_unlock(procp); } @@ -1485,20 +1482,18 @@ aio_enqueue_work( proc_t procp, aio_workq_entry *entryp, int proc_locked) int lio_listio(proc_t p, struct lio_listio_args *uap, int *retval ) { - int i; - int call_result; - int result; - int old_count; - aio_workq_entry **entryp_listp; - user_addr_t *aiocbpp; - struct user_sigevent aiosigev; + int i; + int call_result; + int result; + int old_count; + aio_workq_entry **entryp_listp; + user_addr_t *aiocbpp; + struct user_sigevent aiosigev; aio_lio_context *lio_context; - boolean_t free_context = FALSE; - uint32_t *paio_offset; - uint32_t *paio_nbytes; + boolean_t free_context = FALSE; - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_listio)) | DBG_FUNC_START, - (int)p, uap->nent, uap->mode, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_listio) | DBG_FUNC_START, + VM_KERNEL_ADDRPERM(p), uap->nent, uap->mode, 0, 0); entryp_listp = NULL; lio_context = NULL; @@ -1525,6 +1520,23 @@ lio_listio(proc_t p, struct lio_listio_args *uap, int *retval ) goto ExitRoutine; } + /* + * lio_context ownership rules go as follow: + * + * - when the mode is LIO_WAIT, and that the AIOs aren't cancelled, + * this function will perform the deallocation. + * + * - when the mode is LIO_WAIT but AIOs are cancelled, then io_waiter is + * forced to '0' (pretending the mode is LIO_NOWAIT) and the ownership is + * handed over to the async path. + * + * - when the mode is LIO_NOWAIT, then the aio thread is responsible for + * cleaning up the context. + * + * However, there is a last case, which is when none of the commands pass + * preflight and no submission is done, in this case this function is + * responsible for cleanup. + */ MALLOC( lio_context, aio_lio_context*, sizeof(aio_lio_context), M_TEMP, M_WAITOK ); if (lio_context == NULL) { call_result = EAGAIN; @@ -1575,7 +1587,10 @@ lio_listio(proc_t p, struct lio_listio_args *uap, int *retval ) /* NULL elements are legal so check for 'em */ if (my_aiocbp == USER_ADDR_NULL) { aio_proc_lock_spin(p); - lio_context->io_issued--; + if (--lio_context->io_issued == 0) { + /* no submission made, needs cleanup */ + free_context = TRUE; + } aio_proc_unlock(p); continue; } @@ -1598,7 +1613,10 @@ lio_listio(proc_t p, struct lio_listio_args *uap, int *retval ) entryp = *(entryp_listp + i); if (entryp == NULL) { aio_proc_lock_spin(p); - lio_context->io_issued--; + if (--lio_context->io_issued == 0) { + /* no submission made, needs cleanup */ + free_context = TRUE; + } aio_proc_unlock(p); continue; } @@ -1618,7 +1636,10 @@ lio_listio(proc_t p, struct lio_listio_args *uap, int *retval ) if (old_count >= aio_max_requests || aio_get_process_count( entryp->procp ) >= aio_max_requests_per_process || is_already_queued( entryp->procp, entryp->uaiocbp ) == TRUE) { - lio_context->io_issued--; + if (--lio_context->io_issued == 0) { + /* no submission made, needs cleanup */ + free_context = TRUE; + } aio_proc_unlock(p); aio_decrement_total_count(); @@ -1634,46 +1655,37 @@ lio_listio(proc_t p, struct lio_listio_args *uap, int *retval ) lck_mtx_convert_spin(aio_proc_mutex(p)); aio_enqueue_work(p, entryp, 1); aio_proc_unlock(p); + } - KERNEL_DEBUG_CONSTANT((BSDDBG_CODE(DBG_BSD_AIO, AIO_work_queued)) | DBG_FUNC_START, - (int)p, (int)entryp->uaiocbp, entryp->flags, entryp->aiocb.aio_fildes, 0 ); - paio_offset = (uint32_t*) &entryp->aiocb.aio_offset; - paio_nbytes = (uint32_t*) &entryp->aiocb.aio_nbytes; - KERNEL_DEBUG_CONSTANT((BSDDBG_CODE(DBG_BSD_AIO, AIO_work_queued)) | DBG_FUNC_END, - paio_offset[0], (sizeof(entryp->aiocb.aio_offset) == sizeof(uint64_t) ? paio_offset[1] : 0), - paio_nbytes[0], (sizeof(entryp->aiocb.aio_nbytes) == sizeof(uint64_t) ? paio_nbytes[1] : 0), - 0 ); + if (free_context) { + /* no submission was made, just exit */ + goto ExitRoutine; } - aio_proc_lock_spin(p); - switch (uap->mode) { - case LIO_WAIT: + if (uap->mode == LIO_WAIT) { + aio_proc_lock_spin(p); + while (lio_context->io_completed < lio_context->io_issued) { result = msleep(lio_context, aio_proc_mutex(p), PCATCH | PRIBIO | PSPIN, "lio_listio", 0); /* If we were interrupted, fail out (even if all finished) */ if (result != 0) { call_result = EINTR; - lio_context->io_waiter = 0; break; } } - /* If all IOs have finished must free it */ if (lio_context->io_completed == lio_context->io_issued) { + /* If all IOs have finished must free it */ free_context = TRUE; + } else { + /* handoff to the async codepath for clean up */ + assert(call_result == EINTR); + lio_context->io_waiter = 0; } - break; - - case LIO_NOWAIT: - /* If no IOs were issued must free it (rdar://problem/45717887) */ - if (lio_context->io_issued == 0) { - free_context = TRUE; - } - break; + aio_proc_unlock(p); } - aio_proc_unlock(p); /* call_result == -1 means we had no trouble queueing up requests */ if (call_result == -1) { @@ -1692,8 +1704,8 @@ ExitRoutine: free_lio_context(lio_context); } - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_listio)) | DBG_FUNC_END, - (int)p, call_result, 0, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_listio) | DBG_FUNC_END, + VM_KERNEL_ADDRPERM(p), call_result, 0, 0, 0); return call_result; } /* lio_listio */ @@ -1708,11 +1720,11 @@ __attribute__((noreturn)) static void aio_work_thread(void) { - aio_workq_entry *entryp; - int error; - vm_map_t currentmap; - vm_map_t oldmap = VM_MAP_NULL; - task_t oldaiotask = TASK_NULL; + aio_workq_entry *entryp; + int error; + vm_map_t currentmap; + vm_map_t oldmap = VM_MAP_NULL; + task_t oldaiotask = TASK_NULL; struct uthread *uthreadp = NULL; for (;;) { @@ -1722,8 +1734,9 @@ aio_work_thread(void) */ entryp = aio_get_some_work(); - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_worker_thread)) | DBG_FUNC_START, - (int)entryp->procp, (int)entryp->uaiocbp, entryp->flags, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_worker_thread) | DBG_FUNC_START, + VM_KERNEL_ADDRPERM(p), VM_KERNEL_ADDRPERM(entryp->uaiocbp), + entryp->flags, 0, 0); /* * Assume the target's address space identity for the duration @@ -1756,9 +1769,9 @@ aio_work_thread(void) uthreadp->uu_aio_task = oldaiotask; } - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_worker_thread)) | DBG_FUNC_END, - (int)entryp->procp, (int)entryp->uaiocbp, entryp->errorval, - entryp->returnval, 0 ); + KERNEL_DEBUG(SDDBG_CODE(DBG_BSD_AIO, AIO_worker_thread) | DBG_FUNC_END, + VM_KERNEL_ADDRPERM(p), VM_KERNEL_ADDRPERM(entryp->uaiocbp), + entryp->errorval, entryp->returnval, 0); /* XXX COUNTS */ @@ -1803,8 +1816,8 @@ aio_work_thread(void) static aio_workq_entry * aio_get_some_work( void ) { - aio_workq_entry *entryp = NULL; - aio_workq_t queue = NULL; + aio_workq_entry *entryp = NULL; + aio_workq_t queue = NULL; /* Just one queue for the moment. In the future there will be many. */ queue = &aio_anchor.aio_async_workqs[0]; @@ -1850,8 +1863,9 @@ aio_get_some_work( void ) aio_proc_lock_spin(entryp->procp); if (aio_delay_fsync_request( entryp )) { /* It needs to be delayed. Put it back on the end of the work queue */ - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_fsync_delay)) | DBG_FUNC_NONE, - (int)entryp->procp, (int)entryp->uaiocbp, 0, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_fsync_delay) | DBG_FUNC_NONE, + VM_KERNEL_ADDRPERM(p), VM_KERNEL_ADDRPERM(entryp->uaiocbp), + 0, 0, 0); aio_proc_unlock(entryp->procp); @@ -1888,6 +1902,14 @@ nowork: static boolean_t aio_delay_fsync_request( aio_workq_entry *entryp ) { + if (proc_in_teardown(entryp->procp)) { + /* + * we can't delay FSYNCS when in teardown as it will confuse _aio_exit, + * if it was dequeued, then we must now commit to it + */ + return FALSE; + } + if (entryp == TAILQ_FIRST(&entryp->procp->p_aio_activeq)) { return FALSE; } @@ -1979,8 +2001,6 @@ aio_queue_async_request(proc_t procp, user_addr_t aiocbp, int kindOfIO ) aio_workq_entry *entryp; int result; int old_count; - uint32_t *paio_offset; - uint32_t *paio_nbytes; old_count = aio_increment_total_count(); if (old_count >= aio_max_requests) { @@ -2014,16 +2034,6 @@ aio_queue_async_request(proc_t procp, user_addr_t aiocbp, int kindOfIO ) aio_enqueue_work(procp, entryp, 1); aio_proc_unlock(procp); - - paio_offset = (uint32_t*) &entryp->aiocb.aio_offset; - paio_nbytes = (uint32_t*) &entryp->aiocb.aio_nbytes; - KERNEL_DEBUG_CONSTANT((BSDDBG_CODE(DBG_BSD_AIO, AIO_work_queued)) | DBG_FUNC_START, - (int)procp, (int)aiocbp, entryp->flags, entryp->aiocb.aio_fildes, 0 ); - KERNEL_DEBUG_CONSTANT((BSDDBG_CODE(DBG_BSD_AIO, AIO_work_queued)) | DBG_FUNC_END, - paio_offset[0], (sizeof(entryp->aiocb.aio_offset) == sizeof(uint64_t) ? paio_offset[1] : 0), - paio_nbytes[0], (sizeof(entryp->aiocb.aio_nbytes) == sizeof(uint64_t) ? paio_nbytes[1] : 0), - 0 ); - return 0; error_exit: @@ -2143,9 +2153,9 @@ aio_free_request(aio_workq_entry *entryp) static int aio_validate( aio_workq_entry *entryp ) { - struct fileproc *fp; - int flag; - int result; + struct fileproc *fp; + int flag; + int result; result = 0; @@ -2207,13 +2217,13 @@ aio_validate( aio_workq_entry *entryp ) } /* aio_validate */ static int -aio_increment_total_count() +aio_increment_total_count(void) { return OSIncrementAtomic(&aio_anchor.aio_total_count); } static int -aio_decrement_total_count() +aio_decrement_total_count(void) { int old = OSDecrementAtomic(&aio_anchor.aio_total_count); if (old <= 0) { @@ -2224,7 +2234,7 @@ aio_decrement_total_count() } static int -aio_get_process_count(proc_t procp ) +aio_get_process_count(proc_t procp) { return procp->p_aio_total_count; } /* aio_get_process_count */ @@ -2242,9 +2252,9 @@ aio_get_all_queues_count( void ) static void do_aio_completion( aio_workq_entry *entryp ) { - boolean_t lastLioCompleted = FALSE; + boolean_t lastLioCompleted = FALSE; aio_lio_context *lio_context = NULL; - int waiter = 0; + int waiter = 0; lio_context = (aio_lio_context *)entryp->group_tag; @@ -2284,9 +2294,9 @@ do_aio_completion( aio_workq_entry *entryp ) } if (performSignal) { - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_completion_sig)) | DBG_FUNC_NONE, - (int)entryp->procp, (int)entryp->uaiocbp, - entryp->aiocb.aio_sigevent.sigev_signo, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_completion_sig) | DBG_FUNC_NONE, + VM_KERNEL_ADDRPERM(p), VM_KERNEL_ADDRPERM(entryp->uaiocbp), + entryp->aiocb.aio_sigevent.sigev_signo, 0, 0); psignal( entryp->procp, entryp->aiocb.aio_sigevent.sigev_signo ); } @@ -2312,8 +2322,9 @@ do_aio_completion( aio_workq_entry *entryp ) if ((entryp->flags & AIO_EXIT_WAIT) != 0) { int active_requests; - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_completion_cleanup_wait)) | DBG_FUNC_NONE, - (int)entryp->procp, (int)entryp->uaiocbp, 0, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_completion_cleanup_wait) | DBG_FUNC_NONE, + VM_KERNEL_ADDRPERM(p), VM_KERNEL_ADDRPERM(entryp->uaiocbp), + 0, 0, 0); aio_proc_lock_spin(entryp->procp); active_requests = aio_active_requests_for_process( entryp->procp ); @@ -2325,8 +2336,9 @@ do_aio_completion( aio_workq_entry *entryp ) wakeup_one((caddr_t)&entryp->procp->AIO_CLEANUP_SLEEP_CHAN); aio_proc_unlock(entryp->procp); - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_completion_cleanup_wake)) | DBG_FUNC_NONE, - (int)entryp->procp, (int)entryp->uaiocbp, 0, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_completion_cleanup_wake) | DBG_FUNC_NONE, + VM_KERNEL_ADDRPERM(p), VM_KERNEL_ADDRPERM(entryp->uaiocbp), + 0, 0, 0); } else { aio_proc_unlock(entryp->procp); } @@ -2335,8 +2347,9 @@ do_aio_completion( aio_workq_entry *entryp ) if ((entryp->flags & AIO_CLOSE_WAIT) != 0) { int active_requests; - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_completion_cleanup_wait)) | DBG_FUNC_NONE, - (int)entryp->procp, (int)entryp->uaiocbp, 0, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_completion_cleanup_wait) | DBG_FUNC_NONE, + VM_KERNEL_ADDRPERM(p), VM_KERNEL_ADDRPERM(entryp->uaiocbp), + 0, 0, 0); aio_proc_lock_spin(entryp->procp); active_requests = aio_proc_active_requests_for_file( entryp->procp, entryp->aiocb.aio_fildes); @@ -2345,8 +2358,9 @@ do_aio_completion( aio_workq_entry *entryp ) wakeup(&entryp->procp->AIO_CLEANUP_SLEEP_CHAN); aio_proc_unlock(entryp->procp); - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_completion_cleanup_wake)) | DBG_FUNC_NONE, - (int)entryp->procp, (int)entryp->uaiocbp, 0, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_completion_cleanup_wake) | DBG_FUNC_NONE, + VM_KERNEL_ADDRPERM(p), VM_KERNEL_ADDRPERM(entryp->uaiocbp), + 0, 0, 0); } else { aio_proc_unlock(entryp->procp); } @@ -2359,8 +2373,8 @@ do_aio_completion( aio_workq_entry *entryp ) * can do our wakeup without holding the lock. */ wakeup((caddr_t) &entryp->procp->AIO_SUSPEND_SLEEP_CHAN ); - KERNEL_DEBUG((BSDDBG_CODE(DBG_BSD_AIO, AIO_completion_suspend_wake)) | DBG_FUNC_NONE, - (int)entryp->procp, (int)entryp->uaiocbp, 0, 0, 0 ); + KERNEL_DEBUG(BSDDBG_CODE(DBG_BSD_AIO, AIO_completion_suspend_wake) | DBG_FUNC_NONE, + VM_KERNEL_ADDRPERM(p), VM_KERNEL_ADDRPERM(entryp->uaiocbp), 0, 0, 0); /* * free the LIO context if the last lio completed and no thread is @@ -2378,8 +2392,8 @@ do_aio_completion( aio_workq_entry *entryp ) static int do_aio_read( aio_workq_entry *entryp ) { - struct fileproc *fp; - int error; + struct fileproc *fp; + int error; struct vfs_context context; if ((error = fp_lookup(entryp->procp, entryp->aiocb.aio_fildes, &fp, 0))) { @@ -2410,9 +2424,9 @@ do_aio_read( aio_workq_entry *entryp ) static int do_aio_write( aio_workq_entry *entryp ) { - struct fileproc *fp; - int error, flags; - struct vfs_context context; + struct fileproc *fp; + int error, flags; + struct vfs_context context; if ((error = fp_lookup(entryp->procp, entryp->aiocb.aio_fildes, &fp, 0))) { return error; @@ -2454,7 +2468,7 @@ do_aio_write( aio_workq_entry *entryp ) * requests for the given process. */ static int -aio_active_requests_for_process(proc_t procp ) +aio_active_requests_for_process(proc_t procp) { return procp->p_aio_active_count; } /* aio_active_requests_for_process */ @@ -2542,11 +2556,10 @@ do_aio_fsync( aio_workq_entry *entryp ) * Called with proc aio lock held (can be held spin) */ static boolean_t -is_already_queued(proc_t procp, - user_addr_t aiocbp ) +is_already_queued(proc_t procp, user_addr_t aiocbp) { - aio_workq_entry *entryp; - boolean_t result; + aio_workq_entry *entryp; + boolean_t result; result = FALSE; @@ -2588,7 +2601,7 @@ free_lio_context(aio_lio_context* context) __private_extern__ void aio_init( void ) { - int i; + int i; aio_lock_grp_attr = lck_grp_attr_alloc_init(); aio_proc_lock_grp = lck_grp_alloc_init("aio_proc", aio_lock_grp_attr);; @@ -2622,7 +2635,7 @@ aio_init( void ) __private_extern__ void _aio_create_worker_threads( int num ) { - int i; + int i; /* create some worker threads to handle the async IO requests */ for (i = 0; i < num; i++) { diff --git a/bsd/kern/kern_exec.c b/bsd/kern/kern_exec.c index afa0cb820..a5704a7f2 100644 --- a/bsd/kern/kern_exec.c +++ b/bsd/kern/kern_exec.c @@ -3622,6 +3622,10 @@ bad: proc_legacy_footprint_entitled(p, new_task, __FUNCTION__); proc_ios13extended_footprint_entitled(p, new_task, __FUNCTION__); #endif /* __arm64__ */ + +#if __has_feature(ptrauth_calls) + task_set_pac_exception_fatal_flag(new_task); +#endif /* __has_feature(ptrauth_calls) */ } /* Inherit task role from old task to new task for exec */ @@ -4311,6 +4315,10 @@ __mac_execve(proc_t p, struct __mac_execve_args *uap, int32_t *retval) task_set_main_thread_qos(new_task, main_thread); +#if __has_feature(ptrauth_calls) + task_set_pac_exception_fatal_flag(new_task); +#endif /* __has_feature(ptrauth_calls) */ + #if CONFIG_ARCADE /* * Check to see if we need to trigger an arcade upcall AST now diff --git a/bsd/kern/kern_exit.c b/bsd/kern/kern_exit.c index 825508bf3..7349f618f 100644 --- a/bsd/kern/kern_exit.c +++ b/bsd/kern/kern_exit.c @@ -192,6 +192,12 @@ kern_return_t task_violated_guard(mach_exception_code_t, mach_exception_subcode_ void delay(int); void gather_rusage_info(proc_t p, rusage_info_current *ru, int flavor); +#if __has_feature(ptrauth_calls) +int exit_with_pac_exception(proc_t p, exception_type_t exception, mach_exception_code_t code, + mach_exception_subcode_t subcode); +#endif /* __has_feature(ptrauth_calls) */ + + /* * NOTE: Source and target may *NOT* overlap! * XXX Should share code with bsd/dev/ppc/unix_signal.c @@ -2907,3 +2913,26 @@ kdp_wait4_find_process(thread_t thread, __unused event64_t wait_event, thread_wa // See man wait4 for other valid wait4 arguments. waitinfo->owner = args->pid; } + +#if __has_feature(ptrauth_calls) +int +exit_with_pac_exception(proc_t p, exception_type_t exception, mach_exception_code_t code, + mach_exception_subcode_t subcode) +{ + thread_t self = current_thread(); + struct uthread *ut = get_bsdthread_info(self); + + os_reason_t exception_reason = os_reason_create(OS_REASON_PAC_EXCEPTION, (uint64_t)code); + if (exception_reason == OS_REASON_NULL) { + printf("exit_with_pac_exception: failed to allocate exit reason\n"); + } else { + exception_reason->osr_flags |= OS_REASON_FLAG_GENERATE_CRASH_REPORT; + ut->uu_exception = exception; + ut->uu_code = code; + ut->uu_subcode = subcode; + } + + return exit_with_reason(p, W_EXITCODE(0, SIGKILL), (int *)NULL, TRUE, FALSE, + 0, exception_reason); +} +#endif /* __has_feature(ptrauth_calls) */ diff --git a/bsd/kern/kern_proc.c b/bsd/kern/kern_proc.c index 1a11358be..01f548e79 100644 --- a/bsd/kern/kern_proc.c +++ b/bsd/kern/kern_proc.c @@ -3863,6 +3863,19 @@ proc_set_syscall_filter_mask(proc_t p, int which, unsigned char *maskptr, size_t return KERN_SUCCESS; } +bool +proc_is_traced(proc_t p) +{ + bool ret = FALSE; + assert(p != PROC_NULL); + proc_lock(p); + if (p->p_lflag & P_LTRACED) { + ret = TRUE; + } + proc_unlock(p); + return ret; +} + #ifdef CONFIG_32BIT_TELEMETRY void proc_log_32bit_telemetry(proc_t p) diff --git a/bsd/kern/kern_sysctl.c b/bsd/kern/kern_sysctl.c index edf8d8d22..a6702441c 100644 --- a/bsd/kern/kern_sysctl.c +++ b/bsd/kern/kern_sysctl.c @@ -1465,7 +1465,7 @@ sysctl_procargsx(int *name, u_int namelen, user_addr_t where, if (vm_map_copy_overwrite(kernel_map, (vm_map_address_t)copy_start, - tmp, FALSE) != KERN_SUCCESS) { + tmp, (vm_map_size_t) arg_size, FALSE) != KERN_SUCCESS) { kmem_free(kernel_map, copy_start, round_page(arg_size)); vm_map_copy_discard(tmp); diff --git a/bsd/kern/mach_loader.c b/bsd/kern/mach_loader.c index d51e05c70..0d91fdd48 100644 --- a/bsd/kern/mach_loader.c +++ b/bsd/kern/mach_loader.c @@ -353,6 +353,7 @@ load_machfile( struct vnode *vp = imgp->ip_vp; off_t file_offset = imgp->ip_arch_offset; off_t macho_size = imgp->ip_arch_size; + off_t total_size = 0; off_t file_size = imgp->ip_vattr->va_data_size; pmap_t pmap = 0; /* protected by create_map */ vm_map_t map; @@ -368,7 +369,8 @@ load_machfile( kern_return_t kret; unsigned int pmap_flags = 0; - if (macho_size > file_size) { + if (os_add_overflow(file_offset, macho_size, &total_size) || + total_size > file_size) { return LOAD_BADMACHO; } @@ -2579,6 +2581,10 @@ load_threadstack( int flavor; uint32_t stack_size; + if (total_size == 0) { + return LOAD_BADMACHO; + } + while (total_size > 0) { flavor = *ts++; size = *ts++; @@ -2896,6 +2902,7 @@ load_code_signature( &blob)) { if (addr) { ubc_cs_blob_deallocate(addr, blob_size); + addr = 0; } ret = LOAD_FAILURE; goto out; diff --git a/bsd/kern/uipc_usrreq.c b/bsd/kern/uipc_usrreq.c index 2c4434dc2..b08bbbee7 100644 --- a/bsd/kern/uipc_usrreq.c +++ b/bsd/kern/uipc_usrreq.c @@ -468,6 +468,7 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, } error = unp_connect(so, nam, p); if (error) { + so->so_state &= ~SS_ISCONNECTING; break; } } else { @@ -529,6 +530,7 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, if (nam) { error = unp_connect(so, nam, p); if (error) { + so->so_state &= ~SS_ISCONNECTING; break; /* XXX */ } } else { @@ -1180,6 +1182,9 @@ unp_connect(struct socket *so, struct sockaddr *nam, __unused proc_t p) if (len >= SOCK_MAXADDRLEN) { return EINVAL; } + + soisconnecting(so); + bcopy(soun->sun_path, buf, len); buf[len] = 0; diff --git a/bsd/net/content_filter.c b/bsd/net/content_filter.c index 11b248d0c..68422f880 100644 --- a/bsd/net/content_filter.c +++ b/bsd/net/content_filter.c @@ -2891,10 +2891,10 @@ cfil_sock_attach(struct socket *so, struct sockaddr *local, struct sockaddr *rem * Save passed addresses for attach event msg (in case resend * is needed. */ - if (remote != NULL) { + if (remote != NULL && (remote->sa_len <= sizeof(union sockaddr_in_4_6))) { memcpy(&so->so_cfil->cfi_so_attach_faddr, remote, remote->sa_len); } - if (local != NULL) { + if (local != NULL && (local->sa_len <= sizeof(union sockaddr_in_4_6))) { memcpy(&so->so_cfil->cfi_so_attach_laddr, local, local->sa_len); } diff --git a/bsd/net/if.c b/bsd/net/if.c index dcb728807..308c04b54 100644 --- a/bsd/net/if.c +++ b/bsd/net/if.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2019 Apple Inc. All rights reserved. + * Copyright (c) 2000-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -890,7 +890,7 @@ ifa_foraddr6_scoped(struct in6_addr *addr6, unsigned int scope) struct in6_ifaddr *ia = NULL; lck_rw_lock_shared(&in6_ifaddr_rwlock); - for (ia = in6_ifaddrs; ia; ia = ia->ia_next) { + TAILQ_FOREACH(ia, IN6ADDR_HASH(addr6), ia6_hash) { IFA_LOCK(&ia->ia_ifa); if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, addr6) && (scope == IFSCOPE_NONE || ia->ia_ifp->if_index == scope)) { diff --git a/bsd/net/if_gif.c b/bsd/net/if_gif.c index 0ada425b6..9f9e6c574 100644 --- a/bsd/net/if_gif.c +++ b/bsd/net/if_gif.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2018 Apple Inc. All rights reserved. + * Copyright (c) 2000-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -618,6 +618,12 @@ gif_output( /* XXX should we check if our outer source is legal? */ + /* + * Save the length as m may be free by the output functions + * as they call m_pullup + */ + u_int32_t bytes_out = m->m_pkthdr.len; + /* dispatch to output logic based on outer AF */ switch (sc->gif_psrc->sa_family) { #if INET @@ -641,7 +647,7 @@ end: /* the mbuf was freed either by in_gif_output or in here */ ifnet_stat_increment_out(ifp, 0, 0, 1); } else { - ifnet_stat_increment_out(ifp, 1, m->m_pkthdr.len, 0); + ifnet_stat_increment_out(ifp, 1, bytes_out, 0); } if (error == 0) { error = EJUSTRETURN; /* if no error, packet got sent already */ diff --git a/bsd/net/if_stf.c b/bsd/net/if_stf.c index 05e6087ab..5ceab5438 100644 --- a/bsd/net/if_stf.c +++ b/bsd/net/if_stf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2018 Apple Inc. All rights reserved. + * Copyright (c) 2000-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -571,6 +571,7 @@ stf_pre_output( IFA_REMREF(&ia6->ia_ifa); return ENOBUFS; } + *m0 = m; } ip6 = mtod(m, struct ip6_hdr *); tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; @@ -604,6 +605,8 @@ stf_pre_output( IFA_REMREF(&ia6->ia_ifa); return ENOBUFS; } + + *m0 = m; ip = mtod(m, struct ip *); bzero(ip, sizeof(*ip)); diff --git a/bsd/net/kpi_interface.c b/bsd/net/kpi_interface.c index 2d5c6454b..41fb91f69 100644 --- a/bsd/net/kpi_interface.c +++ b/bsd/net/kpi_interface.c @@ -641,6 +641,7 @@ ifnet_set_eflags(ifnet_t interface, u_int32_t new_flags, u_int32_t mask) */ if ((((new_flags & mask) & IFEF_ADV_REPORT) != 0) && ((interface->if_eflags & IFEF_SKYWALK_NATIVE) == 0)) { + ifnet_lock_done(interface); return EINVAL; } oeflags = interface->if_eflags; diff --git a/bsd/net/necp.c b/bsd/net/necp.c index c73dadf89..0c014f0be 100644 --- a/bsd/net/necp.c +++ b/bsd/net/necp.c @@ -227,6 +227,7 @@ u_int32_t necp_session_count = 0; #define NECP_KERNEL_CONDITION_LOCAL_EMPTY 0x1000000 #define NECP_KERNEL_CONDITION_REMOTE_EMPTY 0x2000000 #define NECP_KERNEL_CONDITION_PLATFORM_BINARY 0x4000000 +#define NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER 0x8000000 #define NECP_MAX_POLICY_RESULT_SIZE 512 #define NECP_MAX_ROUTE_RULES_ARRAY_SIZE 1024 @@ -378,7 +379,7 @@ static bool necp_policy_mark_all_for_deletion(struct necp_session *session); static bool necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy); static void necp_policy_apply_all(struct necp_session *session); -static necp_kernel_policy_id necp_kernel_socket_policy_add(necp_policy_order order, u_int32_t session_order, int session_pid, u_int32_t condition_mask, u_int32_t condition_negated_mask, necp_app_id cond_app_id, necp_app_id cond_real_app_id, char *cond_custom_entitlement, u_int32_t cond_account_id, char *domain, pid_t cond_pid, uid_t cond_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, u_int16_t cond_protocol, union necp_sockaddr_union *cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, struct necp_policy_condition_agent_type *cond_agent_type, u_int32_t cond_client_flags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter); +static necp_kernel_policy_id necp_kernel_socket_policy_add(necp_policy_order order, u_int32_t session_order, int session_pid, u_int32_t condition_mask, u_int32_t condition_negated_mask, necp_app_id cond_app_id, necp_app_id cond_real_app_id, char *cond_custom_entitlement, u_int32_t cond_account_id, char *domain, pid_t cond_pid, uid_t cond_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, u_int16_t cond_protocol, union necp_sockaddr_union *cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, struct necp_policy_condition_agent_type *cond_agent_type, u_int32_t cond_client_flags, char *cond_signing_identifier, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter); static bool necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id); static bool necp_kernel_socket_policies_reprocess(void); static bool necp_kernel_socket_policies_update_uuid_table(void); @@ -1934,7 +1935,8 @@ necp_policy_condition_is_valid(u_int8_t *buffer, u_int32_t length, u_int8_t poli } case NECP_POLICY_CONDITION_DOMAIN: case NECP_POLICY_CONDITION_ACCOUNT: - case NECP_POLICY_CONDITION_BOUND_INTERFACE: { + case NECP_POLICY_CONDITION_BOUND_INTERFACE: + case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER: { if (condition_length > 0) { validated = TRUE; } @@ -2682,6 +2684,11 @@ necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length) if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) { num_conditions++; } + if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) { + u_int32_t identifier_len = strlen(policy->cond_signing_identifier) + 1; + condition_tlv_length += identifier_len; + num_conditions++; + } } condition_tlv_length += num_conditions * (sizeof(u_int8_t) + sizeof(u_int32_t)); // These are for the condition TLVs. The space for "value" is already accounted for above. @@ -2829,6 +2836,10 @@ necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length) if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) { cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY, 0, "", cond_buf, condition_tlv_length); } + if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) { + cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_SIGNING_IDENTIFIER, strlen(policy->cond_signing_identifier) + 1, policy->cond_signing_identifier, + cond_buf, condition_tlv_length); + } } cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_CONDITION, cond_buf_cursor - cond_buf, cond_buf, tlv_buffer, total_allocated_bytes); @@ -3152,6 +3163,7 @@ necp_policy_apply(struct necp_session *session, struct necp_session_policy *poli u_int32_t cond_account_id = 0; char *cond_domain = NULL; char *cond_custom_entitlement = NULL; + char *cond_signing_identifier = NULL; pid_t cond_pid = 0; uid_t cond_uid = 0; necp_app_id cond_app_id = 0; @@ -3501,6 +3513,21 @@ necp_policy_apply(struct necp_session *session, struct necp_session_policy *poli socket_only_conditions = TRUE; break; } + case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER: { + if (condition_length > 0) { + if (cond_signing_identifier == NULL) { + cond_signing_identifier = necp_copy_string((char *)condition_value, condition_length); + if (cond_signing_identifier != NULL) { + master_condition_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER; + socket_only_conditions = TRUE; + if (condition_is_negative) { + master_condition_negated_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER; + } + } + } + } + break; + } default: { break; } @@ -3681,7 +3708,7 @@ necp_policy_apply(struct necp_session *session, struct necp_session_policy *poli } if (socket_layer_non_id_conditions) { - necp_kernel_policy_id policy_id = necp_kernel_socket_policy_add(policy->order, session->session_order, session->proc_pid, master_condition_mask, master_condition_negated_mask, cond_app_id, cond_real_app_id, cond_custom_entitlement, cond_account_id, cond_domain, cond_pid, cond_uid, cond_bound_interface, cond_traffic_class, cond_protocol, &cond_local_start, &cond_local_end, cond_local_prefix, &cond_remote_start, &cond_remote_end, cond_remote_prefix, &cond_agent_type, cond_client_flags, ultimate_result, ultimate_result_parameter); + necp_kernel_policy_id policy_id = necp_kernel_socket_policy_add(policy->order, session->session_order, session->proc_pid, master_condition_mask, master_condition_negated_mask, cond_app_id, cond_real_app_id, cond_custom_entitlement, cond_account_id, cond_domain, cond_pid, cond_uid, cond_bound_interface, cond_traffic_class, cond_protocol, &cond_local_start, &cond_local_end, cond_local_prefix, &cond_remote_start, &cond_remote_end, cond_remote_prefix, &cond_agent_type, cond_client_flags, cond_signing_identifier, ultimate_result, ultimate_result_parameter); if (policy_id == 0) { NECPLOG0(LOG_DEBUG, "Error applying socket kernel policy"); @@ -3850,10 +3877,10 @@ necp_kernel_policy_get_new_id(bool socket_level) return newid; } -#define NECP_KERNEL_VALID_SOCKET_CONDITIONS (NECP_KERNEL_CONDITION_APP_ID | NECP_KERNEL_CONDITION_REAL_APP_ID | NECP_KERNEL_CONDITION_DOMAIN | NECP_KERNEL_CONDITION_ACCOUNT_ID | NECP_KERNEL_CONDITION_PID | NECP_KERNEL_CONDITION_UID | NECP_KERNEL_CONDITION_ALL_INTERFACES | NECP_KERNEL_CONDITION_BOUND_INTERFACE | NECP_KERNEL_CONDITION_TRAFFIC_CLASS | NECP_KERNEL_CONDITION_PROTOCOL | NECP_KERNEL_CONDITION_LOCAL_START | NECP_KERNEL_CONDITION_LOCAL_END | NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_REMOTE_START | NECP_KERNEL_CONDITION_REMOTE_END | NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_ENTITLEMENT | NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT | NECP_KERNEL_CONDITION_AGENT_TYPE | NECP_KERNEL_CONDITION_HAS_CLIENT | NECP_KERNEL_CONDITION_LOCAL_NETWORKS | NECP_KERNEL_CONDITION_CLIENT_FLAGS | NECP_KERNEL_CONDITION_LOCAL_EMPTY | NECP_KERNEL_CONDITION_REMOTE_EMPTY | NECP_KERNEL_CONDITION_PLATFORM_BINARY) +#define NECP_KERNEL_VALID_SOCKET_CONDITIONS (NECP_KERNEL_CONDITION_APP_ID | NECP_KERNEL_CONDITION_REAL_APP_ID | NECP_KERNEL_CONDITION_DOMAIN | NECP_KERNEL_CONDITION_ACCOUNT_ID | NECP_KERNEL_CONDITION_PID | NECP_KERNEL_CONDITION_UID | NECP_KERNEL_CONDITION_ALL_INTERFACES | NECP_KERNEL_CONDITION_BOUND_INTERFACE | NECP_KERNEL_CONDITION_TRAFFIC_CLASS | NECP_KERNEL_CONDITION_PROTOCOL | NECP_KERNEL_CONDITION_LOCAL_START | NECP_KERNEL_CONDITION_LOCAL_END | NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_REMOTE_START | NECP_KERNEL_CONDITION_REMOTE_END | NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_ENTITLEMENT | NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT | NECP_KERNEL_CONDITION_AGENT_TYPE | NECP_KERNEL_CONDITION_HAS_CLIENT | NECP_KERNEL_CONDITION_LOCAL_NETWORKS | NECP_KERNEL_CONDITION_CLIENT_FLAGS | NECP_KERNEL_CONDITION_LOCAL_EMPTY | NECP_KERNEL_CONDITION_REMOTE_EMPTY | NECP_KERNEL_CONDITION_PLATFORM_BINARY | NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) static necp_kernel_policy_id -necp_kernel_socket_policy_add(necp_policy_order order, u_int32_t session_order, int session_pid, u_int32_t condition_mask, u_int32_t condition_negated_mask, necp_app_id cond_app_id, necp_app_id cond_real_app_id, char *cond_custom_entitlement, u_int32_t cond_account_id, char *cond_domain, pid_t cond_pid, uid_t cond_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, u_int16_t cond_protocol, union necp_sockaddr_union *cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, struct necp_policy_condition_agent_type *cond_agent_type, u_int32_t cond_client_flags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter) +necp_kernel_socket_policy_add(necp_policy_order order, u_int32_t session_order, int session_pid, u_int32_t condition_mask, u_int32_t condition_negated_mask, necp_app_id cond_app_id, necp_app_id cond_real_app_id, char *cond_custom_entitlement, u_int32_t cond_account_id, char *cond_domain, pid_t cond_pid, uid_t cond_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, u_int16_t cond_protocol, union necp_sockaddr_union *cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, struct necp_policy_condition_agent_type *cond_agent_type, u_int32_t cond_client_flags, char *cond_signing_identifier, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter) { struct necp_kernel_socket_policy *new_kernel_policy = NULL; struct necp_kernel_socket_policy *tmp_kernel_policy = NULL; @@ -3954,6 +3981,9 @@ necp_kernel_socket_policy_add(necp_policy_order order, u_int32_t session_order, if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) { new_kernel_policy->cond_client_flags = cond_client_flags; } + if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) { + new_kernel_policy->cond_signing_identifier = cond_signing_identifier; + } new_kernel_policy->result = result; memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter)); @@ -4011,6 +4041,11 @@ necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id) policy->cond_custom_entitlement = NULL; } + if (policy->cond_signing_identifier) { + FREE(policy->cond_signing_identifier, M_NECP); + policy->cond_signing_identifier = NULL; + } + FREE_ZONE(policy, sizeof(*policy), M_NECP_SOCKET_POLICY); return TRUE; } @@ -5940,7 +5975,7 @@ necp_get_parent_cred_result(proc_t proc, struct necp_socket_info *info) #define NECP_KERNEL_ADDRESS_TYPE_CONDITIONS (NECP_KERNEL_CONDITION_LOCAL_START | NECP_KERNEL_CONDITION_LOCAL_END | NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_REMOTE_START | NECP_KERNEL_CONDITION_REMOTE_END | NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_LOCAL_EMPTY | NECP_KERNEL_CONDITION_REMOTE_EMPTY | NECP_KERNEL_CONDITION_LOCAL_NETWORKS) static void -necp_application_fillout_info_locked(uuid_t application_uuid, uuid_t real_application_uuid, uuid_t responsible_application_uuid, char *account, char *domain, pid_t pid, uid_t uid, u_int16_t protocol, u_int32_t bound_interface_index, u_int32_t traffic_class, union necp_sockaddr_union *local_addr, union necp_sockaddr_union *remote_addr, u_int16_t local_port, u_int16_t remote_port, bool has_client, proc_t proc, u_int32_t drop_order, u_int32_t client_flags, struct necp_socket_info *info) +necp_application_fillout_info_locked(uuid_t application_uuid, uuid_t real_application_uuid, uuid_t responsible_application_uuid, char *account, char *domain, pid_t pid, uid_t uid, u_int16_t protocol, u_int32_t bound_interface_index, u_int32_t traffic_class, union necp_sockaddr_union *local_addr, union necp_sockaddr_union *remote_addr, u_int16_t local_port, u_int16_t remote_port, bool has_client, proc_t proc, proc_t responsible_proc, u_int32_t drop_order, u_int32_t client_flags, struct necp_socket_info *info) { memset(info, 0, sizeof(struct necp_socket_info)); @@ -5953,18 +5988,6 @@ necp_application_fillout_info_locked(uuid_t application_uuid, uuid_t real_applic info->drop_order = drop_order; info->client_flags = client_flags; - if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT && proc != NULL) { - info->cred_result = priv_check_cred(proc_ucred(proc), PRIV_NET_PRIVILEGED_NECP_MATCH, 0); - if (info->cred_result != 0) { - // Process does not have entitlement, check the parent process - necp_get_parent_cred_result(proc, info); - } - } - - if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY && proc != NULL) { - info->is_platform_binary = csproc_get_platform_binary(proc) ? true : false; - } - if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(application_uuid)) { struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(application_uuid); if (existing_mapping) { @@ -5992,6 +6015,22 @@ necp_application_fillout_info_locked(uuid_t application_uuid, uuid_t real_applic } } + if (info->used_responsible_pid) { + proc = responsible_proc; + } + + if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT && proc != NULL) { + info->cred_result = priv_check_cred(proc_ucred(proc), PRIV_NET_PRIVILEGED_NECP_MATCH, 0); + if (info->cred_result != 0) { + // Process does not have entitlement, check the parent process + necp_get_parent_cred_result(proc, info); + } + } + + if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY && proc != NULL) { + info->is_platform_binary = csproc_get_platform_binary(proc) ? true : false; + } + if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && account != NULL) { struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, account); if (existing_mapping) { @@ -6132,10 +6171,9 @@ necp_application_find_policy_match_internal(proc_t proc, bool has_checked_delegation_entitlement = FALSE; bool has_delegation_entitlement = FALSE; -#if defined(XNU_TARGET_OS_OSX) + proc_t responsible_proc = PROC_NULL; proc_t effective_proc = proc; bool release_eproc = false; -#endif /* defined(XNU_TARGET_OS_OSX) */ if (returned_result == NULL) { return EINVAL; @@ -6364,7 +6402,6 @@ necp_application_find_policy_match_internal(proc_t proc, return 0; } -#if defined(XNU_TARGET_OS_OSX) if (proc_pid(effective_proc) != pid) { proc_t found_proc = proc_find(pid); if (found_proc != PROC_NULL) { @@ -6372,16 +6409,13 @@ necp_application_find_policy_match_internal(proc_t proc, release_eproc = true; } } +#if defined(XNU_TARGET_OS_OSX) if (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid) { - proc_t responsible_proc = proc_find(effective_proc->p_responsible_pid); + responsible_proc = proc_find(effective_proc->p_responsible_pid); if (responsible_proc != PROC_NULL) { proc_getexecutableuuid(responsible_proc, responsible_application_uuid, sizeof(responsible_application_uuid)); - proc_rele(responsible_proc); } } - if (release_eproc && effective_proc != PROC_NULL) { - proc_rele(effective_proc); - } #endif /* defined(XNU_TARGET_OS_OSX) */ // Lock @@ -6389,8 +6423,8 @@ necp_application_find_policy_match_internal(proc_t proc, u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES]; size_t route_rule_id_array_count = 0; - necp_application_fillout_info_locked(application_uuid, real_application_uuid, responsible_application_uuid, account, domain, pid, uid, protocol, bound_interface_index, traffic_class, &local_addr, &remote_addr, local_port, remote_port, has_client, proc, drop_order, client_flags, &info); - matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_app_layer_map, &info, &filter_control_unit, route_rule_id_array, &route_rule_id_array_count, MAX_AGGREGATE_ROUTE_RULES, &service_action, &service, netagent_ids, netagent_use_flags, NECP_MAX_NETAGENTS, required_agent_types, num_required_agent_types, proc, NULL, NULL, &drop_dest_policy_result, &drop_all_bypass); + necp_application_fillout_info_locked(application_uuid, real_application_uuid, responsible_application_uuid, account, domain, pid, uid, protocol, bound_interface_index, traffic_class, &local_addr, &remote_addr, local_port, remote_port, has_client, effective_proc, responsible_proc, drop_order, client_flags, &info); + matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_app_layer_map, &info, &filter_control_unit, route_rule_id_array, &route_rule_id_array_count, MAX_AGGREGATE_ROUTE_RULES, &service_action, &service, netagent_ids, netagent_use_flags, NECP_MAX_NETAGENTS, required_agent_types, num_required_agent_types, info.used_responsible_pid ? responsible_proc : effective_proc, NULL, NULL, &drop_dest_policy_result, &drop_all_bypass); if (matched_policy) { returned_result->policy_id = matched_policy->id; returned_result->routing_result = matched_policy->result; @@ -6809,6 +6843,15 @@ necp_application_find_policy_match_internal(proc_t proc, // Unlock lck_rw_done(&necp_kernel_policy_lock); + if (release_eproc && effective_proc != PROC_NULL) { + proc_rele(effective_proc); + } +#if defined(XNU_TARGET_OS_OSX) + if (responsible_proc != PROC_NULL) { + proc_rele(responsible_proc); + } +#endif + return error; } @@ -6904,6 +6947,30 @@ necp_socket_check_policy(struct necp_kernel_socket_policy *kernel_policy, necp_a return FALSE; } } + + // Check signing identifier only after APP ID matched + if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER || + kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) { + u_int8_t matched = necp_boolean_state_false; + const char *signing_id = cs_identity_get(proc ? proc : current_proc()); + + if (signing_id != NULL) { + size_t signing_id_size = strlen(signing_id) + 1; + if (memcmp(signing_id, kernel_policy->cond_signing_identifier, signing_id_size) == 0) { + matched = necp_boolean_state_true; + } + } + + if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) { + if (matched == necp_boolean_state_true) { + return FALSE; + } + } else { + if (matched != necp_boolean_state_true) { + return FALSE; + } + } + } } if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) { @@ -7185,9 +7252,11 @@ necp_socket_calc_flowhash_locked(struct necp_socket_info *info) } static void -necp_socket_fillout_info_locked(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface, u_int32_t drop_order, struct necp_socket_info *info) +necp_socket_fillout_info_locked(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface, u_int32_t drop_order, proc_t *socket_proc, struct necp_socket_info *info) { struct socket *so = NULL; + proc_t sock_proc = NULL; + proc_t curr_proc = current_proc(); memset(info, 0, sizeof(struct necp_socket_info)); @@ -7278,8 +7347,20 @@ necp_socket_fillout_info_locked(struct inpcb *inp, struct sockaddr *override_loc } } + pid_t socket_pid = +#if defined(XNU_TARGET_OS_OSX) + info->used_responsible_pid ? so->so_rpid : +#endif + ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid); + if (socket_pid && (socket_pid != proc_pid(curr_proc))) { + sock_proc = proc_find(socket_pid); + if (socket_proc) { + *socket_proc = sock_proc; + } + } + if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) { - info->is_platform_binary = csproc_get_platform_binary(current_proc()) ? true : false; + info->is_platform_binary = csproc_get_platform_binary(sock_proc ? sock_proc : curr_proc) ? true : false; } if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && inp->inp_necp_attributes.inp_account != NULL) { @@ -7612,6 +7693,7 @@ necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local necp_kernel_policy_service service = { 0, 0 }; u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE; necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE; + proc_t socket_proc = NULL; u_int32_t netagent_ids[NECP_MAX_NETAGENTS]; memset(&netagent_ids, 0, sizeof(netagent_ids)); @@ -7679,7 +7761,7 @@ necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local // Lock lck_rw_lock_shared(&necp_kernel_policy_lock); - necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, override_bound_interface, drop_order, &info); + necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, override_bound_interface, drop_order, &socket_proc, &info); // Check info u_int32_t flowhash = necp_socket_calc_flowhash_locked(&info); @@ -7691,6 +7773,10 @@ necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local // Unlock lck_rw_done(&necp_kernel_policy_lock); + if (socket_proc) { + proc_rele(socket_proc); + } + return inp->inp_policyresult.policy_id; } @@ -7700,7 +7786,7 @@ necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE; u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES]; size_t route_rule_id_array_count = 0; - matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info.application_id)], &info, &filter_control_unit, route_rule_id_array, &route_rule_id_array_count, MAX_AGGREGATE_ROUTE_RULES, &service_action, &service, netagent_ids, NULL, NECP_MAX_NETAGENTS, NULL, 0, current_proc(), &skip_policy_id, inp->inp_route.ro_rt, &drop_dest_policy_result, &drop_all_bypass); + matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info.application_id)], &info, &filter_control_unit, route_rule_id_array, &route_rule_id_array_count, MAX_AGGREGATE_ROUTE_RULES, &service_action, &service, netagent_ids, NULL, NECP_MAX_NETAGENTS, NULL, 0, socket_proc ? socket_proc : current_proc(), &skip_policy_id, inp->inp_route.ro_rt, &drop_dest_policy_result, &drop_all_bypass); // If the socket matched a scoped service policy, mark as Drop if not registered. // This covers the cases in which a service is required (on demand) but hasn't started yet. @@ -7732,6 +7818,11 @@ necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local // Unlock lck_rw_done(&necp_kernel_policy_lock); + + if (socket_proc) { + proc_rele(socket_proc); + } + return NECP_KERNEL_POLICY_ID_NONE; } } @@ -7773,6 +7864,11 @@ necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local // Unlock lck_rw_done(&necp_kernel_policy_lock); + + if (socket_proc) { + proc_rele(socket_proc); + } + return NECP_KERNEL_POLICY_ID_NONE; } } @@ -7825,7 +7921,7 @@ necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local // Mark socket as a drop if set drop_all = true; if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) { - drop_all_bypass = necp_check_drop_all_bypass_result(NULL); + drop_all_bypass = necp_check_drop_all_bypass_result(socket_proc ? socket_proc : current_proc()); } } if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) { @@ -7856,6 +7952,10 @@ necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local tcp_mtudisc(inp, 0); } + if (socket_proc) { + proc_rele(socket_proc); + } + return matched_policy_id; } @@ -9051,6 +9151,7 @@ necp_socket_is_allowed_to_send_recv_internal(struct inpcb *inp, struct sockaddr necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE; u_int32_t netagent_ids[NECP_MAX_NETAGENTS]; memset(&netagent_ids, 0, sizeof(netagent_ids)); + proc_t socket_proc = NULL; if (return_policy_id) { *return_policy_id = NECP_KERNEL_POLICY_ID_NONE; @@ -9132,7 +9233,7 @@ necp_socket_is_allowed_to_send_recv_internal(struct inpcb *inp, struct sockaddr // Actually calculate policy result lck_rw_lock_shared(&necp_kernel_policy_lock); - necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, 0, drop_order, &info); + necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, 0, drop_order, &socket_proc, &info); flowhash = necp_socket_calc_flowhash_locked(&info); if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE && @@ -9162,7 +9263,7 @@ necp_socket_is_allowed_to_send_recv_internal(struct inpcb *inp, struct sockaddr u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES]; size_t route_rule_id_array_count = 0; - struct necp_kernel_socket_policy *matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info.application_id)], &info, NULL, route_rule_id_array, &route_rule_id_array_count, MAX_AGGREGATE_ROUTE_RULES, &service_action, &service, netagent_ids, NULL, NECP_MAX_NETAGENTS, NULL, 0, current_proc(), return_skip_policy_id, inp->inp_route.ro_rt, &drop_dest_policy_result, &drop_all_bypass); + struct necp_kernel_socket_policy *matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info.application_id)], &info, NULL, route_rule_id_array, &route_rule_id_array_count, MAX_AGGREGATE_ROUTE_RULES, &service_action, &service, netagent_ids, NULL, NECP_MAX_NETAGENTS, NULL, 0, socket_proc ? socket_proc : current_proc(), return_skip_policy_id, inp->inp_route.ro_rt, &drop_dest_policy_result, &drop_all_bypass); if (route_rule_id_array_count == 1) { route_rule_id = route_rule_id_array[0]; @@ -9201,7 +9302,7 @@ necp_socket_is_allowed_to_send_recv_internal(struct inpcb *inp, struct sockaddr if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) { drop_all = true; if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) { - drop_all_bypass = necp_check_drop_all_bypass_result(NULL); + drop_all_bypass = necp_check_drop_all_bypass_result(socket_proc ? socket_proc : current_proc()); } } if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) { @@ -9223,6 +9324,10 @@ done: soevent(inp->inp_socket, (SO_FILT_HINT_LOCKED | SO_FILT_HINT_IFDENIED)); } + if (socket_proc) { + proc_rele(socket_proc); + } + return allowed_to_receive; } diff --git a/bsd/net/necp.h b/bsd/net/necp.h index f658ad1ed..1da29404a 100644 --- a/bsd/net/necp.h +++ b/bsd/net/necp.h @@ -149,6 +149,7 @@ struct necp_packet_header { #define NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY 25 // N/A #define NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY 26 // N/A #define NECP_POLICY_CONDITION_PLATFORM_BINARY 27 // N/A +#define NECP_POLICY_CONDITION_SIGNING_IDENTIFIER 28 // String /* * Results @@ -991,6 +992,7 @@ struct necp_kernel_socket_policy { union necp_sockaddr_union cond_remote_end; // Matches IP address range u_int8_t cond_remote_prefix; // Defines subnet struct necp_policy_condition_agent_type cond_agent_type; + char *cond_signing_identifier; // String necp_kernel_policy_result result; necp_kernel_policy_result_parameter result_parameter; diff --git a/bsd/netinet/flow_divert.c b/bsd/netinet/flow_divert.c index 83d34f1a7..a35ed9ab2 100644 --- a/bsd/netinet/flow_divert.c +++ b/bsd/netinet/flow_divert.c @@ -1458,21 +1458,21 @@ flow_divert_send_close_if_needed(struct flow_divert_pcb *fd_cb) static errno_t flow_divert_send_data_packet(struct flow_divert_pcb *fd_cb, mbuf_t data, size_t data_len, struct sockaddr *toaddr, Boolean force) { - mbuf_t packet; - mbuf_t last; + mbuf_t packet = NULL; + mbuf_t last = NULL; int error = 0; error = flow_divert_packet_init(fd_cb, FLOW_DIVERT_PKT_DATA, &packet); - if (error) { + if (error || packet == NULL) { FDLOG(LOG_ERR, fd_cb, "flow_divert_packet_init failed: %d", error); - return error; + goto done; } if (toaddr != NULL) { error = flow_divert_append_target_endpoint_tlv(packet, toaddr); if (error) { FDLOG(LOG_ERR, fd_cb, "flow_divert_append_target_endpoint_tlv() failed: %d", error); - return error; + goto done; } } @@ -1482,15 +1482,21 @@ flow_divert_send_data_packet(struct flow_divert_pcb *fd_cb, mbuf_t data, size_t mbuf_pkthdr_adjustlen(packet, data_len); } error = flow_divert_send_packet(fd_cb, packet, force); - - if (error) { - mbuf_setnext(last, NULL); - mbuf_freem(packet); - } else { + if (error == 0 && data_len > 0) { fd_cb->bytes_sent += data_len; flow_divert_add_data_statistics(fd_cb, data_len, TRUE); } +done: + if (error) { + if (last != NULL) { + mbuf_setnext(last, NULL); + } + if (packet != NULL) { + mbuf_freem(packet); + } + } + return error; } diff --git a/bsd/netinet/in.c b/bsd/netinet/in.c index f51b22b4e..1e8a63778 100644 --- a/bsd/netinet/in.c +++ b/bsd/netinet/in.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2019 Apple Inc. All rights reserved. + * Copyright (c) 2000-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -695,7 +695,7 @@ inctl_ifaddr(struct ifnet *ifp, struct in_ifaddr *ia, u_long cmd, hostIsNew = 0; } } - if (mask.sin_len) { + if (mask.sin_len != 0) { IFA_UNLOCK(&ia->ia_ifa); in_ifscrub(ifp, ia, 0); IFA_LOCK(&ia->ia_ifa); @@ -710,7 +710,10 @@ inctl_ifaddr(struct ifnet *ifp, struct in_ifaddr *ia, u_long cmd, in_ifscrub(ifp, ia, 0); IFA_LOCK(&ia->ia_ifa); ia->ia_dstaddr = broadaddr; + ia->ia_dstaddr.sin_family = AF_INET; ia->ia_dstaddr.sin_len = sizeof(struct sockaddr_in); + ia->ia_dstaddr.sin_port = 0; + bzero(&ia->ia_dstaddr.sin_zero, sizeof(ia->ia_dstaddr.sin_zero)); maskIsNew = 1; /* We lie; but the effect's the same */ } if (addr.sin_family == AF_INET && (hostIsNew || maskIsNew)) { @@ -725,7 +728,11 @@ inctl_ifaddr(struct ifnet *ifp, struct in_ifaddr *ia, u_long cmd, IFA_LOCK(&ia->ia_ifa); if ((ifp->if_flags & IFF_BROADCAST) && (broadaddr.sin_family == AF_INET)) { - ia->ia_broadaddr = broadaddr; + ia->ia_broadaddr.sin_family = AF_INET; + ia->ia_broadaddr.sin_len = sizeof(struct sockaddr_in); + ia->ia_broadaddr.sin_port = 0; + ia->ia_broadaddr.sin_addr = broadaddr.sin_addr; + bzero(&ia->ia_broadaddr.sin_zero, sizeof(ia->ia_broadaddr.sin_zero)); } /* @@ -940,10 +947,13 @@ inctl_ifdstaddr(struct ifnet *ifp, struct in_ifaddr *ia, u_long cmd, VERIFY(ia != NULL); IFA_LOCK(&ia->ia_ifa); dstaddr = ia->ia_dstaddr; + bcopy(&ifr->ifr_dstaddr, &ia->ia_dstaddr, sizeof(dstaddr)); - if (ia->ia_dstaddr.sin_family == AF_INET) { - ia->ia_dstaddr.sin_len = sizeof(struct sockaddr_in); - } + ia->ia_dstaddr.sin_family = AF_INET; + ia->ia_dstaddr.sin_len = sizeof(struct sockaddr_in); + ia->ia_dstaddr.sin_port = 0; + bzero(&ia->ia_dstaddr.sin_zero, sizeof(ia->ia_dstaddr.sin_zero)); + IFA_UNLOCK(&ia->ia_ifa); /* * NOTE: SIOCSIFDSTADDR is defined with struct ifreq @@ -1061,6 +1071,11 @@ inctl_ifbrdaddr(struct ifnet *ifp, struct in_ifaddr *ia, u_long cmd, bcopy(&ifr->ifr_broadaddr, &ia->ia_broadaddr, sizeof(struct sockaddr_in)); + ia->ia_broadaddr.sin_family = AF_INET; + ia->ia_broadaddr.sin_len = sizeof(struct sockaddr_in); + ia->ia_broadaddr.sin_port = 0; + bzero(&ia->ia_broadaddr.sin_zero, sizeof(ia->ia_broadaddr.sin_zero)); + ev_msg.vendor_code = KEV_VENDOR_APPLE; ev_msg.kev_class = KEV_NETWORK_CLASS; ev_msg.kev_subclass = KEV_INET_SUBCLASS; @@ -1491,7 +1506,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr; ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask; - ia->ia_sockmask.sin_len = 8; + ia->ia_sockmask.sin_len = offsetof(struct sockaddr_in, sin_zero); if (ifp->if_flags & IFF_BROADCAST) { ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr); ia->ia_broadaddr.sin_family = AF_INET; diff --git a/bsd/netinet/ip_input.c b/bsd/netinet/ip_input.c index 1cdd96aff..1c162bf8c 100644 --- a/bsd/netinet/ip_input.c +++ b/bsd/netinet/ip_input.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2019 Apple Inc. All rights reserved. + * Copyright (c) 2000-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -137,6 +137,8 @@ #include #endif /* IPSEC */ +#include + #define DBG_LAYER_BEG NETDBG_CODE(DBG_NETIP, 0) #define DBG_LAYER_END NETDBG_CODE(DBG_NETIP, 2) #define DBG_FNC_IP_INPUT NETDBG_CODE(DBG_NETIP, (2 << 8)) @@ -246,21 +248,57 @@ SYSCTL_UINT(_net_inet_ip, OID_AUTO, adj_partial_sum, "Perform partial sum adjustment of trailing bytes at IP layer"); /* - * XXX - Setting ip_checkinterface mostly implements the receive side of - * the Strong ES model described in RFC 1122, but since the routing table - * and transmit implementation do not implement the Strong ES model, - * setting this to 1 results in an odd hybrid. + * ip_checkinterface controls the receive side of the models for multihoming + * that are discussed in RFC 1122. + * + * ip_checkinterface values are: + * IP_CHECKINTERFACE_WEAK_ES: + * This corresponds to the Weak End-System model where incoming packets from + * any interface are accepted provided the destination address of the incoming packet + * is assigned to some interface. + * + * IP_CHECKINTERFACE_HYBRID_ES: + * The Hybrid End-System model use the Strong End-System for tunnel interfaces + * (ipsec and utun) and the weak End-System model for other interfaces families. + * This prevents a rogue middle box to probe for signs of TCP connections + * that use the tunnel interface. + * + * IP_CHECKINTERFACE_STRONG_ES: + * The Strong model model requires the packet arrived on an interface that + * is assigned the destination address of the packet. * - * XXX - ip_checkinterface currently must be disabled if you use ipnat + * Since the routing table and transmit implementation do not implement the Strong ES model, + * setting this to a value different from IP_CHECKINTERFACE_WEAK_ES may lead to unexpected results. + * + * When forwarding is enabled, the system reverts to the Weak ES model as a router + * is expected by design to receive packets from several interfaces to the same address. + * + * XXX - ip_checkinterface currently must be set to IP_CHECKINTERFACE_WEAK_ES if you use ipnat * to translate the destination address to another local interface. * - * XXX - ip_checkinterface must be disabled if you add IP aliases + * XXX - ip_checkinterface must be set to IP_CHECKINTERFACE_WEAK_ES if you add IP aliases * to the loopback interface instead of the interface where the * packets for those addresses are received. */ -static int ip_checkinterface = 0; -SYSCTL_INT(_net_inet_ip, OID_AUTO, check_interface, CTLFLAG_RW | CTLFLAG_LOCKED, - &ip_checkinterface, 0, "Verify packet arrives on correct interface"); +#define IP_CHECKINTERFACE_WEAK_ES 0 +#define IP_CHECKINTERFACE_HYBRID_ES 1 +#define IP_CHECKINTERFACE_STRONG_ES 2 + +static int ip_checkinterface = IP_CHECKINTERFACE_HYBRID_ES; + +static int sysctl_ip_checkinterface SYSCTL_HANDLER_ARGS; +SYSCTL_PROC(_net_inet_ip, OID_AUTO, check_interface, + CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, + 0, 0, sysctl_ip_checkinterface, "I", "Verify packet arrives on correct interface"); + +#if (DEBUG || DEVELOPMENT) +#define IP_CHECK_IF_DEBUG 1 +#else +#define IP_CHECK_IF_DEBUG 0 +#endif /* (DEBUG || DEVELOPMENT) */ +static int ip_checkinterface_debug = IP_CHECK_IF_DEBUG; +SYSCTL_INT(_net_inet_ip, OID_AUTO, checkinterface_debug, CTLFLAG_RW | CTLFLAG_LOCKED, + &ip_checkinterface_debug, IP_CHECK_IF_DEBUG, ""); static int ip_chaining = 1; SYSCTL_INT(_net_inet_ip, OID_AUTO, rx_chaining, CTLFLAG_RW | CTLFLAG_LOCKED, @@ -425,6 +463,16 @@ SYSCTL_INT(_net_inet_ip, OID_AUTO, random_id, CTLFLAG_RW | CTLFLAG_LOCKED, } while (0) #endif /* !__i386__ && !__x86_64__ */ + +typedef enum ip_check_if_result { + IP_CHECK_IF_NONE = 0, + IP_CHECK_IF_OURS = 1, + IP_CHECK_IF_DROP = 2, + IP_CHECK_IF_FORWARD = 3 +} ip_check_if_result_t; + +static ip_check_if_result_t ip_input_check_interface(struct mbuf **, struct ip *, struct ifnet *); + /* * GRE input handler function, settable via ip_gre_register_input() for PPTP. */ @@ -542,6 +590,17 @@ ip_init(struct protosw *pp, struct domain *dp) ipf_init(); + PE_parse_boot_argn("ip_checkinterface", &i, sizeof(i)); + switch (i) { + case IP_CHECKINTERFACE_WEAK_ES: + case IP_CHECKINTERFACE_HYBRID_ES: + case IP_CHECKINTERFACE_STRONG_ES: + ip_checkinterface = i; + break; + default: + break; + } + #if IPSEC sadb_stat_mutex_grp_attr = lck_grp_attr_alloc_init(); sadb_stat_mutex_grp = lck_grp_alloc_init("sadb_stat", @@ -681,11 +740,6 @@ ip_proto_dispatch_in(struct mbuf *m, int hlen, u_int8_t proto, /* Perform IP header alignment fixup (post-filters), if needed */ IP_HDR_ALIGNMENT_FIXUP(m, m->m_pkthdr.rcvif, return ); - /* - * If there isn't a specific lock for the protocol - * we're about to call, use the generic lock for AF_INET. - * otherwise let the protocol deal with its own locking - */ ip = mtod(m, struct ip *); if (changed_header) { @@ -693,6 +747,11 @@ ip_proto_dispatch_in(struct mbuf *m, int hlen, u_int8_t proto, ip->ip_off = ntohs(ip->ip_off); } + /* + * If there isn't a specific lock for the protocol + * we're about to call, use the generic lock for AF_INET. + * otherwise let the protocol deal with its own locking + */ if ((pr_input = ip_protox[ip->ip_p]->pr_input) == NULL) { m_freem(m); } else if (!(ip_protox[ip->ip_p]->pr_flags & PR_PROTOLOCK)) { @@ -837,7 +896,7 @@ ip_input_dispatch_chain(struct mbuf *m) ip = mtod(tmp_mbuf, struct ip *); hlen = IP_VHL_HL(ip->ip_vhl) << 2; - while (tmp_mbuf) { + while (tmp_mbuf != NULL) { nxt_mbuf = mbuf_nextpkt(tmp_mbuf); mbuf_setnextpkt(tmp_mbuf, NULL); @@ -862,7 +921,7 @@ ip_input_setdst_chain(struct mbuf *m, uint32_t ifindex, struct in_ifaddr *ia) { struct mbuf *tmp_mbuf = m; - while (tmp_mbuf) { + while (tmp_mbuf != NULL) { ip_setdstifaddr_info(tmp_mbuf, ifindex, ia); tmp_mbuf = mbuf_nextpkt(tmp_mbuf); } @@ -1411,14 +1470,175 @@ bad: #endif } +/* + * Because the call to m_pullup() may freem the mbuf, the function frees the mbuf packet + * chain before it return IP_CHECK_IF_DROP + */ +static ip_check_if_result_t +ip_input_check_interface(struct mbuf **mp, struct ip *ip, struct ifnet *inifp) +{ + struct mbuf *m = *mp; + struct in_ifaddr *ia = NULL; + struct in_ifaddr *best_ia = NULL; + struct ifnet *match_ifp = NULL; + ip_check_if_result_t result = IP_CHECK_IF_NONE; + + /* + * Host broadcast and all network broadcast addresses are always a match + */ + if (ip->ip_dst.s_addr == (u_int32_t)INADDR_BROADCAST || + ip->ip_dst.s_addr == INADDR_ANY) { + ip_input_setdst_chain(m, inifp->if_index, NULL); + return IP_CHECK_IF_OURS; + } + + /* + * Check for a match in the hash bucket. + */ + lck_rw_lock_shared(in_ifaddr_rwlock); + TAILQ_FOREACH(ia, INADDR_HASH(ip->ip_dst.s_addr), ia_hash) { + if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) { + best_ia = ia; + match_ifp = best_ia->ia_ifp; + + if (ia->ia_ifp == inifp || (inifp->if_flags & IFF_LOOPBACK) || + (m->m_pkthdr.pkt_flags & PKTF_LOOP)) { + /* + * A locally originated packet or packet from the loopback + * interface is always an exact interface address match + */ + match_ifp = inifp; + break; + } + /* + * Continue the loop in case there's a exact match with another + * interface + */ + } + } + if (best_ia != NULL) { + if (match_ifp != inifp && ipforwarding == 0 && + ((ip_checkinterface == IP_CHECKINTERFACE_HYBRID_ES && + (match_ifp->if_family == IFNET_FAMILY_IPSEC || + match_ifp->if_family == IFNET_FAMILY_UTUN)) || + ip_checkinterface == IP_CHECKINTERFACE_STRONG_ES)) { + /* + * Drop when interface address check is strict and forwarding + * is disabled + */ + result = IP_CHECK_IF_DROP; + } else { + result = IP_CHECK_IF_OURS; + ip_input_setdst_chain(m, 0, best_ia); + } + } + lck_rw_done(in_ifaddr_rwlock); + + if (result == IP_CHECK_IF_NONE && (inifp->if_flags & IFF_BROADCAST)) { + /* + * Check for broadcast addresses. + * + * Only accept broadcast packets that arrive via the matching + * interface. Reception of forwarded directed broadcasts would be + * handled via ip_forward() and ether_frameout() with the loopback + * into the stack for SIMPLEX interfaces handled by ether_frameout(). + */ + struct ifaddr *ifa; + + ifnet_lock_shared(inifp); + TAILQ_FOREACH(ifa, &inifp->if_addrhead, ifa_link) { + if (ifa->ifa_addr->sa_family != AF_INET) { + continue; + } + ia = ifatoia(ifa); + if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == ip->ip_dst.s_addr || + ia->ia_netbroadcast.s_addr == ip->ip_dst.s_addr) { + ip_input_setdst_chain(m, 0, ia); + result = IP_CHECK_IF_OURS; + match_ifp = inifp; + break; + } + } + ifnet_lock_done(inifp); + } + + /* Allow DHCP/BootP responses through */ + if (result == IP_CHECK_IF_NONE && (inifp->if_eflags & IFEF_AUTOCONFIGURING) && + ip->ip_p == IPPROTO_UDP && (IP_VHL_HL(ip->ip_vhl) << 2) == sizeof(struct ip)) { + struct udpiphdr *ui; + + if (m->m_len < sizeof(struct udpiphdr)) { + if ((m = m_pullup(m, sizeof(struct udpiphdr))) == NULL) { + OSAddAtomic(1, &udpstat.udps_hdrops); + *mp = NULL; + return IP_CHECK_IF_DROP; + } + /* + * m_pullup can return a different mbuf + */ + *mp = m; + ip = mtod(m, struct ip *); + } + ui = mtod(m, struct udpiphdr *); + if (ntohs(ui->ui_dport) == IPPORT_BOOTPC) { + ASSERT(m->m_nextpkt == NULL); + ip_setdstifaddr_info(m, inifp->if_index, NULL); + result = IP_CHECK_IF_OURS; + match_ifp = inifp; + } + } + + if (result == IP_CHECK_IF_NONE) { + if (ipforwarding == 0) { + result = IP_CHECK_IF_DROP; + } else { + result = IP_CHECK_IF_FORWARD; + ip_input_setdst_chain(m, inifp->if_index, NULL); + } + } + + if (result == IP_CHECK_IF_OURS && match_ifp != inifp) { + ipstat.ips_rcv_if_weak_match++; + + /* Logging is too noisy when forwarding is enabled */ + if (ip_checkinterface_debug != 0 && ipforwarding == 0) { + char src_str[MAX_IPv4_STR_LEN]; + char dst_str[MAX_IPv4_STR_LEN]; + + inet_ntop(AF_INET, &ip->ip_src, src_str, sizeof(src_str)); + inet_ntop(AF_INET, &ip->ip_dst, dst_str, sizeof(dst_str)); + os_log_info(OS_LOG_DEFAULT, + "%s: weak ES interface match to %s for packet from %s to %s proto %u received via %s", + __func__, best_ia->ia_ifp->if_xname, src_str, dst_str, ip->ip_p, inifp->if_xname); + } + } else if (result == IP_CHECK_IF_DROP) { + if (ip_checkinterface_debug > 0) { + char src_str[MAX_IPv4_STR_LEN]; + char dst_str[MAX_IPv4_STR_LEN]; + + inet_ntop(AF_INET, &ip->ip_src, src_str, sizeof(src_str)); + inet_ntop(AF_INET, &ip->ip_dst, dst_str, sizeof(dst_str)); + os_log_info(OS_LOG_DEFAULT, + "%s: no interface match for packet from %s to %s proto %u received via %s", + __func__, src_str, dst_str, ip->ip_p, inifp->if_xname); + } + struct mbuf *tmp_mbuf = m; + while (tmp_mbuf != NULL) { + ipstat.ips_rcv_if_no_match++; + tmp_mbuf = tmp_mbuf->m_nextpkt; + } + m_freem_list(m); + *mp = NULL; + } + + return result; +} + static void ip_input_second_pass(struct mbuf *m, struct ifnet *inifp, u_int32_t div_info, int npkts_in_chain, int bytes_in_chain, struct ip_fw_in_args *args, int ours) { - unsigned int checkif; struct mbuf *tmp_mbuf = NULL; - struct in_ifaddr *ia = NULL; - struct in_addr pkt_dst; unsigned int hlen; #if !IPFIREWALL @@ -1460,7 +1680,7 @@ ip_input_second_pass(struct mbuf *m, struct ifnet *inifp, u_int32_t div_info, */ tmp_mbuf = m; if (TAILQ_EMPTY(&in_ifaddrhead)) { - while (tmp_mbuf) { + while (tmp_mbuf != NULL) { if (!(tmp_mbuf->m_flags & (M_MCAST | M_BCAST))) { ip_setdstifaddr_info(tmp_mbuf, inifp->if_index, NULL); @@ -1469,16 +1689,6 @@ ip_input_second_pass(struct mbuf *m, struct ifnet *inifp, u_int32_t div_info, } goto ours; } - /* - * Cache the destination address of the packet; this may be - * changed by use of 'ipfw fwd'. - */ -#if IPFIREWALL - pkt_dst = args->fwai_next_hop == NULL ? - ip->ip_dst : args->fwai_next_hop->sin_addr; -#else /* !IPFIREWALL */ - pkt_dst = ip->ip_dst; -#endif /* !IPFIREWALL */ /* * Enable a consistency check between the destination address @@ -1494,63 +1704,17 @@ ip_input_second_pass(struct mbuf *m, struct ifnet *inifp, u_int32_t div_info, * to the loopback interface instead of the interface where * the packets are received. */ - checkif = ip_checkinterface && (ipforwarding == 0) && - !(inifp->if_flags & IFF_LOOPBACK) && - !(m->m_pkthdr.pkt_flags & PKTF_LOOP) -#if IPFIREWALL - && (args->fwai_next_hop == NULL); -#else /* !IPFIREWALL */ - ; -#endif /* !IPFIREWALL */ + if (!IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { + ip_check_if_result_t ip_check_if_result = IP_CHECK_IF_NONE; - /* - * Check for exact addresses in the hash bucket. - */ - lck_rw_lock_shared(in_ifaddr_rwlock); - TAILQ_FOREACH(ia, INADDR_HASH(pkt_dst.s_addr), ia_hash) { - /* - * If the address matches, verify that the packet - * arrived via the correct interface if checking is - * enabled. - */ - if (IA_SIN(ia)->sin_addr.s_addr == pkt_dst.s_addr && - (!checkif || ia->ia_ifp == inifp)) { - ip_input_setdst_chain(m, 0, ia); - lck_rw_done(in_ifaddr_rwlock); + ip_check_if_result = ip_input_check_interface(&m, ip, inifp); + ASSERT(ip_check_if_result != IP_CHECK_IF_NONE); + if (ip_check_if_result == IP_CHECK_IF_OURS) { goto ours; + } else if (ip_check_if_result == IP_CHECK_IF_DROP) { + return; } - } - lck_rw_done(in_ifaddr_rwlock); - - /* - * Check for broadcast addresses. - * - * Only accept broadcast packets that arrive via the matching - * interface. Reception of forwarded directed broadcasts would be - * handled via ip_forward() and ether_frameout() with the loopback - * into the stack for SIMPLEX interfaces handled by ether_frameout(). - */ - if (inifp->if_flags & IFF_BROADCAST) { - struct ifaddr *ifa; - - ifnet_lock_shared(inifp); - TAILQ_FOREACH(ifa, &inifp->if_addrhead, ifa_link) { - if (ifa->ifa_addr->sa_family != AF_INET) { - continue; - } - ia = ifatoia(ifa); - if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == - pkt_dst.s_addr || ia->ia_netbroadcast.s_addr == - pkt_dst.s_addr) { - ip_input_setdst_chain(m, 0, ia); - ifnet_lock_done(inifp); - goto ours; - } - } - ifnet_lock_done(inifp); - } - - if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { + } else { struct in_multi *inm; /* * See if we belong to the destination multicast group on the @@ -1570,23 +1734,9 @@ ip_input_second_pass(struct mbuf *m, struct ifnet *inifp, u_int32_t div_info, goto ours; } - if (ip->ip_dst.s_addr == (u_int32_t)INADDR_BROADCAST || - ip->ip_dst.s_addr == INADDR_ANY) { - ip_input_setdst_chain(m, inifp->if_index, NULL); - goto ours; - } - - if (ip->ip_p == IPPROTO_UDP) { - struct udpiphdr *ui; - ui = mtod(m, struct udpiphdr *); - if (ntohs(ui->ui_dport) == IPPORT_BOOTPC) { - goto ours; - } - } - tmp_mbuf = m; struct mbuf *nxt_mbuf = NULL; - while (tmp_mbuf) { + while (tmp_mbuf != NULL) { nxt_mbuf = mbuf_nextpkt(tmp_mbuf); /* * Not for us; forward if possible and desirable. @@ -1607,6 +1757,7 @@ ip_input_second_pass(struct mbuf *m, struct ifnet *inifp, u_int32_t div_info, KERNEL_DEBUG(DBG_LAYER_END, 0, 0, 0, 0, 0); return; ours: + ip = mtod(m, struct ip *); /* in case it changed */ /* * If offset or IP_MF are set, must reassemble. */ @@ -1872,15 +2023,9 @@ void ip_input(struct mbuf *m) { struct ip *ip; - struct in_ifaddr *ia = NULL; - unsigned int hlen, checkif; + unsigned int hlen; u_short sum = 0; - struct in_addr pkt_dst; -#if IPFIREWALL - int i; - u_int32_t div_info = 0; /* packet divert/tee info */ -#endif -#if IPFIREWALL || DUMMYNET +#if DUMMYNET struct ip_fw_args args; struct m_tag *tag; #endif @@ -1945,7 +2090,7 @@ ip_input(struct mbuf *m) m_tag_delete(m, tag); } -#if DIAGNOSTIC +#if DIAGNOSTIC if (m == NULL || !(m->m_flags & M_PKTHDR)) { panic("ip_input no HDR"); } @@ -2242,17 +2387,6 @@ pass: goto ours; } - /* - * Cache the destination address of the packet; this may be - * changed by use of 'ipfw fwd'. - */ -#if IPFIREWALL - pkt_dst = args.fwa_next_hop == NULL ? - ip->ip_dst : args.fwa_next_hop->sin_addr; -#else /* !IPFIREWALL */ - pkt_dst = ip->ip_dst; -#endif /* !IPFIREWALL */ - /* * Enable a consistency check between the destination address * and the arrival interface for a unicast packet (the RFC 1122 @@ -2267,63 +2401,17 @@ pass: * to the loopback interface instead of the interface where * the packets are received. */ - checkif = ip_checkinterface && (ipforwarding == 0) && - !(inifp->if_flags & IFF_LOOPBACK) && - !(m->m_pkthdr.pkt_flags & PKTF_LOOP) -#if IPFIREWALL - && (args.fwa_next_hop == NULL); -#else /* !IPFIREWALL */ - ; -#endif /* !IPFIREWALL */ + if (!IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { + ip_check_if_result_t check_if_result = IP_CHECK_IF_NONE; - /* - * Check for exact addresses in the hash bucket. - */ - lck_rw_lock_shared(in_ifaddr_rwlock); - TAILQ_FOREACH(ia, INADDR_HASH(pkt_dst.s_addr), ia_hash) { - /* - * If the address matches, verify that the packet - * arrived via the correct interface if checking is - * enabled. - */ - if (IA_SIN(ia)->sin_addr.s_addr == pkt_dst.s_addr && - (!checkif || ia->ia_ifp == inifp)) { - ip_setdstifaddr_info(m, 0, ia); - lck_rw_done(in_ifaddr_rwlock); + check_if_result = ip_input_check_interface(&m, ip, inifp); + ASSERT(check_if_result != IP_CHECK_IF_NONE); + if (check_if_result == IP_CHECK_IF_OURS) { goto ours; + } else if (check_if_result == IP_CHECK_IF_DROP) { + return; } - } - lck_rw_done(in_ifaddr_rwlock); - - /* - * Check for broadcast addresses. - * - * Only accept broadcast packets that arrive via the matching - * interface. Reception of forwarded directed broadcasts would be - * handled via ip_forward() and ether_frameout() with the loopback - * into the stack for SIMPLEX interfaces handled by ether_frameout(). - */ - if (inifp->if_flags & IFF_BROADCAST) { - struct ifaddr *ifa; - - ifnet_lock_shared(inifp); - TAILQ_FOREACH(ifa, &inifp->if_addrhead, ifa_link) { - if (ifa->ifa_addr->sa_family != AF_INET) { - continue; - } - ia = ifatoia(ifa); - if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == - pkt_dst.s_addr || ia->ia_netbroadcast.s_addr == - pkt_dst.s_addr) { - ip_setdstifaddr_info(m, 0, ia); - ifnet_lock_done(inifp); - goto ours; - } - } - ifnet_lock_done(inifp); - } - - if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { + } else { struct in_multi *inm; /* * See if we belong to the destination multicast group on the @@ -2341,29 +2429,6 @@ pass: INM_REMREF(inm); goto ours; } - if (ip->ip_dst.s_addr == (u_int32_t)INADDR_BROADCAST || - ip->ip_dst.s_addr == INADDR_ANY) { - ip_setdstifaddr_info(m, inifp->if_index, NULL); - goto ours; - } - - /* Allow DHCP/BootP responses through */ - if ((inifp->if_eflags & IFEF_AUTOCONFIGURING) && - hlen == sizeof(struct ip) && ip->ip_p == IPPROTO_UDP) { - struct udpiphdr *ui; - - if (m->m_len < sizeof(struct udpiphdr) && - (m = m_pullup(m, sizeof(struct udpiphdr))) == NULL) { - OSAddAtomic(1, &udpstat.udps_hdrops); - return; - } - ui = mtod(m, struct udpiphdr *); - if (ntohs(ui->ui_dport) == IPPORT_BOOTPC) { - ip_setdstifaddr_info(m, inifp->if_index, NULL); - goto ours; - } - ip = mtod(m, struct ip *); /* in case it changed */ - } /* * Not for us; forward if possible and desirable. @@ -4671,3 +4736,32 @@ sysctl_ip_input_getperf SYSCTL_HANDLER_ARGS return SYSCTL_OUT(req, &net_perf, MIN(sizeof(net_perf), req->oldlen)); } #endif /* (DEBUG || DEVELOPMENT) */ + +static int +sysctl_ip_checkinterface SYSCTL_HANDLER_ARGS +{ +#pragma unused(arg1, arg2) + int error, i; + + i = ip_checkinterface; + error = sysctl_handle_int(oidp, &i, 0, req); + if (error != 0 || req->newptr == USER_ADDR_NULL) { + return error; + } + + switch (i) { + case IP_CHECKINTERFACE_WEAK_ES: + case IP_CHECKINTERFACE_HYBRID_ES: + case IP_CHECKINTERFACE_STRONG_ES: + if (ip_checkinterface != i) { + ip_checkinterface = i; + os_log(OS_LOG_DEFAULT, "%s: ip_checkinterface is now %d\n", + __func__, ip_checkinterface); + } + break; + default: + error = EINVAL; + break; + } + return error; +} diff --git a/bsd/netinet/ip_var.h b/bsd/netinet/ip_var.h index a9ecaa856..ab4d5336d 100644 --- a/bsd/netinet/ip_var.h +++ b/bsd/netinet/ip_var.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2017 Apple Inc. All rights reserved. + * Copyright (c) 2000-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -229,6 +229,8 @@ struct ipstat { u_int32_t ips_rxc_notlist; /* count of pkts through ip_input */ u_int32_t ips_raw_sappend_fail; /* sock append failed */ u_int32_t ips_necp_policy_drop; /* NECP policy related drop */ + u_int32_t ips_rcv_if_weak_match; /* packets whose receive interface that passed the Weak ES address check */ + u_int32_t ips_rcv_if_no_match; /* packets whose receive interface did not pass the address check */ }; struct ip_linklocal_stat { diff --git a/bsd/netinet/kpi_ipfilter.c b/bsd/netinet/kpi_ipfilter.c index b783eb214..a47c52b4a 100644 --- a/bsd/netinet/kpi_ipfilter.c +++ b/bsd/netinet/kpi_ipfilter.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2018 Apple Inc. All rights reserved. + * Copyright (c) 2004-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -329,7 +329,7 @@ ipf_inject_input( ip6 = mtod(m, struct ip6_hdr *); pkt_dst6.sin6_addr = ip6->ip6_dst; lck_rw_lock_shared(&in6_ifaddr_rwlock); - for (ia6 = in6_ifaddrs; ia6 != NULL; ia6 = ia6->ia_next) { + TAILQ_FOREACH(ia6, IN6ADDR_HASH(&pkt_dst6.sin6_addr), ia6_hash) { if (IN6_ARE_ADDR_EQUAL(&ia6->ia_addr.sin6_addr, &pkt_dst6.sin6_addr)) { m->m_pkthdr.rcvif = ia6->ia_ifp; break; diff --git a/bsd/netinet6/ah_input.c b/bsd/netinet6/ah_input.c index 67a664ec6..a2620405f 100644 --- a/bsd/netinet6/ah_input.c +++ b/bsd/netinet6/ah_input.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2016 Apple Inc. All rights reserved. + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -631,17 +631,17 @@ ah6_input(struct mbuf **mp, int *offp, int proto) #pragma unused(proto) struct mbuf *m = *mp; int off = *offp; - struct ip6_hdr *ip6; - struct ah *ah; - u_int32_t spi; - const struct ah_algorithm *algo; - size_t siz; - size_t siz1; - u_char *cksum; + struct ip6_hdr *ip6 = NULL; + struct ah *ah = NULL; + u_int32_t spi = 0; + const struct ah_algorithm *algo = NULL; + size_t siz = 0; + size_t siz1 = 0; + u_char *cksum = NULL; struct secasvar *sav = NULL; - u_int16_t nxt; + u_int16_t nxt = IPPROTO_DONE; size_t stripsiz = 0; - sa_family_t ifamily; + sa_family_t ifamily = AF_UNSPEC; IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), {return IPPROTO_DONE;}); ah = (struct ah *)(void *)(mtod(m, caddr_t) + off); @@ -724,6 +724,8 @@ ah6_input(struct mbuf **mp, int *offp, int proto) } IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1, {return IPPROTO_DONE;}); + ip6 = mtod(m, struct ip6_hdr *); + ah = (struct ah *)(void *)(mtod(m, caddr_t) + off); } /* @@ -1026,6 +1028,7 @@ fail: } if (m) { m_freem(m); + *mp = NULL; } return IPPROTO_DONE; } diff --git a/bsd/netinet6/dest6.c b/bsd/netinet6/dest6.c index ef80246c9..48dc59cf1 100644 --- a/bsd/netinet6/dest6.c +++ b/bsd/netinet6/dest6.c @@ -1,3 +1,30 @@ +/* + * Copyright (c) 2020 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ /* $FreeBSD: src/sys/netinet6/dest6.c,v 1.1.2.3 2001/07/03 11:01:49 ume Exp $ */ /* $KAME: dest6.c,v 1.27 2001/03/29 05:34:30 itojun Exp $ */ @@ -58,9 +85,9 @@ dest6_input(struct mbuf **mp, int *offp, int proto) { #pragma unused(proto) struct mbuf *m = *mp; - int off = *offp, dstoptlen, optlen; - struct ip6_dest *dstopts; - u_int8_t *opt; + int off = *offp, dstoptlen = 0, optlen = 0; + struct ip6_dest *dstopts = NULL; + u_int8_t *opt = NULL; /* validation of the length of the header */ IP6_EXTHDR_CHECK(m, off, sizeof(*dstopts), return IPPROTO_DONE); @@ -99,11 +126,12 @@ dest6_input(struct mbuf **mp, int *offp, int proto) break; } } - + *mp = m; *offp = off; return dstopts->ip6d_nxt; bad: + *mp = NULL; m_freem(m); return IPPROTO_DONE; } diff --git a/bsd/netinet6/esp_input.c b/bsd/netinet6/esp_input.c index 8e99b3eb7..849dc02af 100644 --- a/bsd/netinet6/esp_input.c +++ b/bsd/netinet6/esp_input.c @@ -529,6 +529,7 @@ noreplaycheck: IPSEC_STAT_INCREMENT(ipsecstat.in_inval); goto bad; } + ip = mtod(m, struct ip *); } // check the UDP encap header to detect changes in the source port, and then strip the header @@ -1199,6 +1200,7 @@ noreplaycheck: IPSEC_STAT_INCREMENT(ipsec6stat.in_inval); goto bad; } + ip6 = mtod(m, struct ip6_hdr *); } // check the UDP encap header to detect changes in the source port, and then strip the header diff --git a/bsd/netinet6/frag6.c b/bsd/netinet6/frag6.c index 9357d5e99..001cd1f12 100644 --- a/bsd/netinet6/frag6.c +++ b/bsd/netinet6/frag6.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2019 Apple Inc. All rights reserved. + * Copyright (c) 2000-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -277,18 +277,18 @@ int frag6_input(struct mbuf **mp, int *offp, int proto) { #pragma unused(proto) - struct mbuf *m = *mp, *t; - struct ip6_hdr *ip6; - struct ip6_frag *ip6f; - struct ip6q *q6; - struct ip6asfrag *af6, *ip6af, *af6dwn; - int offset = *offp, nxt, i, next; + struct mbuf *m = *mp, *t = NULL; + struct ip6_hdr *ip6 = NULL; + struct ip6_frag *ip6f = NULL; + struct ip6q *q6 = NULL; + struct ip6asfrag *af6 = NULL, *ip6af = NULL, *af6dwn = NULL; + int offset = *offp, nxt = 0, i = 0, next = 0; int first_frag = 0; - int fragoff, frgpartlen; /* must be larger than u_int16_t */ + int fragoff = 0, frgpartlen = 0; /* must be larger than u_int16_t */ struct ifnet *dstifp = NULL; - u_int8_t ecn, ecn0; - uint32_t csum, csum_flags; - struct fq6_head diq6; + u_int8_t ecn = 0, ecn0 = 0; + uint32_t csum = 0, csum_flags = 0; + struct fq6_head diq6 = {}; int locked = 0; VERIFY(m->m_flags & M_PKTHDR); @@ -298,8 +298,8 @@ frag6_input(struct mbuf **mp, int *offp, int proto) /* Expect 32-bit aligned data pointer on strict-align platforms */ MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m); - ip6 = mtod(m, struct ip6_hdr *); IP6_EXTHDR_CHECK(m, offset, sizeof(struct ip6_frag), goto done); + ip6 = mtod(m, struct ip6_hdr *); ip6f = (struct ip6_frag *)((caddr_t)ip6 + offset); #ifdef IN6_IFSTAT_STRICT @@ -375,6 +375,7 @@ frag6_input(struct mbuf **mp, int *offp, int proto) m->m_pkthdr.pkt_flags |= PKTF_REASSEMBLED; ip6stat.ip6s_atmfrag_rcvd++; in6_ifstat_inc(dstifp, ifs6_atmfrag_rcvd); + *mp = m; *offp = offset; return ip6f->ip6f_nxt; } @@ -539,6 +540,20 @@ frag6_input(struct mbuf **mp, int *offp, int proto) * fragment already stored in the reassembly queue. */ if (fragoff == 0) { + /* + * https://tools.ietf.org/html/rfc8200#page-20 + * If the first fragment does not include all headers through an + * Upper-Layer header, then that fragment should be discarded and + * an ICMP Parameter Problem, Code 3, message should be sent to + * the source of the fragment, with the Pointer field set to zero. + */ + if (!ip6_pkt_has_ulp(m)) { + lck_mtx_unlock(&ip6qlock); + locked = 0; + icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, 0); + m = NULL; + goto done; + } for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; af6 = af6dwn) { af6dwn = af6->ip6af_down; @@ -862,6 +877,7 @@ insert: done: VERIFY(m == NULL); + *mp = m; if (!locked) { if (frag6_nfragpackets == 0) { frag6_icmp6_paramprob_error(&diq6); @@ -884,6 +900,7 @@ dropfrag: lck_mtx_unlock(&ip6qlock); in6_ifstat_inc(dstifp, ifs6_reass_fail); m_freem(m); + *mp = NULL; frag6_icmp6_paramprob_error(&diq6); VERIFY(MBUFQ_EMPTY(&diq6)); return IPPROTO_DONE; diff --git a/bsd/netinet6/icmp6.c b/bsd/netinet6/icmp6.c index 042244b83..b6f48a666 100644 --- a/bsd/netinet6/icmp6.c +++ b/bsd/netinet6/icmp6.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2019 Apple Inc. All rights reserved. + * Copyright (c) 2000-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -2334,7 +2334,7 @@ icmp6_reflect(struct mbuf *m, size_t off) * to search in the ifaddr list. */ lck_rw_lock_shared(&in6_ifaddr_rwlock); - for (ia = in6_ifaddrs; ia; ia = ia->ia_next) { + TAILQ_FOREACH(ia, IN6ADDR_HASH(&t), ia6_hash) { IFA_LOCK(&ia->ia_ifa); if (IN6_ARE_ADDR_EQUAL(&t, &ia->ia_addr.sin6_addr) && (ia->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY | IN6_IFF_CLAT46)) == 0) { @@ -2469,12 +2469,12 @@ icmp6_redirect_input(struct mbuf *m, int off) u_char *redirhdr = NULL; int redirhdrlen = 0; struct rtentry *rt = NULL; - int is_router; - int is_onlink; - struct in6_addr src6; - struct in6_addr redtgt6; - struct in6_addr reddst6; - union nd_opts ndopts; + int is_router = 0; + int is_onlink = 0; + struct in6_addr src6 = {}; + struct in6_addr redtgt6 = {}; + struct in6_addr reddst6 = {}; + union nd_opts ndopts = {}; if (m == NULL) { return; @@ -2485,10 +2485,6 @@ icmp6_redirect_input(struct mbuf *m, int off) goto freeit; } - ip6 = mtod(m, struct ip6_hdr *); - icmp6len = ntohs(ip6->ip6_plen); - src6 = ip6->ip6_src; - /* * If we are an advertising router on this interface, * don't update route by icmp6 redirect. @@ -2500,9 +2496,12 @@ icmp6_redirect_input(struct mbuf *m, int off) goto freeit; } + ip6 = mtod(m, struct ip6_hdr *); + icmp6len = ntohs(ip6->ip6_plen); + src6 = ip6->ip6_src; #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, icmp6len, return ); - nd_rd = (struct nd_redirect *)((caddr_t)ip6 + off); + nd_rd = (struct nd_redirect *)(mtod(m, caddr_t) + off); #else IP6_EXTHDR_GET(nd_rd, struct nd_redirect *, m, off, icmp6len); if (nd_rd == NULL) { @@ -2510,6 +2509,8 @@ icmp6_redirect_input(struct mbuf *m, int off) goto freeit; } #endif + ip6 = mtod(m, struct ip6_hdr *); + redtgt6 = nd_rd->nd_rd_target; reddst6 = nd_rd->nd_rd_dst; diff --git a/bsd/netinet6/in6.c b/bsd/netinet6/in6.c index 5ed976827..176bd11cc 100644 --- a/bsd/netinet6/in6.c +++ b/bsd/netinet6/in6.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2019 Apple Inc. All rights reserved. + * Copyright (c) 2003-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -223,6 +223,19 @@ static int in6_getconnids(struct socket *, sae_associd_t, uint32_t *, static void in6_if_up_dad_start(struct ifnet *); +#define IA6_HASH_INIT(ia) { \ + (ia)->ia6_hash.tqe_next = (void *)(uintptr_t)-1; \ + (ia)->ia6_hash.tqe_prev = (void *)(uintptr_t)-1; \ +} + +#define IA6_IS_HASHED(ia) \ + (!((ia)->ia6_hash.tqe_next == (void *)(uintptr_t)-1 || \ + (ia)->ia6_hash.tqe_prev == (void *)(uintptr_t)-1)) + +static void in6_iahash_remove(struct in6_ifaddr *); +static void in6_iahash_insert(struct in6_ifaddr *); +static void in6_iahash_insert_ptp(struct in6_ifaddr *); + extern lck_mtx_t *nd6_mutex; #define IN6IFA_TRACE_HIST_SIZE 32 /* size of trace history */ @@ -399,7 +412,7 @@ in6_ifremloop(struct ifaddr *ifa) * XXX: we should avoid such a configuration in IPv6... */ lck_rw_lock_exclusive(&in6_ifaddr_rwlock); - for (ia = in6_ifaddrs; ia; ia = ia->ia_next) { + TAILQ_FOREACH(ia, IN6ADDR_HASH(IFA_IN6(ifa)), ia6_hash) { IFA_LOCK(&ia->ia_ifa); if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ia->ia_addr.sin6_addr)) { ia_count++; @@ -788,31 +801,32 @@ in6ctl_llstop(struct ifnet *ifp) /* Remove link local addresses from interface */ lck_rw_lock_exclusive(&in6_ifaddr_rwlock); - ia = in6_ifaddrs; - while (ia != NULL) { - if (ia->ia_ifa.ifa_ifp != ifp) { - ia = ia->ia_next; - continue; - } - IFA_LOCK(&ia->ia_ifa); - if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr)) { - IFA_ADDREF_LOCKED(&ia->ia_ifa); /* for us */ + boolean_t from_begining = TRUE; + while (from_begining) { + from_begining = FALSE; + TAILQ_FOREACH(ia, &in6_ifaddrhead, ia6_link) { + if (ia->ia_ifa.ifa_ifp != ifp) { + continue; + } + IFA_LOCK(&ia->ia_ifa); + if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr)) { + IFA_ADDREF_LOCKED(&ia->ia_ifa); /* for us */ + IFA_UNLOCK(&ia->ia_ifa); + lck_rw_done(&in6_ifaddr_rwlock); + in6_purgeaddr(&ia->ia_ifa); + IFA_REMREF(&ia->ia_ifa); /* for us */ + lck_rw_lock_exclusive(&in6_ifaddr_rwlock); + /* + * Purging the address caused in6_ifaddr_rwlock + * to be dropped and reacquired; + * therefore search again from the beginning + * of in6_ifaddrs list. + */ + from_begining = TRUE; + break; + } IFA_UNLOCK(&ia->ia_ifa); - lck_rw_done(&in6_ifaddr_rwlock); - in6_purgeaddr(&ia->ia_ifa); - IFA_REMREF(&ia->ia_ifa); /* for us */ - lck_rw_lock_exclusive(&in6_ifaddr_rwlock); - /* - * Purging the address caused in6_ifaddr_rwlock - * to be dropped and reacquired; - * therefore search again from the beginning - * of in6_ifaddrs list. - */ - ia = in6_ifaddrs; - continue; } - IFA_UNLOCK(&ia->ia_ifa); - ia = ia->ia_next; } lck_rw_done(&in6_ifaddr_rwlock); @@ -1856,31 +1870,32 @@ in6_autoconf(struct ifnet *ifp, int enable) /* Remove autoconfigured address from interface */ lck_rw_lock_exclusive(&in6_ifaddr_rwlock); - ia = in6_ifaddrs; - while (ia != NULL) { - if (ia->ia_ifa.ifa_ifp != ifp) { - ia = ia->ia_next; - continue; - } - IFA_LOCK(&ia->ia_ifa); - if (ia->ia6_flags & IN6_IFF_AUTOCONF) { - IFA_ADDREF_LOCKED(&ia->ia_ifa); /* for us */ + boolean_t from_begining = TRUE; + while (from_begining) { + from_begining = FALSE; + TAILQ_FOREACH(ia, &in6_ifaddrhead, ia6_link) { + if (ia->ia_ifa.ifa_ifp != ifp) { + continue; + } + IFA_LOCK(&ia->ia_ifa); + if (ia->ia6_flags & IN6_IFF_AUTOCONF) { + IFA_ADDREF_LOCKED(&ia->ia_ifa); /* for us */ + IFA_UNLOCK(&ia->ia_ifa); + lck_rw_done(&in6_ifaddr_rwlock); + in6_purgeaddr(&ia->ia_ifa); + IFA_REMREF(&ia->ia_ifa); /* for us */ + lck_rw_lock_exclusive(&in6_ifaddr_rwlock); + /* + * Purging the address caused in6_ifaddr_rwlock + * to be dropped and reacquired; + * therefore search again from the beginning + * of in6_ifaddrs list. + */ + from_begining = TRUE; + break; + } IFA_UNLOCK(&ia->ia_ifa); - lck_rw_done(&in6_ifaddr_rwlock); - in6_purgeaddr(&ia->ia_ifa); - IFA_REMREF(&ia->ia_ifa); /* for us */ - lck_rw_lock_exclusive(&in6_ifaddr_rwlock); - /* - * Purging the address caused in6_ifaddr_rwlock - * to be dropped and reacquired; - * therefore search again from the beginning - * of in6_ifaddrs list. - */ - ia = in6_ifaddrs; - continue; } - IFA_UNLOCK(&ia->ia_ifa); - ia = ia->ia_next; } lck_rw_done(&in6_ifaddr_rwlock); } @@ -2414,6 +2429,7 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, int ifaupflags, * Please enjoy the dancing sea turtle. */ IFA_ADDREF(ifa); /* for this and optionally for caller */ + IA6_HASH_INIT(ia); ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr; if (ifra->ifra_dstaddr.sin6_family == AF_INET6 || (ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) { @@ -2462,16 +2478,7 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, int ifaupflags, ifnet_lock_done(ifp); lck_rw_lock_exclusive(&in6_ifaddr_rwlock); - if (in6_ifaddrs != NULL) { - struct in6_ifaddr *iac; - for (iac = in6_ifaddrs; iac->ia_next != NULL; - iac = iac->ia_next) { - continue; - } - iac->ia_next = ia; - } else { - in6_ifaddrs = ia; - } + TAILQ_INSERT_TAIL(&in6_ifaddrhead, ia, ia6_link); IFA_ADDREF(ifa); /* hold for in6_ifaddrs link */ lck_rw_done(&in6_ifaddr_rwlock); } else { @@ -2610,7 +2617,7 @@ in6_purgeaddr(struct ifaddr *ifa) static void in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp) { - struct in6_ifaddr *oia; + struct in6_ifaddr *nia; struct ifaddr *ifa; int unlinked; @@ -2627,21 +2634,18 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp) IFA_UNLOCK(ifa); ifnet_lock_done(ifp); - unlinked = 1; + unlinked = 0; lck_rw_lock_exclusive(&in6_ifaddr_rwlock); - oia = ia; - if (oia == (ia = in6_ifaddrs)) { - in6_ifaddrs = ia->ia_next; - } else { - while (ia->ia_next && (ia->ia_next != oia)) { - ia = ia->ia_next; - } - if (ia->ia_next) { - ia->ia_next = oia->ia_next; - } else { - /* search failed */ - log(LOG_NOTICE, "%s: search failed.\n", __func__); - unlinked = 0; + TAILQ_FOREACH(nia, &in6_ifaddrhead, ia6_link) { + if (ia == nia) { + TAILQ_REMOVE(&in6_ifaddrhead, ia, ia6_link); + IFA_LOCK(ifa); + if (IA6_IS_HASHED(ia)) { + in6_iahash_remove(ia); + } + IFA_UNLOCK(ifa); + unlinked = 1; + break; } } @@ -2652,7 +2656,6 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp) * of other (detached) addresses, call * pfxlist_onlink_check(). */ - ifa = &oia->ia_ifa; IFA_LOCK(ifa); /* * Only log the below message for addresses other than @@ -2666,19 +2669,19 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp) * * For now quiece down the log message for LLAs. */ - if (!IN6_IS_ADDR_LINKLOCAL(&oia->ia_addr.sin6_addr)) { - if (oia->ia6_ndpr == NULL) { + if (!IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr)) { + if (ia->ia6_ndpr == NULL) { log(LOG_NOTICE, "in6_unlink_ifa: IPv6 address " "0x%llx has no prefix\n", - (uint64_t)VM_KERNEL_ADDRPERM(oia)); + (uint64_t)VM_KERNEL_ADDRPERM(ia)); } else { - struct nd_prefix *pr = oia->ia6_ndpr; - oia->ia6_flags &= ~IN6_IFF_AUTOCONF; - oia->ia6_ndpr = NULL; + struct nd_prefix *pr = ia->ia6_ndpr; + ia->ia6_flags &= ~IN6_IFF_AUTOCONF; + ia->ia6_ndpr = NULL; NDPR_LOCK(pr); VERIFY(pr->ndpr_addrcnt != 0); pr->ndpr_addrcnt--; - if (oia->ia6_flags & IN6_IFF_CLAT46) { + if (ia->ia6_flags & IN6_IFF_CLAT46) { pr->ndpr_stateflags &= ~NDPRF_CLAT46; } NDPR_UNLOCK(pr); @@ -2688,7 +2691,7 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp) IFA_UNLOCK(ifa); lck_rw_done(&in6_ifaddr_rwlock); - if ((oia->ia6_flags & IN6_IFF_AUTOCONF) != 0) { + if ((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0) { lck_mtx_lock(nd6_mutex); pfxlist_onlink_check(); lck_mtx_unlock(nd6_mutex); @@ -2721,24 +2724,27 @@ in6_purgeif(struct ifnet *ifp) LCK_MTX_ASSERT(nd6_mutex, LCK_MTX_ASSERT_NOTOWNED); lck_rw_lock_exclusive(&in6_ifaddr_rwlock); - ia = in6_ifaddrs; - while (ia != NULL) { - if (ia->ia_ifa.ifa_ifp != ifp) { - ia = ia->ia_next; - continue; + boolean_t from_begining = TRUE; + while (from_begining) { + from_begining = FALSE; + TAILQ_FOREACH(ia, &in6_ifaddrhead, ia6_link) { + if (ia->ia_ifa.ifa_ifp != ifp) { + continue; + } + IFA_ADDREF(&ia->ia_ifa); /* for us */ + lck_rw_done(&in6_ifaddr_rwlock); + in6_purgeaddr(&ia->ia_ifa); + IFA_REMREF(&ia->ia_ifa); /* for us */ + lck_rw_lock_exclusive(&in6_ifaddr_rwlock); + /* + * Purging the address would have caused + * in6_ifaddr_rwlock to be dropped and reacquired; + * therefore search again from the beginning + * of in6_ifaddrs list. + */ + from_begining = TRUE; + break; } - IFA_ADDREF(&ia->ia_ifa); /* for us */ - lck_rw_done(&in6_ifaddr_rwlock); - in6_purgeaddr(&ia->ia_ifa); - IFA_REMREF(&ia->ia_ifa); /* for us */ - lck_rw_lock_exclusive(&in6_ifaddr_rwlock); - /* - * Purging the address would have caused - * in6_ifaddr_rwlock to be dropped and reacquired; - * therefore search again from the beginning - * of in6_ifaddrs list. - */ - ia = in6_ifaddrs; } lck_rw_done(&in6_ifaddr_rwlock); @@ -2757,6 +2763,19 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia, int ifaupflags) error = 0; ifa = &ia->ia_ifa; + lck_rw_lock_exclusive(&in6_ifaddr_rwlock); + IFA_LOCK(&ia->ia_ifa); + if (IA6_IS_HASHED(ia)) { + in6_iahash_remove(ia); + } + if ((ifp->if_flags & IFF_POINTOPOINT)) { + in6_iahash_insert_ptp(ia); + } else { + in6_iahash_insert(ia); + } + IFA_UNLOCK(&ia->ia_ifa); + lck_rw_done(&in6_ifaddr_rwlock); + /* * NOTE: SIOCSIFADDR is defined with struct ifreq as parameter, * but here we are sending it down to the interface with a pointer @@ -2766,7 +2785,7 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia, int ifaupflags) error = ifnet_ioctl(ifp, PF_INET6, SIOCSIFADDR, ia); if (error != 0) { if (error != EOPNOTSUPP) { - return error; + goto failed; } error = 0; } @@ -2785,7 +2804,7 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia, int ifaupflags) IFA_UNLOCK(ifa); error = rtinit(ifa, RTM_ADD, RTF_UP | RTF_HOST); if (error != 0) { - return error; + goto failed; } IFA_LOCK(ifa); ia->ia_flags |= IFA_ROUTE; @@ -2810,6 +2829,17 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia, int ifaupflags) VERIFY(error == 0); return 0; +failed: + VERIFY(error != 0); + lck_rw_lock_exclusive(&in6_ifaddr_rwlock); + IFA_LOCK(&ia->ia_ifa); + if (IA6_IS_HASHED(ia)) { + in6_iahash_remove(ia); + } + IFA_UNLOCK(&ia->ia_ifa); + lck_rw_done(&in6_ifaddr_rwlock); + + return error; } void @@ -2910,7 +2940,7 @@ in6ifa_prproxyaddr(struct in6_addr *addr) struct in6_ifaddr *ia; lck_rw_lock_shared(&in6_ifaddr_rwlock); - for (ia = in6_ifaddrs; ia; ia = ia->ia_next) { + TAILQ_FOREACH(ia, IN6ADDR_HASH(addr), ia6_hash) { IFA_LOCK(&ia->ia_ifa); if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(&ia->ia_ifa))) { IFA_ADDREF_LOCKED(&ia->ia_ifa); /* for caller */ @@ -3103,7 +3133,7 @@ in6_localaddr(struct in6_addr *in6) } lck_rw_lock_shared(&in6_ifaddr_rwlock); - for (ia = in6_ifaddrs; ia; ia = ia->ia_next) { + TAILQ_FOREACH(ia, &in6_ifaddrhead, ia6_link) { IFA_LOCK_SPIN(&ia->ia_ifa); if (IN6_ARE_MASKED_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr, &ia->ia_prefixmask.sin6_addr)) { @@ -4883,3 +4913,94 @@ in6_event_enqueue_nwk_wq_entry(in6_evhdlr_code_t in6_event_code, nwk_wq_enqueue((struct nwk_wq_entry*)p_in6_ev); } + +/* + * Caller must hold in6_ifaddr_rwlock as writer. + */ +static void +in6_iahash_remove(struct in6_ifaddr *ia) +{ + LCK_RW_ASSERT(&in6_ifaddr_rwlock, LCK_RW_ASSERT_EXCLUSIVE); + IFA_LOCK_ASSERT_HELD(&ia->ia_ifa); + + if (!IA6_IS_HASHED(ia)) { + panic("%s: attempt to remove wrong ia %p from ipv6 hash table\n", __func__, ia); + /* NOTREACHED */ + } + TAILQ_REMOVE(IN6ADDR_HASH(&ia->ia_addr.sin6_addr), ia, ia6_hash); + IA6_HASH_INIT(ia); + if (IFA_REMREF_LOCKED(&ia->ia_ifa) == NULL) { + panic("%s: unexpected (missing) refcnt ifa=%p", __func__, + &ia->ia_ifa); + /* NOTREACHED */ + } +} + +/* + * Caller must hold in6_ifaddr_rwlock as writer. + */ +static void +in6_iahash_insert(struct in6_ifaddr *ia) +{ + LCK_RW_ASSERT(&in6_ifaddr_rwlock, LCK_RW_ASSERT_EXCLUSIVE); + IFA_LOCK_ASSERT_HELD(&ia->ia_ifa); + + if (ia->ia_addr.sin6_family != AF_INET6) { + panic("%s: attempt to insert wrong ia %p into hash table\n", __func__, ia); + /* NOTREACHED */ + } else if (IA6_IS_HASHED(ia)) { + panic("%s: attempt to double-insert ia %p into hash table\n", __func__, ia); + /* NOTREACHED */ + } + TAILQ_INSERT_HEAD(IN6ADDR_HASH(&ia->ia_addr.sin6_addr), + ia, ia6_hash); + IFA_ADDREF_LOCKED(&ia->ia_ifa); +} + +/* + * Some point to point interfaces that are tunnels borrow the address from + * an underlying interface (e.g. VPN server). In order for source address + * selection logic to find the underlying interface first, we add the address + * of borrowing point to point interfaces at the end of the list. + * (see rdar://6733789) + * + * Caller must hold in6_ifaddr_rwlock as writer. + */ +static void +in6_iahash_insert_ptp(struct in6_ifaddr *ia) +{ + struct in6_ifaddr *tmp_ifa; + struct ifnet *tmp_ifp; + + LCK_RW_ASSERT(&in6_ifaddr_rwlock, LCK_RW_ASSERT_EXCLUSIVE); + IFA_LOCK_ASSERT_HELD(&ia->ia_ifa); + + if (ia->ia_addr.sin6_family != AF_INET6) { + panic("%s: attempt to insert wrong ia %p into hash table\n", __func__, ia); + /* NOTREACHED */ + } else if (IA6_IS_HASHED(ia)) { + panic("%s: attempt to double-insert ia %p into hash table\n", __func__, ia); + /* NOTREACHED */ + } + IFA_UNLOCK(&ia->ia_ifa); + TAILQ_FOREACH(tmp_ifa, IN6ADDR_HASH(&ia->ia_addr.sin6_addr), ia6_hash) { + IFA_LOCK(&tmp_ifa->ia_ifa); + /* ia->ia_addr won't change, so check without lock */ + if (IN6_ARE_ADDR_EQUAL(&tmp_ifa->ia_addr.sin6_addr, &ia->ia_addr.sin6_addr)) { + IFA_UNLOCK(&tmp_ifa->ia_ifa); + break; + } + IFA_UNLOCK(&tmp_ifa->ia_ifa); + } + tmp_ifp = (tmp_ifa == NULL) ? NULL : tmp_ifa->ia_ifp; + + IFA_LOCK(&ia->ia_ifa); + if (tmp_ifp == NULL) { + TAILQ_INSERT_HEAD(IN6ADDR_HASH(&ia->ia_addr.sin6_addr), + ia, ia6_hash); + } else { + TAILQ_INSERT_TAIL(IN6ADDR_HASH(&ia->ia_addr.sin6_addr), + ia, ia6_hash); + } + IFA_ADDREF_LOCKED(&ia->ia_ifa); +} diff --git a/bsd/netinet6/in6_ifattach.c b/bsd/netinet6/in6_ifattach.c index bd4ad95c0..194e996e1 100644 --- a/bsd/netinet6/in6_ifattach.c +++ b/bsd/netinet6/in6_ifattach.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2018 Apple Inc. All rights reserved. + * Copyright (c) 2003-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -1032,7 +1032,7 @@ in6_ifattach_llcgareq(struct ifnet *ifp, struct in6_cgareq *llcgasr) void in6_ifdetach(struct ifnet *ifp) { - struct in6_ifaddr *ia, *oia; + struct in6_ifaddr *ia, *nia; struct ifaddr *ifa; struct rtentry *rt; struct sockaddr_in6 sin6; @@ -1050,24 +1050,27 @@ in6_ifdetach(struct ifnet *ifp) /* nuke any of IPv6 addresses we have */ lck_rw_lock_exclusive(&in6_ifaddr_rwlock); - ia = in6_ifaddrs; - while (ia != NULL) { - if (ia->ia_ifa.ifa_ifp != ifp) { - ia = ia->ia_next; - continue; + boolean_t from_begining = TRUE; + while (from_begining) { + from_begining = FALSE; + TAILQ_FOREACH(ia, &in6_ifaddrhead, ia6_link) { + if (ia->ia_ifa.ifa_ifp != ifp) { + continue; + } + IFA_ADDREF(&ia->ia_ifa); /* for us */ + lck_rw_done(&in6_ifaddr_rwlock); + in6_purgeaddr(&ia->ia_ifa); + IFA_REMREF(&ia->ia_ifa); /* for us */ + lck_rw_lock_exclusive(&in6_ifaddr_rwlock); + /* + * Purging the address caused in6_ifaddr_rwlock + * to be dropped and reacquired; + * therefore search again from the beginning + * of in6_ifaddrs list. + */ + from_begining = TRUE; + break; } - IFA_ADDREF(&ia->ia_ifa); /* for us */ - lck_rw_done(&in6_ifaddr_rwlock); - in6_purgeaddr(&ia->ia_ifa); - IFA_REMREF(&ia->ia_ifa); /* for us */ - lck_rw_lock_exclusive(&in6_ifaddr_rwlock); - /* - * Purging the address caused in6_ifaddr_rwlock - * to be dropped and reacquired; - * therefore search again from the beginning - * of in6_ifaddrs list. - */ - ia = in6_ifaddrs; } lck_rw_done(&in6_ifaddr_rwlock); @@ -1135,27 +1138,17 @@ in6_ifdetach(struct ifnet *ifp) } /* also remove from the IPv6 address chain(itojun&jinmei) */ - unlinked = 1; - oia = ia; + unlinked = 0; lck_rw_lock_exclusive(&in6_ifaddr_rwlock); - if (oia == (ia = in6_ifaddrs)) { - in6_ifaddrs = ia->ia_next; - } else { - while (ia->ia_next && (ia->ia_next != oia)) { - ia = ia->ia_next; - } - if (ia->ia_next) { - ia->ia_next = oia->ia_next; - } else { - nd6log(error, - "%s: didn't unlink in6ifaddr from " - "list\n", if_name(ifp)); - unlinked = 0; + TAILQ_FOREACH(nia, &in6_ifaddrhead, ia6_link) { + if (ia == nia) { + TAILQ_REMOVE(&in6_ifaddrhead, ia, ia6_link); + unlinked = 1; + break; } } lck_rw_done(&in6_ifaddr_rwlock); - ifa = &oia->ia_ifa; /* * release another refcnt for the link from in6_ifaddrs. * Do this only if it's not already unlinked in the event diff --git a/bsd/netinet6/in6_pcb.c b/bsd/netinet6/in6_pcb.c index c1d2ff08e..1af6aa583 100644 --- a/bsd/netinet6/in6_pcb.c +++ b/bsd/netinet6/in6_pcb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2019 Apple Inc. All rights reserved. + * Copyright (c) 2003-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -200,7 +200,7 @@ in6_pcbbind(struct inpcb *inp, struct sockaddr *nam, struct proc *p) kauth_cred_t cred; #endif /* !CONFIG_EMBEDDED */ - if (!in6_ifaddrs) { /* XXX broken! */ + if (TAILQ_EMPTY(&in6_ifaddrhead)) { /* XXX broken! */ return EADDRNOTAVAIL; } if (!(so->so_options & (SO_REUSEADDR | SO_REUSEPORT))) { @@ -489,7 +489,7 @@ in6_pcbladdr(struct inpcb *inp, struct sockaddr *nam, return EINVAL; } - if (in6_ifaddrs) { + if (!TAILQ_EMPTY(&in6_ifaddrhead)) { /* * If the destination address is UNSPECIFIED addr, * use the loopback addr, e.g ::1. diff --git a/bsd/netinet6/in6_src.c b/bsd/netinet6/in6_src.c index f018e5111..4af6fed4a 100644 --- a/bsd/netinet6/in6_src.c +++ b/bsd/netinet6/in6_src.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2019 Apple Inc. All rights reserved. + * Copyright (c) 2000-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -318,7 +318,7 @@ in6_selectsrc_core(struct sockaddr_in6 *dstsock, uint32_t hint_mask, } lck_rw_lock_shared(&in6_ifaddr_rwlock); - for (ia = in6_ifaddrs; ia; ia = ia->ia_next) { + TAILQ_FOREACH(ia, &in6_ifaddrhead, ia6_link) { int new_scope = -1, new_matchlen = -1; struct in6_addrpolicy *new_policy = NULL; u_int32_t srczone = 0, osrczone, dstzone; diff --git a/bsd/netinet6/in6_var.h b/bsd/netinet6/in6_var.h index b7c080352..bd1a424ae 100644 --- a/bsd/netinet6/in6_var.h +++ b/bsd/netinet6/in6_var.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2018 Apple Inc. All rights reserved. + * Copyright (c) 2000-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -161,7 +161,8 @@ struct in6_ifaddr { struct sockaddr_in6 ia_dstaddr; /* space for destination addr */ struct sockaddr_in6 ia_prefixmask; /* prefix mask */ u_int32_t ia_plen; /* prefix length */ - struct in6_ifaddr *ia_next; /* next in6 list of IP6 addresses */ + TAILQ_ENTRY(in6_ifaddr) ia6_link; /* next in6 list of IP6 addresses */ + TAILQ_ENTRY(in6_ifaddr) ia6_hash; /* hash bucket entry */ int ia6_flags; struct in6_addrlifetime_i ia6_lifetime; @@ -180,6 +181,34 @@ struct in6_ifaddr { }; #define ifatoia6(ifa) ((struct in6_ifaddr *)(void *)(ifa)) + +extern TAILQ_HEAD(in6_ifaddrhead, in6_ifaddr) in6_ifaddrhead; +extern TAILQ_HEAD(in6_ifaddrhashhead, in6_ifaddr) * in6_ifaddrhashtbl; +extern uint32_t in6addr_nhash; /* hash table size */ +extern uint32_t in6addr_hashp; /* next largest prime */ + +static __inline uint32_t +in6addr_hashval(const struct in6_addr *in6) +{ + /* + * The hash index is the computed prime times the key modulo + * the hash size, as documented in "Introduction to Algorithms" + * (Cormen, Leiserson, Rivest). + */ + if (in6addr_nhash > 1) { + uint32_t x; + + x = in6->s6_addr32[0] ^ in6->s6_addr32[1] ^ in6->s6_addr32[2] ^ + in6->s6_addr32[3]; + + return (x * in6addr_hashp) % in6addr_nhash; + } else { + return 0; + } +} + +#define IN6ADDR_HASH(x) (&in6_ifaddrhashtbl[in6addr_hashval(x)]) + #endif /* BSD_KERNEL_PRIVATE */ /* control structure to manage address selection policy */ @@ -775,8 +804,6 @@ void in6_post_msg(struct ifnet *, u_int32_t, struct in6_ifaddr *, uint8_t *mac); #endif /* KERNEL */ #ifdef BSD_KERNEL_PRIVATE -extern struct in6_ifaddr *in6_ifaddrs; - extern struct icmp6stat icmp6stat; extern lck_rw_t in6_ifaddr_rwlock; extern lck_mtx_t proxy6_lock; diff --git a/bsd/netinet6/ip6_input.c b/bsd/netinet6/ip6_input.c index 8d9241fc1..0a9a2d13a 100644 --- a/bsd/netinet6/ip6_input.c +++ b/bsd/netinet6/ip6_input.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2018 Apple Inc. All rights reserved. + * Copyright (c) 2003-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -131,6 +131,7 @@ #endif /* INET */ #include #include +#include #include #include #include @@ -158,6 +159,8 @@ extern int ipsec_bypass; #include #endif /* PF */ +#include + struct ip6protosw *ip6_protox[IPPROTO_MAX]; static lck_grp_attr_t *in6_ifaddr_rwlock_grp_attr; @@ -166,7 +169,14 @@ static lck_attr_t *in6_ifaddr_rwlock_attr; decl_lck_rw_data(, in6_ifaddr_rwlock); /* Protected by in6_ifaddr_rwlock */ -struct in6_ifaddr *in6_ifaddrs = NULL; +struct in6_ifaddrhead in6_ifaddrhead; +struct in6_ifaddrhashhead * in6_ifaddrhashtbl; +uint32_t in6_ifaddrhmask; + +#define IN6ADDR_NHASH 61 +u_int32_t in6addr_nhash = 0; /* hash table size */ +u_int32_t in6addr_hashp = 0; /* next largest prime */ + #define IN6_IFSTAT_REQUIRE_ALIGNED_64(f) \ _CASSERT(!(offsetof(struct in6_ifstat, f) % sizeof (uint64_t))) @@ -200,6 +210,8 @@ static int sysctl_ip6_input_getperf SYSCTL_HANDLER_ARGS; static void ip6_init_delayed(void); static int ip6_hopopts_input(u_int32_t *, u_int32_t *, struct mbuf **, int *); +static void in6_ifaddrhashtbl_init(void); + #if NSTF extern void stfattach(void); #endif /* NSTF */ @@ -233,6 +245,61 @@ SYSCTL_PROC(_net_inet6_ip6, OID_AUTO, input_perf_data, 0, 0, sysctl_ip6_input_getperf, "S,net_perf", "IP6 input performance data (struct net_perf, net/net_perf.h)"); +/* + * ip6_checkinterface controls the receive side of the models for multihoming + * that are discussed in RFC 1122. + * + * sysctl_ip6_checkinterface values are: + * IP6_CHECKINTERFACE_WEAK_ES: + * This corresponds to the Weak End-System model where incoming packets from + * any interface are accepted provided the destination address of the incoming packet + * is assigned to some interface. + * + * IP6_CHECKINTERFACE_HYBRID_ES: + * The Hybrid End-System model use the Strong End-System for tunnel interfaces + * (ipsec and utun) and the weak End-System model for other interfaces families. + * This prevents a rogue middle box to probe for signs of TCP connections + * that use the tunnel interface. + * + * IP6_CHECKINTERFACE_STRONG_ES: + * The Strong model model requires the packet arrived on an interface that + * is assigned the destination address of the packet. + * + * Since the routing table and transmit implementation do not implement the Strong ES model, + * setting this to a value different from IP6_CHECKINTERFACE_WEAK_ES may lead to unexpected results. + * + * When forwarding is enabled, the system reverts to the Weak ES model as a router + * is expected by design to receive packets from several interfaces to the same address. + */ +#define IP6_CHECKINTERFACE_WEAK_ES 0 +#define IP6_CHECKINTERFACE_HYBRID_ES 1 +#define IP6_CHECKINTERFACE_STRONG_ES 2 + +static int ip6_checkinterface = IP6_CHECKINTERFACE_HYBRID_ES; + +static int sysctl_ip6_checkinterface SYSCTL_HANDLER_ARGS; +SYSCTL_PROC(_net_inet6_ip6, OID_AUTO, check_interface, + CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, + 0, 0, sysctl_ip6_checkinterface, "I", "Verify packet arrives on correct interface"); + +#if (DEBUG || DEVELOPMENT) +#define IP6_CHECK_IFDEBUG 1 +#else +#define IP6_CHECK_IFDEBUG 0 +#endif /* (DEBUG || DEVELOPMENT) */ +static int ip6_checkinterface_debug = IP6_CHECK_IFDEBUG; +SYSCTL_INT(_net_inet6_ip6, OID_AUTO, checkinterface_debug, CTLFLAG_RW | CTLFLAG_LOCKED, + &ip6_checkinterface_debug, IP6_CHECK_IFDEBUG, ""); + +typedef enum ip6_check_if_result { + IP6_CHECK_IF_NONE = 0, + IP6_CHECK_IF_OURS = 1, + IP6_CHECK_IF_DROP = 2, + IP6_CHECK_IF_FORWARD = 3 +} ip6_check_if_result_t; + +static ip6_check_if_result_t ip6_input_check_interface(struct mbuf *, struct ip6_hdr *, struct ifnet *, struct route_in6 *rin6, struct ifnet **); + /* * On platforms which require strict alignment (currently for anything but * i386 or x86_64), check if the IP header pointer is 32-bit aligned; if not, @@ -376,6 +443,9 @@ ip6_init(struct ip6protosw *pp, struct domain *dp) lck_rw_init(&in6_ifaddr_rwlock, in6_ifaddr_rwlock_grp, in6_ifaddr_rwlock_attr); + TAILQ_INIT(&in6_ifaddrhead); + in6_ifaddrhashtbl_init(); + IN6_IFSTAT_REQUIRE_ALIGNED_64(ifs6_in_receive); IN6_IFSTAT_REQUIRE_ALIGNED_64(ifs6_in_hdrerr); IN6_IFSTAT_REQUIRE_ALIGNED_64(ifs6_in_toobig); @@ -437,6 +507,17 @@ ip6_init(struct ip6protosw *pp, struct domain *dp) ip6_desync_factor = (RandomULong() ^ tv.tv_usec) % MAX_TEMP_DESYNC_FACTOR; + PE_parse_boot_argn("ip6_checkinterface", &i, sizeof(i)); + switch (i) { + case IP6_CHECKINTERFACE_WEAK_ES: + case IP6_CHECKINTERFACE_HYBRID_ES: + case IP6_CHECKINTERFACE_STRONG_ES: + ip6_checkinterface = i; + break; + default: + break; + } + in6_ifaddr_init(); ip6_moptions_init(); nd6_init(); @@ -547,6 +628,171 @@ ip6_input_adjust(struct mbuf *m, struct ip6_hdr *ip6, uint32_t plen, } } } +static ip6_check_if_result_t +ip6_input_check_interface(struct mbuf *m, struct ip6_hdr *ip6, struct ifnet *inifp, struct route_in6 *rin6, struct ifnet **deliverifp) +{ + struct in6_ifaddr *ia6 = NULL; + struct in6_addr tmp_dst = ip6->ip6_dst; /* copy to avoid unaligned access */ + struct in6_ifaddr *best_ia6 = NULL; + ip6_check_if_result_t result = IP6_CHECK_IF_NONE; + + *deliverifp = NULL; + + /* + * Check for exact addresses in the hash bucket. + */ + lck_rw_lock_shared(&in6_ifaddr_rwlock); + TAILQ_FOREACH(ia6, IN6ADDR_HASH(&tmp_dst), ia6_hash) { + /* + * TODO: should we accept loopbacl + */ + if (IN6_ARE_ADDR_EQUAL(&ia6->ia_addr.sin6_addr, &tmp_dst)) { + if ((ia6->ia6_flags & (IN6_IFF_NOTREADY | IN6_IFF_CLAT46))) { + continue; + } + best_ia6 = ia6; + if (ia6->ia_ifp == inifp) { + /* + * TODO: should we also accept locally originated packets + * or from loopback ??? + */ + break; + } + /* + * Continue the loop in case there's a exact match with another + * interface + */ + } + } + if (best_ia6 != NULL) { + if (best_ia6->ia_ifp != inifp && ip6_forwarding == 0 && + ((ip6_checkinterface == IP6_CHECKINTERFACE_HYBRID_ES && + (best_ia6->ia_ifp->if_family == IFNET_FAMILY_IPSEC || + best_ia6->ia_ifp->if_family == IFNET_FAMILY_UTUN)) || + ip6_checkinterface == IP6_CHECKINTERFACE_STRONG_ES)) { + /* + * Drop when interface address check is strict and forwarding + * is disabled + */ + result = IP6_CHECK_IF_DROP; + } else { + result = IP6_CHECK_IF_OURS; + *deliverifp = best_ia6->ia_ifp; + ip6_setdstifaddr_info(m, 0, best_ia6); + } + } + lck_rw_done(&in6_ifaddr_rwlock); + + if (result == IP6_CHECK_IF_NONE) { + /* + * Slow path: route lookup. + */ + struct sockaddr_in6 *dst6; + + dst6 = SIN6(&rin6->ro_dst); + dst6->sin6_len = sizeof(struct sockaddr_in6); + dst6->sin6_family = AF_INET6; + dst6->sin6_addr = ip6->ip6_dst; + + rtalloc_scoped_ign((struct route *)rin6, + RTF_PRCLONING, IFSCOPE_NONE); + if (rin6->ro_rt != NULL) { + RT_LOCK_SPIN(rin6->ro_rt); + } + +#define rt6_key(r) (SIN6((r)->rt_nodes->rn_key)) + + /* + * Accept the packet if the forwarding interface to the destination + * according to the routing table is the loopback interface, + * unless the associated route has a gateway. + * Note that this approach causes to accept a packet if there is a + * route to the loopback interface for the destination of the packet. + * But we think it's even useful in some situations, e.g. when using + * a special daemon which wants to intercept the packet. + * + * XXX: some OSes automatically make a cloned route for the destination + * of an outgoing packet. If the outgoing interface of the packet + * is a loopback one, the kernel would consider the packet to be + * accepted, even if we have no such address assinged on the interface. + * We check the cloned flag of the route entry to reject such cases, + * assuming that route entries for our own addresses are not made by + * cloning (it should be true because in6_addloop explicitly installs + * the host route). However, we might have to do an explicit check + * while it would be less efficient. Or, should we rather install a + * reject route for such a case? + */ + if (rin6->ro_rt != NULL && + (rin6->ro_rt->rt_flags & (RTF_HOST | RTF_GATEWAY)) == RTF_HOST && +#if RTF_WASCLONED + !(rin6->ro_rt->rt_flags & RTF_WASCLONED) && +#endif + rin6->ro_rt->rt_ifp->if_type == IFT_LOOP) { + ia6 = (struct in6_ifaddr *)rin6->ro_rt->rt_ifa; + /* + * Packets to a tentative, duplicated, or somehow invalid + * address must not be accepted. + * + * For performance, test without acquiring the address lock; + * a lot of things in the address are set once and never + * changed (e.g. ia_ifp.) + */ + if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) { + /* this address is ready */ + result = IP6_CHECK_IF_OURS; + *deliverifp = ia6->ia_ifp; /* correct? */ + /* + * record dst address information into mbuf. + */ + (void) ip6_setdstifaddr_info(m, 0, ia6); + } + } + + if (rin6->ro_rt != NULL) { + RT_UNLOCK(rin6->ro_rt); + } + } + + if (result == IP6_CHECK_IF_NONE) { + if (ip6_forwarding == 0) { + result = IP6_CHECK_IF_DROP; + } else { + result = IP6_CHECK_IF_FORWARD; + ip6_setdstifaddr_info(m, inifp->if_index, NULL); + } + } + + if (result == IP6_CHECK_IF_OURS && *deliverifp != inifp) { + ASSERT(*deliverifp != NULL); + ip6stat.ip6s_rcv_if_weak_match++; + + /* Logging is too noisy when forwarding is enabled */ + if (ip6_checkinterface_debug != IP6_CHECKINTERFACE_WEAK_ES && ip6_forwarding != 0) { + char src_str[MAX_IPv6_STR_LEN]; + char dst_str[MAX_IPv6_STR_LEN]; + + inet_ntop(AF_INET6, &ip6->ip6_src, src_str, sizeof(src_str)); + inet_ntop(AF_INET6, &ip6->ip6_dst, dst_str, sizeof(dst_str)); + os_log_info(OS_LOG_DEFAULT, + "%s: weak ES interface match to %s for packet from %s to %s proto %u received via %s", + __func__, (*deliverifp)->if_xname, src_str, dst_str, ip6->ip6_nxt, inifp->if_xname); + } + } else if (result == IP6_CHECK_IF_DROP) { + ip6stat.ip6s_rcv_if_no_match++; + if (ip6_checkinterface_debug > 0) { + char src_str[MAX_IPv6_STR_LEN]; + char dst_str[MAX_IPv6_STR_LEN]; + + inet_ntop(AF_INET6, &ip6->ip6_src, src_str, sizeof(src_str)); + inet_ntop(AF_INET6, &ip6->ip6_dst, dst_str, sizeof(dst_str)); + os_log_info(OS_LOG_DEFAULT, + "%s: no interface match for packet from %s to %s proto %u received via %s", + __func__, src_str, dst_str, ip6->ip6_nxt, inifp->if_xname); + } + } + + return result; +} void ip6_input(struct mbuf *m) @@ -559,22 +805,11 @@ ip6_input(struct mbuf *m) struct ifnet *inifp, *deliverifp = NULL; ipfilter_t inject_ipfref = NULL; int seen = 1; - struct in6_ifaddr *ia6 = NULL; - struct sockaddr_in6 *dst6; #if DUMMYNET struct m_tag *tag; + struct ip_fw_args args = {}; #endif /* DUMMYNET */ - struct { - struct route_in6 rin6; -#if DUMMYNET - struct ip_fw_args args; -#endif /* DUMMYNET */ - } ip6ibz; -#define rin6 ip6ibz.rin6 -#define args ip6ibz.args - - /* zero out {rin6, args} */ - bzero(&ip6ibz, sizeof(ip6ibz)); + struct route_in6 rin6 = {}; /* * Check if the packet we received is valid after interface filter @@ -885,126 +1120,36 @@ check_with_pf: goto bad; } deliverifp = inifp; - VERIFY(ia6 == NULL); - goto hbhcheck; - } - - /* - * Unicast check - * - * Fast path: see if the target is ourselves. - */ - lck_rw_lock_shared(&in6_ifaddr_rwlock); - for (ia6 = in6_ifaddrs; ia6 != NULL; ia6 = ia6->ia_next) { /* - * No reference is held on the address, as we just need - * to test for a few things while holding the RW lock. + * record dst address information into mbuf, if we don't have one yet. + * note that we are unable to record it, if the address is not listed + * as our interface address (e.g. multicast addresses, etc.) */ - if (IN6_ARE_ADDR_EQUAL(&ia6->ia_addr.sin6_addr, &ip6->ip6_dst)) { - break; - } - } + if (deliverifp != NULL) { + struct in6_ifaddr *ia6 = NULL; - if (ia6 != NULL) { - /* - * For performance, test without acquiring the address lock; - * a lot of things in the address are set once and never - * changed (e.g. ia_ifp.) - */ - if (!(ia6->ia6_flags & (IN6_IFF_NOTREADY | IN6_IFF_CLAT46))) { - /* this address is ready */ - ours = 1; - deliverifp = ia6->ia_ifp; - /* - * record dst address information into mbuf. - */ - (void) ip6_setdstifaddr_info(m, 0, ia6); - lck_rw_done(&in6_ifaddr_rwlock); - goto hbhcheck; + ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst); + if (ia6 != NULL) { + (void) ip6_setdstifaddr_info(m, 0, ia6); + IFA_REMREF(&ia6->ia_ifa); + } else { + (void) ip6_setdstifaddr_info(m, inifp->if_index, NULL); + } } - lck_rw_done(&in6_ifaddr_rwlock); - ia6 = NULL; - /* address is not ready, so discard the packet. */ - nd6log(info, "%s: packet to an unready address %s->%s\n", - __func__, ip6_sprintf(&ip6->ip6_src), - ip6_sprintf(&ip6->ip6_dst)); - goto bad; - } - lck_rw_done(&in6_ifaddr_rwlock); - - /* - * Slow path: route lookup. - */ - dst6 = SIN6(&rin6.ro_dst); - dst6->sin6_len = sizeof(struct sockaddr_in6); - dst6->sin6_family = AF_INET6; - dst6->sin6_addr = ip6->ip6_dst; - - rtalloc_scoped_ign((struct route *)&rin6, - RTF_PRCLONING, IFSCOPE_NONE); - if (rin6.ro_rt != NULL) { - RT_LOCK_SPIN(rin6.ro_rt); - } - -#define rt6_key(r) (SIN6((r)->rt_nodes->rn_key)) - - /* - * Accept the packet if the forwarding interface to the destination - * according to the routing table is the loopback interface, - * unless the associated route has a gateway. - * Note that this approach causes to accept a packet if there is a - * route to the loopback interface for the destination of the packet. - * But we think it's even useful in some situations, e.g. when using - * a special daemon which wants to intercept the packet. - * - * XXX: some OSes automatically make a cloned route for the destination - * of an outgoing packet. If the outgoing interface of the packet - * is a loopback one, the kernel would consider the packet to be - * accepted, even if we have no such address assinged on the interface. - * We check the cloned flag of the route entry to reject such cases, - * assuming that route entries for our own addresses are not made by - * cloning (it should be true because in6_addloop explicitly installs - * the host route). However, we might have to do an explicit check - * while it would be less efficient. Or, should we rather install a - * reject route for such a case? - */ - if (rin6.ro_rt != NULL && - (rin6.ro_rt->rt_flags & (RTF_HOST | RTF_GATEWAY)) == RTF_HOST && -#if RTF_WASCLONED - !(rin6.ro_rt->rt_flags & RTF_WASCLONED) && -#endif - rin6.ro_rt->rt_ifp->if_type == IFT_LOOP) { - ia6 = (struct in6_ifaddr *)rin6.ro_rt->rt_ifa; + goto hbhcheck; + } else { /* - * Packets to a tentative, duplicated, or somehow invalid - * address must not be accepted. - * - * For performance, test without acquiring the address lock; - * a lot of things in the address are set once and never - * changed (e.g. ia_ifp.) + * Unicast check */ - if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) { - /* this address is ready */ + ip6_check_if_result_t check_if_result = IP6_CHECK_IF_NONE; + check_if_result = ip6_input_check_interface(m, ip6, inifp, &rin6, &deliverifp); + ASSERT(check_if_result != IP6_CHECK_IF_NONE); + if (check_if_result == IP6_CHECK_IF_OURS) { ours = 1; - deliverifp = ia6->ia_ifp; /* correct? */ - /* - * record dst address information into mbuf. - */ - (void) ip6_setdstifaddr_info(m, 0, ia6); - RT_UNLOCK(rin6.ro_rt); goto hbhcheck; + } else if (check_if_result == IP6_CHECK_IF_DROP) { + goto bad; } - RT_UNLOCK(rin6.ro_rt); - ia6 = NULL; - /* address is not ready, so discard the packet. */ - nd6log(error, "%s: packet to an unready address %s->%s\n", - __func__, ip6_sprintf(&ip6->ip6_src), - ip6_sprintf(&ip6->ip6_dst)); - goto bad; - } - - if (rin6.ro_rt != NULL) { - RT_UNLOCK(rin6.ro_rt); } /* @@ -1027,19 +1172,6 @@ check_with_pf: } hbhcheck: - /* - * record dst address information into mbuf, if we don't have one yet. - * note that we are unable to record it, if the address is not listed - * as our interface address (e.g. multicast addresses, etc.) - */ - if (deliverifp != NULL && ia6 == NULL) { - ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst); - if (ia6 != NULL) { - (void) ip6_setdstifaddr_info(m, 0, ia6); - IFA_REMREF(&ia6->ia_ifa); - } - } - /* * Process Hop-by-Hop options header if it's contained. * m may be modified in ip6_hopopts_input(). @@ -2120,6 +2252,44 @@ ip6_lasthdr(struct mbuf *m, int off, int proto, int *nxtp) } } +boolean_t +ip6_pkt_has_ulp(struct mbuf *m) +{ + int off = 0, nxt = IPPROTO_NONE; + + off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt); + if (off < 0 || m->m_pkthdr.len < off) { + return FALSE; + } + + switch (nxt) { + case IPPROTO_TCP: + if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) { + return FALSE; + } + break; + case IPPROTO_UDP: + if (off + sizeof(struct udphdr) > m->m_pkthdr.len) { + return FALSE; + } + break; + case IPPROTO_ICMPV6: + if (off + sizeof(uint32_t) > m->m_pkthdr.len) { + return FALSE; + } + break; + case IPPROTO_NONE: + return TRUE; + case IPPROTO_ESP: + return TRUE; + case IPPROTO_IPCOMP: + return TRUE; + default: + return FALSE; + } + return TRUE; +} + struct ip6aux * ip6_addaux(struct mbuf *m) { @@ -2240,8 +2410,82 @@ sysctl_ip6_input_getperf SYSCTL_HANDLER_ARGS { #pragma unused(oidp, arg1, arg2) if (req->oldptr == USER_ADDR_NULL) { - req->oldlen = (size_t)sizeof(struct ipstat); + req->oldlen = (size_t)sizeof(struct net_perf); } return SYSCTL_OUT(req, &net_perf, MIN(sizeof(net_perf), req->oldlen)); } + + +/* + * Initialize IPv6 source address hash table. + */ +static void +in6_ifaddrhashtbl_init(void) +{ + int i, k, p; + + if (in6_ifaddrhashtbl != NULL) { + return; + } + + PE_parse_boot_argn("ina6ddr_nhash", &in6addr_nhash, + sizeof(in6addr_nhash)); + if (in6addr_nhash == 0) { + in6addr_nhash = IN6ADDR_NHASH; + } + + MALLOC(in6_ifaddrhashtbl, struct in6_ifaddrhashhead *, + in6addr_nhash * sizeof(*in6_ifaddrhashtbl), + M_IFADDR, M_WAITOK | M_ZERO); + if (in6_ifaddrhashtbl == NULL) { + panic("in6_ifaddrhashtbl allocation failed"); + } + + /* + * Generate the next largest prime greater than in6addr_nhash. + */ + k = (in6addr_nhash % 2 == 0) ? in6addr_nhash + 1 : in6addr_nhash + 2; + for (;;) { + p = 1; + for (i = 3; i * i <= k; i += 2) { + if (k % i == 0) { + p = 0; + } + } + if (p == 1) { + break; + } + k += 2; + } + in6addr_hashp = k; +} + +static int +sysctl_ip6_checkinterface SYSCTL_HANDLER_ARGS +{ +#pragma unused(arg1, arg2) + int error, i; + + i = ip6_checkinterface; + error = sysctl_handle_int(oidp, &i, 0, req); + if (error || req->newptr == USER_ADDR_NULL) { + return error; + } + + switch (i) { + case IP6_CHECKINTERFACE_WEAK_ES: + case IP6_CHECKINTERFACE_HYBRID_ES: + case IP6_CHECKINTERFACE_STRONG_ES: + if (ip6_checkinterface != i) { + ip6_checkinterface = i; + os_log(OS_LOG_DEFAULT, "%s: ip6_checkinterface is now %d\n", + __func__, ip6_checkinterface); + } + break; + default: + error = EINVAL; + break; + } + return error; +} diff --git a/bsd/netinet6/ip6_output.c b/bsd/netinet6/ip6_output.c index 1d2f1a9a4..ccb9a37d0 100644 --- a/bsd/netinet6/ip6_output.c +++ b/bsd/netinet6/ip6_output.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2019 Apple Inc. All rights reserved. + * Copyright (c) 2000-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -4143,7 +4143,7 @@ ip6_mloopback(struct ifnet *srcifp, struct ifnet *origifp, struct mbuf *m, struct in6_ifaddr *ia; lck_rw_lock_shared(&in6_ifaddr_rwlock); - for (ia = in6_ifaddrs; ia != NULL; ia = ia->ia_next) { + TAILQ_FOREACH(ia, IN6ADDR_HASH(&src), ia6_hash) { IFA_LOCK_SPIN(&ia->ia_ifa); /* compare against src addr with embedded scope */ if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, &src)) { diff --git a/bsd/netinet6/ip6_var.h b/bsd/netinet6/ip6_var.h index 3dca8411e..a9b9cab15 100644 --- a/bsd/netinet6/ip6_var.h +++ b/bsd/netinet6/ip6_var.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2019 Apple Inc. All rights reserved. + * Copyright (c) 2000-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -365,6 +365,9 @@ struct ip6stat { u_quad_t ip6s_clat464_v6addr_conffail; u_quad_t ip6s_clat464_plat64_pfx_setfail; u_quad_t ip6s_clat464_plat64_pfx_getfail; + + u_quad_t ip6s_rcv_if_weak_match; + u_quad_t ip6s_rcv_if_no_match; }; enum ip6s_sources_rule_index { @@ -525,6 +528,7 @@ extern int ip6_unknown_opt(u_int8_t *, struct mbuf *, int); extern char *ip6_get_prevhdr(struct mbuf *, int); extern int ip6_nexthdr(struct mbuf *, int, int, int *); extern int ip6_lasthdr(struct mbuf *, int, int, int *); +extern boolean_t ip6_pkt_has_ulp(struct mbuf *m); extern void ip6_moptions_init(void); extern struct ip6_moptions *ip6_allocmoptions(int); diff --git a/bsd/netinet6/mld6.c b/bsd/netinet6/mld6.c index ba2daacdc..9f5d020bf 100644 --- a/bsd/netinet6/mld6.c +++ b/bsd/netinet6/mld6.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2019 Apple Inc. All rights reserved. + * Copyright (c) 2000-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -1512,18 +1512,16 @@ out: int mld_input(struct mbuf *m, int off, int icmp6len) { - struct ifnet *ifp; - struct ip6_hdr *ip6; - struct mld_hdr *mld; - int mldlen; + struct ifnet *ifp = NULL; + struct ip6_hdr *ip6 = NULL; + struct mld_hdr *mld = NULL; + int mldlen = 0; MLD_PRINTF(("%s: called w/mbuf (0x%llx,%d)\n", __func__, (uint64_t)VM_KERNEL_ADDRPERM(m), off)); ifp = m->m_pkthdr.rcvif; - ip6 = mtod(m, struct ip6_hdr *); - /* Pullup to appropriate size. */ mld = (struct mld_hdr *)(mtod(m, uint8_t *) + off); if (mld->mld_type == MLD_LISTENER_QUERY && @@ -1539,6 +1537,7 @@ mld_input(struct mbuf *m, int off, int icmp6len) icmp6stat.icp6s_badlen++; return IPPROTO_DONE; } + ip6 = mtod(m, struct ip6_hdr *); /* * Userland needs to see all of this traffic for implementing diff --git a/bsd/netinet6/nd6.c b/bsd/netinet6/nd6.c index 0af74cc8d..e55d05571 100644 --- a/bsd/netinet6/nd6.c +++ b/bsd/netinet6/nd6.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2019 Apple Inc. All rights reserved. + * Copyright (c) 2000-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -1267,10 +1267,10 @@ again: */ addrloop: lck_rw_lock_exclusive(&in6_ifaddr_rwlock); - for (ia6 = in6_ifaddrs; ia6; ia6 = nia6) { + + TAILQ_FOREACH_SAFE(ia6, &in6_ifaddrhead, ia6_link, nia6) { int oldflags = ia6->ia6_flags; ap->found++; - nia6 = ia6->ia_next; IFA_LOCK(&ia6->ia_ifa); /* * Extra reference for ourselves; it's no-op if @@ -2991,39 +2991,40 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp) NDPR_ADDREF_LOCKED(pr); NDPR_UNLOCK(pr); lck_rw_lock_exclusive(&in6_ifaddr_rwlock); - ia = in6_ifaddrs; - while (ia != NULL) { - IFA_LOCK(&ia->ia_ifa); - if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0) { - IFA_UNLOCK(&ia->ia_ifa); - ia = ia->ia_next; - continue; - } + bool from_begining = true; + while (from_begining) { + from_begining = false; + TAILQ_FOREACH(ia, &in6_ifaddrhead, ia6_link) { + IFA_LOCK(&ia->ia_ifa); + if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0) { + IFA_UNLOCK(&ia->ia_ifa); + continue; + } - if (ia->ia6_ndpr == pr) { - IFA_ADDREF_LOCKED(&ia->ia_ifa); + if (ia->ia6_ndpr == pr) { + IFA_ADDREF_LOCKED(&ia->ia_ifa); + IFA_UNLOCK(&ia->ia_ifa); + lck_rw_done(&in6_ifaddr_rwlock); + lck_mtx_unlock(nd6_mutex); + in6_purgeaddr(&ia->ia_ifa); + IFA_REMREF(&ia->ia_ifa); + lck_mtx_lock(nd6_mutex); + lck_rw_lock_exclusive( + &in6_ifaddr_rwlock); + /* + * Purging the address caused + * in6_ifaddr_rwlock to be + * dropped and + * reacquired; therefore search again + * from the beginning of in6_ifaddrs. + * The same applies for the prefix list. + */ + iterate_pfxlist_again = true; + from_begining = true; + break; + } IFA_UNLOCK(&ia->ia_ifa); - lck_rw_done(&in6_ifaddr_rwlock); - lck_mtx_unlock(nd6_mutex); - in6_purgeaddr(&ia->ia_ifa); - IFA_REMREF(&ia->ia_ifa); - lck_mtx_lock(nd6_mutex); - lck_rw_lock_exclusive( - &in6_ifaddr_rwlock); - /* - * Purging the address caused - * in6_ifaddr_rwlock to be - * dropped and - * reacquired; therefore search again - * from the beginning of in6_ifaddrs. - * The same applies for the prefix list. - */ - ia = in6_ifaddrs; - iterate_pfxlist_again = true; - continue; } - IFA_UNLOCK(&ia->ia_ifa); - ia = ia->ia_next; } lck_rw_done(&in6_ifaddr_rwlock); NDPR_LOCK(pr); diff --git a/bsd/netinet6/nd6_nbr.c b/bsd/netinet6/nd6_nbr.c index ae3e33e53..5b57e6387 100644 --- a/bsd/netinet6/nd6_nbr.c +++ b/bsd/netinet6/nd6_nbr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2019 Apple Inc. All rights reserved. + * Copyright (c) 2000-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -259,30 +259,30 @@ nd6_ns_input( { struct ifnet *ifp = m->m_pkthdr.rcvif; struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); - struct nd_neighbor_solicit *nd_ns; + struct nd_neighbor_solicit *nd_ns = NULL; struct in6_addr saddr6 = ip6->ip6_src; struct in6_addr daddr6 = ip6->ip6_dst; - struct in6_addr taddr6; - struct in6_addr myaddr6; + struct in6_addr taddr6 = {}; + struct in6_addr myaddr6 = {}; char *lladdr = NULL; struct ifaddr *ifa = NULL; int lladdrlen = 0; int anycast = 0, proxy = 0, dadprogress = 0; - int tlladdr; - union nd_opts ndopts; - struct sockaddr_dl proxydl; - boolean_t advrouter; - boolean_t is_dad_probe; + int tlladdr = 0; + union nd_opts ndopts = {}; + struct sockaddr_dl proxydl = {}; + boolean_t advrouter = FALSE; + boolean_t is_dad_probe = FALSE; int oflgclr = 0; /* Expect 32-bit aligned data pointer on strict-align platforms */ MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m); IP6_EXTHDR_CHECK(m, off, icmp6len, return ); + ip6 = mtod(m, struct ip6_hdr *); nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off); m->m_pkthdr.pkt_flags |= PKTF_INET6_RESOLVE; - ip6 = mtod(m, struct ip6_hdr *); /* adjust pointer for safety */ taddr6 = nd_ns->nd_ns_target; if (in6_setscope(&taddr6, ifp, NULL) != 0) { goto bad; @@ -923,6 +923,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) } IP6_EXTHDR_CHECK(m, off, icmp6len, return ); + ip6 = mtod(m, struct ip6_hdr *); nd_na = (struct nd_neighbor_advert *)((caddr_t)ip6 + off); m->m_pkthdr.pkt_flags |= PKTF_INET6_RESOLVE; diff --git a/bsd/netinet6/nd6_rtr.c b/bsd/netinet6/nd6_rtr.c index e0c8b4864..e47f614ba 100644 --- a/bsd/netinet6/nd6_rtr.c +++ b/bsd/netinet6/nd6_rtr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2018 Apple Inc. All rights reserved. + * Copyright (c) 2003-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -270,11 +270,11 @@ nd6_rs_input( { struct ifnet *ifp = m->m_pkthdr.rcvif; struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); - struct nd_router_solicit *nd_rs; + struct nd_router_solicit *nd_rs = NULL; struct in6_addr saddr6 = ip6->ip6_src; char *lladdr = NULL; int lladdrlen = 0; - union nd_opts ndopts; + union nd_opts ndopts = {}; /* Expect 32-bit aligned data pointer on strict-align platforms */ MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m); @@ -315,6 +315,7 @@ nd6_rs_input( } IP6_EXTHDR_CHECK(m, off, icmp6len, return ); + ip6 = mtod(m, struct ip6_hdr *); nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off); icmp6len -= sizeof(*nd_rs); nd6_option_init(nd_rs + 1, icmp6len, &ndopts); @@ -425,6 +426,7 @@ nd6_ra_input( } IP6_EXTHDR_CHECK(m, off, icmp6len, return ); + ip6 = mtod(m, struct ip6_hdr *); nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off); icmp6len -= sizeof(*nd_ra); diff --git a/bsd/netinet6/route6.c b/bsd/netinet6/route6.c index cc0886d44..87af9c753 100644 --- a/bsd/netinet6/route6.c +++ b/bsd/netinet6/route6.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2013 Apple Inc. All rights reserved. + * Copyright (c) 2000-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -77,22 +77,24 @@ int route6_input(struct mbuf **mp, int *offp, int proto) { #pragma unused(proto) - struct ip6_hdr *ip6; + struct ip6_hdr *ip6 = NULL; struct mbuf *m = *mp; - struct ip6_rthdr *rh; - int off = *offp, rhlen; + struct ip6_rthdr *rh = NULL; + int off = *offp, rhlen = 0; #ifdef notyet - struct ip6aux *ip6a; + struct ip6aux *ip6a = NULL; ip6a = ip6_findaux(m); if (ip6a) { /* XXX reject home-address option before rthdr */ if (ip6a->ip6a_flags & IP6A_SWAP) { ip6stat.ip6s_badoptions++; + *mp = NULL; m_freem(m); return IPPROTO_DONE; } } + ip6a = NULL; #endif /* notyet */ IP6_EXTHDR_CHECK(m, off, sizeof(*rh), return IPPROTO_DONE); @@ -116,6 +118,7 @@ route6_input(struct mbuf **mp, int *offp, int proto) return IPPROTO_DONE; } + *mp = m; *offp += rhlen; return rh->ip6r_nxt; } diff --git a/bsd/netkey/key.c b/bsd/netkey/key.c index 87d880897..2639379d1 100644 --- a/bsd/netkey/key.c +++ b/bsd/netkey/key.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2016 Apple Inc. All rights reserved. + * Copyright (c) 2008-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -163,8 +163,8 @@ static int key_blockacq_count = 10; /* counter for blocking SADB_ACQUIRE.*/ static int key_blockacq_lifetime = 20; /* lifetime for blocking SADB_ACQUIRE.*/ static int key_preferred_oldsa = 0; /* preferred old sa rather than new sa.*/ __private_extern__ int natt_keepalive_interval = 20; /* interval between natt keepalives.*/ -__private_extern__ int ipsec_policy_count = 0; -static int ipsec_sav_count = 0; +static u_int32_t ipsec_policy_count = 0; +static u_int32_t ipsec_sav_count = 0; static u_int32_t acq_seq = 0; static int key_tick_init_random = 0; @@ -369,9 +369,9 @@ ipseclog((LOG_DEBUG, "%s: direction mismatched (TREE=%d SP=%d), " \ #if 1 #define KMALLOC_WAIT(p, t, n) \ -((p) = (t) _MALLOC((u_int32_t)(n), M_SECA, M_WAITOK)) +((p) = (t) _MALLOC((n), M_SECA, M_WAITOK)) #define KMALLOC_NOWAIT(p, t, n) \ -((p) = (t) _MALLOC((u_int32_t)(n), M_SECA, M_NOWAIT)) +((p) = (t) _MALLOC((n), M_SECA, M_NOWAIT)) #define KFREE(p) \ _FREE((caddr_t)(p), M_SECA); #else @@ -527,9 +527,6 @@ static int key_getspi(struct socket *, struct mbuf *, static u_int32_t key_do_getnewspi(struct sadb_spirange *, struct secasindex *); static int key_update(struct socket *, struct mbuf *, const struct sadb_msghdr *); -#if IPSEC_DOSEQCHECK -static struct secasvar *key_getsavbyseq(struct secashead *, u_int32_t); -#endif static int key_add(struct socket *, struct mbuf *, const struct sadb_msghdr *); static int key_setident(struct secashead *, struct mbuf *, const struct sadb_msghdr *); @@ -3127,6 +3124,7 @@ key_spdenable( } sp->disabled = 0; + key_freesp(sp, KEY_SADB_LOCKED); lck_mtx_unlock(sadb_mutex); { @@ -3190,6 +3188,7 @@ key_spddisable( } sp->disabled = 1; + key_freesp(sp, KEY_SADB_LOCKED); lck_mtx_unlock(sadb_mutex); { @@ -3265,6 +3264,7 @@ key_spdget( } lck_mtx_unlock(sadb_mutex); n = key_setdumpsp(sp, SADB_X_SPDGET, 0, mhp->msg->sadb_msg_pid); + key_freesp(sp, KEY_SADB_UNLOCKED); if (n != NULL) { m_freem(m); return key_sendup_mbuf(so, n, KEY_SENDUP_ONE); @@ -3432,7 +3432,8 @@ key_spddump( const struct sadb_msghdr *mhp) { struct secpolicy *sp, **spbuf = NULL, **sp_ptr; - int cnt = 0, bufcount; + u_int32_t cnt = 0, bufcount = 0; + size_t total_req_size = 0; u_int dir; struct mbuf *n; int error = 0; @@ -3446,8 +3447,17 @@ key_spddump( error = ENOENT; goto end; } - bufcount += 256; /* extra */ - KMALLOC_WAIT(spbuf, struct secpolicy**, bufcount * sizeof(struct secpolicy*)); + + if (os_add_overflow(bufcount, 256, &bufcount)) { + ipseclog((LOG_DEBUG, "key_spddump: bufcount overflow, ipsec policy count %u.\n", ipsec_policy_count)); + bufcount = ipsec_policy_count; + } + + if (os_mul_overflow(bufcount, sizeof(struct secpolicy *), &total_req_size)) { + panic("key_spddump spbuf requested memory overflow %u\n", bufcount); + } + + KMALLOC_WAIT(spbuf, struct secpolicy**, total_req_size); if (spbuf == NULL) { ipseclog((LOG_DEBUG, "key_spddump: No more memory.\n")); error = ENOMEM; @@ -3992,14 +4002,6 @@ key_newsav( switch (mhp->msg->sadb_msg_type) { case SADB_GETSPI: key_setspi(newsav, 0); - -#if IPSEC_DOSEQCHECK - /* sync sequence number */ - if (mhp->msg->sadb_msg_seq == 0) { - newsav->seq = - (acq_seq = (acq_seq == ~0 ? 1 : ++acq_seq)); - } else -#endif newsav->seq = mhp->msg->sadb_msg_seq; break; @@ -4156,12 +4158,6 @@ key_newsav2(struct secashead *sah, } bzero((caddr_t)newsav, sizeof(struct secasvar)); -#if IPSEC_DOSEQCHECK - /* sync sequence number */ - if (seq == 0) { - newsav->seq = (acq_seq = (acq_seq == ~0 ? 1 : ++acq_seq)); - } else -#endif newsav->seq = seq; key_setspi(newsav, spi); @@ -5834,7 +5830,7 @@ key_ismyaddr6( struct in6_multi *in6m; lck_rw_lock_shared(&in6_ifaddr_rwlock); - for (ia = in6_ifaddrs; ia; ia = ia->ia_next) { + TAILQ_FOREACH(ia, &in6_ifaddrhead, ia6_link) { IFA_LOCK(&ia->ia_ifa); if (key_sockaddrcmp((struct sockaddr *)&sin6, (struct sockaddr *)&ia->ia_addr, 0) == 0) { @@ -6358,7 +6354,8 @@ key_timehandler(void) struct secpolicy **spbuf = NULL, **spptr = NULL; struct secasvar **savexbuf = NULL, **savexptr = NULL; struct secasvar **savkabuf = NULL, **savkaptr = NULL; - int spbufcount = 0, savbufcount = 0, spcount = 0, savexcount = 0, savkacount = 0, cnt; + u_int64_t total_req_size = 0; + u_int32_t spbufcount = 0, savbufcount = 0, spcount = 0, savexcount = 0, savkacount = 0, cnt; int stop_handler = 1; /* stop the timehandler */ microtime(&tv); @@ -6366,19 +6363,32 @@ key_timehandler(void) /* pre-allocate buffers before taking the lock */ /* if allocation failures occur - portions of the processing will be skipped */ if ((spbufcount = ipsec_policy_count) != 0) { - spbufcount += 256; - KMALLOC_WAIT(spbuf, struct secpolicy **, spbufcount * sizeof(struct secpolicy *)); + if (os_add_overflow(spbufcount, 256, &spbufcount)) { + ipseclog((LOG_DEBUG, "key_timehandler: spbufcount overflow, ipsec policy count %u.\n", ipsec_policy_count)); + spbufcount = ipsec_policy_count; + } + + if (os_mul_overflow(spbufcount, sizeof(struct secpolicy *), &total_req_size)) { + panic("key_timehandler spbuf requested memory overflow %u\n", spbufcount); + } + KMALLOC_WAIT(spbuf, struct secpolicy **, total_req_size); if (spbuf) { spptr = spbuf; } } if ((savbufcount = ipsec_sav_count) != 0) { - savbufcount += 512; - KMALLOC_WAIT(savexbuf, struct secasvar **, savbufcount * sizeof(struct secasvar *)); + if (os_add_overflow(savbufcount, 512, &savbufcount)) { + ipseclog((LOG_DEBUG, "key_timehandler: savbufcount overflow, ipsec sa count %u.\n", ipsec_sav_count)); + savbufcount = ipsec_sav_count; + } + if (os_mul_overflow(savbufcount, sizeof(struct secasvar *), &total_req_size)) { + panic("key_timehandler savexbuf requested memory overflow %u\n", savbufcount); + } + KMALLOC_WAIT(savexbuf, struct secasvar **, total_req_size); if (savexbuf) { savexptr = savexbuf; } - KMALLOC_WAIT(savkabuf, struct secasvar **, savbufcount * sizeof(struct secasvar *)); + KMALLOC_WAIT(savkabuf, struct secasvar **, total_req_size); if (savkabuf) { savkaptr = savkabuf; } @@ -6600,26 +6610,6 @@ key_timehandler(void) sav = NULL; } } -#if 0 /* XXX Should we keep to send expire message until HARD lifetime ? */ - else if (savbuf && savexcount < savbufcount - && sav->lft_s != NULL - && sav->lft_s->sadb_lifetime_addtime != 0 - && tv.tv_sec - sav->created > sav->lft_s->sadb_lifetime_addtime) { - /* - * XXX: should be checked to be - * installed the valid SA. - */ - - /* - * If there is no SA then sending - * expire message. - */ - //key_expire(sav); - sav->refcnt++; - *savexptr++ = sav; - savexcount++; - } -#endif /* check HARD lifetime by bytes */ else if (sav->lft_h->sadb_lifetime_bytes != 0 && sav->lft_h->sadb_lifetime_bytes < sav->lft_c->sadb_lifetime_bytes) { @@ -6741,13 +6731,13 @@ key_timehandler(void) } if (savkabuf && savkacount > 0) { struct secasvar **savkaptr_sav = savkaptr; - int cnt_send = savkacount; + u_int32_t cnt_send = savkacount; while (cnt_send--) { if (ipsec_send_natt_keepalive(*(--savkaptr))) { // iterate (all over again) and update timestamps struct secasvar **savkaptr_update = savkaptr_sav; - int cnt_update = savkacount; + u_int32_t cnt_update = savkacount; while (cnt_update--) { key_update_natt_keepalive_timestamp(*savkaptr, *(--savkaptr_update)); @@ -7126,6 +7116,7 @@ key_getspi( off += PFKEY_ALIGN8(sizeof(struct sadb_msg)); m_sa = (struct sadb_sa *)(void *)(mtod(n, caddr_t) + off); + memset(m_sa, 0, PFKEY_ALIGN8(sizeof(struct sadb_sa))); m_sa->sadb_sa_len = PFKEY_UNIT64(sizeof(struct sadb_sa)); m_sa->sadb_sa_exttype = SADB_EXT_SA; m_sa->sadb_sa_spi = htonl(spi); @@ -7394,17 +7385,6 @@ key_update( return key_senderror(so, m, error); } - /* find a SA with sequence number. */ -#if IPSEC_DOSEQCHECK - if (mhp->msg->sadb_msg_seq != 0 - && (sav = key_getsavbyseq(sah, mhp->msg->sadb_msg_seq)) == NULL) { - lck_mtx_unlock(sadb_mutex); - ipseclog((LOG_DEBUG, - "key_update: no larval SA with sequence %u exists.\n", - mhp->msg->sadb_msg_seq)); - return key_senderror(so, m, ENOENT); - } -#else if ((sav = key_getsavbyspi(sah, sa0->sadb_sa_spi)) == NULL) { lck_mtx_unlock(sadb_mutex); ipseclog((LOG_DEBUG, @@ -7412,38 +7392,27 @@ key_update( (u_int32_t)ntohl(sa0->sadb_sa_spi))); return key_senderror(so, m, EINVAL); } -#endif /* validity check */ if (sav->sah->saidx.proto != proto) { - lck_mtx_unlock(sadb_mutex); ipseclog((LOG_DEBUG, "key_update: protocol mismatched (DB=%u param=%u)\n", sav->sah->saidx.proto, proto)); - return key_senderror(so, m, EINVAL); - } -#if IPSEC_DOSEQCHECK - if (sav->spi != sa0->sadb_sa_spi) { lck_mtx_unlock(sadb_mutex); - ipseclog((LOG_DEBUG, - "key_update: SPI mismatched (DB:%u param:%u)\n", - (u_int32_t)ntohl(sav->spi), - (u_int32_t)ntohl(sa0->sadb_sa_spi))); return key_senderror(so, m, EINVAL); } -#endif + if (sav->pid != mhp->msg->sadb_msg_pid) { - lck_mtx_unlock(sadb_mutex); ipseclog((LOG_DEBUG, "key_update: pid mismatched (DB:%u param:%u)\n", sav->pid, mhp->msg->sadb_msg_pid)); + lck_mtx_unlock(sadb_mutex); return key_senderror(so, m, EINVAL); } /* copy sav values */ error = key_setsaval(sav, m, mhp); if (error) { - key_freesav(sav, KEY_SADB_LOCKED); lck_mtx_unlock(sadb_mutex); return key_senderror(so, m, error); } @@ -7465,7 +7434,6 @@ key_update( /* check SA values to be mature. */ if ((error = key_mature(sav)) != 0) { - key_freesav(sav, KEY_SADB_LOCKED); lck_mtx_unlock(sadb_mutex); return key_senderror(so, m, error); } @@ -7648,44 +7616,6 @@ key_migrate(struct socket *so, } } -/* - * search SAD with sequence for a SA which state is SADB_SASTATE_LARVAL. - * only called by key_update(). - * OUT: - * NULL : not found - * others : found, pointer to a SA. - */ -#if IPSEC_DOSEQCHECK -static struct secasvar * -key_getsavbyseq( - struct secashead *sah, - u_int32_t seq) -{ - struct secasvar *sav; - u_int state; - - LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED); - - state = SADB_SASTATE_LARVAL; - - /* search SAD with sequence number ? */ - LIST_FOREACH(sav, &sah->savtree[state], chain) { - KEY_CHKSASTATE(state, sav->state, "key_getsabyseq"); - - if (sav->seq == seq) { - sav->refcnt++; - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP key_getsavbyseq cause " - "refcnt++:%d SA:0x%llx\n", sav->refcnt, - (uint64_t)VM_KERNEL_ADDRPERM(sav))); - return sav; - } - } - - return NULL; -} -#endif - /* * SADB_ADD processing * add a entry to SA database, when received @@ -9564,11 +9494,12 @@ key_dump( struct secashead *sah; struct secasvar *sav; struct sav_dump_elem *savbuf = NULL, *elem_ptr; + size_t total_req_size = 0; + u_int32_t bufcount = 0, cnt = 0, cnt2 = 0; u_int16_t proto; u_int stateidx; u_int8_t satype; u_int8_t state; - int cnt = 0, cnt2, bufcount; struct mbuf *n; int error = 0; @@ -9585,12 +9516,21 @@ key_dump( return key_senderror(so, m, EINVAL); } - if ((bufcount = ipsec_sav_count) <= 0) { + if ((bufcount = ipsec_sav_count) == 0) { error = ENOENT; goto end; } - bufcount += 512; /* extra */ - KMALLOC_WAIT(savbuf, struct sav_dump_elem*, bufcount * sizeof(struct sav_dump_elem)); + + if (os_add_overflow(bufcount, 512, &bufcount)) { + ipseclog((LOG_DEBUG, "key_dump: bufcount overflow, ipsec sa count %u.\n", ipsec_sav_count)); + bufcount = ipsec_sav_count; + } + + if (os_mul_overflow(bufcount, sizeof(struct sav_dump_elem), &total_req_size)) { + panic("key_dump savbuf requested memory overflow %u\n", bufcount); + } + + KMALLOC_WAIT(savbuf, struct sav_dump_elem*, total_req_size); if (savbuf == NULL) { ipseclog((LOG_DEBUG, "key_dump: No more memory.\n")); error = ENOMEM; @@ -10111,6 +10051,16 @@ key_parse( } } + void *migrate_src = mh.ext[SADB_EXT_MIGRATE_ADDRESS_SRC]; + void *migrate_dst = mh.ext[SADB_EXT_MIGRATE_ADDRESS_DST]; + if (migrate_src != NULL && migrate_dst != NULL) { + error = key_validate_address_pair((struct sadb_address *)(migrate_src), + (struct sadb_address *)(migrate_dst)); + if (error != 0) { + goto senderror; + } + } + if (msg->sadb_msg_type >= sizeof(key_typesw) / sizeof(key_typesw[0]) || key_typesw[msg->sadb_msg_type] == NULL) { PFKEY_STAT_INCREMENT(pfkeystat.out_invmsgtype); @@ -10247,6 +10197,16 @@ key_align( } extlen = PFKEY_UNUNIT64(ext->sadb_ext_len); + if (off + extlen > end) { + ipseclog((LOG_DEBUG, + "key_align: ext type %u invalid ext length %d " + "offset %zu sadb message total len %zu is passed.\n", + ext->sadb_ext_type, extlen, off, end)); + bzero_mbuf(m); + m_freem(m); + PFKEY_STAT_INCREMENT(pfkeystat.out_invlen); + return EINVAL; + } if (key_validate_ext(ext, extlen)) { bzero_mbuf(m); @@ -10606,7 +10566,8 @@ key_getsastat(struct socket *so, const struct sadb_msghdr *mhp) { struct sadb_session_id *session_id; - u_int32_t bufsize, arg_count, res_count; + u_int64_t bufsize = 0; + u_int32_t arg_count, res_count; struct sadb_sastat *sa_stats_arg; struct sastat *sa_stats_sav = NULL; struct mbuf *n; @@ -10637,12 +10598,15 @@ key_getsastat(struct socket *so, LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED); // exit early if there are no active SAs - if (ipsec_sav_count <= 0) { + if (ipsec_sav_count == 0) { printf("%s: No active SAs.\n", __FUNCTION__); error = ENOENT; goto end; } - bufsize = (ipsec_sav_count + 1) * sizeof(*sa_stats_sav); + + if (os_mul_overflow(ipsec_sav_count + 1, sizeof(*sa_stats_sav), &bufsize)) { + panic("key_getsastat bufsize requested memory overflow %u\n", ipsec_sav_count); + } KMALLOC_WAIT(sa_stats_sav, __typeof__(sa_stats_sav), bufsize); if (sa_stats_sav == NULL) { @@ -10661,6 +10625,13 @@ key_getsastat(struct socket *so, error = ENOENT; goto end; } + if (PFKEY_UNUNIT64(sa_stats_arg->sadb_sastat_len) < (sizeof(*sa_stats_arg) + + (arg_count * sizeof(struct sastat)))) { + printf("%s: invalid message is passed. sa stat extlen shorter than requested stat length.\n", __FUNCTION__); + error = EINVAL; + goto end; + } + res_count = 0; if (key_getsastatbyspi((struct sastat *)(sa_stats_arg + 1), diff --git a/bsd/nfs/nfs_socket.c b/bsd/nfs/nfs_socket.c index e5c2a590e..b0fad27f1 100644 --- a/bsd/nfs/nfs_socket.c +++ b/bsd/nfs/nfs_socket.c @@ -1799,23 +1799,21 @@ keepsearching: if (!NFS_BITMAP_ISSET(nmp->nm_mattrs, NFS_MATTR_SOCKET_TYPE)) { nmp->nm_sotype = 0; } - if (!NFS_BITMAP_ISSET(nmp->nm_mattrs, NFS_MATTR_NFS_VERSION)) { #if CONFIG_NFS4 - if (nmp->nm_vers >= NFS_VER4) { - if (!NFS_BITMAP_ISSET(nmp->nm_mattrs, NFS_MATTR_NFS_PORT)) { - nmp->nm_nfsport = 0; - } - if (nmp->nm_cbid) { - nfs4_mount_callback_shutdown(nmp); - } - if (IS_VALID_CRED(nmp->nm_mcred)) { - kauth_cred_unref(&nmp->nm_mcred); - } - bzero(&nmp->nm_un, sizeof(nmp->nm_un)); + if (nmp->nm_vers >= NFS_VER4) { + if (!NFS_BITMAP_ISSET(nmp->nm_mattrs, NFS_MATTR_NFS_PORT)) { + nmp->nm_nfsport = 0; } -#endif - nmp->nm_vers = 0; + if (nmp->nm_cbid) { + nfs4_mount_callback_shutdown(nmp); + } + if (IS_VALID_CRED(nmp->nm_mcred)) { + kauth_cred_unref(&nmp->nm_mcred); + } + bzero(&nmp->nm_un, sizeof(nmp->nm_un)); } +#endif + nmp->nm_vers = 0; } lck_mtx_unlock(&nmp->nm_lock); nmp->nm_nso = NULL; diff --git a/bsd/sys/proc.h b/bsd/sys/proc.h index e427f2ebe..65ab9901a 100644 --- a/bsd/sys/proc.h +++ b/bsd/sys/proc.h @@ -414,6 +414,7 @@ extern int proc_pidoriginatoruuid(uuid_t uuid_buf, uint32_t buffersize); extern uint64_t proc_was_throttled(proc_t); extern uint64_t proc_did_throttle(proc_t); +extern bool proc_is_traced(proc_t p); extern void proc_coalitionids(proc_t, uint64_t[COALITION_NUM_TYPES]); diff --git a/bsd/sys/reason.h b/bsd/sys/reason.h index 355b59ae9..516521f9f 100644 --- a/bsd/sys/reason.h +++ b/bsd/sys/reason.h @@ -113,11 +113,12 @@ void os_reason_set_description_data(os_reason_t cur_reason, uint32_t type, void #define OS_REASON_SANDBOX 25 #define OS_REASON_SECURITY 26 #define OS_REASON_ENDPOINTSECURITY 27 +#define OS_REASON_PAC_EXCEPTION 28 /* * Update whenever new OS_REASON namespaces are added. */ -#define OS_REASON_MAX_VALID_NAMESPACE OS_REASON_ENDPOINTSECURITY +#define OS_REASON_MAX_VALID_NAMESPACE OS_REASON_PAC_EXCEPTION #define OS_REASON_BUFFER_MAX_SIZE 5120 diff --git a/bsd/sys/vnode.h b/bsd/sys/vnode.h index 7dfb01ef2..3a727171c 100644 --- a/bsd/sys/vnode.h +++ b/bsd/sys/vnode.h @@ -1769,6 +1769,24 @@ int vn_getpath_fsenter_with_parent(struct vnode *dvp, struct vnode *vp, char */ int vn_getpath_ext(struct vnode *vp, struct vnode *dvp, char *pathbuf, int *len, int flags); +/*! + * @function vn_getpath_ext_with_mntlen + * @abstract Attempt to get a vnode's path without rentering filesystem (unless passed an option to allow) + * @discussion Paths to vnodes are not always straightforward: a file with multiple hard-links will have multiple pathnames, + * and it is sometimes impossible to determine a vnode's full path. vn_getpath_fsenter() may enter the filesystem + * to try to construct a path, so filesystems should be wary of calling it. + * @param vp Vnode whose path to get + * @param dvp parent vnode of vnode whose path to get, can be NULL if not available. + * @param pathbuf Buffer in which to store path. + * @param len Destination for length of resulting path string. Result will include NULL-terminator in count--that is, "len" + * will be strlen(pathbuf) + 1. + * @param mntlen Destination for length of path that is the mount point for the returned path. Will always be less than or equal to len. + * will be strlen(pathbuf) + 1. + * @param flags flags for controlling behavior. + * @return 0 for success or an error. + */ +int vn_getpath_ext_with_mntlen(struct vnode *vp, struct vnode *dvp, char *pathbuf, size_t *len, size_t *mntlen, int flags); + /* supported flags for vn_getpath_ext */ #define VN_GETPATH_FSENTER 0x0001 /* Can re-enter filesystem */ #define VN_GETPATH_NO_FIRMLINK 0x0002 diff --git a/bsd/sys/vnode_internal.h b/bsd/sys/vnode_internal.h index 29d6d9f72..0bc52b141 100644 --- a/bsd/sys/vnode_internal.h +++ b/bsd/sys/vnode_internal.h @@ -604,7 +604,7 @@ void vnode_trigger_rearm(vnode_t, vfs_context_t); void vfs_nested_trigger_unmounts(mount_t, int, vfs_context_t); #endif /* CONFIG_TRIGGERS */ -int build_path_with_parent(vnode_t, vnode_t /* parent */, char *, int, int *, int, vfs_context_t); +int build_path_with_parent(vnode_t, vnode_t /* parent */, char *, int, int *, size_t *, int, vfs_context_t); void nspace_resolver_init(void); void nspace_resolver_exited(struct proc *); diff --git a/bsd/vfs/vfs_cache.c b/bsd/vfs/vfs_cache.c index b027e9535..e6a802323 100644 --- a/bsd/vfs/vfs_cache.c +++ b/bsd/vfs/vfs_cache.c @@ -428,12 +428,14 @@ vnode_issubdir(vnode_t vp, vnode_t dvp, int *is_subdir, vfs_context_t ctx) * */ int -build_path_with_parent(vnode_t first_vp, vnode_t parent_vp, char *buff, int buflen, int *outlen, int flags, vfs_context_t ctx) +build_path_with_parent(vnode_t first_vp, vnode_t parent_vp, char *buff, int buflen, + int *outlen, size_t *mntpt_outlen, int flags, vfs_context_t ctx) { vnode_t vp, tvp; vnode_t vp_with_iocount; vnode_t proc_root_dir_vp; char *end; + char *mntpt_end; const char *str; int len; int ret = 0; @@ -462,6 +464,7 @@ again: end = &buff[buflen - 1]; *end = '\0'; + mntpt_end = NULL; /* * holding the NAME_CACHE_LOCK in shared mode is @@ -520,6 +523,9 @@ again: goto out_unlock; } else { vp = vp->v_mount->mnt_vnodecovered; + if (!mntpt_end && vp) { + mntpt_end = end; + } } } } @@ -761,6 +767,9 @@ bad_news: tvp = NULL; } else { tvp = tvp->v_mount->mnt_vnodecovered; + if (!mntpt_end && tvp) { + mntpt_end = end; + } } } if (tvp == NULLVP) { @@ -782,7 +791,10 @@ out: /* * length includes the trailing zero byte */ - *outlen = &buff[buflen] - end; + *outlen = (int)(&buff[buflen] - end); + if (mntpt_outlen && mntpt_end) { + *mntpt_outlen = (size_t)*outlen - (size_t)(&buff[buflen] - mntpt_end); + } /* One of the parents was moved during path reconstruction. * The caller is interested in knowing whether any of the @@ -798,7 +810,7 @@ out: int build_path(vnode_t first_vp, char *buff, int buflen, int *outlen, int flags, vfs_context_t ctx) { - return build_path_with_parent(first_vp, NULL, buff, buflen, outlen, flags, ctx); + return build_path_with_parent(first_vp, NULL, buff, buflen, outlen, NULL, flags, ctx); } /* diff --git a/bsd/vfs/vfs_subr.c b/bsd/vfs/vfs_subr.c index 0d44e828b..08459f529 100644 --- a/bsd/vfs/vfs_subr.c +++ b/bsd/vfs/vfs_subr.c @@ -2890,7 +2890,7 @@ vn_getpath_fsenter(struct vnode *vp, char *pathbuf, int *len) int vn_getpath_fsenter_with_parent(struct vnode *dvp, struct vnode *vp, char *pathbuf, int *len) { - return build_path_with_parent(vp, dvp, pathbuf, *len, len, 0, vfs_context_current()); + return build_path_with_parent(vp, dvp, pathbuf, *len, len, NULL, 0, vfs_context_current()); } int @@ -2910,7 +2910,7 @@ vn_getpath_ext(struct vnode *vp, struct vnode *dvp, char *pathbuf, int *len, int } } - return build_path_with_parent(vp, dvp, pathbuf, *len, len, bpflags, vfs_context_current()); + return build_path_with_parent(vp, dvp, pathbuf, *len, len, NULL, bpflags, vfs_context_current()); } int @@ -2919,6 +2919,40 @@ vn_getpath_no_firmlink(struct vnode *vp, char *pathbuf, int *len) return vn_getpath_ext(vp, NULLVP, pathbuf, len, VN_GETPATH_NO_FIRMLINK); } +int +vn_getpath_ext_with_mntlen(struct vnode *vp, struct vnode *dvp, char *pathbuf, size_t *len, size_t *mntlen, int flags) +{ + int bpflags = (flags & VN_GETPATH_FSENTER) ? 0 : BUILDPATH_NO_FS_ENTER; + int local_len; + int error; + + if (*len > INT_MAX) { + return EINVAL; + } + + local_len = *len; + + if (flags && (flags != VN_GETPATH_FSENTER)) { + if (flags & VN_GETPATH_NO_FIRMLINK) { + bpflags |= BUILDPATH_NO_FIRMLINK;; + } + if (flags & VN_GETPATH_VOLUME_RELATIVE) { + bpflags |= (BUILDPATH_VOLUME_RELATIVE | BUILDPATH_NO_FIRMLINK); + } + if (flags & VN_GETPATH_NO_PROCROOT) { + bpflags |= BUILDPATH_NO_PROCROOT; + } + } + + error = build_path_with_parent(vp, dvp, pathbuf, local_len, &local_len, mntlen, bpflags, vfs_context_current()); + + if (local_len >= 0 && local_len <= (int)*len) { + *len = (size_t)local_len; + } + + return error; +} + int vn_getcdhash(struct vnode *vp, off_t offset, unsigned char *cdhash) { @@ -3899,6 +3933,12 @@ sysctl_vfs_ctlbyfsid(__unused struct sysctl_oid *oidp, void *arg1, int arg2, error = safedounmount(mp, flags, ctx); break; case VFS_CTL_STATFS: +#if CONFIG_MACF + error = mac_mount_check_stat(ctx, mp); + if (error != 0) { + break; + } +#endif req->newidx = 0; if (is_64_bit) { req->newptr = vc.vc64.vc_ptr; diff --git a/config/IOKit.exports b/config/IOKit.exports index d29f1f01c..86f00a27d 100644 --- a/config/IOKit.exports +++ b/config/IOKit.exports @@ -8,6 +8,9 @@ __ZN22IOInterruptEventSource27getPimaryInterruptTimestampEv __ZN22IOInterruptEventSource31enablePrimaryInterruptTimestampEb __ZN14IOPMrootDomain11setWakeTimeEy + +__ZN12IODMACommand8DispatchE5IORPC + _IOAlignmentToSize _IOBSDNameMatching _IOBSDRegistryEntryForDeviceTree diff --git a/config/MasterVersion b/config/MasterVersion index 9259dc79e..3686593d5 100644 --- a/config/MasterVersion +++ b/config/MasterVersion @@ -1,4 +1,4 @@ -19.5.0 +19.6.0 # The first line of this file contains the master version number for the kernel. # All other instances of the kernel version in xnu are derived from this file. diff --git a/config/Private.exports b/config/Private.exports index 0436ff54f..2a8547757 100644 --- a/config/Private.exports +++ b/config/Private.exports @@ -507,6 +507,7 @@ _vm_map_trunc_page_mask _vm_map_wire_and_extract:_vm_map_wire_and_extract_external _vm_page_wire_count _vn_getpath_ext +_vn_getpath_ext_with_mntlen _vn_getpath_fsenter _vn_getpath_fsenter_with_parent _vn_getpath_no_firmlink diff --git a/iokit/DriverKit/IODMACommand.iig b/iokit/DriverKit/IODMACommand.iig new file mode 100644 index 000000000..de4dd6d3d --- /dev/null +++ b/iokit/DriverKit/IODMACommand.iig @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2020 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +#if !__IIG +#if KERNEL +#include +#endif +#endif + +#ifndef _IOKIT_UIODMACOMMMAND_H +#define _IOKIT_UIODMACOMMMAND_H + +#include +#include + +// IODMACommand Create options +enum { + kIODMACommandCreateNoOptions = 0, +}; + +// IODMACommand PrepareForDMA options +enum { + kIODMACommandPrepareForDMANoOptions = 0, +}; + +// IODMACommand CompleteDMA options +enum { + kIODMACommandCompleteDMANoOptions = 0, +}; + +// IODMACommand PerformOperation options +enum { + kIODMACommandPerformOperationOptionRead = 0x00000001, + kIODMACommandPerformOperationOptionWrite = 0x00000002, + kIODMACommandPerformOperationOptionZero = 0x00000004, +}; + +// IODMACommandSpecification options +enum { + kIODMACommandSpecificationNoOptions = 0, +}; + +struct IODMACommandSpecification { + uint64_t options; + uint64_t maxAddressBits; + uint64_t _resv[16]; +}; + +/*! + * @class IODMACommand + * + * @abstract + * IODMACommand allows a mapping for DMA to be created from an IOMemoryDescriptor. + * + * @discussion + * IODMACommand allows a mapping for DMA to be created from an IOMemoryDescriptor. + * The IODMACommand instance represents the mapping and should be kept prepared for the + * duration of the I/O, and completed when the I/O is finished. + * IODMACommand does not perform bounce buffering but allows access to the mapping with + * the PerformOperation method so that data can moved into and out of the mapping, eg. + * to/from a driver allocated bounce buffer. + * +*/ + +class KERNEL IODMACommand : public OSObject +{ +public: + + virtual bool + init() override; + + virtual void + free() override; + + /*! + * @brief Create an IODMACommand instance. + * @param device The device (typically an IOPCIDevice instance that will be + * generating the I/O. + * @param options + * kIODMACommandCreateNoOptions No options needed + * @param specification A caller initialized structure describing + * the hardware's DMA capaibilities + * @param command Returned IODMACommand object with +1 retain count. + * It should be retained until the map is no longer required. + * @return kIOReturnSuccess on success. See IOReturn.h for error codes. + */ + static kern_return_t + Create( + IOService * device, + uint64_t options, + const IODMACommandSpecification * specification, + IODMACommand ** command); + + /*! + * @brief Create a DMA mapping for memory. + * @param options + * kIODMACommandPrepareForDMANoOptions No options needed. + * @param memory IOMemoryDescriptor for memory. + * @param offset Start offset of the DMA operation in the descriptor. + * @param length Pass zero to map the entire memory, or a value <= the length of the descriptor. + * @param flags Returned bit mask of flags + kIOMemoryDirectionOut the memory is readable + kIOMemoryDirectionIn the memory is writable + * @param segmentsCount Returned count of segements returned in segments + * @param segments Returned DMA physical address and length segments covering the DMA + * @return kIOReturnSuccess on success. See IOReturn.h for error codes. + */ + virtual kern_return_t + PrepareForDMA( + uint64_t options, + IOMemoryDescriptor * memory, + uint64_t offset, + uint64_t length, + uint64_t * flags, + uint32_t * segmentsCount, + IOAddressSegment segments[32]); + + /*! + * @brief Release a DMA mapping for memory. + * @param options + * kIODMACommandCompleteDMANoOptions No options needed. + * @return kIOReturnSuccess on success. See IOReturn.h for error codes. + */ + virtual kern_return_t + CompleteDMA( + uint64_t options); + + /*! + * @brief Obtain the parameters of a DMA preparation. + * @param offset Returned starting offset of the preparation. + * @param length Returned length of the preparation. + * @param memory Returned IOMemoryDescriptor of the preparation. This should be + * released by the caller. + * @return kIOReturnSuccess on success. See IOReturn.h for error codes. + */ + virtual kern_return_t + GetPreparation( + uint64_t * offset, + uint64_t * length, + IOMemoryDescriptor ** memory); + + /*! + * @brief Perform CPU access to the DMA mapping. + * @param options Flags for the operation to be performed + kIODMACommandPerformOperationOptionRead read from the DMA mapping to + the memory specified with the data param + kIODMACommandPerformOperationOptionWrite write to the DMA mapping from + the memory specified with the data param + kIODMACommandPerformOperationOptionZero zero the DMA mapping + * @param dmaOffset Offset into the DMA mapping for the operation to begin. + * @param length Length of the operation. + * @param dataffset Offset into the memory specified with the data param + * @param data Callers buffer to read into or write from. Pass NULL when + * using kIODMACommandPerformOperationOptionZero. + * @return kIOReturnSuccess on success. See IOReturn.h for error codes. + */ + virtual kern_return_t + PerformOperation( + uint64_t options, + uint64_t dmaOffset, + uint64_t length, + uint64_t dataOffset, + IOMemoryDescriptor * data); +}; + +#endif /* ! _IOKIT_UIODMACOMMMAND_H */ diff --git a/iokit/DriverKit/IOInterruptDispatchSource.iig b/iokit/DriverKit/IOInterruptDispatchSource.iig index ecd4b5c80..855d6beb1 100644 --- a/iokit/DriverKit/IOInterruptDispatchSource.iig +++ b/iokit/DriverKit/IOInterruptDispatchSource.iig @@ -37,6 +37,11 @@ struct IOInterruptDispatchSourcePayload { uint64_t count; }; +enum { + kIOInterruptDispatchSourceTypeEdge = 0x00000000, + kIOInterruptDispatchSourceTypeLevel = 0x00000001 +}; + /*! * @class IOInterruptDispatchSource * @@ -67,6 +72,22 @@ public: IODispatchQueue * queue, IOInterruptDispatchSource ** source) LOCAL; + /*! + * @brief Returns the type of interrupt used for a device supplying hardware interrupts, by index from an IOService provider. + * @param provider The IOService object representing the HW device producing the interrupt. + * @param index Index for the interrupt. + * @param interruptType The interrupt type for the interrupt source will be stored here. + * kIOInterruptTypeEdge will be returned for edge-trigggered sources. + * kIOInterruptTypeLevel will be returned for level-trigggered sources. + * Other flags may be returned depending on the provider, for example PCI flags for messaged interrupts. + * @return kIOReturnSuccess on success. See IOReturn.h for error codes. + */ + + static kern_return_t + GetInterruptType(IOService * provider, + uint32_t index, + uint64_t * interruptType); + virtual bool init() override; diff --git a/iokit/IOKit/IODMACommand.h b/iokit/IOKit/IODMACommand.h index adaaf4cd0..2188f9577 100644 --- a/iokit/IOKit/IODMACommand.h +++ b/iokit/IOKit/IODMACommand.h @@ -30,6 +30,7 @@ #include #include +#include class IOMapper; class IOBufferMemoryDescriptor; @@ -61,7 +62,7 @@ enum{ class IODMACommand : public IOCommand { - OSDeclareDefaultStructors(IODMACommand); + OSDeclareDefaultStructorsWithDispatch(IODMACommand); friend class IODMAEventSource; diff --git a/iokit/IOKit/IOKitKeys.h b/iokit/IOKit/IOKitKeys.h index 34da31735..2e1a2fe04 100644 --- a/iokit/IOKit/IOKitKeys.h +++ b/iokit/IOKit/IOKitKeys.h @@ -110,6 +110,9 @@ // Property is an array of strings containing CFBundleIdentifiers of service being opened #define kIODriverKitUserClientEntitlementsKey "com.apple.developer.driverkit.userclient-access" +// Entitlement of a dext that allows any task to open one of its IOUserClients +#define kIODriverKitUserClientEntitlementAllowAnyKey "com.apple.developer.driverkit.allow-any-userclient-access" + // Other DriverKit entitlements #define kIODriverKitUSBTransportEntitlementKey "com.apple.developer.driverkit.transport.usb" #define kIODriverKitHIDTransportEntitlementKey "com.apple.developer.driverkit.transport.hid" diff --git a/iokit/IOKit/IOService.h b/iokit/IOKit/IOService.h index 28c99e74c..b99bf60b0 100644 --- a/iokit/IOKit/IOService.h +++ b/iokit/IOKit/IOService.h @@ -174,6 +174,7 @@ extern const OSSymbol * gIOBSDUnitKey; extern const OSSymbol * gIODriverKitEntitlementKey; extern const OSSymbol * gIOServiceDEXTEntitlementsKey; extern const OSSymbol * gIODriverKitUserClientEntitlementsKey; +extern const OSSymbol * gIODriverKitUserClientEntitlementAllowAnyKey; extern const OSSymbol * gIOMatchDeferKey; extern SInt32 IOServiceOrdering( const OSMetaClassBase * inObj1, const OSMetaClassBase * inObj2, void * ref ); diff --git a/iokit/Kernel/IOService.cpp b/iokit/Kernel/IOService.cpp index a8387bf2a..3189e590c 100644 --- a/iokit/Kernel/IOService.cpp +++ b/iokit/Kernel/IOService.cpp @@ -185,6 +185,7 @@ const OSSymbol * gIOWillTerminateNotification; const OSSymbol * gIOServiceDEXTEntitlementsKey; const OSSymbol * gIODriverKitEntitlementKey; const OSSymbol * gIODriverKitUserClientEntitlementsKey; +const OSSymbol * gIODriverKitUserClientEntitlementAllowAnyKey; const OSSymbol * gIOMatchDeferKey; const OSSymbol * gIOGeneralInterest; @@ -485,6 +486,7 @@ IOService::initialize( void ) gIOServiceDEXTEntitlementsKey = OSSymbol::withCStringNoCopy( kIOServiceDEXTEntitlementsKey ); gIODriverKitEntitlementKey = OSSymbol::withCStringNoCopy( kIODriverKitEntitlementKey ); gIODriverKitUserClientEntitlementsKey = OSSymbol::withCStringNoCopy( kIODriverKitUserClientEntitlementsKey ); + gIODriverKitUserClientEntitlementAllowAnyKey = OSSymbol::withCStringNoCopy( kIODriverKitUserClientEntitlementAllowAnyKey ); gIOMatchDeferKey = OSSymbol::withCStringNoCopy( kIOMatchDeferKey ); gIOPlatformFunctionHandlerSet = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerSet); diff --git a/iokit/Kernel/IOUserServer.cpp b/iokit/Kernel/IOUserServer.cpp index 52508a761..df4172f3c 100644 --- a/iokit/Kernel/IOUserServer.cpp +++ b/iokit/Kernel/IOUserServer.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -502,6 +503,233 @@ IMPL(IOBufferMemoryDescriptor, SetLength) return kIOReturnSuccess; } + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +kern_return_t +IMPL(IODMACommand, Create) +{ + IOReturn ret; + IODMACommand * dma; + IODMACommand::SegmentOptions segmentOptions; + IOMapper * mapper; + + if (options & ~((uint64_t) kIODMACommandCreateNoOptions)) { + // no other options currently defined + return kIOReturnBadArgument; + } + + if (os_convert_overflow(specification->maxAddressBits, &segmentOptions.fNumAddressBits)) { + return kIOReturnBadArgument; + } + segmentOptions.fMaxSegmentSize = 0; + segmentOptions.fMaxTransferSize = 0; + segmentOptions.fAlignment = 1; + segmentOptions.fAlignmentLength = 1; + segmentOptions.fAlignmentInternalSegments = 1; + segmentOptions.fStructSize = sizeof(segmentOptions); + + mapper = IOMapper::copyMapperForDevice(device); + + dma = IODMACommand::withSpecification( + kIODMACommandOutputHost64, + &segmentOptions, + kIODMAMapOptionMapped, + mapper, + NULL); + + OSSafeReleaseNULL(mapper); + *command = dma; + + if (!dma) { + return kIOReturnNoMemory; + } + ret = kIOReturnSuccess; + + return ret; +} + +kern_return_t +IMPL(IODMACommand, PrepareForDMA) +{ + IOReturn ret; + uint64_t lflags, mdFlags; + UInt32 numSegments; + UInt64 genOffset; + + if (options & ~((uint64_t) kIODMACommandPrepareForDMANoOptions)) { + // no other options currently defined + return kIOReturnBadArgument; + } + + ret = setMemoryDescriptor(memory, false); + if (kIOReturnSuccess != ret) { + return ret; + } + + ret = prepare(offset, length); + if (kIOReturnSuccess != ret) { + clearMemoryDescriptor(false); + return ret; + } + + static_assert(sizeof(IODMACommand::Segment64) == sizeof(IOAddressSegment)); + + numSegments = *segmentsCount; + genOffset = offset; + ret = genIOVMSegments(&genOffset, segments, &numSegments); + + if (kIOReturnSuccess == ret) { + IOMemoryDescriptor * mem; + mem = __IODEQUALIFY(IOMemoryDescriptor *, fMemory); + mdFlags = mem->getFlags(); + lflags = 0; + if (kIODirectionOut & mdFlags) { + lflags |= kIOMemoryDirectionOut; + } + if (kIODirectionIn & mdFlags) { + lflags |= kIOMemoryDirectionIn; + } + *flags = lflags; + *segmentsCount = numSegments; + } + + return ret; +} + +kern_return_t +IMPL(IODMACommand, CompleteDMA) +{ + IOReturn ret; + + if (options & ~((uint64_t) kIODMACommandCompleteDMANoOptions)) { + // no other options currently defined + return kIOReturnBadArgument; + } + + ret = clearMemoryDescriptor(true); + + return ret; +} + +kern_return_t +IMPL(IODMACommand, GetPreparation) +{ + IOReturn ret; + IOMemoryDescriptor * md; + + if (!fActive) { + return kIOReturnNotReady; + } + + ret = getPreparedOffsetAndLength(offset, length); + if (kIOReturnSuccess != ret) { + return ret; + } + + if (memory) { + md = __DECONST(IOMemoryDescriptor *, fMemory); + *memory = md; + if (!md) { + ret = kIOReturnNotReady; + } else { + md->retain(); + } + } + return ret; +} + +kern_return_t +IMPL(IODMACommand, PerformOperation) +{ + IOReturn ret; + void * buffer; + UInt64 copiedDMA; + IOByteCount mdOffset, mdLength, copied; + + if (options & ~((uint64_t) + (kIODMACommandPerformOperationOptionRead + | kIODMACommandPerformOperationOptionWrite + | kIODMACommandPerformOperationOptionZero))) { + // no other options currently defined + return kIOReturnBadArgument; + } + + if (!fActive) { + return kIOReturnNotReady; + } + if (os_convert_overflow(dataOffset, &mdOffset)) { + return kIOReturnBadArgument; + } + if (os_convert_overflow(length, &mdLength)) { + return kIOReturnBadArgument; + } + if (length > fMemory->getLength()) { + return kIOReturnBadArgument; + } + buffer = IONew(uint8_t, length); + if (NULL == buffer) { + return kIOReturnNoMemory; + } + + switch (options) { + case kIODMACommandPerformOperationOptionZero: + bzero(buffer, length); + copiedDMA = writeBytes(dmaOffset, buffer, length); + if (copiedDMA != length) { + ret = kIOReturnUnderrun; + break; + } + ret = kIOReturnSuccess; + break; + + case kIODMACommandPerformOperationOptionRead: + case kIODMACommandPerformOperationOptionWrite: + + if (!data) { + ret = kIOReturnBadArgument; + break; + } + if (length > data->getLength()) { + ret = kIOReturnBadArgument; + break; + } + if (kIODMACommandPerformOperationOptionWrite == options) { + copied = data->readBytes(mdOffset, buffer, mdLength); + if (copied != mdLength) { + ret = kIOReturnUnderrun; + break; + } + copiedDMA = writeBytes(dmaOffset, buffer, length); + if (copiedDMA != length) { + ret = kIOReturnUnderrun; + break; + } + } else { /* kIODMACommandPerformOperationOptionRead */ + copiedDMA = readBytes(dmaOffset, buffer, length); + if (copiedDMA != length) { + ret = kIOReturnUnderrun; + break; + } + copied = data->writeBytes(mdOffset, buffer, mdLength); + if (copied != mdLength) { + ret = kIOReturnUnderrun; + break; + } + } + ret = kIOReturnSuccess; + break; + default: + ret = kIOReturnBadArgument; + break; + } + + IODelete(buffer, uint8_t, length); + + return ret; +} + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ kern_return_t @@ -667,6 +895,21 @@ IMPL(IOInterruptDispatchSource, Create) return ret; } +kern_return_t +IMPL(IOInterruptDispatchSource, GetInterruptType) +{ + IOReturn ret; + int type; + + *interruptType = 0; + ret = provider->getInterruptType(index, &type); + if (kIOReturnSuccess == ret) { + *interruptType = type; + } + + return ret; +} + bool IOInterruptDispatchSource::init() { @@ -2199,9 +2442,11 @@ IOUserServerUEXTTrap(OSObject * object, void * p1, void * p2, void * p3, void * } else { objectArg1 = NULL; if (refs > 1) { - objectArg1 = iokit_lookup_uext_ref_current_task(objectName1); - if (!objectArg1) { - return kIOReturnIPCError; + if (objectName1) { + objectArg1 = iokit_lookup_uext_ref_current_task(objectName1); + if (!objectArg1) { + return kIOReturnIPCError; + } } message->objects[1] = (OSObjectRef) objectArg1; } @@ -3123,18 +3368,24 @@ IOUserServer::serviceNewUserClient(IOService * service, task_t owningTask, void userUC->setTask(owningTask); if (!(kIODKDisableEntitlementChecking & gIODKDebug)) { - entitlements = IOUserClient::copyClientEntitlements(owningTask); - bundleID = service->copyProperty(gIOModuleIdentifierKey); - ok = (entitlements - && bundleID - && (prop = entitlements->getObject(gIODriverKitUserClientEntitlementsKey))); - if (ok) { - bool found __block = false; - ok = prop->iterateObjects(^bool (OSObject * object) { - found = object->isEqualTo(bundleID); - return found; - }); - ok = found; + bundleID = NULL; + entitlements = NULL; + if (fEntitlements && fEntitlements->getObject(gIODriverKitUserClientEntitlementAllowAnyKey)) { + ok = true; + } else { + entitlements = IOUserClient::copyClientEntitlements(owningTask); + bundleID = service->copyProperty(gIOModuleIdentifierKey); + ok = (entitlements + && bundleID + && (prop = entitlements->getObject(gIODriverKitUserClientEntitlementsKey))); + if (ok) { + bool found __block = false; + ok = prop->iterateObjects(^bool (OSObject * object) { + found = object->isEqualTo(bundleID); + return found; + }); + ok = found; + } } if (ok) { prop = userUC->copyProperty(gIOServiceDEXTEntitlementsKey); diff --git a/iokit/conf/files b/iokit/conf/files index 77b47578c..48db7bedf 100644 --- a/iokit/conf/files +++ b/iokit/conf/files @@ -23,6 +23,7 @@ OPTIONS/mach_assert optional mach_assert ./DriverKit/IODataQueueDispatchSource.iig.cpp optional iokitcpp ./DriverKit/IOServiceNotificationDispatchSource.iig.cpp optional iokitcpp ./DriverKit/IOUserServer.iig.cpp optional iokitcpp +./DriverKit/IODMACommand.iig.cpp optional iokitcpp # libIOKit diff --git a/osfmk/arm/pmap.c b/osfmk/arm/pmap.c index cd07ccaba..2d082d60d 100644 --- a/osfmk/arm/pmap.c +++ b/osfmk/arm/pmap.c @@ -2543,7 +2543,7 @@ pmap_pages_reclaim( && ((*tte_p & ARM_TTE_TYPE_MASK) == ARM_TTE_TYPE_TABLE)) { pte_p = (pt_entry_t *) ttetokv(*tte_p); bpte = &pte_p[pte_index(pmap, pt_attr, va)]; - epte = bpte + PAGE_SIZE / sizeof(pt_entry_t); + epte = bpte + pt_attr_leaf_size(pt_attr) / sizeof(pt_entry_t); /* * Use PMAP_OPTIONS_REMOVE to clear any * "compressed" markers and update the @@ -6164,6 +6164,13 @@ pmap_remove_range_options( PMAP_ASSERT_LOCKED(pmap); + const pt_attr_t * const pt_attr = pmap_get_pt_attr(pmap); + uint64_t pmap_page_size = pt_attr_leaf_size(pt_attr); + + if (__improbable((uintptr_t)epte > (((uintptr_t)bpte + pmap_page_size) & ~(pmap_page_size - 1)))) { + panic("%s: PTE range [%p, %p) in pmap %p crosses page table boundary", __func__, bpte, epte, pmap); + } + num_removed = 0; num_unwired = 0; num_pte_changed = 0; @@ -7114,8 +7121,8 @@ pmap_protect_options_internal( boolean_t should_have_removed = FALSE; bool need_strong_sync = false; - if (__improbable(end < start)) { - panic("%s called with bogus range: %p, %p", __func__, (void*)start, (void*)end); + if (__improbable((end < start) || (end > ((start + pt_attr_twig_size(pt_attr)) & ~pt_attr_twig_offmask(pt_attr))))) { + panic("%s: invalid address range %p, %p", __func__, (void*)start, (void*)end); } #if DEVELOPMENT || DEBUG diff --git a/osfmk/arm/status.c b/osfmk/arm/status.c index 2f35514a3..40c1f5e1d 100644 --- a/osfmk/arm/status.c +++ b/osfmk/arm/status.c @@ -773,6 +773,10 @@ thread_entrypoint( { struct arm_thread_state *state; + if (count != ARM_THREAD_STATE_COUNT) { + return KERN_INVALID_ARGUMENT; + } + state = (struct arm_thread_state *) tstate; /* diff --git a/osfmk/arm64/cswitch.s b/osfmk/arm64/cswitch.s index c9b1893a1..d691acc1a 100644 --- a/osfmk/arm64/cswitch.s +++ b/osfmk/arm64/cswitch.s @@ -52,6 +52,9 @@ stp x25, x26, [$0, SS64_X25] stp x27, x28, [$0, SS64_X27] stp fp, lr, [$0, SS64_FP] + str xzr, [$0, SS64_PC] + MOV32 w$1, PSR64_KERNEL_POISON + str w$1, [$0, SS64_CPSR] #ifdef HAS_APPLE_PAC stp x0, x1, [sp, #-16]! stp x2, x3, [sp, #-16]! @@ -64,8 +67,8 @@ * Arg3: LR to sign */ mov x0, $0 - ldr x1, [x0, SS64_PC] - ldr w2, [x0, SS64_CPSR] + mov x1, #0 + mov w2, w$1 mov x3, lr mov x4, x16 mov x5, x17 @@ -76,8 +79,8 @@ ldp x0, x1, [sp], #16 ldp fp, lr, [$0, SS64_FP] #endif /* defined(HAS_APPLE_PAC) */ - mov $1, sp - str $1, [$0, SS64_SP] + mov x$1, sp + str x$1, [$0, SS64_SP] /* AAPCS-64 Page 14 * @@ -265,7 +268,7 @@ LEXT(Call_continuation) LEXT(Switch_context) cbnz x1, Lswitch_threads // Skip saving old state if blocking on continuation ldr x3, [x0, TH_KSTACKPTR] // Get the old kernel stack top - save_general_registers x3, x4 + save_general_registers x3, 4 Lswitch_threads: set_thread_registers x2, x3, x4 ldr x3, [x2, TH_KSTACKPTR] @@ -286,7 +289,7 @@ Lswitch_threads: LEXT(Shutdown_context) mrs x10, TPIDR_EL1 // Get thread pointer ldr x11, [x10, TH_KSTACKPTR] // Get the top of the kernel stack - save_general_registers x11, x12 + save_general_registers x11, 12 msr DAIFSet, #(DAIFSC_FIQF | DAIFSC_IRQF) // Disable interrupts ldr x11, [x10, ACT_CPUDATAP] // Get current cpu ldr x12, [x11, CPU_ISTACKPTR] // Switch to interrupt stack @@ -304,7 +307,7 @@ LEXT(Shutdown_context) LEXT(Idle_context) mrs x0, TPIDR_EL1 // Get thread pointer ldr x1, [x0, TH_KSTACKPTR] // Get the top of the kernel stack - save_general_registers x1, x2 + save_general_registers x1, 2 ldr x1, [x0, ACT_CPUDATAP] // Get current cpu ldr x2, [x1, CPU_ISTACKPTR] // Switch to interrupt stack mov sp, x2 diff --git a/osfmk/arm64/exception_asm.h b/osfmk/arm64/exception_asm.h index 60aa8b83f..8234158e9 100644 --- a/osfmk/arm64/exception_asm.h +++ b/osfmk/arm64/exception_asm.h @@ -117,7 +117,7 @@ str $1, [$0, NS_COUNT] /* * SPILL_REGISTERS * - * Spills the current set of registers (excluding x0, x1, sp, fp) to the specified + * Spills the current set of registers (excluding x0, x1, sp) to the specified * save area. * x0 - Address of the save area */ @@ -136,7 +136,8 @@ stp x20, x21, [x0, SS64_X20] stp x22, x23, [x0, SS64_X22] stp x24, x25, [x0, SS64_X24] stp x26, x27, [x0, SS64_X26] -str x28, [x0, SS64_X28] +stp x28, fp, [x0, SS64_X28] +str lr, [x0, SS64_LR] /* Save arm_neon_saved_state64 */ @@ -157,7 +158,7 @@ stp q26, q27, [x0, NS64_Q26] stp q28, q29, [x0, NS64_Q28] stp q30, q31, [x0, NS64_Q30] -mrs lr, ELR_EL1 // Get exception link register +mrs x22, ELR_EL1 // Get exception link register mrs x23, SPSR_EL1 // Load CPSR into var reg x23 mrs x24, FPSR mrs x25, FPCR @@ -177,9 +178,9 @@ mov x20, lr * Arg4: The X16 value to sign * Arg5: The X17 value to sign */ -mov x1, lr +mov x1, x22 mov w2, w23 -ldr x3, [x0, SS64_LR] +mov x3, x20 mov x4, x16 mov x5, x17 bl _ml_sign_thread_state @@ -188,7 +189,7 @@ mov lr, x20 mov x1, x21 #endif /* defined(HAS_APPLE_PAC) */ -str lr, [x0, SS64_PC] // Save ELR to PCB +str x22, [x0, SS64_PC] // Save ELR to PCB str w23, [x0, SS64_CPSR] // Save CPSR to PCB str w24, [x0, NS64_FPSR] str w25, [x0, NS64_FPCR] diff --git a/osfmk/arm64/locore.s b/osfmk/arm64/locore.s index 1efc217f9..75b314e83 100644 --- a/osfmk/arm64/locore.s +++ b/osfmk/arm64/locore.s @@ -183,7 +183,6 @@ /* Save the context that was interrupted. */ ldp x2, x3, [x3, SS64_X2] - stp fp, lr, [x0, SS64_FP] SPILL_REGISTERS KERNEL_MODE /* @@ -296,6 +295,59 @@ #endif /* __ARM_KERNEL_PROTECT__ */ .endmacro +/* + * CHECK_KERNEL_STACK + * + * Verifies that the kernel stack is aligned and mapped within an expected + * stack address range. Note: happens before saving registers (in case we can't + * save to kernel stack). + * + * Expects: + * {x0, x1, sp} - saved + * x0 - SP_EL0 + * x1 - Exception syndrome + * sp - Saved state + * + * Seems like we need an unused argument to the macro for the \@ syntax to work + * + */ +.macro CHECK_KERNEL_STACK unused + stp x2, x3, [sp, SS64_X2] // Save {x2-x3} + and x1, x1, #ESR_EC_MASK // Mask the exception class + mov x2, #(ESR_EC_SP_ALIGN << ESR_EC_SHIFT) + cmp x1, x2 // If we have a stack alignment exception + b.eq Lcorrupt_stack_\@ // ...the stack is definitely corrupted + mov x2, #(ESR_EC_DABORT_EL1 << ESR_EC_SHIFT) + cmp x1, x2 // If we have a data abort, we need to + b.ne Lvalid_stack_\@ // ...validate the stack pointer + mrs x1, TPIDR_EL1 // Get thread pointer +Ltest_kstack_\@: + ldr x2, [x1, TH_KSTACKPTR] // Get top of kernel stack + sub x3, x2, KERNEL_STACK_SIZE // Find bottom of kernel stack + cmp x0, x2 // if (SP_EL0 >= kstack top) + b.ge Ltest_istack_\@ // jump to istack test + cmp x0, x3 // if (SP_EL0 > kstack bottom) + b.gt Lvalid_stack_\@ // stack pointer valid +Ltest_istack_\@: + ldr x1, [x1, ACT_CPUDATAP] // Load the cpu data ptr + ldr x2, [x1, CPU_INTSTACK_TOP] // Get top of istack + sub x3, x2, INTSTACK_SIZE_NUM // Find bottom of istack + cmp x0, x2 // if (SP_EL0 >= istack top) + b.ge Lcorrupt_stack_\@ // corrupt stack pointer + cmp x0, x3 // if (SP_EL0 > istack bottom) + b.gt Lvalid_stack_\@ // stack pointer valid +Lcorrupt_stack_\@: + INIT_SAVED_STATE_FLAVORS sp, w0, w1 + mov x0, sp // Copy exception frame pointer to x0 + adrp x1, fleh_invalid_stack@page // Load address for fleh + add x1, x1, fleh_invalid_stack@pageoff // fleh_dispatch64 will save register state before we get there + ldp x2, x3, [sp, SS64_X2] // Restore {x2-x3} + b fleh_dispatch64 +Lvalid_stack_\@: + ldp x2, x3, [sp, SS64_X2] // Restore {x2-x3} +.endmacro + + #if __ARM_KERNEL_PROTECT__ .text .align 3 @@ -407,7 +459,6 @@ Lel0_serror_vector_64: stp x0, x1, [sp, SS64_X0] // Save x0, x1 to exception frame add x0, sp, ARM_CONTEXT_SIZE // Calculate the original stack pointer str x0, [sp, SS64_SP] // Save stack pointer to exception frame - stp fp, lr, [sp, SS64_FP] // Save fp and lr to exception frame INIT_SAVED_STATE_FLAVORS sp, w0, w1 mov x0, sp // Copy saved state pointer to x0 .endmacro @@ -430,10 +481,8 @@ Lel1_sp0_synchronous_vector_kernel: */ tbz x1, #(5 + ESR_EC_SHIFT), Lkernel_stack_valid mrs x0, SP_EL0 // Get SP_EL0 - stp fp, lr, [sp, SS64_FP] // Save fp, lr to the stack str x0, [sp, SS64_SP] // Save sp to the stack - bl check_kernel_stack - ldp fp, lr, [sp, SS64_FP] // Restore fp, lr + CHECK_KERNEL_STACK Lkernel_stack_valid: ldp x0, x1, [sp, SS64_X0] // Restore x0, x1 add sp, sp, ARM_CONTEXT_SIZE // Restore SP1 @@ -487,7 +536,6 @@ Lel1_sp0_serror_vector_kernel: add x0, sp, ARM_CONTEXT_SIZE // Calculate the original stack pointer str x0, [sp, SS64_SP] // Save stack pointer to exception frame INIT_SAVED_STATE_FLAVORS sp, w0, w1 - stp fp, lr, [sp, SS64_FP] // Save fp and lr to exception frame mov x0, sp // Copy saved state pointer to x0 .endmacro @@ -566,9 +614,6 @@ el1_sp1_serror_vector_long: ldp x0, x1, [sp], #16 // Restore x0 and x1 from the exception stack msr SPSel, #0 // Switch to SP0 stp x0, x1, [sp, SS64_X0] // Save x0, x1 to the user PCB - stp fp, lr, [sp, SS64_FP] // Save fp and lr to the user PCB - mov fp, #0 // Clear the fp and lr for the - mov lr, #0 // debugger stack frame mov x0, sp // Copy the user PCB pointer to x0 .endmacro @@ -643,56 +688,6 @@ Lvalid_exception_stack: mov x18, #0 b Lel1_sp1_synchronous_valid_stack -/* - * check_kernel_stack - * - * Verifies that the kernel stack is aligned and mapped within an expected - * stack address range. Note: happens before saving registers (in case we can't - * save to kernel stack). - * - * Expects: - * {x0, x1, sp} - saved - * x0 - SP_EL0 - * x1 - Exception syndrome - * sp - Saved state - */ - .text - .align 2 -check_kernel_stack: - stp x2, x3, [sp, SS64_X2] // Save {x2-x3} - and x1, x1, #ESR_EC_MASK // Mask the exception class - mov x2, #(ESR_EC_SP_ALIGN << ESR_EC_SHIFT) - cmp x1, x2 // If we have a stack alignment exception - b.eq Lcorrupt_stack // ...the stack is definitely corrupted - mov x2, #(ESR_EC_DABORT_EL1 << ESR_EC_SHIFT) - cmp x1, x2 // If we have a data abort, we need to - b.ne Lvalid_stack // ...validate the stack pointer - mrs x1, TPIDR_EL1 // Get thread pointer -Ltest_kstack: - ldr x2, [x1, TH_KSTACKPTR] // Get top of kernel stack - sub x3, x2, KERNEL_STACK_SIZE // Find bottom of kernel stack - cmp x0, x2 // if (SP_EL0 >= kstack top) - b.ge Ltest_istack // jump to istack test - cmp x0, x3 // if (SP_EL0 > kstack bottom) - b.gt Lvalid_stack // stack pointer valid -Ltest_istack: - ldr x1, [x1, ACT_CPUDATAP] // Load the cpu data ptr - ldr x2, [x1, CPU_INTSTACK_TOP] // Get top of istack - sub x3, x2, INTSTACK_SIZE_NUM // Find bottom of istack - cmp x0, x2 // if (SP_EL0 >= istack top) - b.ge Lcorrupt_stack // corrupt stack pointer - cmp x0, x3 // if (SP_EL0 > istack bottom) - b.gt Lvalid_stack // stack pointer valid -Lcorrupt_stack: - INIT_SAVED_STATE_FLAVORS sp, w0, w1 - mov x0, sp // Copy exception frame pointer to x0 - adrp x1, fleh_invalid_stack@page // Load address for fleh - add x1, x1, fleh_invalid_stack@pageoff // fleh_dispatch64 will save register state before we get there - ldp x2, x3, [sp, SS64_X2] // Restore {x2-x3} - b fleh_dispatch64 -Lvalid_stack: - ldp x2, x3, [sp, SS64_X2] // Restore {x2-x3} - ret #if defined(KERNEL_INTEGRITY_KTRR) .text @@ -731,7 +726,7 @@ check_ktrr_sctlr_trap: /* 64-bit first level exception handler dispatcher. * Completes register context saving and branches to FLEH. * Expects: - * {x0, x1, fp, lr, sp} - saved + * {x0, x1, sp} - saved * x0 - arm_context_t * x1 - address of FLEH * fp - previous stack frame if EL1 @@ -777,7 +772,8 @@ fleh_dispatch64: #endif mov x27, #0 mov x28, #0 - /* fp/lr already cleared by EL0_64_VECTOR */ + mov fp, #0 + mov lr, #0 1: mov x21, x0 // Copy arm_context_t pointer to x21 diff --git a/osfmk/arm64/pcb.c b/osfmk/arm64/pcb.c index 29f2b7185..9b2b057b1 100644 --- a/osfmk/arm64/pcb.c +++ b/osfmk/arm64/pcb.c @@ -340,9 +340,17 @@ machine_stack_attach(thread_t thread, savestate = saved_state64(&context->ss); savestate->fp = 0; savestate->sp = thread->machine.kstackptr; + + /* + * The PC and CPSR of the kernel stack saved state are never used by context switch + * code, and should never be used on exception return either. We're going to poison + * these values to ensure they never get copied to the exception frame and used to + * hijack control flow or privilege level on exception return. + */ + + const uint32_t default_cpsr = PSR64_KERNEL_POISON; #if defined(HAS_APPLE_PAC) /* Sign the initial kernel stack saved state */ - const uint32_t default_cpsr = PSR64_KERNEL_DEFAULT & ~PSR64_MODE_EL_MASK; boolean_t intr = ml_set_interrupts_enabled(FALSE); asm volatile ( "mov x0, %[ss]" "\n" @@ -352,8 +360,6 @@ machine_stack_attach(thread_t thread, "mov x2, %[default_cpsr_lo]" "\n" "movk x2, %[default_cpsr_hi], lsl #16" "\n" - "mrs x3, CurrentEL" "\n" - "orr w2, w2, w3" "\n" "str w2, [x0, %[SS64_CPSR]]" "\n" "adrp x3, _thread_continue@page" "\n" @@ -380,7 +386,8 @@ machine_stack_attach(thread_t thread, ml_set_interrupts_enabled(intr); #else savestate->lr = (uintptr_t)thread_continue; - savestate->cpsr = (PSR64_KERNEL_DEFAULT & ~PSR64_MODE_EL_MASK) | current_el; + savestate->cpsr = default_cpsr; + savestate->pc = 0; #endif /* defined(HAS_APPLE_PAC) */ machine_stack_attach_kprintf("thread = %p pc = %llx, sp = %llx\n", thread, savestate->lr, savestate->sp); } diff --git a/osfmk/arm64/proc_reg.h b/osfmk/arm64/proc_reg.h index 69533e29e..7226338ad 100644 --- a/osfmk/arm64/proc_reg.h +++ b/osfmk/arm64/proc_reg.h @@ -203,6 +203,7 @@ #else #define PSR64_KERNEL_DEFAULT PSR64_KERNEL_STANDARD #endif +#define PSR64_KERNEL_POISON (PSR64_IL | PSR64_MODE_EL1) #define PSR64_IS_KERNEL(x) ((x & PSR64_MODE_EL_MASK) > PSR64_MODE_EL0) #define PSR64_IS_USER(x) ((x & PSR64_MODE_EL_MASK) == PSR64_MODE_EL0) @@ -1496,6 +1497,19 @@ typedef enum { #define ISS_FP_IOF_SHIFT 0 #define ISS_FP_IOF (0x1 << ISS_FP_IOF_SHIFT) +/* + * Breakpoint Exception ISS (EL1) + * 24 16 0 + * +---------+---------+ + * |000000000| Comment | + * +---------+---------+ + * + * where: + * Comment: Instruction Comment Field Value + */ +#define ISS_BRK_COMMENT_MASK 0xFFFF +#define ISS_BRK_COMMENT(x) (x & ISS_BRK_COMMENT_MASK) + /* * Physical Address Register (EL1) diff --git a/osfmk/arm64/sleh.c b/osfmk/arm64/sleh.c index b6a1f10ae..87891018b 100644 --- a/osfmk/arm64/sleh.c +++ b/osfmk/arm64/sleh.c @@ -114,7 +114,7 @@ static void handle_msr_trap(arm_saved_state_t *state, uint32_t iss); extern kern_return_t arm_fast_fault(pmap_t, vm_map_address_t, vm_prot_t, bool, bool); static void handle_uncategorized(arm_saved_state_t *); -static void handle_breakpoint(arm_saved_state_t *) __dead2; +static void handle_breakpoint(arm_saved_state_t *, uint32_t) __dead2; typedef void (*abort_inspector_t)(uint32_t, fault_status_t *, vm_prot_t *); static void inspect_instruction_abort(uint32_t, fault_status_t *, vm_prot_t *); @@ -547,20 +547,20 @@ sleh_synchronous(arm_context_t *context, uint32_t esr, vm_offset_t far) __builtin_unreachable(); case ESR_EC_BKPT_AARCH32: - handle_breakpoint(state); + handle_breakpoint(state, esr); __builtin_unreachable(); case ESR_EC_BRK_AARCH64: if (PSR64_IS_KERNEL(get_saved_state_cpsr(state))) { panic_with_thread_kernel_state("Break instruction exception from kernel. Panic (by design)", state); } else { - handle_breakpoint(state); + handle_breakpoint(state, esr); } __builtin_unreachable(); case ESR_EC_BKPT_REG_MATCH_EL0: if (FSC_DEBUG_FAULT == ISS_SSDE_FSC(esr)) { - handle_breakpoint(state); + handle_breakpoint(state, esr); } panic("Unsupported Class %u event code. state=%p class=%u esr=%u far=%p", class, state, class, esr, (void *)far); @@ -750,13 +750,31 @@ handle_uncategorized(arm_saved_state_t *state) __builtin_unreachable(); } +#if __has_feature(ptrauth_calls) +static const uint16_t ptrauth_brk_comment_base = 0xc470; + +static inline bool +brk_comment_is_ptrauth(uint16_t comment) +{ + return comment >= ptrauth_brk_comment_base && + comment <= ptrauth_brk_comment_base + ptrauth_key_asdb; +} +#endif /* __has_feature(ptrauth_calls) */ + static void -handle_breakpoint(arm_saved_state_t *state) +handle_breakpoint(arm_saved_state_t *state, uint32_t esr __unused) { exception_type_t exception = EXC_BREAKPOINT; mach_exception_data_type_t codes[2] = {EXC_ARM_BREAKPOINT}; mach_msg_type_number_t numcodes = 2; +#if __has_feature(ptrauth_calls) + if (ESR_EC(esr) == ESR_EC_BRK_AARCH64 && + brk_comment_is_ptrauth(ISS_BRK_COMMENT(esr))) { + exception |= EXC_PTRAUTH_BIT; + } +#endif /* __has_feature(ptrauth_calls) */ + codes[1] = get_saved_state_pc(state); exception_triage(exception, codes, numcodes); __builtin_unreachable(); @@ -807,6 +825,36 @@ inspect_data_abort(uint32_t iss, fault_status_t *fault_code, vm_prot_t *fault_ty } } +#if __has_feature(ptrauth_calls) +static inline bool +fault_addr_bit(vm_offset_t fault_addr, unsigned int bit) +{ + return (bool)((fault_addr >> bit) & 1); +} + +/** + * Determines whether a fault address taken at EL0 contains a PAC error code + * corresponding to the specified kind of ptrauth key. + */ +static bool +user_fault_addr_matches_pac_error_code(vm_offset_t fault_addr, bool data_key) +{ + bool instruction_tbi = !(get_tcr() & TCR_TBID0_TBI_DATA_ONLY); + bool tbi = data_key || __improbable(instruction_tbi); + unsigned int poison_shift; + if (tbi) { + poison_shift = 53; + } else { + poison_shift = 61; + } + + /* PAC error codes are always in the form key_number:NOT(key_number) */ + bool poison_bit_1 = fault_addr_bit(fault_addr, poison_shift); + bool poison_bit_2 = fault_addr_bit(fault_addr, poison_shift + 1); + return poison_bit_1 != poison_bit_2; +} +#endif /* __has_feature(ptrauth_calls) */ + static void handle_pc_align(arm_saved_state_t *ss) { @@ -819,6 +867,12 @@ handle_pc_align(arm_saved_state_t *ss) } exc = EXC_BAD_ACCESS; +#if __has_feature(ptrauth_calls) + if (user_fault_addr_matches_pac_error_code(get_saved_state_pc(ss), false)) { + exc |= EXC_PTRAUTH_BIT; + } +#endif /* __has_feature(ptrauth_calls) */ + codes[0] = EXC_ARM_DA_ALIGN; codes[1] = get_saved_state_pc(ss); @@ -838,6 +892,12 @@ handle_sp_align(arm_saved_state_t *ss) } exc = EXC_BAD_ACCESS; +#if __has_feature(ptrauth_calls) + if (user_fault_addr_matches_pac_error_code(get_saved_state_sp(ss), true)) { + exc |= EXC_PTRAUTH_BIT; + } +#endif /* __has_feature(ptrauth_calls) */ + codes[0] = EXC_ARM_SP_ALIGN; codes[1] = get_saved_state_sp(ss); @@ -1132,6 +1192,12 @@ handle_user_abort(arm_saved_state_t *state, uint32_t esr, vm_offset_t fault_addr } codes[1] = fault_addr; +#if __has_feature(ptrauth_calls) + bool is_data_abort = (ESR_EC(esr) == ESR_EC_DABORT_EL0); + if (user_fault_addr_matches_pac_error_code(fault_addr, is_data_abort)) { + exc |= EXC_PTRAUTH_BIT; + } +#endif /* __has_feature(ptrauth_calls) */ exception_triage(exc, codes, numcodes); __builtin_unreachable(); } diff --git a/osfmk/arm64/status.c b/osfmk/arm64/status.c index a9f1eec26..0d8b7c7c9 100644 --- a/osfmk/arm64/status.c +++ b/osfmk/arm64/status.c @@ -1582,7 +1582,7 @@ kern_return_t thread_entrypoint(__unused thread_t thread, int flavor, thread_state_t tstate, - unsigned int count __unused, + unsigned int count, mach_vm_offset_t * entry_point ) { @@ -1591,6 +1591,10 @@ thread_entrypoint(__unused thread_t thread, { struct arm_thread_state *state; + if (count != ARM_THREAD_STATE_COUNT) { + return KERN_INVALID_ARGUMENT; + } + state = (struct arm_thread_state *) tstate; /* @@ -1608,6 +1612,10 @@ thread_entrypoint(__unused thread_t thread, { struct arm_thread_state64 *state; + if (count != ARM_THREAD_STATE64_COUNT) { + return KERN_INVALID_ARGUMENT; + } + state = (struct arm_thread_state64*) tstate; /* diff --git a/osfmk/i386/acpi.c b/osfmk/i386/acpi.c index ee93c2eb8..ecd26bfae 100644 --- a/osfmk/i386/acpi.c +++ b/osfmk/i386/acpi.c @@ -286,8 +286,8 @@ acpi_sleep_kernel(acpi_sleep_callback func, void *refcon) mtrr_update_cpu(); #endif - /* update CPU microcode */ - ucode_update_wake(); + /* update CPU microcode and apply CPU workarounds */ + ucode_update_wake_and_apply_cpu_was(); #if CONFIG_MTRR /* set up PAT following boot processor power up */ diff --git a/osfmk/i386/bsd_i386.c b/osfmk/i386/bsd_i386.c index 039a31bb6..ee93e5b10 100644 --- a/osfmk/i386/bsd_i386.c +++ b/osfmk/i386/bsd_i386.c @@ -92,7 +92,7 @@ thread_userstack( __unused thread_t thread, int flavor, thread_state_t tstate, - __unused unsigned int count, + unsigned int count, mach_vm_offset_t *user_stack, int *customstack, __unused boolean_t is64bit @@ -107,6 +107,10 @@ thread_userstack( { x86_thread_state32_t *state25; + if (__improbable(count != x86_THREAD_STATE32_COUNT)) { + return KERN_INVALID_ARGUMENT; + } + state25 = (x86_thread_state32_t *) tstate; if (state25->esp) { @@ -124,11 +128,37 @@ thread_userstack( } case x86_THREAD_FULL_STATE64: - /* FALL THROUGH */ + { + x86_thread_full_state64_t *state25; + + if (__improbable(count != x86_THREAD_FULL_STATE64_COUNT)) { + return KERN_INVALID_ARGUMENT; + } + + state25 = (x86_thread_full_state64_t *) tstate; + + if (state25->ss64.rsp) { + *user_stack = state25->ss64.rsp; + if (customstack) { + *customstack = 1; + } + } else { + *user_stack = VM_USRSTACK64; + if (customstack) { + *customstack = 0; + } + } + break; + } + case x86_THREAD_STATE64: { x86_thread_state64_t *state25; + if (__improbable(count != x86_THREAD_STATE64_COUNT)) { + return KERN_INVALID_ARGUMENT; + } + state25 = (x86_thread_state64_t *) tstate; if (state25->rsp) { @@ -176,7 +206,7 @@ thread_entrypoint( __unused thread_t thread, int flavor, thread_state_t tstate, - __unused unsigned int count, + unsigned int count, mach_vm_offset_t *entry_point ) { @@ -192,6 +222,10 @@ thread_entrypoint( { x86_thread_state32_t *state25; + if (count != x86_THREAD_STATE32_COUNT) { + return KERN_INVALID_ARGUMENT; + } + state25 = (i386_thread_state_t *) tstate; *entry_point = state25->eip ? state25->eip : VM_MIN_ADDRESS; break; @@ -201,6 +235,10 @@ thread_entrypoint( { x86_thread_state64_t *state25; + if (count != x86_THREAD_STATE64_COUNT) { + return KERN_INVALID_ARGUMENT; + } + state25 = (x86_thread_state64_t *) tstate; *entry_point = state25->rip ? state25->rip : VM_MIN_ADDRESS64; break; diff --git a/osfmk/i386/cpuid.c b/osfmk/i386/cpuid.c index ff6c8c1fc..2187c5938 100644 --- a/osfmk/i386/cpuid.c +++ b/osfmk/i386/cpuid.c @@ -212,6 +212,7 @@ static cpuid_cache_descriptor_t intel_cpuid_leaf2_descriptor_table[] = { #define INTEL_LEAF2_DESC_NUM (sizeof(intel_cpuid_leaf2_descriptor_table) / \ sizeof(cpuid_cache_descriptor_t)) + static void do_cwas(i386_cpu_info_t *cpuinfo, boolean_t on_slave); static void cpuid_do_precpuid_was(void); @@ -251,6 +252,7 @@ static void do_cwas(i386_cpu_info_t *cpuinfo, boolean_t on_slave) { extern int force_thread_policy_tecs; + cwa_classifier_e wa_reqd; /* * Workaround for reclaiming perf counter 3 due to TSX memory ordering erratum. @@ -263,6 +265,7 @@ do_cwas(i386_cpu_info_t *cpuinfo, boolean_t on_slave) rdmsr64(MSR_IA32_TSX_FORCE_ABORT) | MSR_IA32_TSXFA_RTM_FORCE_ABORT); } + if (on_slave) { return; } @@ -1432,6 +1435,7 @@ cpuid_wa_required(cpu_wa_e wa) } break; + default: break; } diff --git a/osfmk/i386/cpuid.h b/osfmk/i386/cpuid.h index 146e77b15..b63bd71bb 100644 --- a/osfmk/i386/cpuid.h +++ b/osfmk/i386/cpuid.h @@ -183,6 +183,7 @@ #define CPUID_LEAF7_EXTFEATURE_AVX5124VNNIW _Bit(2) /* AVX512_4VNNIW */ #define CPUID_LEAF7_EXTFEATURE_AVX5124FMAPS _Bit(3) /* AVX512_4FMAPS */ #define CPUID_LEAF7_EXTFEATURE_FSREPMOV _Bit(4) /* Fast Short REP MOV */ +#define CPUID_LEAF7_EXTFEATURE_SRBDS_CTRL _Bit(9) /* SRBDS MSR Presence and Mitigation Control */ #define CPUID_LEAF7_EXTFEATURE_MDCLEAR _Bit(10) /* Overloaded VERW / L1D_FLUSH */ #define CPUID_LEAF7_EXTFEATURE_TSXFA _Bit(13) /* TSX RTM_FORCE_ABORT MSR */ #define CPUID_LEAF7_EXTFEATURE_IBRS _Bit(26) /* IBRS / IBPB */ diff --git a/osfmk/i386/fpu.c b/osfmk/i386/fpu.c index 1d7475429..2e90ed752 100644 --- a/osfmk/i386/fpu.c +++ b/osfmk/i386/fpu.c @@ -80,6 +80,9 @@ xstate_t fpu_capability = UNDEFINED; /* extended state capability */ xstate_t fpu_default = UNDEFINED; /* default extended state */ #define ALIGNED(addr, size) (((uintptr_t)(addr)&((size)-1))==0) +#define VERIFY_SAVEAREA_ALIGNED(p, a) \ + assertf(!(((uintptr_t)(p)) & ((a) - 1)), \ + "FP save area component @ 0x%lx not 8-byte aligned", ((uintptr_t)(p))) /* Forward */ @@ -535,6 +538,19 @@ clear_fpu(void) set_ts(); } +static boolean_t +fpu_allzeroes(uint64_t * __attribute((aligned(8)))ptr, uint32_t size) +{ + VERIFY_SAVEAREA_ALIGNED(ptr, sizeof(uint64_t)); + assertf((size & (sizeof(uint64_t) - 1)) == 0, "FP save area component not a multiple of 8 bytes"); + + for (uint32_t count = 0; count < (size / sizeof(uint64_t)); count++) { + if (ptr[count] != 0) { + return FALSE; + } + } + return TRUE; +} static void fpu_load_registers(void *fstate) @@ -730,13 +746,19 @@ fpu_free(thread_t thread, void *fps) } /* - * Set the floating-point state for a thread based - * on the FXSave formatted data. This is basically - * the same as fpu_set_state except it uses the - * expanded data structure. - * If the thread is not the current thread, it is - * not running (held). Locking needed against - * concurrent fpu_set_state or fpu_get_state. + * Set the floating-point state for a thread based on the FXSave formatted data. + * This is basically the same as fpu_set_state except it uses the expanded data + * structure. + * If the thread is not the current thread, it is not running (held). Locking + * needed against concurrent fpu_set_state or fpu_get_state. + * + * While translating between XNU FP state structures and the CPU-native XSAVE area, + * if we detect state components that are all zeroes, we clear the corresponding + * xstate_bv bit in the XSAVE area, because that allows the corresponding state to + * be initialized to a "clean" state. That's most important when clearing the YMM + * bit, since an initialized "upper clean" state results in a massive performance + * improvement due to elimination of false dependencies between the XMMs and the + * upper bits of the YMMs. */ kern_return_t fpu_set_fxstate( @@ -860,10 +882,20 @@ Retry: iavx->_xh.xstate_bv = AVX_XMASK; iavx->_xh.xcomp_bv = 0; + /* + * See the block comment at the top of the function for a description of why we're clearing + * xstate_bv bits. + */ if (f == x86_AVX_STATE32) { __nochk_bcopy(&xs->fpu_ymmh0, iavx->x_YMM_Hi128, 8 * sizeof(_STRUCT_XMM_REG)); + if (fpu_allzeroes((uint64_t *)(void *)iavx->x_YMM_Hi128, 8 * sizeof(_STRUCT_XMM_REG)) == TRUE) { + iavx->_xh.xstate_bv &= ~XFEM_YMM; + } } else if (f == x86_AVX_STATE64) { __nochk_bcopy(&xs->fpu_ymmh0, iavx->x_YMM_Hi128, 16 * sizeof(_STRUCT_XMM_REG)); + if (fpu_allzeroes((uint64_t *)(void *)iavx->x_YMM_Hi128, 16 * sizeof(_STRUCT_XMM_REG)) == TRUE) { + iavx->_xh.xstate_bv &= ~XFEM_YMM; + } } else { iavx->_xh.xstate_bv = (XFEM_SSE | XFEM_X87); } @@ -884,25 +916,55 @@ Retry: iavx->_xh.xstate_bv = AVX512_XMASK; iavx->_xh.xcomp_bv = 0; + /* + * See the block comment at the top of the function for a description of why we're clearing + * xstate_bv bits. + */ switch (f) { case x86_AVX512_STATE32: __nochk_bcopy(&xs.s32->fpu_k0, iavx->x_Opmask, 8 * sizeof(_STRUCT_OPMASK_REG)); __nochk_bcopy(&xs.s32->fpu_zmmh0, iavx->x_ZMM_Hi256, 8 * sizeof(_STRUCT_YMM_REG)); + if (fpu_allzeroes((uint64_t *)(void *)iavx->x_ZMM_Hi256, 8 * sizeof(_STRUCT_YMM_REG)) == TRUE) { + iavx->_xh.xstate_bv &= ~XFEM_ZMM; + } __nochk_bcopy(&xs.s32->fpu_ymmh0, iavx->x_YMM_Hi128, 8 * sizeof(_STRUCT_XMM_REG)); + if (fpu_allzeroes((uint64_t *)(void *)iavx->x_YMM_Hi128, 8 * sizeof(_STRUCT_XMM_REG)) == TRUE) { + iavx->_xh.xstate_bv &= ~XFEM_YMM; + } + DBG_AVX512_STATE(iavx); break; case x86_AVX_STATE32: __nochk_bcopy(&xs.s32->fpu_ymmh0, iavx->x_YMM_Hi128, 8 * sizeof(_STRUCT_XMM_REG)); + if (fpu_allzeroes((uint64_t *)(void *)iavx->x_YMM_Hi128, 8 * sizeof(_STRUCT_XMM_REG)) == TRUE) { + iavx->_xh.xstate_bv &= ~XFEM_YMM; + } break; case x86_AVX512_STATE64: __nochk_bcopy(&xs.s64->fpu_k0, iavx->x_Opmask, 8 * sizeof(_STRUCT_OPMASK_REG)); __nochk_bcopy(&xs.s64->fpu_zmm16, iavx->x_Hi16_ZMM, 16 * sizeof(_STRUCT_ZMM_REG)); __nochk_bcopy(&xs.s64->fpu_zmmh0, iavx->x_ZMM_Hi256, 16 * sizeof(_STRUCT_YMM_REG)); + /* + * Note that it is valid to have XFEM_ZMM set but XFEM_YMM cleared. In that case, + * the upper bits of the YMMs would be cleared and would result in a clean-upper + * state, allowing SSE instruction to avoid false dependencies. + */ + if (fpu_allzeroes((uint64_t *)(void *)iavx->x_Hi16_ZMM, 16 * sizeof(_STRUCT_ZMM_REG)) == TRUE && + fpu_allzeroes((uint64_t *)(void *)iavx->x_ZMM_Hi256, 16 * sizeof(_STRUCT_YMM_REG)) == TRUE) { + iavx->_xh.xstate_bv &= ~XFEM_ZMM; + } + __nochk_bcopy(&xs.s64->fpu_ymmh0, iavx->x_YMM_Hi128, 16 * sizeof(_STRUCT_XMM_REG)); + if (fpu_allzeroes((uint64_t *)(void *)iavx->x_YMM_Hi128, 16 * sizeof(_STRUCT_XMM_REG)) == TRUE) { + iavx->_xh.xstate_bv &= ~XFEM_YMM; + } DBG_AVX512_STATE(iavx); break; case x86_AVX_STATE64: __nochk_bcopy(&xs.s64->fpu_ymmh0, iavx->x_YMM_Hi128, 16 * sizeof(_STRUCT_XMM_REG)); + if (fpu_allzeroes((uint64_t *)(void *)iavx->x_YMM_Hi128, 16 * sizeof(_STRUCT_XMM_REG)) == TRUE) { + iavx->_xh.xstate_bv &= ~XFEM_YMM; + } break; } break; diff --git a/osfmk/i386/i386_init.c b/osfmk/i386/i386_init.c index 70fa633d7..8c1662eea 100644 --- a/osfmk/i386/i386_init.c +++ b/osfmk/i386/i386_init.c @@ -871,8 +871,8 @@ do_init_slave(boolean_t fast_restart) #if CONFIG_MTRR mtrr_update_cpu(); #endif - /* update CPU microcode */ - ucode_update_wake(); + /* update CPU microcode and apply CPU workarounds */ + ucode_update_wake_and_apply_cpu_was(); } else { init_param = FAST_SLAVE_INIT; } diff --git a/osfmk/i386/proc_reg.h b/osfmk/i386/proc_reg.h index 4ff579713..c6b8f0be9 100644 --- a/osfmk/i386/proc_reg.h +++ b/osfmk/i386/proc_reg.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2019 Apple Inc. All rights reserved. + * Copyright (c) 2000-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * diff --git a/osfmk/i386/ucode.c b/osfmk/i386/ucode.c index 139250617..9c10adb4d 100644 --- a/osfmk/i386/ucode.c +++ b/osfmk/i386/ucode.c @@ -190,13 +190,14 @@ cpu_update(__unused void *arg) * by sleeping. */ void -ucode_update_wake() +ucode_update_wake_and_apply_cpu_was() { if (global_update) { kprintf("ucode: Re-applying update after wake (CPU #%d)\n", cpu_number()); cpu_update(NULL); -#if DEBUG } else { + cpuid_do_was(); +#if DEBUG kprintf("ucode: No update to apply (CPU #%d)\n", cpu_number()); #endif } diff --git a/osfmk/i386/ucode.h b/osfmk/i386/ucode.h index e36380ba9..9c42e0ca4 100644 --- a/osfmk/i386/ucode.h +++ b/osfmk/i386/ucode.h @@ -54,4 +54,4 @@ struct intel_ucupdate { }; extern int ucode_interface(uint64_t addr); -extern void ucode_update_wake(void); +extern void ucode_update_wake_and_apply_cpu_was(void); diff --git a/osfmk/ipc/ipc_importance.c b/osfmk/ipc/ipc_importance.c index c403b9f46..2b7391cd6 100644 --- a/osfmk/ipc/ipc_importance.c +++ b/osfmk/ipc/ipc_importance.c @@ -2659,7 +2659,7 @@ portupdate: #if IMPORTANCE_TRACE if (kdebug_enable) { mach_msg_max_trailer_t *dbgtrailer = (mach_msg_max_trailer_t *) - ((vm_offset_t)kmsg->ikm_header + round_msg(kmsg->ikm_header->msgh_size)); + ((vm_offset_t)kmsg->ikm_header + mach_round_msg(kmsg->ikm_header->msgh_size)); unsigned int sender_pid = dbgtrailer->msgh_audit.val[5]; mach_msg_id_t imp_msgh_id = kmsg->ikm_header->msgh_id; KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, (IMPORTANCE_CODE(IMP_MSG, IMP_MSG_SEND)) | DBG_FUNC_START, @@ -3174,7 +3174,7 @@ ipc_importance_receive( task_t task_self = current_task(); unsigned int sender_pid = ((mach_msg_max_trailer_t *) ((vm_offset_t)kmsg->ikm_header + - round_msg(kmsg->ikm_header->msgh_size)))->msgh_audit.val[5]; + mach_round_msg(kmsg->ikm_header->msgh_size)))->msgh_audit.val[5]; #endif /* convert to a voucher with an inherit importance attribute? */ diff --git a/osfmk/ipc/ipc_kmsg.c b/osfmk/ipc/ipc_kmsg.c index 3a40a39ff..95ff1fb29 100644 --- a/osfmk/ipc/ipc_kmsg.c +++ b/osfmk/ipc/ipc_kmsg.c @@ -832,7 +832,7 @@ ipc_kmsg_trace_send(ipc_kmsg_t kmsg, * Trailer contents */ trailer = (mach_msg_trailer_t *)((vm_offset_t)msg + - round_msg((vm_offset_t)msg->msgh_size)); + (vm_offset_t)mach_round_msg(msg->msgh_size)); if (trailer->msgh_trailer_size <= sizeof(mach_msg_security_trailer_t)) { extern const security_token_t KERNEL_SECURITY_TOKEN; mach_msg_security_trailer_t *strailer; @@ -4627,6 +4627,7 @@ ipc_kmsg_copyout_ool_descriptor(mach_msg_ool_descriptor_t *dsc, mach_msg_descrip mach_msg_copy_options_t copy_options; vm_map_size_t size; mach_msg_descriptor_type_t dsc_type; + boolean_t misaligned = FALSE; //SKIP_PORT_DESCRIPTORS(saddr, sdsc_count); @@ -4644,7 +4645,59 @@ ipc_kmsg_copyout_ool_descriptor(mach_msg_ool_descriptor_t *dsc, mach_msg_descrip panic("Inconsistent OOL/copyout size on %p: expected %d, got %lld @%p", dsc, dsc->size, (unsigned long long)copy->size, copy); } - kr = vm_map_copyout_size(map, &rcv_addr, copy, size); + + if ((copy->type == VM_MAP_COPY_ENTRY_LIST) && + (trunc_page(copy->offset) != copy->offset || + round_page(dsc->size) != dsc->size)) { + misaligned = TRUE; + } + + if (misaligned) { + vm_map_address_t rounded_addr; + vm_map_size_t rounded_size; + vm_map_offset_t effective_page_mask, effective_page_size; + + effective_page_mask = VM_MAP_PAGE_MASK(map); + effective_page_size = effective_page_mask + 1; + + rounded_size = vm_map_round_page(copy->offset + size, effective_page_mask) - vm_map_trunc_page(copy->offset, effective_page_mask); + + kr = vm_allocate_kernel(map, (vm_offset_t*)&rounded_addr, rounded_size, VM_FLAGS_ANYWHERE, 0); + + if (kr == KERN_SUCCESS) { + /* + * vm_map_copy_overwrite does a full copy + * if size is too small to optimize. + * So we tried skipping the offset adjustment + * if we fail the 'size' test. + * + * if (size >= VM_MAP_COPY_OVERWRITE_OPTIMIZATION_THRESHOLD_PAGES * effective_page_size) { + * + * This resulted in leaked memory especially on the + * older watches (16k user - 4k kernel) because we + * would do a physical copy into the start of this + * rounded range but could leak part of it + * on deallocation if the 'size' being deallocated + * does not cover the full range. So instead we do + * the misalignment adjustment always so that on + * deallocation we will remove the full range. + */ + if ((rounded_addr & effective_page_mask) != + (copy->offset & effective_page_mask)) { + /* + * Need similar mis-alignment of source and destination... + */ + rounded_addr += (copy->offset & effective_page_mask); + + assert((rounded_addr & effective_page_mask) == (copy->offset & effective_page_mask)); + } + rcv_addr = rounded_addr; + + kr = vm_map_copy_overwrite(map, rcv_addr, copy, size, FALSE); + } + } else { + kr = vm_map_copyout_size(map, &rcv_addr, copy, size); + } if (kr != KERN_SUCCESS) { if (kr == KERN_RESOURCE_SHORTAGE) { *mr |= MACH_MSG_VM_KERNEL; @@ -5532,7 +5585,7 @@ ipc_kmsg_add_trailer(ipc_kmsg_t kmsg, ipc_space_t space __unused, mach_msg_max_trailer_t tmp_trailer; /* This accommodates U64, and we'll munge */ void *real_trailer_out = (void*)(mach_msg_max_trailer_t *) ((vm_offset_t)kmsg->ikm_header + - round_msg(kmsg->ikm_header->msgh_size)); + mach_round_msg(kmsg->ikm_header->msgh_size)); /* * Populate scratch with initial values set up at message allocation time. @@ -5545,7 +5598,7 @@ ipc_kmsg_add_trailer(ipc_kmsg_t kmsg, ipc_space_t space __unused, (void)thread; trailer = (mach_msg_max_trailer_t *) ((vm_offset_t)kmsg->ikm_header + - round_msg(kmsg->ikm_header->msgh_size)); + mach_round_msg(kmsg->ikm_header->msgh_size)); #endif /* __arm64__ */ if (!(option & MACH_RCV_TRAILER_MASK)) { diff --git a/osfmk/ipc/ipc_mqueue.c b/osfmk/ipc/ipc_mqueue.c index 360879748..7626a1ad2 100644 --- a/osfmk/ipc/ipc_mqueue.c +++ b/osfmk/ipc/ipc_mqueue.c @@ -1424,7 +1424,7 @@ ipc_mqueue_peek_locked(ipc_mqueue_t mq, if (msg_trailerp != NULL) { memcpy(msg_trailerp, (mach_msg_max_trailer_t *)((vm_offset_t)kmsg->ikm_header + - round_msg(kmsg->ikm_header->msgh_size)), + mach_round_msg(kmsg->ikm_header->msgh_size)), sizeof(mach_msg_max_trailer_t)); } if (kmsgp != NULL) { diff --git a/osfmk/ipc/mach_msg.c b/osfmk/ipc/mach_msg.c index f367c8e00..01a5531cf 100644 --- a/osfmk/ipc/mach_msg.c +++ b/osfmk/ipc/mach_msg.c @@ -762,7 +762,7 @@ msg_receive_error( */ trailer = (mach_msg_max_trailer_t *) ((vm_offset_t)kmsg->ikm_header + - round_msg(sizeof(mach_msg_header_t))); + mach_round_msg(sizeof(mach_msg_header_t))); kmsg->ikm_header->msgh_size = sizeof(mach_msg_header_t); bcopy((char *)&trailer_template, (char *)trailer, diff --git a/osfmk/kern/exception.c b/osfmk/kern/exception.c index c059f1c50..4cbd102c1 100644 --- a/osfmk/kern/exception.c +++ b/osfmk/kern/exception.c @@ -123,6 +123,16 @@ kern_return_t bsd_exception( mach_msg_type_number_t codeCnt); #endif /* MACH_BSD */ +#if __has_feature(ptrauth_calls) +extern int exit_with_pac_exception( + void *proc, + exception_type_t exception, + mach_exception_code_t code, + mach_exception_subcode_t subcode); + +extern bool proc_is_traced(void *p); +#endif /* __has_feature(ptrauth_calls) */ + /* * Routine: exception_init * Purpose: @@ -525,6 +535,29 @@ exception_triage( mach_msg_type_number_t codeCnt) { thread_t thread = current_thread(); +#if __has_feature(ptrauth_calls) + /* + * If it is a ptrauth violation, then check if the task has the TF_PAC_EXC_FATAL + * flag set and isn't being ptraced. If so, terminate the task via exit_with_reason + */ + if (exception & EXC_PTRAUTH_BIT) { + exception &= ~EXC_PTRAUTH_BIT; + + boolean_t traced_flag = FALSE; + task_t task = thread->task; + void *proc = task->bsd_info; + + if (task->bsd_info) { + traced_flag = proc_is_traced(proc); + } + + if (task_is_pac_exception_fatal(current_task()) && !traced_flag) { + exit_with_pac_exception(proc, exception, code[0], code[1]); + thread_exception_return(); + /* NOT_REACHABLE */ + } + } +#endif /* __has_feature(ptrauth_calls) */ return exception_triage_thread(exception, code, codeCnt, thread); } diff --git a/osfmk/kern/task.c b/osfmk/kern/task.c index df259cf29..6c1d1aa80 100644 --- a/osfmk/kern/task.c +++ b/osfmk/kern/task.c @@ -177,12 +177,14 @@ #include #endif +#include + #if KPERF extern int kpc_force_all_ctrs(task_t, int); #endif -task_t kernel_task; -zone_t task_zone; +SECURITY_READ_ONLY_LATE(task_t) kernel_task; +SECURITY_READ_ONLY_LATE(zone_t) task_zone; lck_attr_t task_lck_attr; lck_grp_t task_lck_grp; lck_grp_attr_t task_lck_grp_attr; @@ -750,6 +752,7 @@ task_reference_internal(task_t task) void * bt[TASK_REF_BTDEPTH]; int numsaved = 0; + zone_require(task, task_zone); os_ref_retain(&task->ref_count); numsaved = OSBacktrace(bt, TASK_REF_BTDEPTH); @@ -7492,3 +7495,35 @@ task_copy_vmobjects(task_t task, vm_object_query_t query, int len, int64_t* num) *num = i; } + +#if __has_feature(ptrauth_calls) + +#define PAC_EXCEPTION_ENTITLEMENT "com.apple.private.pac.exception" + +void +task_set_pac_exception_fatal_flag( + task_t task) +{ + assert(task != TASK_NULL); + + if (!IOTaskHasEntitlement(task, PAC_EXCEPTION_ENTITLEMENT)) { + return; + } + + task_lock(task); + task->t_flags |= TF_PAC_EXC_FATAL; + task_unlock(task); +} + +bool +task_is_pac_exception_fatal( + task_t task) +{ + uint32_t flags = 0; + + assert(task != TASK_NULL); + + flags = os_atomic_load(&task->t_flags, relaxed); + return (bool)(flags & TF_PAC_EXC_FATAL); +} +#endif /* __has_feature(ptrauth_calls) */ diff --git a/osfmk/kern/task.h b/osfmk/kern/task.h index 1c7ec758b..df8c779dd 100644 --- a/osfmk/kern/task.h +++ b/osfmk/kern/task.h @@ -271,6 +271,7 @@ struct task { #define TF_CA_CLIENT_WI 0x00000800 /* task has CA_CLIENT work interval */ #define TF_DARKWAKE_MODE 0x00001000 /* task is in darkwake mode */ #define TF_NO_SMT 0x00002000 /* task threads must not be paired with SMT threads */ +#define TF_PAC_EXC_FATAL 0x00004000 /* task is marked a corpse if a PAC exception occurs */ /* * Task is running within a 64-bit address space. @@ -500,11 +501,17 @@ extern kern_return_t #define TASK_REFERENCE_LEAK_DEBUG 0 +extern zone_t task_zone; + #if TASK_REFERENCE_LEAK_DEBUG extern void task_reference_internal(task_t task); extern os_ref_count_t task_deallocate_internal(task_t task); #else -#define task_reference_internal(task) os_ref_retain(&(task)->ref_count) +#define task_reference_internal(task) \ +MACRO_BEGIN \ + zone_require(task, task_zone); \ + os_ref_retain(&(task)->ref_count); \ +MACRO_END #define task_deallocate_internal(task) os_ref_release(&(task)->ref_count) #endif @@ -956,6 +963,11 @@ extern void task_copy_fields_for_exec(task_t dst_task, task_t src_task); extern void task_copy_vmobjects(task_t task, vm_object_query_t query, int len, int64_t* num); +#if __has_feature(ptrauth_calls) +extern bool task_is_pac_exception_fatal(task_t task); +extern void task_set_pac_exception_fatal_flag(task_t task); +#endif /*__has_feature(ptrauth_calls)*/ + #endif /* XNU_KERNEL_PRIVATE */ #ifdef KERNEL_PRIVATE diff --git a/osfmk/kern/thread.h b/osfmk/kern/thread.h index f5b7cf612..380c3ad40 100644 --- a/osfmk/kern/thread.h +++ b/osfmk/kern/thread.h @@ -214,7 +214,7 @@ struct thread { #define TH_OPT_SCHED_VM_GROUP 0x0200 /* Thread belongs to special scheduler VM group */ #define TH_OPT_HONOR_QLIMIT 0x0400 /* Thread will honor qlimit while sending mach_msg, regardless of MACH_SEND_ALWAYS */ #define TH_OPT_SEND_IMPORTANCE 0x0800 /* Thread will allow importance donation from kernel rpc */ -#define TH_OPT_ZONE_GC 0x1000 /* zone_gc() called on this thread */ +#define TH_OPT_ZONE_PRIV 0x1000 /* Thread may use the zone replenish reserve */ bool wake_active; /* wake event on stop */ bool at_safe_point; /* thread_abort_safely allowed */ diff --git a/osfmk/kern/zalloc.c b/osfmk/kern/zalloc.c index f25e40407..3ee2ae14f 100644 --- a/osfmk/kern/zalloc.c +++ b/osfmk/kern/zalloc.c @@ -120,8 +120,9 @@ lck_grp_attr_t zone_locks_grp_attr; */ #define from_zone_map(addr, size) \ - ((vm_offset_t)(addr) >= zone_map_min_address && \ - ((vm_offset_t)(addr) + size - 1) < zone_map_max_address ) + ((vm_offset_t)(addr) >= zone_map_min_address && \ + ((vm_offset_t)(addr) + size) >= zone_map_min_address && \ + ((vm_offset_t)(addr) + size) <= zone_map_max_address ) /* * Zone Corruption Debugging @@ -646,16 +647,19 @@ get_zone_page(struct zone_page_metadata *page_meta) void zone_require(void *addr, zone_t expected_zone) { - struct zone *src_zone = NULL; - struct zone_page_metadata *page_meta = get_zone_page_metadata((struct zone_free_element *)addr, FALSE); + struct zone_page_metadata *page_meta; - src_zone = PAGE_METADATA_GET_ZONE(page_meta); - if (__improbable(src_zone == NULL)) { - panic("Address not in a zone for zone_require check (addr: %p)", addr); + if (!from_zone_map(addr, expected_zone->elem_size)) { + panic("Address not in a zone map for zone_require check (addr: %p)", addr); } - if (__improbable(src_zone != expected_zone)) { - panic("Address not in expected zone for zone_require check (addr: %p, zone: %s)", addr, src_zone->zone_name); + page_meta = PAGE_METADATA_FOR_ELEMENT(addr); + if (PAGE_METADATA_GET_ZINDEX(page_meta) == MULTIPAGE_METADATA_MAGIC) { + page_meta = page_metadata_get_realmeta(page_meta); + } + if (PAGE_METADATA_GET_ZINDEX(page_meta) != expected_zone->index) { + panic("Address not in expected zone for zone_require check (addr: %p, zone: %s)", + addr, expected_zone->zone_name); } } @@ -2401,7 +2405,7 @@ zinit( z->gzalloc_exempt = FALSE; z->alignment_required = FALSE; z->zone_replenishing = FALSE; - z->prio_refill_watermark = 0; + z->prio_refill_count = 0; z->zone_replenish_thread = NULL; z->zp_count = 0; z->kasan_quarantine = TRUE; @@ -2565,7 +2569,52 @@ zinit( return z; } -unsigned zone_replenish_loops, zone_replenish_wakeups, zone_replenish_wakeups_initiated, zone_replenish_throttle_count; + +/* + * Dealing with zone allocations from the mach VM code. + * + * The implementation of the mach VM itself uses the zone allocator + * for things like the vm_map_entry data structure. In order to prevent + * an infinite recursion problem when adding more pages to a zone, zalloc + * uses a replenish thread to refill the VM layer's zones before they have + * too few remaining free entries. The reserved remaining free entries + * guarantee that the VM routines can get entries from already mapped pages. + * + * In order for that to work, the amount of allocations in the nested + * case have to be bounded. There are currently 2 replenish zones, and + * if each needs 1 element of each zone to add a new page to itself, that + * gives us a minumum reserve of 2 elements. + * + * There is also a deadlock issue with the zone garbage collection thread, + * or any thread that is trying to free zone pages. While holding + * the kernel's map lock they may need to allocate new VM map entries, hence + * we need enough reserve to allow them to get past the point of holding the + * map lock. After freeing that page, the GC thread will wait in drop_free_elements() + * until the replenish threads can finish. Since there's only 1 GC thread at a time, + * that adds a minimum of 1 to the reserve size. + * + * Since the minumum amount you can add to a zone is 1 page, we'll use 16K (from ARM) + * as the refill size on all platforms. + * + * When a refill zone drops to half that available, i.e. REFILL_SIZE / 2, + * zalloc_internal() will wake the replenish thread. The replenish thread runs + * until at least REFILL_SIZE worth of free elements exist, before sleeping again. + * In the meantime threads may continue to use the reserve until there are only REFILL_SIZE / 4 + * elements left. Below that point only the replenish threads themselves and the GC + * thread may continue to use from the reserve. + */ +static unsigned zone_replenish_loops; +static unsigned zone_replenish_wakeups; +static unsigned zone_replenish_wakeups_initiated; +static unsigned zone_replenish_throttle_count; + +#define ZONE_REPLENISH_TARGET (16 * 1024) +static unsigned int zone_replenish_active = 0; /* count of zones currently replenishing */ +static unsigned int zone_replenish_max_threads = 0; +static lck_spin_t zone_replenish_lock; +static lck_attr_t zone_replenish_lock_attr; +static lck_grp_t zone_replenish_lock_grp; +static lck_grp_attr_t zone_replenish_lock_grp_attr; static void zone_replenish_thread(zone_t); @@ -2576,15 +2625,14 @@ __dead2 static void zone_replenish_thread(zone_t z) { - vm_size_t free_size; - current_thread()->options |= TH_OPT_VMPRIV; + current_thread()->options |= (TH_OPT_VMPRIV | TH_OPT_ZONE_PRIV); for (;;) { lock_zone(z); assert(z->zone_valid); - z->zone_replenishing = TRUE; - assert(z->prio_refill_watermark != 0); - while ((free_size = (z->cur_size - (z->count * z->elem_size))) < (z->prio_refill_watermark * z->elem_size)) { + assert(z->zone_replenishing); + assert(z->prio_refill_count != 0); + while ((z->cur_size / z->elem_size) - z->count < z->prio_refill_count) { assert(z->doing_alloc_without_vm_priv == FALSE); assert(z->doing_alloc_with_vm_priv == FALSE); assert(z->async_prio_refill == TRUE); @@ -2634,13 +2682,23 @@ zone_replenish_thread(zone_t z) zone_replenish_loops++; } - z->zone_replenishing = FALSE; - /* Signal any potential throttled consumers, terminating - * their timer-bounded waits. - */ + /* Wakeup any potentially throttled allocations. */ thread_wakeup(z); assert_wait(&z->zone_replenish_thread, THREAD_UNINT); + + /* + * We finished refilling the zone, so decrement the active count + * and wake up any waiting GC threads. + */ + lck_spin_lock(&zone_replenish_lock); + assert(zone_replenish_active > 0); + if (--zone_replenish_active == 0) { + thread_wakeup((event_t)&zone_replenish_active); + } + lck_spin_unlock(&zone_replenish_lock); + + z->zone_replenishing = FALSE; unlock_zone(z); thread_block(THREAD_CONTINUE_NULL); zone_replenish_wakeups++; @@ -2648,11 +2706,16 @@ zone_replenish_thread(zone_t z) } void -zone_prio_refill_configure(zone_t z, vm_size_t low_water_mark) +zone_prio_refill_configure(zone_t z) { - z->prio_refill_watermark = low_water_mark; + z->prio_refill_count = ZONE_REPLENISH_TARGET / z->elem_size; z->async_prio_refill = TRUE; + z->zone_replenishing = TRUE; + lck_spin_lock(&zone_replenish_lock); + ++zone_replenish_max_threads; + ++zone_replenish_active; + lck_spin_unlock(&zone_replenish_lock); OSMemoryBarrier(); kern_return_t tres = kernel_thread_start_priority((thread_continue_t)zone_replenish_thread, z, MAXPRI_KERNEL, &z->zone_replenish_thread); @@ -3005,6 +3068,11 @@ zone_bootstrap(void) lck_attr_setdefault(&zone_metadata_lock_attr); lck_mtx_init_ext(&zone_metadata_region_lck, &zone_metadata_region_lck_ext, &zone_locks_grp, &zone_metadata_lock_attr); + lck_grp_attr_setdefault(&zone_replenish_lock_grp_attr); + lck_grp_init(&zone_replenish_lock_grp, "zone_replenish_lock", &zone_replenish_lock_grp_attr); + lck_attr_setdefault(&zone_replenish_lock_attr); + lck_spin_init(&zone_replenish_lock, &zone_replenish_lock_grp, &zone_replenish_lock_attr); + #if CONFIG_ZCACHE /* zcc_enable_for_zone_name=: enable per-cpu zone caching for . */ if (PE_parse_boot_arg_str("zcc_enable_for_zone_name", cache_zone_name, sizeof(cache_zone_name))) { @@ -3246,18 +3314,6 @@ zalloc_poison_element(boolean_t check_poison, zone_t zone, vm_offset_t addr) } } -/* - * When deleting page mappings from the kernel map, it might be necessary to split - * apart an existing vm_map_entry. That means that a "free" operation, will need to - * *allocate* new vm_map_entry structures before it can free a page. - * - * This reserve here is the number of elements which are held back from everyone except - * the zone_gc thread. This is done so the zone_gc thread should never have to wait for - * the zone replenish thread for vm_map_entry structs. If it did, it could wind up - * in a deadlock. - */ -#define VM_MAP_ENTRY_RESERVE_CNT 8 - /* * zalloc returns an element from the specified zone. */ @@ -3280,6 +3336,9 @@ zalloc_internal( thread_t thr = current_thread(); boolean_t check_poison = FALSE; boolean_t set_doing_alloc_with_vm_priv = FALSE; + vm_size_t curr_free; + vm_size_t min_free; + vm_size_t resv_free; #if CONFIG_ZLEAKS uint32_t zleak_tracedepth = 0; /* log this allocation if nonzero */ @@ -3357,47 +3416,56 @@ zalloc_internal( assert(zone->zone_valid); /* - * Check if we need another thread to replenish the zone. + * Check if we need another thread to replenish the zone or + * if we have to wait for a replenish thread to finish. * This is used for elements, like vm_map_entry, which are * needed themselves to implement zalloc(). */ - if (zone->async_prio_refill && zone->zone_replenish_thread) { - vm_size_t curr_free; - vm_size_t refill_level; - const vm_size_t reserved_min = VM_MAP_ENTRY_RESERVE_CNT * zone->elem_size; - + if (addr == 0 && zone->async_prio_refill && zone->zone_replenish_thread) { + min_free = (zone->prio_refill_count * zone->elem_size) / 2; + resv_free = min_free / 2; for (;;) { - curr_free = (zone->cur_size - (zone->count * zone->elem_size)); - refill_level = zone->prio_refill_watermark * zone->elem_size; + curr_free = zone->cur_size - (zone->count * zone->elem_size); /* * Nothing to do if there are plenty of elements. */ - if (curr_free > refill_level) { + if (curr_free > min_free) { break; } /* - * Wakeup the replenish thread. + * Wakeup the replenish thread if not running. */ - zone_replenish_wakeups_initiated++; - thread_wakeup(&zone->zone_replenish_thread); + if (!zone->zone_replenishing) { + lck_spin_lock(&zone_replenish_lock); + assert(zone_replenish_active < zone_replenish_max_threads); + ++zone_replenish_active; + lck_spin_unlock(&zone_replenish_lock); + zone->zone_replenishing = TRUE; + zone_replenish_wakeups_initiated++; + thread_wakeup(&zone->zone_replenish_thread); + } /* - * If we: - * - still have head room, more than half the refill amount, or - * - this is a VMPRIV thread and we're still above reserved, or - * - this is the zone garbage collection thread which may use the reserve - * then we don't have to wait for the replenish thread. + * We'll let VM_PRIV threads to continue to allocate until the + * reserve drops to 25%. After that only TH_OPT_ZONE_PRIV threads + * may continue. * - * The reserve for the garbage collection thread is to avoid a deadlock - * on the zone_map_lock between the replenish thread and GC thread. + * TH_OPT_ZONE_PRIV threads are the GC thread and a replenish thread itself. + * Replenish threads *need* to use the reserve. GC threads need to + * get through the current allocation, but then will wait at a higher + * level after they've dropped any locks which would deadlock the + * replenish thread. */ - if (curr_free > refill_level / 2 || - ((thr->options & TH_OPT_VMPRIV) && curr_free > reserved_min) || - (thr->options & TH_OPT_ZONE_GC)) { + if ((curr_free > resv_free && (thr->options & TH_OPT_VMPRIV)) || + (thr->options & TH_OPT_ZONE_PRIV)) { break; } + + /* + * Wait for the replenish threads to add more elements for us to allocate from. + */ zone_replenish_throttle_count++; unlock_zone(zone); assert_wait_timeout(zone, THREAD_UNINT, 1, NSEC_PER_MSEC); @@ -3412,17 +3480,17 @@ zalloc_internal( addr = try_alloc_from_zone(zone, tag, &check_poison); } - /* If we're here because of zone_gc(), we didn't wait for zone_replenish_thread to finish. - * So we need to ensure that we did successfully grab an element. And we only need to assert - * this for zones that have a replenish thread configured (in this case, the Reserved VM map - * entries zone). The value of reserved_min in the previous bit of code should have given us - * headroom even though the GC thread didn't wait. + /* + * If we didn't wait for zone_replenish_thread to finish, ensure that we did successfully grab + * an element. Obviously we only need to assert this for zones that have a replenish thread configured. + * The value of (refill_level / 2) in the previous bit of code should have given us + * headroom even though this thread didn't wait. */ - if ((thr->options & TH_OPT_ZONE_GC) && zone->async_prio_refill) { + if ((thr->options & TH_OPT_ZONE_PRIV) && zone->async_prio_refill) { assert(addr != 0); } - while ((addr == 0) && canblock) { + while (addr == 0 && canblock) { /* * zone is empty, try to expand it * @@ -4107,11 +4175,30 @@ drop_free_elements(zone_t z) vm_address_t free_page_address; vm_size_t size_to_free; + current_thread()->options |= TH_OPT_ZONE_PRIV; lock_zone(z); elt_size = z->elem_size; while (!queue_empty(&z->pages.all_free)) { + /* + * If any replenishment threads are running, defer to them, so that we don't deplete reserved zones. + * The timing of the check isn't super important, as there are enough reserves to allow freeing an + * extra page_meta. Hence, we can check without grabbing the lock every time through the loop. + * We do need the lock however to avoid missing a wakeup when we decide to block. + */ + if (zone_replenish_active > 0) { + lck_spin_lock(&zone_replenish_lock); + if (zone_replenish_active > 0) { + assert_wait(&zone_replenish_active, THREAD_UNINT); + lck_spin_unlock(&zone_replenish_lock); + unlock_zone(z); + thread_block(THREAD_CONTINUE_NULL); + lock_zone(z); + continue; + } + lck_spin_unlock(&zone_replenish_lock); + } page_meta = (struct zone_page_metadata *)queue_first(&z->pages.all_free); assert(from_zone_map((vm_address_t)page_meta, sizeof(*page_meta))); /* foreign elements should be in any_free_foreign */ /* @@ -4120,7 +4207,7 @@ drop_free_elements(zone_t z) */ if (!z->zone_destruction && z->async_prio_refill && z->zone_replenish_thread && - (vm_size_t)(page_meta->free_count - z->countfree) < z->prio_refill_watermark) { + (vm_size_t)(page_meta->free_count - z->countfree) < z->prio_refill_count) { break; } @@ -4151,9 +4238,7 @@ drop_free_elements(zone_t z) } #endif /* VM_MAX_TAG_ZONES */ kmem_free(zone_map, free_page_address, size_to_free); - if (current_thread()->options & TH_OPT_ZONE_GC) { - thread_yield_to_preemption(); - } + thread_yield_to_preemption(); lock_zone(z); } if (z->zone_destruction) { @@ -4161,6 +4246,7 @@ drop_free_elements(zone_t z) assert(z->count_all_free_pages == 0); } unlock_zone(z); + current_thread()->options &= ~TH_OPT_ZONE_PRIV; #if DEBUG || DEVELOPMENT @@ -4198,8 +4284,6 @@ zone_gc(boolean_t consider_jetsams) lck_mtx_lock(&zone_gc_lock); - current_thread()->options |= TH_OPT_ZONE_GC; - simple_lock(&all_zones_lock, &zone_locks_grp); max_zones = num_zones; simple_unlock(&all_zones_lock); @@ -4229,8 +4313,6 @@ zone_gc(boolean_t consider_jetsams) drop_free_elements(z); } - current_thread()->options &= ~TH_OPT_ZONE_GC; - lck_mtx_unlock(&zone_gc_lock); } diff --git a/osfmk/kern/zalloc.h b/osfmk/kern/zalloc.h index c5f356ff9..5e3caa6de 100644 --- a/osfmk/kern/zalloc.h +++ b/osfmk/kern/zalloc.h @@ -166,8 +166,8 @@ struct zone { uint32_t zleak_capture; /* per-zone counter for capturing every N allocations */ #endif /* CONFIG_ZLEAKS */ uint32_t zp_count; /* counter for poisoning every N frees */ - vm_size_t prio_refill_watermark; - thread_t zone_replenish_thread; + uint32_t prio_refill_count; /* if async_prio_refill, refill to this count */ + thread_t zone_replenish_thread; #if CONFIG_GZALLOC gzalloc_data_t gz; #endif /* CONFIG_GZALLOC */ @@ -325,7 +325,7 @@ extern int zfill( zone_t zone, int nelem); -extern void zone_prio_refill_configure(zone_t, vm_size_t); +extern void zone_prio_refill_configure(zone_t); /* See above/top of file. Z_* definitions moved so they would be usable by kexts */ diff --git a/osfmk/mach/arm/exception.h b/osfmk/mach/arm/exception.h index 06658bc1e..42a802824 100644 --- a/osfmk/mach/arm/exception.h +++ b/osfmk/mach/arm/exception.h @@ -35,6 +35,12 @@ #define EXCEPTION_CODE_MAX 2 /* code and subcode */ +#if XNU_KERNEL_PRIVATE +#if __has_feature(ptrauth_calls) +#define EXC_PTRAUTH_BIT 0x200 /* bit set if exception could have been caused by ptrauth failure */ +#endif /* __has_feature(ptrauth_calls) */ +#endif /* XNU_KERNEL_PRIVATE */ + /* * Trap numbers as defined by the hardware exception vectors. */ diff --git a/osfmk/mach/message.h b/osfmk/mach/message.h index a1a3a0325..cb789b57b 100644 --- a/osfmk/mach/message.h +++ b/osfmk/mach/message.h @@ -654,6 +654,28 @@ typedef union{ #define round_msg(x) (((mach_msg_size_t)(x) + sizeof (natural_t) - 1) & \ ~(sizeof (natural_t) - 1)) +#ifdef XNU_KERNEL_PRIVATE + +#include +#include +#include + +#define round_msg_overflow(in, out) __os_warn_unused(({ \ + bool __ovr = os_add_overflow(in, (__typeof__(*out))(sizeof(natural_t) - 1), out); \ + *out &= ~((__typeof__(*out))(sizeof(natural_t) - 1)); \ + __ovr; \ + })) + +static inline mach_msg_size_t +mach_round_msg(mach_msg_size_t x) +{ + if (round_msg_overflow(x, &x)) { + panic("round msg overflow"); + } + return x; +} +#endif /* XNU_KERNEL_PRIVATE */ + /* * There is no fixed upper bound to the size of Mach messages. */ diff --git a/osfmk/vm/vm_fault.c b/osfmk/vm/vm_fault.c index 0cfa66169..e558508d7 100644 --- a/osfmk/vm/vm_fault.c +++ b/osfmk/vm/vm_fault.c @@ -2580,7 +2580,12 @@ vm_fault_enter(vm_page_t m, * from the current map. We do that below right before we do the * PMAP_ENTER. */ - cs_enforcement_enabled = cs_process_enforcement(NULL); + if (pmap == kernel_pmap) { + /* kernel fault: cs_process_enforcement() does not apply */ + cs_enforcement_enabled = 0; + } else { + cs_enforcement_enabled = cs_process_enforcement(NULL); + } if (cs_enforcement_enabled && map_is_switched && map_is_switch_protected && page_immutable(m, prot) && diff --git a/osfmk/vm/vm_map.c b/osfmk/vm/vm_map.c index ab0d87614..9aa1eb9b5 100644 --- a/osfmk/vm/vm_map.c +++ b/osfmk/vm/vm_map.c @@ -552,11 +552,11 @@ override_nx(vm_map_t map, uint32_t user_tag) /* map unused on arm */ * vm_object_copy_strategically() in vm_object.c. */ -static zone_t vm_map_zone; /* zone for vm_map structures */ -zone_t vm_map_entry_zone; /* zone for vm_map_entry structures */ -static zone_t vm_map_entry_reserved_zone; /* zone with reserve for non-blocking allocations */ -static zone_t vm_map_copy_zone; /* zone for vm_map_copy structures */ -zone_t vm_map_holes_zone; /* zone for vm map holes (vm_map_links) structures */ +static zone_t vm_map_zone; /* zone for vm_map structures */ +zone_t vm_map_entry_zone; /* zone for vm_map_entry structures */ +static zone_t vm_map_entry_reserved_zone; /* zone with reserve for non-blocking allocations */ +static SECURITY_READ_ONLY_LATE(zone_t) vm_map_copy_zone; /* zone for vm_map_copy structures */ +zone_t vm_map_holes_zone; /* zone for vm map holes (vm_map_links) structures */ /* @@ -1072,12 +1072,12 @@ boolean_t vm_map_supports_hole_optimization = FALSE; void vm_kernel_reserved_entry_init(void) { - zone_prio_refill_configure(vm_map_entry_reserved_zone, (6 * PAGE_SIZE) / sizeof(struct vm_map_entry)); + zone_prio_refill_configure(vm_map_entry_reserved_zone); /* * Once we have our replenish thread set up, we can start using the vm_map_holes zone. */ - zone_prio_refill_configure(vm_map_holes_zone, (6 * PAGE_SIZE) / sizeof(struct vm_map_links)); + zone_prio_refill_configure(vm_map_holes_zone); vm_map_supports_hole_optimization = TRUE; } @@ -4185,6 +4185,7 @@ vm_map_enter_mem_object_helper( copy_map = named_entry->backing.copy; assert(copy_map->type == VM_MAP_COPY_ENTRY_LIST); + zone_require(copy_map, vm_map_copy_zone); if (copy_map->type != VM_MAP_COPY_ENTRY_LIST) { /* unsupported type; should not happen */ printf("vm_map_enter_mem_object: " @@ -6681,7 +6682,7 @@ vm_map_wire_nested( if ((entry->protection & VM_PROT_EXECUTE) #if !CONFIG_EMBEDDED && - map != kernel_map && + map->pmap != kernel_pmap && cs_process_enforcement(NULL) #endif /* !CONFIG_EMBEDDED */ ) { @@ -8446,6 +8447,7 @@ vm_map_copy_discard( switch (copy->type) { case VM_MAP_COPY_ENTRY_LIST: + zone_require(copy, vm_map_copy_zone); while (vm_map_copy_first_entry(copy) != vm_map_copy_to_entry(copy)) { vm_map_entry_t entry = vm_map_copy_first_entry(copy); @@ -8460,6 +8462,7 @@ vm_map_copy_discard( } break; case VM_MAP_COPY_OBJECT: + zone_require(copy, vm_map_copy_zone); vm_object_deallocate(copy->cpy_object); break; case VM_MAP_COPY_KERNEL_BUFFER: @@ -8515,6 +8518,7 @@ vm_map_copy_copy( *new_copy = *copy; if (copy->type == VM_MAP_COPY_ENTRY_LIST) { + zone_require(copy, vm_map_copy_zone); /* * The links in the entry chain must be * changed to point to the new copy object. @@ -8783,6 +8787,7 @@ vm_map_copy_overwrite_nested( */ assert(copy->type == VM_MAP_COPY_ENTRY_LIST); + zone_require(copy, vm_map_copy_zone); if (copy->size == 0) { if (discard_on_success) { @@ -9359,6 +9364,7 @@ vm_map_copy_overwrite( vm_map_t dst_map, vm_map_offset_t dst_addr, vm_map_copy_t copy, + vm_map_size_t copy_size, boolean_t interruptible) { vm_map_size_t head_size, tail_size; @@ -9396,7 +9402,7 @@ blunt_copy: effective_page_mask); effective_page_size = effective_page_mask + 1; - if (copy->size < 3 * effective_page_size) { + if (copy_size < VM_MAP_COPY_OVERWRITE_OPTIMIZATION_THRESHOLD_PAGES * effective_page_size) { /* * Too small to bother with optimizing... */ @@ -9420,24 +9426,24 @@ blunt_copy: head_addr = dst_addr; head_size = (effective_page_size - (copy->offset & effective_page_mask)); - head_size = MIN(head_size, copy->size); + head_size = MIN(head_size, copy_size); } - if (!vm_map_page_aligned(copy->offset + copy->size, + if (!vm_map_page_aligned(copy->offset + copy_size, effective_page_mask)) { /* * Mis-alignment at the end. * Do an aligned copy up to the last page and * then an unaligned copy for the remaining bytes. */ - tail_size = ((copy->offset + copy->size) & + tail_size = ((copy->offset + copy_size) & effective_page_mask); - tail_size = MIN(tail_size, copy->size); - tail_addr = dst_addr + copy->size - tail_size; + tail_size = MIN(tail_size, copy_size); + tail_addr = dst_addr + copy_size - tail_size; assert(tail_addr >= head_addr + head_size); } - assert(head_size + tail_size <= copy->size); + assert(head_size + tail_size <= copy_size); - if (head_size + tail_size == copy->size) { + if (head_size + tail_size == copy_size) { /* * It's all unaligned, no optimization possible... */ @@ -9457,7 +9463,7 @@ blunt_copy: } for (; (entry != vm_map_copy_to_entry(copy) && - entry->vme_start < dst_addr + copy->size); + entry->vme_start < dst_addr + copy_size); entry = entry->vme_next) { if (entry->is_sub_map) { vm_map_unlock_read(dst_map); @@ -9490,6 +9496,8 @@ blunt_copy: head_copy->size = head_size; copy->offset += head_size; copy->size -= head_size; + copy_size -= head_size; + assert(copy_size > 0); vm_map_copy_clip_end(copy, entry, copy->offset); vm_map_copy_entry_unlink(copy, entry); @@ -9521,10 +9529,12 @@ blunt_copy: copy->cpy_hdr.entries_pageable; vm_map_store_init(&tail_copy->cpy_hdr); - tail_copy->offset = copy->offset + copy->size - tail_size; + tail_copy->offset = copy->offset + copy_size - tail_size; tail_copy->size = tail_size; copy->size -= tail_size; + copy_size -= tail_size; + assert(copy_size > 0); entry = vm_map_copy_last_entry(copy); vm_map_copy_clip_start(copy, entry, tail_copy->offset); @@ -9535,6 +9545,24 @@ blunt_copy: entry); } + /* + * If we are here from ipc_kmsg_copyout_ool_descriptor(), + * we want to avoid TOCTOU issues w.r.t copy->size but + * we don't need to change vm_map_copy_overwrite_nested() + * and all other vm_map_copy_overwrite variants. + * + * So we assign the original copy_size that was passed into + * this routine back to copy. + * + * This use of local 'copy_size' passed into this routine is + * to try and protect against TOCTOU attacks where the kernel + * has been exploited. We don't expect this to be an issue + * during normal system operation. + */ + assertf(copy->size == copy_size, + "Mismatch of copy sizes. Expected 0x%llx, Got 0x%llx\n", (uint64_t) copy_size, (uint64_t) copy->size); + copy->size = copy_size; + /* * Copy most (or possibly all) of the data. */ @@ -9559,6 +9587,7 @@ blunt_copy: done: assert(copy->type == VM_MAP_COPY_ENTRY_LIST); + zone_require(copy, vm_map_copy_zone); if (kr == KERN_SUCCESS) { /* * Discard all the copy maps. @@ -10539,6 +10568,7 @@ vm_map_copy_validate_size( vm_map_size_t sz = *size; switch (copy->type) { case VM_MAP_COPY_OBJECT: + zone_require(copy, vm_map_copy_zone); case VM_MAP_COPY_KERNEL_BUFFER: if (sz == copy_sz) { return TRUE; @@ -10550,6 +10580,7 @@ vm_map_copy_validate_size( * validating this flavor of vm_map_copy, but we can at least * assert that it's within a range. */ + zone_require(copy, vm_map_copy_zone); if (copy_sz >= sz && copy_sz <= vm_map_round_page(sz, VM_MAP_PAGE_MASK(dst_map))) { *size = copy_sz; @@ -10649,6 +10680,7 @@ vm_map_copyout_internal( */ if (copy->type == VM_MAP_COPY_OBJECT) { + zone_require(copy, vm_map_copy_zone); vm_object_t object = copy->cpy_object; kern_return_t kr; vm_object_offset_t offset; @@ -10688,7 +10720,7 @@ vm_map_copyout_internal( consume_on_success); } - + zone_require(copy, vm_map_copy_zone); /* * Find space for the data */ diff --git a/osfmk/vm/vm_map.h b/osfmk/vm/vm_map.h index e49170c5d..f56606f8f 100644 --- a/osfmk/vm/vm_map.h +++ b/osfmk/vm/vm_map.h @@ -1377,8 +1377,12 @@ extern kern_return_t vm_map_copy_overwrite( vm_map_t dst_map, vm_map_address_t dst_addr, vm_map_copy_t copy, + vm_map_size_t copy_size, boolean_t interruptible); +#define VM_MAP_COPY_OVERWRITE_OPTIMIZATION_THRESHOLD_PAGES (3) + + /* returns TRUE if size of vm_map_copy == size parameter FALSE otherwise */ extern boolean_t vm_map_copy_validate_size( vm_map_t dst_map, diff --git a/osfmk/vm/vm_user.c b/osfmk/vm/vm_user.c index 027d0c992..2dc0be56b 100644 --- a/osfmk/vm/vm_user.c +++ b/osfmk/vm/vm_user.c @@ -800,9 +800,13 @@ mach_vm_read_overwrite( (vm_map_size_t)size, FALSE, ©); if (KERN_SUCCESS == error) { + if (copy) { + assertf(copy->size == (vm_map_size_t) size, "Req size: 0x%llx, Copy size: 0x%llx\n", (uint64_t) size, (uint64_t) copy->size); + } + error = vm_map_copy_overwrite(current_thread()->map, (vm_map_address_t)data, - copy, FALSE); + copy, (vm_map_size_t) size, FALSE); if (KERN_SUCCESS == error) { *data_size = size; return error; @@ -843,9 +847,13 @@ vm_read_overwrite( (vm_map_size_t)size, FALSE, ©); if (KERN_SUCCESS == error) { + if (copy) { + assertf(copy->size == (vm_map_size_t) size, "Req size: 0x%llx, Copy size: 0x%llx\n", (uint64_t) size, (uint64_t) copy->size); + } + error = vm_map_copy_overwrite(current_thread()->map, (vm_map_address_t)data, - copy, FALSE); + copy, (vm_map_size_t) size, FALSE); if (KERN_SUCCESS == error) { *data_size = size; return error; @@ -866,14 +874,14 @@ mach_vm_write( vm_map_t map, mach_vm_address_t address, pointer_t data, - __unused mach_msg_type_number_t size) + mach_msg_type_number_t size) { if (map == VM_MAP_NULL) { return KERN_INVALID_ARGUMENT; } return vm_map_copy_overwrite(map, (vm_map_address_t)address, - (vm_map_copy_t) data, FALSE /* interruptible XXX */); + (vm_map_copy_t) data, size, FALSE /* interruptible XXX */); } /* @@ -891,14 +899,14 @@ vm_write( vm_map_t map, vm_address_t address, pointer_t data, - __unused mach_msg_type_number_t size) + mach_msg_type_number_t size) { if (map == VM_MAP_NULL) { return KERN_INVALID_ARGUMENT; } return vm_map_copy_overwrite(map, (vm_map_address_t)address, - (vm_map_copy_t) data, FALSE /* interruptible XXX */); + (vm_map_copy_t) data, size, FALSE /* interruptible XXX */); } /* @@ -925,9 +933,13 @@ mach_vm_copy( (vm_map_size_t)size, FALSE, ©); if (KERN_SUCCESS == kr) { + if (copy) { + assertf(copy->size == (vm_map_size_t) size, "Req size: 0x%llx, Copy size: 0x%llx\n", (uint64_t) size, (uint64_t) copy->size); + } + kr = vm_map_copy_overwrite(map, (vm_map_address_t)dest_address, - copy, FALSE /* interruptible XXX */); + copy, (vm_map_size_t) size, FALSE /* interruptible XXX */); if (KERN_SUCCESS != kr) { vm_map_copy_discard(copy); @@ -954,9 +966,13 @@ vm_copy( (vm_map_size_t)size, FALSE, ©); if (KERN_SUCCESS == kr) { + if (copy) { + assertf(copy->size == (vm_map_size_t) size, "Req size: 0x%llx, Copy size: 0x%llx\n", (uint64_t) size, (uint64_t) copy->size); + } + kr = vm_map_copy_overwrite(map, (vm_map_address_t)dest_address, - copy, FALSE /* interruptible XXX */); + copy, (vm_map_size_t) size, FALSE /* interruptible XXX */); if (KERN_SUCCESS != kr) { vm_map_copy_discard(copy); diff --git a/tests/IP6_EXTHDR_CHECK_61873584.c b/tests/IP6_EXTHDR_CHECK_61873584.c new file mode 100644 index 000000000..3569cde58 --- /dev/null +++ b/tests/IP6_EXTHDR_CHECK_61873584.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct packet1 { + struct ip6_hbh hbh; + struct ip6_opt hbh_opt; + uint8_t hbh_pad[4]; + struct ip6_frag frag; + struct ip6_dest dest; + struct ip6_opt dest_opt; + uint8_t dest_pad[4]; +}; + +struct packet2 { + struct ip6_hbh hbh; + struct ip6_opt hbh_opt; + uint8_t hbh_pad[4]; + struct ip6_frag frag; + struct ip6_opt dest_opt; + uint8_t dest_pad[6]; + uint8_t payload[16]; +}; + +T_DECL(IP6_EXTHDR_CHECK_ICMPV6_61873584, "ICMPv6 test for IP6_EXTHDR_CHECK stale mbuf pointer vulnerability", T_META("as_root", "true")) +{ + struct sockaddr_in6 daddr; + struct packet1 packet1; + struct packet2 packet2; + int s, id, res; + + srand(time(NULL)); + id = rand(); + + T_SETUPBEGIN; + T_ASSERT_POSIX_SUCCESS(s = socket(AF_INET6, SOCK_RAW, IPPROTO_HOPOPTS), NULL); + T_SETUPEND; + + memset(&daddr, 0, sizeof(daddr)); + daddr.sin6_family = AF_INET6; + daddr.sin6_port = 0; + inet_pton(AF_INET6, "::1", &daddr.sin6_addr); + + memset(&packet1, 'A', sizeof(struct packet1)); + packet1.hbh.ip6h_nxt = IPPROTO_FRAGMENT; + packet1.hbh.ip6h_len = 0; + packet1.hbh_opt.ip6o_type = IP6OPT_PADN; + packet1.hbh_opt.ip6o_len = 4; + packet1.frag.ip6f_nxt = IPPROTO_DSTOPTS; + packet1.frag.ip6f_reserved = 0; + packet1.frag.ip6f_offlg = htons(0) | IP6F_MORE_FRAG; + packet1.frag.ip6f_ident = id; + // Use IPPROTO_RAW for "assertion failed: m->m_flags & M_PKTHDR" panic + // Use IPPROTO_ICMPV6 for "m_free: freeing an already freed mbuf" panic + packet1.dest.ip6d_nxt = IPPROTO_RAW; + packet1.dest.ip6d_len = 1; + packet1.dest_opt.ip6o_type = IP6OPT_PADN; + packet1.dest_opt.ip6o_len = 4; + + memset(&packet2, 'B', sizeof(struct packet2)); + packet2.hbh.ip6h_nxt = IPPROTO_FRAGMENT; + packet2.hbh.ip6h_len = 0; + packet2.hbh_opt.ip6o_type = IP6OPT_PADN; + packet2.hbh_opt.ip6o_len = 4; + packet2.frag.ip6f_nxt = IPPROTO_DSTOPTS; + packet2.frag.ip6f_reserved = 0; + packet2.frag.ip6f_offlg = htons(8); + packet2.frag.ip6f_ident = id; + packet2.dest_opt.ip6o_type = IP6OPT_PADN; + packet2.dest_opt.ip6o_len = 6; + + T_ASSERT_POSIX_SUCCESS(res = sendto(s, (char *)&packet1, sizeof(packet1), 0, + (struct sockaddr *)&daddr, (socklen_t)sizeof(daddr)), NULL); + T_ASSERT_POSIX_SUCCESS(res = sendto(s, (char *)&packet2, sizeof(packet2), 0, + (struct sockaddr *)&daddr, (socklen_t)sizeof(daddr)), NULL); + T_ASSERT_POSIX_SUCCESS(res = close(s), NULL); +} diff --git a/tests/Makefile b/tests/Makefile index 790dc11c1..5fef05882 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -277,6 +277,8 @@ task_vm_info_decompressions: INVALID_ARCHS = x86_64 i386 socket_bind_35243417: CODE_SIGN_ENTITLEMENTS = network_entitlements.plist socket_bind_35685803: CODE_SIGN_ENTITLEMENTS = network_entitlements.plist +sioc-if-addr-bounds: sioc-if-addr-bounds.c + net_tuntests: CODE_SIGN_ENTITLEMENTS = network_entitlements.plist net_bridge: OTHER_CFLAGS += bpflib.c in_cksum.c diff --git a/tests/ioc_str.h b/tests/ioc_str.h new file mode 100644 index 000000000..f1794bf61 --- /dev/null +++ b/tests/ioc_str.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2020 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +#ifndef ioc_str_h +#define ioc_str_h + +#include +#include +#include + +#include + +#include + +#include +#include + +#define SIOC_LIST \ + X(SIOCSIFADDR_IN6) \ + X(SIOCGIFADDR_IN6) \ + X(SIOCSIFDSTADDR_IN6) \ + X(SIOCSIFNETMASK_IN6) \ + X(SIOCGIFDSTADDR_IN6) \ + X(SIOCGIFNETMASK_IN6) \ + X(SIOCDIFADDR_IN6) \ + X(SIOCAIFADDR_IN6) \ + X(SIOCSIFPHYADDR_IN6) \ + X(SIOCGIFPSRCADDR_IN6) \ + X(SIOCGIFPDSTADDR_IN6) \ + X(SIOCGIFAFLAG_IN6) \ + X(SIOCGDRLST_IN6) \ + X(SIOCGPRLST_IN6) \ + X(SIOCGIFINFO_IN6) \ + X(SIOCSNDFLUSH_IN6) \ + X(SIOCGNBRINFO_IN6) \ + X(SIOCSPFXFLUSH_IN6) \ + X(SIOCSRTRFLUSH_IN6) \ + X(SIOCGIFALIFETIME_IN6) \ + X(SIOCSIFALIFETIME_IN6) \ + X(SIOCGIFSTAT_IN6) \ + X(SIOCGIFSTAT_ICMP6) \ + X(SIOCSDEFIFACE_IN6) \ + X(SIOCGDEFIFACE_IN6) \ + X(SIOCSIFINFO_FLAGS) \ + X(SIOCSSCOPE6) \ + X(SIOCGSCOPE6) \ + X(SIOCGSCOPE6DEF) \ + X(SIOCSIFPREFIX_IN6) \ + X(SIOCGIFPREFIX_IN6) \ + X(SIOCDIFPREFIX_IN6) \ + X(SIOCAIFPREFIX_IN6) \ + X(SIOCCIFPREFIX_IN6) \ + X(SIOCSGIFPREFIX_IN6) \ + X(SIOCAADDRCTL_POLICY) \ + X(SIOCDADDRCTL_POLICY) \ + X(SIOCSHIWAT) \ + X(SIOCGHIWAT) \ + X(SIOCSLOWAT) \ + X(SIOCGLOWAT) \ + X(SIOCATMARK) \ + X(SIOCSPGRP) \ + X(SIOCGPGRP) \ + X(SIOCSIFADDR) \ + X(SIOCSIFDSTADDR) \ + X(SIOCSIFFLAGS) \ + X(SIOCGIFFLAGS) \ + X(SIOCSIFBRDADDR) \ + X(SIOCSIFNETMASK) \ + X(SIOCGIFMETRIC) \ + X(SIOCSIFMETRIC) \ + X(SIOCDIFADDR) \ + X(SIOCAIFADDR) \ + X(SIOCGIFADDR) \ + X(SIOCGIFDSTADDR) \ + X(SIOCGIFBRDADDR) \ + X(SIOCGIFCONF) \ + X(SIOCGIFNETMASK) \ + X(SIOCAUTOADDR) \ + X(SIOCAUTONETMASK) \ + X(SIOCARPIPLL) \ + X(SIOCADDMULTI) \ + X(SIOCDELMULTI) \ + X(SIOCGIFMTU) \ + X(SIOCSIFMTU) \ + X(SIOCGIFPHYS) \ + X(SIOCSIFPHYS) \ + X(SIOCSIFMEDIA) \ + X(SIOCGIFMEDIA) \ + X(SIOCSIFGENERIC) \ + X(SIOCGIFGENERIC) \ + X(SIOCRSLVMULTI) \ + X(SIOCSIFLLADDR) \ + X(SIOCGIFSTATUS) \ + X(SIOCSIFPHYADDR) \ + X(SIOCGIFPSRCADDR) \ + X(SIOCGIFPDSTADDR) \ + X(SIOCDIFPHYADDR) \ + X(SIOCGIFDEVMTU) \ + X(SIOCSIFALTMTU) \ + X(SIOCGIFALTMTU) \ + X(SIOCSIFBOND) \ + X(SIOCGIFBOND) \ + X(SIOCGIFXMEDIA) \ + X(SIOCSIFCAP) \ + X(SIOCGIFCAP) \ + X(SIOCIFCREATE) \ + X(SIOCIFDESTROY) \ + X(SIOCIFCREATE2) \ + X(SIOCSDRVSPEC) \ + X(SIOCGDRVSPEC) \ + X(SIOCSIFVLAN) \ + X(SIOCGIFVLAN) \ + X(SIOCIFGCLONERS) \ + X(SIOCGIFASYNCMAP) \ + X(SIOCSIFASYNCMAP) \ + X(SIOCGIFMAC) \ + X(SIOCSIFMAC) \ + X(SIOCSIFKPI) \ + X(SIOCGIFKPI) \ + X(SIOCGIFWAKEFLAGS) \ + X(SIOCGIFFUNCTIONALTYPE) \ + X(SIOCSIF6LOWPAN) \ + X(SIOCGIF6LOWPAN) \ + X(SIOCGKEVID) \ + X(SIOCSKEVFILT) \ + X(SIOCGKEVFILT) \ + X(SIOCGKEVVENDOR) + +#endif /* ioc_str_h */ diff --git a/tests/macho_size_63133398.c b/tests/macho_size_63133398.c new file mode 100644 index 000000000..7266fb0cf --- /dev/null +++ b/tests/macho_size_63133398.c @@ -0,0 +1,3223 @@ +/* + * rdar://63133398 (XNU: load_machfile improperly validates macho_size) + * + * Chris J-D + * SEAR Red Team / 2020-May-18 + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define ADJUSTMENT_SIZE (1337 * PAGE_SIZE) + +/* + * The hexdumps below are for a minimal Mach-O: + * + * int main(int argc, char *argv[]) { return 0; } + * + * We need a well-formed Mach-O to wrap inside a malicious fat binary. The + * steps required to make the malicious fat binary are included programmatically + * to make it clear what we're testing for (slice size should take into account + * the file offset). See the line labelled "<-- bug". + */ +#if __x86_64__ +static const unsigned char macho[] = { + 0xcf, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xe8, 0x02, 0x00, 0x00, + 0x85, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x50, 0x41, 0x47, 0x45, 0x5a, 0x45, + 0x52, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0xe8, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65, + 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb0, 0x0f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x0f, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x75, 0x6e, 0x77, 0x69, 0x6e, 0x64, + 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, + 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb8, 0x0f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb8, 0x0f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x4c, 0x49, + 0x4e, 0x4b, 0x45, 0x44, 0x49, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x38, 0x10, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x68, 0x10, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x2f, 0x75, 0x73, 0x72, + 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x64, 0x79, 0x6c, 0x64, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0xa3, 0xc0, 0xb5, 0x19, 0x06, 0x4a, 0x31, 0xb0, 0xa9, 0x65, 0x0f, 0xd5, + 0x2f, 0xf4, 0x7e, 0x1b, 0x32, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0a, 0x00, 0x00, 0x10, 0x0a, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x58, 0x02, + 0x2a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x80, 0x18, 0x00, 0x00, 0x00, + 0xb0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, + 0x00, 0x00, 0x01, 0x00, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x69, 0x62, + 0x2f, 0x6c, 0x69, 0x62, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x42, + 0x2e, 0x64, 0x79, 0x6c, 0x69, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x26, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x10, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x48, 0x89, 0xe5, + 0x31, 0xc0, 0x5d, 0xc3, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xb0, 0x0f, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0xb9, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x01, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x5f, 0x00, 0x05, 0x00, 0x02, 0x5f, + 0x6d, 0x68, 0x5f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x5f, 0x68, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x00, 0x21, 0x6d, 0x61, 0x69, 0x6e, 0x00, + 0x25, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0xb0, 0x1f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x00, + 0xb0, 0x0f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x5f, 0x5f, 0x6d, 0x68, 0x5f, 0x65, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x00, 0x5f, 0x6d, + 0x61, 0x69, 0x6e, 0x00, 0x64, 0x79, 0x6c, 0x64, 0x5f, 0x73, 0x74, 0x75, + 0x62, 0x5f, 0x62, 0x69, 0x6e, 0x64, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00 +}; +static const size_t macho_size = 4248; +#elif __arm64__ +static const unsigned char macho[] = { + 0xcf, 0xfa, 0xed, 0xfe, 0x0c, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x85, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x50, 0x41, 0x47, 0x45, 0x5a, 0x45, + 0x52, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0xe8, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65, + 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb0, 0x7f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x7f, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x75, 0x6e, 0x77, 0x69, 0x6e, 0x64, + 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, + 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb8, 0x7f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb8, 0x7f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x4c, 0x49, + 0x4e, 0x4b, 0x45, 0x44, 0x49, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x38, 0x80, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x68, 0x80, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x2f, 0x75, 0x73, 0x72, + 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x64, 0x79, 0x6c, 0x64, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x24, 0xa7, 0x74, 0x0c, 0x30, 0x84, 0x32, 0x71, 0xa3, 0xb2, 0x38, 0xab, + 0xd5, 0x63, 0x33, 0x71, 0x32, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x5b, 0x02, + 0x2a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x80, 0x18, 0x00, 0x00, 0x00, + 0xb0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, + 0x00, 0x00, 0x01, 0x00, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x69, 0x62, + 0x2f, 0x6c, 0x69, 0x62, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x42, + 0x2e, 0x64, 0x79, 0x6c, 0x69, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x26, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x80, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x38, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x52, 0xc0, 0x03, 0x5f, 0xd6, 0x01, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xb0, 0x7f, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0xb9, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x10, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x5f, 0x00, + 0x05, 0x00, 0x02, 0x5f, 0x6d, 0x68, 0x5f, 0x65, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x00, 0x21, 0x6d, + 0x61, 0x69, 0x6e, 0x00, 0x25, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0xb0, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xff, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x0f, 0x01, 0x00, 0x00, 0xb0, 0x7f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x5f, 0x5f, 0x6d, 0x68, 0x5f, 0x65, + 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x00, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x64, 0x79, 0x6c, 0x64, + 0x5f, 0x73, 0x74, 0x75, 0x62, 0x5f, 0x62, 0x69, 0x6e, 0x64, 0x65, 0x72, + 0x00, 0x00, 0x00, 0x00 +}; +static const size_t macho_size = 32920; +#endif + +#if defined(__x86_64__) || defined(__arm64__) +static char bin_path[128]; + +static void +cleanup_bin(void) +{ + unlink(bin_path); + bin_path[0] = '\0'; +} +#endif + +T_DECL(macho_size_63133398, "load_machfile improperly validates macho_size") +{ +#if defined(__x86_64__) || defined(__arm64__) + char * const av[] = { bin_path, NULL }; + char * const ev[] = { NULL }; + int fd; + void *dst_buf; + struct fat_header *fat_header; + struct fat_arch *fat_arch; + struct mach_header *mach_header; + const size_t dst_size = macho_size + ADJUSTMENT_SIZE; + pid_t child; + int status = 0; + + T_SETUPBEGIN; + + /* prepare the temp file: */ + strcpy(bin_path, "/tmp/macho_size.XXXXXX"); + T_ASSERT_POSIX_SUCCESS(fd = mkstemp(bin_path), NULL); + atexit(cleanup_bin); + + /* size accordingly and map it in: */ + T_ASSERT_POSIX_SUCCESS(ftruncate(fd, (off_t)dst_size), NULL); + + dst_buf = mmap(NULL, (dst_size + PAGE_SIZE - 1) & ~PAGE_MASK, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0); + T_ASSERT_NE(MAP_FAILED, dst_buf, NULL); + + /* put the mach-o in: */ + mach_header = (struct mach_header *)(void *)((char *)dst_buf + ADJUSTMENT_SIZE); + memcpy(mach_header, macho, macho_size); + + /* fat binary with a single entry matching our mach-o: */ + fat_header = (struct fat_header *)(void *)dst_buf; + fat_header->magic = htonl(FAT_MAGIC); + fat_header->nfat_arch = htonl(1); + + fat_arch = (struct fat_arch *)(fat_header + 1); + fat_arch->cputype = (cpu_type_t)htonl(mach_header->cputype); + fat_arch->cpusubtype = (cpu_subtype_t)htonl(mach_header->cpusubtype); + fat_arch->offset = htonl(ADJUSTMENT_SIZE); + fat_arch->size = htonl(dst_size); /* <-- bug */ + + /* make it executable: */ + T_ASSERT_POSIX_SUCCESS(fchmod(fd, 0755), NULL); + + /* clear up anything we don't need: */ + T_ASSERT_POSIX_SUCCESS(close(fd), NULL); + T_ASSERT_POSIX_SUCCESS(munmap(dst_buf, (dst_size + PAGE_SIZE - 1) & ~PAGE_MASK), NULL); + + T_SETUPEND; + + /* and let's give it a try: */ + T_ASSERT_NE(-1, child = fork(), NULL); + if (0 == child) { + execve(av[0], av, ev); + T_ASSERT_FAIL("execve failed"); + } + + T_ASSERT_POSIX_SUCCESS(waitpid(child, &status, 0), NULL); + T_ASSERT_EQ(SIGKILL, status, NULL); +#else + T_PASS("Architecture not supported by this test; passing."); +#endif +} diff --git a/tests/pfkey.c b/tests/pfkey.c new file mode 100644 index 000000000..cebd5a74b --- /dev/null +++ b/tests/pfkey.c @@ -0,0 +1,1778 @@ +#include +#include +#include +#include +#include +#include + +T_GLOBAL_META( + T_META_NAMESPACE("xnu.pfkey"), + T_META_ASROOT(true), + T_META_CHECK_LEAKS(false)); + +#define MAX_SPD_CHECK 100 +#define TEST_SRC_ADDRESS_IPv4 "192.168.2.2" +#define TEST_DST_ADDRESS_IPv4 "192.168.2.3" +#define TEST_SRC_ADDRESS_IPv6 "fd04:5c6b:8df7:7092:0000:0000:0000:0002" +#define TEST_DST_ADDRESS_IPv6 "fd04:5c6b:8df7:7092:0000:0000:0000:0003" +#define TEST_MIGRATE_SRC_ADDRESS_IPv4 "192.168.2.10" +#define TEST_MIGRATE_DST_ADDRESS_IPv4 "192.168.2.11" +#define TEST_MIGRATE_SRC_ADDRESS_IPv6 "fd04:5c6b:8df7:7092:0000:0000:0002:0000" +#define TEST_MIGRATE_DST_ADDRESS_IPv6 "fd04:5c6b:8df7:7092:0000:0000:0003:0000" + +typedef enum { + TEST_INVALID = 0, + TEST_SADB_X_GET_OVERFLOW_60822136 = 1, + TEST_SADB_X_SPDENABLE_OVERFLOW_60822924 = 2, + TEST_SADB_X_SPDDISABLE_OVERFLOW_60822956 = 3, + TEST_SADB_UPDATE_USE_AFTER_FREE_60679513 = 4, + TEST_SADB_DUMP_HEAP_OVERFLOW_60768729 = 5, + TEST_SADB_POLICY_DUMP_HEAP_OVERFLOW_60769680 = 6, + TEST_SADB_GETSASTAT_OOB_READ_60822823 = 7, + TEST_SADB_GETSASTAT_OOB_READ_SUCCESS = 8, + TEST_SADB_EXT_MIGRATE_ADDRESS_IPv4 = 9, + TEST_SADB_EXT_MIGRATE_ADDRESS_IPv6 = 10, + TEST_SADB_EXT_MIGRATE_BAD_ADDRESS = 11, +} test_identifier; + +static test_identifier test_id = TEST_INVALID; +static dispatch_source_t pfkey_source = NULL; + +static void pfkey_cleanup(void); + +static void pfkey_process_message_test_60822136(uint8_t **mhp, int pfkey_socket); +static void pfkey_process_message_test_60822924(uint8_t **mhp, int pfkey_socket); +static void pfkey_process_message_test_60822956(uint8_t **mhp, int pfkey_socket); +static void pfkey_process_message_test_60679513(uint8_t **mhp, int pfkey_socket); +static void pfkey_process_message_test_60768729(uint8_t **mhp, int pfkey_socket); +static void pfkey_process_message_test_60769680(uint8_t **mhp, int pfkey_socket); +static void pfkey_process_message_test_60822823(uint8_t **mhp, int pfkey_socket); +static void pfkey_process_message_test_60822823_1(uint8_t **mhp, int pfkey_socket); +static void pfkey_process_message_test_60687183(uint8_t **mhp, int pfkey_socket); +static void pfkey_process_message_test_60687183_1(uint8_t **mhp, int pfkey_socket); +static void pfkey_process_message_test_60687183_2(uint8_t **mhp, int pfkey_socket); + +static void(*const process_pfkey_message_tests[])(uint8_t * *mhp, int pfkey_socket) = +{ + NULL, + pfkey_process_message_test_60822136, // TEST_SADB_X_GET_OVERFLOW_60822136 + pfkey_process_message_test_60822924, // TEST_SADB_X_SPDENABLE_OVERFLOW_60822924 + pfkey_process_message_test_60822956, // TEST_SADB_X_SPDDISABLE_OVERFLOW_60822956 + pfkey_process_message_test_60679513, // TEST_SADB_UPDATE_USE_AFTER_FREE_60679513 + pfkey_process_message_test_60768729, // TEST_SADB_DUMP_HEAP_OVERFLOW_60768729 + pfkey_process_message_test_60769680, // TEST_SADB_POLICY_DUMP_HEAP_OVERFLOW_60769680 + pfkey_process_message_test_60822823, // TEST_SADB_GETSASTAT_OOB_READ_60822823 + pfkey_process_message_test_60822823_1, // TEST_SADB_GETSASTAT_OOB_READ_SUCCESS + pfkey_process_message_test_60687183, // TEST_SADB_EXT_MIGRATE_ADDRESS_IPv4 + pfkey_process_message_test_60687183_1, // TEST_SADB_EXT_MIGRATE_ADDRESS_IPv6 + pfkey_process_message_test_60687183_2, // TEST_SADB_EXT_MIGRATE_BAD_ADDRESS +}; + +static void +pfkey_align(struct sadb_msg *msg, uint8_t **mhp) +{ + struct sadb_ext *ext; + int i; + uint8_t *p; + uint8_t *ep; /* XXX should be passed from upper layer */ + + /* validity check */ + T_QUIET; T_ASSERT_NOTNULL(msg, "pfkey align msg"); + T_QUIET; T_ASSERT_NOTNULL(mhp, "pfkey align mhp"); + + /* initialize */ + for (i = 0; i < SADB_EXT_MAX + 1; i++) { + mhp[i] = NULL; + } + + mhp[0] = (void *)msg; + + /* initialize */ + p = (void *) msg; + ep = p + PFKEY_UNUNIT64(msg->sadb_msg_len); + + /* skip base header */ + p += sizeof(struct sadb_msg); + + while (p < ep) { + ext = (void *)p; + T_QUIET; T_ASSERT_GE_PTR((void *)ep, (void *)(p + sizeof(*ext)), "pfkey extension header beyond end of buffer"); + T_QUIET; T_ASSERT_GE_ULONG((unsigned long)PFKEY_EXTLEN(ext), sizeof(*ext), "pfkey extension shorter than extension header"); + T_QUIET; T_ASSERT_GE_PTR((void *)ep, (void *)(p + PFKEY_EXTLEN(ext)), "pfkey extension length beyond end of buffer"); + + T_QUIET; T_EXPECT_NULL(mhp[ext->sadb_ext_type], "duplicate extension type %u payload", ext->sadb_ext_type); + + /* set pointer */ + switch (ext->sadb_ext_type) { + case SADB_EXT_SA: + case SADB_EXT_LIFETIME_CURRENT: + case SADB_EXT_LIFETIME_HARD: + case SADB_EXT_LIFETIME_SOFT: + case SADB_EXT_ADDRESS_SRC: + case SADB_EXT_ADDRESS_DST: + case SADB_EXT_ADDRESS_PROXY: + case SADB_EXT_KEY_AUTH: + /* XXX should to be check weak keys. */ + case SADB_EXT_KEY_ENCRYPT: + /* XXX should to be check weak keys. */ + case SADB_EXT_IDENTITY_SRC: + case SADB_EXT_IDENTITY_DST: + case SADB_EXT_SENSITIVITY: + case SADB_EXT_PROPOSAL: + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + case SADB_EXT_SPIRANGE: + case SADB_X_EXT_POLICY: + case SADB_X_EXT_SA2: + case SADB_EXT_SESSION_ID: + case SADB_EXT_SASTAT: +#ifdef SADB_X_EXT_NAT_T_TYPE + case SADB_X_EXT_NAT_T_TYPE: + case SADB_X_EXT_NAT_T_SPORT: + case SADB_X_EXT_NAT_T_DPORT: + case SADB_X_EXT_NAT_T_OA: +#endif +#ifdef SADB_X_EXT_TAG + case SADB_X_EXT_TAG: +#endif +#ifdef SADB_X_EXT_PACKET + case SADB_X_EXT_PACKET: +#endif + case SADB_X_EXT_IPSECIF: + case SADB_X_EXT_ADDR_RANGE_SRC_START: + case SADB_X_EXT_ADDR_RANGE_SRC_END: + case SADB_X_EXT_ADDR_RANGE_DST_START: + case SADB_X_EXT_ADDR_RANGE_DST_END: +#ifdef SADB_MIGRATE + case SADB_EXT_MIGRATE_ADDRESS_SRC: + case SADB_EXT_MIGRATE_ADDRESS_DST: + case SADB_X_EXT_MIGRATE_IPSECIF: +#endif + mhp[ext->sadb_ext_type] = (void *)ext; + break; + default: + T_FAIL("bad extension type %u", ext->sadb_ext_type); + T_END; + } + + p += PFKEY_EXTLEN(ext); + } + + T_QUIET; T_EXPECT_EQ_PTR((void *)ep, (void *)p, "invalid pfkey message length"); + return; +} + + +static void +recv_pfkey_message(int pfkey_socket) +{ + uint8_t buffer[8192] __attribute__((aligned(4))); + struct iovec iovecs[1] = { + { buffer, sizeof(buffer) }, + }; + struct msghdr msg = { + NULL, + 0, + iovecs, + sizeof(iovecs) / sizeof(iovecs[0]), + NULL, + 0, + 0, + }; + + do { + ssize_t result = -1; + memset(buffer, 0, sizeof(buffer)); + T_QUIET; T_ASSERT_POSIX_SUCCESS(result = recvmsg(pfkey_socket, &msg, 0), NULL); + + if (result > 0) { + T_QUIET; T_ASSERT_GE_ULONG((size_t)result, sizeof(struct sadb_msg), "Invalid PFKey message size: %zu", result); + struct sadb_msg *hdr = (struct sadb_msg *)buffer; + uint8_t *mhp[SADB_EXT_MAX + 1]; + pfkey_align(hdr, mhp); + (*process_pfkey_message_tests[test_id])(mhp, pfkey_socket); + } else if (result == 0) { + T_LOG("PFKey socket received EOF"); + break; + } + } while (1); +} + +static void +send_pfkey_spd_add_message(int pfkey_socket, uint8_t proto) +{ + uint8_t payload[MCLBYTES] __attribute__ ((aligned(32))); + bzero(payload, sizeof(payload)); + uint16_t tlen = 0; + + struct sadb_msg *msg_payload = (struct sadb_msg *)payload; + msg_payload->sadb_msg_version = PF_KEY_V2; + msg_payload->sadb_msg_type = SADB_X_SPDADD; + msg_payload->sadb_msg_errno = 0; + msg_payload->sadb_msg_satype = SADB_SATYPE_UNSPEC; + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + msg_payload->sadb_msg_reserved = 0; + msg_payload->sadb_msg_seq = 0; + msg_payload->sadb_msg_pid = (u_int32_t)getpid(); + tlen += sizeof(*msg_payload); + + struct sadb_address *src_address_payload = (struct sadb_address *)(void *)(payload + tlen); + src_address_payload->sadb_address_exttype = SADB_EXT_ADDRESS_SRC & 0xffff; + src_address_payload->sadb_address_proto = proto & 0xff; + src_address_payload->sadb_address_prefixlen = (sizeof(struct in_addr) << 3); + src_address_payload->sadb_address_reserved = 0; + tlen += sizeof(*src_address_payload); + + struct sockaddr_in *src = (struct sockaddr_in *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET, TEST_SRC_ADDRESS_IPv4, &src->sin_addr), 1, "src address fail"); + src->sin_family = AF_INET; + src->sin_len = sizeof(*src); + uint16_t len = sizeof(*src_address_payload) + PFKEY_ALIGN8(src->sin_len); + src_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(src->sin_len); + + struct sadb_address *dst_address_payload = (struct sadb_address *)(void *)(payload + tlen); + dst_address_payload->sadb_address_exttype = SADB_EXT_ADDRESS_DST & 0xffff; + dst_address_payload->sadb_address_proto = proto & 0xff; + dst_address_payload->sadb_address_prefixlen = (sizeof(struct in_addr) << 3); + dst_address_payload->sadb_address_reserved = 0; + tlen += sizeof(*dst_address_payload); + + struct sockaddr_in *dst = (struct sockaddr_in *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET, TEST_DST_ADDRESS_IPv4, &dst->sin_addr), 1, "dst address fail"); + dst->sin_family = AF_INET; + dst->sin_len = sizeof(*dst); + len = sizeof(*dst_address_payload) + PFKEY_ALIGN8(dst->sin_len); + dst_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(dst->sin_len); + + struct sadb_lifetime *lifetime_payload = (struct sadb_lifetime *)(void *)(payload + tlen); + lifetime_payload->sadb_lifetime_len = PFKEY_UNIT64(sizeof(*lifetime_payload)); + lifetime_payload->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; + tlen += sizeof(*lifetime_payload); + + struct sadb_x_policy *policy_payload = (struct sadb_x_policy *)(void *)(payload + tlen); + policy_payload->sadb_x_policy_len = PFKEY_UNIT64(sizeof(*policy_payload)); + policy_payload->sadb_x_policy_exttype = SADB_X_EXT_POLICY; + policy_payload->sadb_x_policy_type = IPSEC_POLICY_DISCARD; + policy_payload->sadb_x_policy_dir = IPSEC_DIR_OUTBOUND; + tlen += sizeof(*policy_payload); + + // Update the total length + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + T_QUIET; T_ASSERT_POSIX_SUCCESS(send(pfkey_socket, payload, (size_t)PFKEY_UNUNIT64(msg_payload->sadb_msg_len), 0), "pfkey send spd add"); +} + +static void +send_pfkey_spd_get_message(int pfkey_socket, uint32_t policy_id) +{ + uint8_t payload[MCLBYTES] __attribute__ ((aligned(32))); + bzero(payload, sizeof(payload)); + uint16_t tlen = 0; + + struct sadb_msg *msg_payload = (struct sadb_msg *)(void *)payload; + msg_payload->sadb_msg_version = PF_KEY_V2; + msg_payload->sadb_msg_type = SADB_X_SPDGET; + msg_payload->sadb_msg_errno = 0; + msg_payload->sadb_msg_satype = SADB_SATYPE_UNSPEC; + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + msg_payload->sadb_msg_reserved = 0; + msg_payload->sadb_msg_seq = 0; + msg_payload->sadb_msg_pid = (uint32_t)getpid(); + tlen += sizeof(*msg_payload); + + struct sadb_x_policy *policy_payload = (struct sadb_x_policy *)(void *)(payload + tlen); + policy_payload->sadb_x_policy_len = PFKEY_UNIT64(sizeof(*policy_payload)); + policy_payload->sadb_x_policy_exttype = SADB_X_EXT_POLICY; + policy_payload->sadb_x_policy_id = policy_id; + tlen += sizeof(*policy_payload); + + // Update the total length + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + T_QUIET; T_ASSERT_POSIX_SUCCESS(send(pfkey_socket, payload, (size_t)PFKEY_UNUNIT64(msg_payload->sadb_msg_len), 0), "pfkey send spd get failed"); +} + +static void +send_pfkey_spd_enable_message(int pfkey_socket, uint32_t policy_id) +{ + uint8_t payload[MCLBYTES] __attribute__ ((aligned(32))); + bzero(payload, sizeof(payload)); + uint16_t tlen = 0; + + struct sadb_msg *msg_payload = (struct sadb_msg *)(void *)payload; + msg_payload->sadb_msg_version = PF_KEY_V2; + msg_payload->sadb_msg_type = SADB_X_SPDENABLE; + msg_payload->sadb_msg_errno = 0; + msg_payload->sadb_msg_satype = SADB_SATYPE_UNSPEC; + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + msg_payload->sadb_msg_reserved = 0; + msg_payload->sadb_msg_seq = 0; + msg_payload->sadb_msg_pid = (uint32_t)getpid(); + tlen += sizeof(*msg_payload); + + struct sadb_x_policy *policy_payload = (struct sadb_x_policy *)(void *)(payload + tlen); + policy_payload->sadb_x_policy_len = PFKEY_UNIT64(sizeof(*policy_payload)); + policy_payload->sadb_x_policy_exttype = SADB_X_EXT_POLICY; + policy_payload->sadb_x_policy_id = policy_id; + tlen += sizeof(*policy_payload); + + // Update the total length + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + T_QUIET; T_ASSERT_POSIX_SUCCESS(send(pfkey_socket, payload, (size_t)PFKEY_UNUNIT64(msg_payload->sadb_msg_len), 0), "pfkey send spd enable failed"); +} + +static void +send_pfkey_spd_disable_message(int pfkey_socket, uint32_t policy_id) +{ + uint8_t payload[MCLBYTES] __attribute__ ((aligned(32))); + bzero(payload, sizeof(payload)); + uint16_t tlen = 0; + + struct sadb_msg *msg_payload = (struct sadb_msg *)(void *)payload; + msg_payload->sadb_msg_version = PF_KEY_V2; + msg_payload->sadb_msg_type = SADB_X_SPDDISABLE; + msg_payload->sadb_msg_errno = 0; + msg_payload->sadb_msg_satype = SADB_SATYPE_UNSPEC; + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + msg_payload->sadb_msg_reserved = 0; + msg_payload->sadb_msg_seq = 0; + msg_payload->sadb_msg_pid = (uint32_t)getpid(); + tlen += sizeof(*msg_payload); + + struct sadb_x_policy *policy_payload = (struct sadb_x_policy *)(void *)(payload + tlen); + policy_payload->sadb_x_policy_len = PFKEY_UNIT64(sizeof(*policy_payload)); + policy_payload->sadb_x_policy_exttype = SADB_X_EXT_POLICY; + policy_payload->sadb_x_policy_id = policy_id; + tlen += sizeof(*policy_payload); + + // Update the total length + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + T_QUIET; T_ASSERT_POSIX_SUCCESS(send(pfkey_socket, payload, (size_t)PFKEY_UNUNIT64(msg_payload->sadb_msg_len), 0), "pfkey send spd disable failed"); +} + +static void +send_pfkey_spd_delete_message(int pfkey_socket, uint32_t policy_id) +{ + uint8_t payload[MCLBYTES] __attribute__ ((aligned(32))); + bzero(payload, sizeof(payload)); + uint16_t tlen = 0; + + struct sadb_msg *msg_payload = (struct sadb_msg *)payload; + msg_payload->sadb_msg_version = PF_KEY_V2; + msg_payload->sadb_msg_type = SADB_X_SPDDELETE2; + msg_payload->sadb_msg_errno = 0; + msg_payload->sadb_msg_satype = SADB_SATYPE_UNSPEC; + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + msg_payload->sadb_msg_reserved = 0; + msg_payload->sadb_msg_seq = 0; + msg_payload->sadb_msg_pid = (uint32_t)getpid(); + tlen += sizeof(*msg_payload); + + struct sadb_x_policy *policy_payload = (struct sadb_x_policy *)(void *)(payload + tlen); + policy_payload->sadb_x_policy_len = PFKEY_UNIT64(sizeof(*policy_payload)); + policy_payload->sadb_x_policy_exttype = SADB_X_EXT_POLICY; + policy_payload->sadb_x_policy_id = policy_id; + tlen += sizeof(*policy_payload); + + // Update the total length + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + T_QUIET; T_ASSERT_POSIX_SUCCESS(send(pfkey_socket, payload, (size_t)PFKEY_UNUNIT64(msg_payload->sadb_msg_len), 0), "pfkey send spd delete failed"); +} + +static void +send_pfkey_spd_dump_message(int pfkey_socket) +{ + uint8_t payload[MCLBYTES] __attribute__ ((aligned(32))); + bzero(payload, sizeof(payload)); + uint16_t tlen = 0; + + struct sadb_msg *msg_payload = (struct sadb_msg *)(void *)payload; + msg_payload->sadb_msg_version = PF_KEY_V2; + msg_payload->sadb_msg_type = SADB_X_SPDDUMP; + msg_payload->sadb_msg_errno = 0; + msg_payload->sadb_msg_satype = SADB_SATYPE_UNSPEC; + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + msg_payload->sadb_msg_reserved = 0; + msg_payload->sadb_msg_seq = 0; + msg_payload->sadb_msg_pid = (uint32_t)getpid(); + tlen += sizeof(*msg_payload); + + // Update the total length + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + T_QUIET; T_ASSERT_POSIX_SUCCESS(send(pfkey_socket, payload, (size_t)PFKEY_UNUNIT64(msg_payload->sadb_msg_len), 0), "pfkey send spd dump failed"); +} + +static void +send_pfkey_flush_sp(int pfkey_socket) +{ + uint8_t payload[MCLBYTES] __attribute__ ((aligned(32))); + bzero(payload, sizeof(payload)); + uint16_t tlen = 0; + + struct sadb_msg *msg_payload = (struct sadb_msg *)payload; + msg_payload->sadb_msg_version = PF_KEY_V2; + msg_payload->sadb_msg_type = SADB_X_SPDFLUSH; + msg_payload->sadb_msg_errno = 0; + msg_payload->sadb_msg_satype = SADB_SATYPE_UNSPEC; + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + msg_payload->sadb_msg_reserved = 0; + msg_payload->sadb_msg_seq = 0; + msg_payload->sadb_msg_pid = (u_int32_t)getpid(); + tlen += sizeof(*msg_payload); + + // Update the total length + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + T_QUIET; T_ASSERT_POSIX_SUCCESS(send(pfkey_socket, payload, (size_t)PFKEY_UNUNIT64(msg_payload->sadb_msg_len), 0), "pfkey flush security policies"); +} + +static void +send_pkey_get_spi(int pfkey_socket) +{ + uint8_t payload[MCLBYTES] __attribute__ ((aligned(32))); + bzero(payload, sizeof(payload)); + uint16_t tlen = 0; + + struct sadb_msg *msg_payload = (struct sadb_msg *)payload; + msg_payload->sadb_msg_version = PF_KEY_V2; + msg_payload->sadb_msg_type = SADB_GETSPI; + msg_payload->sadb_msg_errno = 0; + msg_payload->sadb_msg_satype = SADB_SATYPE_ESP; + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + msg_payload->sadb_msg_reserved = 0; + msg_payload->sadb_msg_seq = 0; + msg_payload->sadb_msg_pid = (u_int32_t)getpid(); + tlen += sizeof(*msg_payload); + + struct sadb_x_sa2 *sa2_payload = (struct sadb_x_sa2 *)(void *)(payload + tlen); + sa2_payload->sadb_x_sa2_len = PFKEY_UNIT64(sizeof(*sa2_payload)); + sa2_payload->sadb_x_sa2_exttype = SADB_X_EXT_SA2; + sa2_payload->sadb_x_sa2_mode = IPSEC_MODE_TRANSPORT; + sa2_payload->sadb_x_sa2_reqid = 0; + tlen += sizeof(*sa2_payload); + + struct sadb_address *src_address_payload = (struct sadb_address *)(void *)(payload + tlen); + src_address_payload->sadb_address_exttype = SADB_EXT_ADDRESS_SRC & 0xffff; + src_address_payload->sadb_address_proto = IPSEC_ULPROTO_ANY & 0xff; + src_address_payload->sadb_address_prefixlen = (sizeof(struct in_addr) << 3); + src_address_payload->sadb_address_reserved = 0; + tlen += sizeof(*src_address_payload); + + struct sockaddr_in *src = (struct sockaddr_in *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET, TEST_SRC_ADDRESS_IPv4, &src->sin_addr), 1, "src address fail"); + src->sin_family = AF_INET; + src->sin_len = sizeof(*src); + uint16_t len = sizeof(*src_address_payload) + PFKEY_ALIGN8(src->sin_len); + src_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(src->sin_len); + + struct sadb_address *dst_address_payload = (struct sadb_address *)(void *)(payload + tlen); + dst_address_payload->sadb_address_exttype = SADB_EXT_ADDRESS_DST & 0xffff; + dst_address_payload->sadb_address_proto = IPSEC_ULPROTO_ANY & 0xff; + dst_address_payload->sadb_address_prefixlen = (sizeof(struct in_addr) << 3); + dst_address_payload->sadb_address_reserved = 0; + tlen += sizeof(*dst_address_payload); + + struct sockaddr_in *dst = (struct sockaddr_in *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET, TEST_DST_ADDRESS_IPv4, &dst->sin_addr), 1, "dst address fail"); + dst->sin_family = AF_INET; + dst->sin_len = sizeof(*dst); + len = sizeof(*dst_address_payload) + PFKEY_ALIGN8(dst->sin_len); + dst_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(dst->sin_len); + + // Update the total length + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + T_QUIET; T_ASSERT_POSIX_SUCCESS(send(pfkey_socket, payload, (size_t)PFKEY_UNUNIT64(msg_payload->sadb_msg_len), 0), "pfkey send get spi"); +} + +static void +send_pkey_add_sa(int pfkey_socket, uint32_t spi, const char *src, const char *dst, int family) +{ + uint8_t payload[MCLBYTES] __attribute__ ((aligned(32))); + bzero(payload, sizeof(payload)); + uint16_t tlen = 0; + + struct sadb_msg *msg_payload = (struct sadb_msg *)payload; + msg_payload->sadb_msg_version = PF_KEY_V2; + msg_payload->sadb_msg_type = SADB_ADD; + msg_payload->sadb_msg_errno = 0; + msg_payload->sadb_msg_satype = SADB_SATYPE_ESP; + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + msg_payload->sadb_msg_reserved = 0; + msg_payload->sadb_msg_seq = 0; + msg_payload->sadb_msg_pid = (u_int32_t)getpid(); + tlen += sizeof(*msg_payload); + + struct sadb_sa_2 *sa2_payload = (struct sadb_sa_2 *)(void *)(payload + tlen); + sa2_payload->sa.sadb_sa_len = PFKEY_UNIT64(sizeof(*sa2_payload)); + sa2_payload->sa.sadb_sa_exttype = SADB_EXT_SA; + sa2_payload->sa.sadb_sa_spi = htonl(spi); + sa2_payload->sa.sadb_sa_replay = 4; + sa2_payload->sa.sadb_sa_state = SADB_SASTATE_LARVAL; + sa2_payload->sa.sadb_sa_auth = SADB_X_AALG_SHA2_256; + sa2_payload->sa.sadb_sa_encrypt = SADB_X_EALG_AESCBC; + sa2_payload->sa.sadb_sa_flags |= (SADB_X_EXT_NATT | SADB_X_EXT_NATT_KEEPALIVE); + sa2_payload->sadb_sa_natt_src_port = htons(4500); + sa2_payload->sadb_sa_natt_port = 4500; + sa2_payload->sadb_sa_natt_interval = 20; + sa2_payload->sadb_sa_natt_offload_interval = 0; + tlen += sizeof(*sa2_payload); + + struct sadb_x_sa2 *sa2_x_payload = (struct sadb_x_sa2 *)(void *)(payload + tlen); + sa2_x_payload->sadb_x_sa2_len = PFKEY_UNIT64(sizeof(*sa2_x_payload)); + sa2_x_payload->sadb_x_sa2_exttype = SADB_X_EXT_SA2; + sa2_x_payload->sadb_x_sa2_mode = IPSEC_MODE_TRANSPORT; + sa2_x_payload->sadb_x_sa2_reqid = 0; + tlen += sizeof(*sa2_x_payload); + + uint8_t prefixlen = (family == AF_INET) ? (sizeof(struct in_addr) << 3) : (sizeof(struct in6_addr) << 3); + + struct sadb_address *src_address_payload = (struct sadb_address *)(void *)(payload + tlen); + src_address_payload->sadb_address_exttype = SADB_EXT_ADDRESS_SRC & 0xffff; + src_address_payload->sadb_address_proto = IPSEC_ULPROTO_ANY & 0xff; + src_address_payload->sadb_address_prefixlen = prefixlen; + src_address_payload->sadb_address_reserved = 0; + tlen += sizeof(*src_address_payload); + + if (family == AF_INET) { + struct sockaddr_in *src4 = (struct sockaddr_in *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET, src, &src4->sin_addr), 1, "src address fail"); + src4->sin_family = AF_INET; + src4->sin_len = sizeof(*src4); + uint16_t len = sizeof(*src_address_payload) + PFKEY_ALIGN8(src4->sin_len); + src_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(src4->sin_len); + } else { + struct sockaddr_in6 *src6 = (struct sockaddr_in6 *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET6, src, &src6->sin6_addr), 1, "src address fail"); + src6->sin6_family = AF_INET6; + src6->sin6_len = sizeof(*src6); + uint16_t len = sizeof(*src_address_payload) + PFKEY_ALIGN8(src6->sin6_len); + src_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(src6->sin6_len); + } + + struct sadb_address *dst_address_payload = (struct sadb_address *)(void *)(payload + tlen); + dst_address_payload->sadb_address_exttype = SADB_EXT_ADDRESS_DST & 0xffff; + dst_address_payload->sadb_address_proto = IPSEC_ULPROTO_ANY & 0xff; + dst_address_payload->sadb_address_prefixlen = prefixlen; + dst_address_payload->sadb_address_reserved = 0; + tlen += sizeof(*dst_address_payload); + + if (family == AF_INET) { + struct sockaddr_in *dst4 = (struct sockaddr_in *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET, dst, &dst4->sin_addr), 1, "dst address fail"); + dst4->sin_family = AF_INET; + dst4->sin_len = sizeof(*dst4); + uint16_t len = sizeof(*dst_address_payload) + PFKEY_ALIGN8(dst4->sin_len); + dst_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(dst4->sin_len); + } else { + struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET6, dst, &dst6->sin6_addr), 1, "dst address fail"); + dst6->sin6_family = AF_INET6; + dst6->sin6_len = sizeof(*dst6); + uint16_t len = sizeof(*dst_address_payload) + PFKEY_ALIGN8(dst6->sin6_len); + dst_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(dst6->sin6_len); + } + + struct sadb_key *encrypt_key_payload = (struct sadb_key *)(void *)(payload + tlen); + uint16_t len = sizeof(*encrypt_key_payload) + PFKEY_ALIGN8(32); + encrypt_key_payload->sadb_key_len = PFKEY_UNIT64(len); + encrypt_key_payload->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; + encrypt_key_payload->sadb_key_bits = (uint16_t)(32 << 3); + encrypt_key_payload->sadb_key_reserved = 0; + tlen += sizeof(*encrypt_key_payload); + arc4random_buf(payload + tlen, 32); + tlen += PFKEY_ALIGN8(32); + + struct sadb_key *auth_key_payload = (struct sadb_key *)(void *)(payload + tlen); + len = sizeof(*auth_key_payload) + PFKEY_ALIGN8(32); + auth_key_payload->sadb_key_len = PFKEY_UNIT64(len); + auth_key_payload->sadb_key_exttype = SADB_EXT_KEY_AUTH; + auth_key_payload->sadb_key_bits = (uint16_t)(32 << 3); + auth_key_payload->sadb_key_reserved = 0; + tlen += sizeof(*auth_key_payload); + arc4random_buf(payload + tlen, 32); + tlen += PFKEY_ALIGN8(32); + + struct sadb_lifetime *hard_lifetime_payload = (struct sadb_lifetime *)(void *)(payload + tlen); + hard_lifetime_payload->sadb_lifetime_len = PFKEY_UNIT64(sizeof(*hard_lifetime_payload)); + hard_lifetime_payload->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; + tlen += sizeof(*hard_lifetime_payload); + + struct sadb_lifetime *soft_lifetime_payload = (struct sadb_lifetime *)(void *)(payload + tlen); + soft_lifetime_payload->sadb_lifetime_len = PFKEY_UNIT64(sizeof(*soft_lifetime_payload)); + soft_lifetime_payload->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; + tlen += sizeof(*soft_lifetime_payload); + + // Update the total length + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + T_QUIET; T_ASSERT_POSIX_SUCCESS(send(pfkey_socket, payload, (size_t)PFKEY_UNUNIT64(msg_payload->sadb_msg_len), 0), "pfkey send update sa"); +} + +static void +send_pkey_update_sa(int pfkey_socket, uint32_t spi) +{ + uint8_t payload[MCLBYTES] __attribute__ ((aligned(32))); + bzero(payload, sizeof(payload)); + uint16_t tlen = 0; + + struct sadb_msg *msg_payload = (struct sadb_msg *)payload; + msg_payload->sadb_msg_version = PF_KEY_V2; + msg_payload->sadb_msg_type = SADB_UPDATE; + msg_payload->sadb_msg_errno = 0; + msg_payload->sadb_msg_satype = SADB_SATYPE_ESP; + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + msg_payload->sadb_msg_reserved = 0; + msg_payload->sadb_msg_seq = 0; + msg_payload->sadb_msg_pid = (u_int32_t)getpid(); + tlen += sizeof(*msg_payload); + + struct sadb_sa_2 *sa2_payload = (struct sadb_sa_2 *)(void *)(payload + tlen); + sa2_payload->sa.sadb_sa_len = PFKEY_UNIT64(sizeof(*sa2_payload)); + sa2_payload->sa.sadb_sa_exttype = SADB_EXT_SA; + sa2_payload->sa.sadb_sa_spi = htonl(spi); + sa2_payload->sa.sadb_sa_replay = 4; + sa2_payload->sa.sadb_sa_state = SADB_SASTATE_LARVAL; + sa2_payload->sa.sadb_sa_auth = SADB_X_AALG_SHA2_256; + sa2_payload->sa.sadb_sa_encrypt = SADB_X_EALG_AESCBC; + sa2_payload->sa.sadb_sa_flags |= (SADB_X_EXT_NATT | SADB_X_EXT_NATT_KEEPALIVE); + sa2_payload->sadb_sa_natt_src_port = htons(4500); + sa2_payload->sadb_sa_natt_port = 0; // Bad value to trigger failure + sa2_payload->sadb_sa_natt_interval = 20; + sa2_payload->sadb_sa_natt_offload_interval = 0; + tlen += sizeof(*sa2_payload); + + struct sadb_x_sa2 *sa2_x_payload = (struct sadb_x_sa2 *)(void *)(payload + tlen); + sa2_x_payload->sadb_x_sa2_len = PFKEY_UNIT64(sizeof(*sa2_x_payload)); + sa2_x_payload->sadb_x_sa2_exttype = SADB_X_EXT_SA2; + sa2_x_payload->sadb_x_sa2_mode = IPSEC_MODE_TRANSPORT; + sa2_x_payload->sadb_x_sa2_reqid = 0; + tlen += sizeof(*sa2_x_payload); + + struct sadb_address *src_address_payload = (struct sadb_address *)(void *)(payload + tlen); + src_address_payload->sadb_address_exttype = SADB_EXT_ADDRESS_SRC & 0xffff; + src_address_payload->sadb_address_proto = IPSEC_ULPROTO_ANY & 0xff; + src_address_payload->sadb_address_prefixlen = (sizeof(struct in_addr) << 3); + src_address_payload->sadb_address_reserved = 0; + tlen += sizeof(*src_address_payload); + + struct sockaddr_in *src = (struct sockaddr_in *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET, TEST_SRC_ADDRESS_IPv4, &src->sin_addr), 1, "src address fail"); + src->sin_family = AF_INET; + src->sin_len = sizeof(*src); + uint16_t len = sizeof(*src_address_payload) + PFKEY_ALIGN8(src->sin_len); + src_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(src->sin_len); + + struct sadb_address *dst_address_payload = (struct sadb_address *)(void *)(payload + tlen); + dst_address_payload->sadb_address_exttype = SADB_EXT_ADDRESS_DST & 0xffff; + dst_address_payload->sadb_address_proto = IPSEC_ULPROTO_ANY & 0xff; + dst_address_payload->sadb_address_prefixlen = (sizeof(struct in_addr) << 3); + dst_address_payload->sadb_address_reserved = 0; + tlen += sizeof(*dst_address_payload); + + struct sockaddr_in *dst = (struct sockaddr_in *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET, TEST_DST_ADDRESS_IPv4, &dst->sin_addr), 1, "dst address fail"); + dst->sin_family = AF_INET; + dst->sin_len = sizeof(*dst); + len = sizeof(*dst_address_payload) + PFKEY_ALIGN8(dst->sin_len); + dst_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(dst->sin_len); + + struct sadb_key *encrypt_key_payload = (struct sadb_key *)(void *)(payload + tlen); + len = sizeof(*encrypt_key_payload) + PFKEY_ALIGN8(32); + encrypt_key_payload->sadb_key_len = PFKEY_UNIT64(len); + encrypt_key_payload->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; + encrypt_key_payload->sadb_key_bits = (uint16_t)(32 << 3); + encrypt_key_payload->sadb_key_reserved = 0; + tlen += sizeof(*encrypt_key_payload); + arc4random_buf(payload + tlen, 32); + tlen += PFKEY_ALIGN8(32); + + struct sadb_key *auth_key_payload = (struct sadb_key *)(void *)(payload + tlen); + len = sizeof(*auth_key_payload) + PFKEY_ALIGN8(32); + auth_key_payload->sadb_key_len = PFKEY_UNIT64(len); + auth_key_payload->sadb_key_exttype = SADB_EXT_KEY_AUTH; + auth_key_payload->sadb_key_bits = (uint16_t)(32 << 3); + auth_key_payload->sadb_key_reserved = 0; + tlen += sizeof(*auth_key_payload); + arc4random_buf(payload + tlen, 32); + tlen += PFKEY_ALIGN8(32); + + struct sadb_lifetime *hard_lifetime_payload = (struct sadb_lifetime *)(void *)(payload + tlen); + hard_lifetime_payload->sadb_lifetime_len = PFKEY_UNIT64(sizeof(*hard_lifetime_payload)); + hard_lifetime_payload->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; + tlen += sizeof(*hard_lifetime_payload); + + struct sadb_lifetime *soft_lifetime_payload = (struct sadb_lifetime *)(void *)(payload + tlen); + soft_lifetime_payload->sadb_lifetime_len = PFKEY_UNIT64(sizeof(*soft_lifetime_payload)); + soft_lifetime_payload->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; + tlen += sizeof(*soft_lifetime_payload); + + // Update the total length + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + T_QUIET; T_ASSERT_POSIX_SUCCESS(send(pfkey_socket, payload, (size_t)PFKEY_UNUNIT64(msg_payload->sadb_msg_len), 0), "pfkey send update sa"); +} + +static void +send_pkey_migrate_sa(int pfkey_socket, uint32_t spi, const char *src, const char *dst, int family, + const char *migrate_src, const char *migrate_dst, int migrate_family) +{ + uint8_t payload[MCLBYTES] __attribute__ ((aligned(32))); + bzero(payload, sizeof(payload)); + uint16_t tlen = 0; + + struct sadb_msg *msg_payload = (struct sadb_msg *)payload; + msg_payload->sadb_msg_version = PF_KEY_V2; + msg_payload->sadb_msg_type = SADB_MIGRATE; + msg_payload->sadb_msg_errno = 0; + msg_payload->sadb_msg_satype = SADB_SATYPE_ESP; + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + msg_payload->sadb_msg_reserved = 0; + msg_payload->sadb_msg_seq = 0; + msg_payload->sadb_msg_pid = (u_int32_t)getpid(); + tlen += sizeof(*msg_payload); + + struct sadb_sa_2 *sa2_payload = (struct sadb_sa_2 *)(void *)(payload + tlen); + sa2_payload->sa.sadb_sa_len = PFKEY_UNIT64(sizeof(*sa2_payload)); + sa2_payload->sa.sadb_sa_exttype = SADB_EXT_SA; + sa2_payload->sa.sadb_sa_spi = htonl(spi); + sa2_payload->sa.sadb_sa_replay = 4; + sa2_payload->sa.sadb_sa_state = SADB_SASTATE_LARVAL; + sa2_payload->sa.sadb_sa_auth = SADB_X_AALG_SHA2_256; + sa2_payload->sa.sadb_sa_encrypt = SADB_X_EALG_AESCBC; + sa2_payload->sa.sadb_sa_flags |= (SADB_X_EXT_NATT | SADB_X_EXT_NATT_KEEPALIVE); + sa2_payload->sadb_sa_natt_src_port = htons(4500); + sa2_payload->sadb_sa_natt_port = 0; // Bad value to trigger failure + sa2_payload->sadb_sa_natt_interval = 20; + sa2_payload->sadb_sa_natt_offload_interval = 0; + tlen += sizeof(*sa2_payload); + + struct sadb_x_sa2 *sa2_x_payload = (struct sadb_x_sa2 *)(void *)(payload + tlen); + sa2_x_payload->sadb_x_sa2_len = PFKEY_UNIT64(sizeof(*sa2_x_payload)); + sa2_x_payload->sadb_x_sa2_exttype = SADB_X_EXT_SA2; + sa2_x_payload->sadb_x_sa2_mode = IPSEC_MODE_TRANSPORT; + sa2_x_payload->sadb_x_sa2_reqid = 0; + tlen += sizeof(*sa2_x_payload); + + uint8_t prefixlen = (family == AF_INET) ? (sizeof(struct in_addr) << 3) : (sizeof(struct in6_addr) << 3); + + struct sadb_address *src_address_payload = (struct sadb_address *)(void *)(payload + tlen); + src_address_payload->sadb_address_exttype = SADB_EXT_ADDRESS_SRC & 0xffff; + src_address_payload->sadb_address_proto = IPSEC_ULPROTO_ANY & 0xff; + src_address_payload->sadb_address_prefixlen = prefixlen; + src_address_payload->sadb_address_reserved = 0; + tlen += sizeof(*src_address_payload); + + if (family == AF_INET) { + struct sockaddr_in *src4 = (struct sockaddr_in *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET, src, &src4->sin_addr), 1, "src address fail"); + src4->sin_family = AF_INET; + src4->sin_len = sizeof(*src4); + uint16_t len = sizeof(*src_address_payload) + PFKEY_ALIGN8(src4->sin_len); + src_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(src4->sin_len); + } else { + struct sockaddr_in6 *src6 = (struct sockaddr_in6 *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET6, src, &src6->sin6_addr), 1, "src address fail"); + src6->sin6_family = AF_INET6; + src6->sin6_len = sizeof(*src6); + uint16_t len = sizeof(*src_address_payload) + PFKEY_ALIGN8(src6->sin6_len); + src_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(src6->sin6_len); + } + + struct sadb_address *dst_address_payload = (struct sadb_address *)(void *)(payload + tlen); + dst_address_payload->sadb_address_exttype = SADB_EXT_ADDRESS_DST & 0xffff; + dst_address_payload->sadb_address_proto = IPSEC_ULPROTO_ANY & 0xff; + dst_address_payload->sadb_address_prefixlen = prefixlen; + dst_address_payload->sadb_address_reserved = 0; + tlen += sizeof(*dst_address_payload); + + if (family == AF_INET) { + struct sockaddr_in *dst4 = (struct sockaddr_in *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET, dst, &dst4->sin_addr), 1, "dst address fail"); + dst4->sin_family = AF_INET; + dst4->sin_len = sizeof(*dst4); + uint16_t len = sizeof(*dst_address_payload) + PFKEY_ALIGN8(dst4->sin_len); + dst_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(dst4->sin_len); + } else { + struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET6, dst, &dst6->sin6_addr), 1, "dst address fail"); + dst6->sin6_family = AF_INET6; + dst6->sin6_len = sizeof(*dst6); + uint16_t len = sizeof(*dst_address_payload) + PFKEY_ALIGN8(dst6->sin6_len); + dst_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(dst6->sin6_len); + } + + prefixlen = (migrate_family == AF_INET) ? (sizeof(struct in_addr) << 3) : (sizeof(struct in6_addr) << 3); + + struct sadb_address *migrate_src_address_payload = (struct sadb_address *)(void *)(payload + tlen); + migrate_src_address_payload->sadb_address_exttype = SADB_EXT_MIGRATE_ADDRESS_SRC & 0xffff; + migrate_src_address_payload->sadb_address_proto = IPSEC_ULPROTO_ANY & 0xff; + migrate_src_address_payload->sadb_address_prefixlen = prefixlen; + migrate_src_address_payload->sadb_address_reserved = 0; + tlen += sizeof(*migrate_src_address_payload); + + if (migrate_family == AF_INET) { + struct sockaddr_in *migrate_src4 = (struct sockaddr_in *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET, migrate_src, &migrate_src4->sin_addr), 1, "migrate src fail"); + migrate_src4->sin_family = AF_INET; + migrate_src4->sin_len = sizeof(*migrate_src4); + uint16_t len = sizeof(*migrate_src_address_payload) + PFKEY_ALIGN8(migrate_src4->sin_len); + migrate_src_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(migrate_src4->sin_len); + } else if (migrate_family == AF_INET6) { + struct sockaddr_in6 *migrate_src6 = (struct sockaddr_in6 *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET6, migrate_src, &migrate_src6->sin6_addr), 1, "migrate src fail"); + migrate_src6->sin6_family = AF_INET6; + migrate_src6->sin6_len = sizeof(*migrate_src6); + uint16_t len = sizeof(*migrate_src_address_payload) + PFKEY_ALIGN8(migrate_src6->sin6_len); + migrate_src_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(migrate_src6->sin6_len); + } else if (migrate_family == AF_CHAOS) { + struct sockaddr_in6 *migrate_src6 = (struct sockaddr_in6 *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET6, migrate_src, &migrate_src6->sin6_addr), 1, "migrate src fail"); + migrate_src6->sin6_family = AF_INET6; + migrate_src6->sin6_len = sizeof(*migrate_src6) + 100; // Bad value to trigger exploit + uint16_t len = sizeof(*migrate_src_address_payload) + PFKEY_ALIGN8(migrate_src6->sin6_len); + migrate_src_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(migrate_src6->sin6_len); + } + + struct sadb_address *migrate_dst_address_payload = (struct sadb_address *)(void *)(payload + tlen); + migrate_dst_address_payload->sadb_address_exttype = SADB_EXT_MIGRATE_ADDRESS_DST & 0xffff; + migrate_dst_address_payload->sadb_address_proto = IPSEC_ULPROTO_ANY & 0xff; + migrate_dst_address_payload->sadb_address_prefixlen = prefixlen; + migrate_dst_address_payload->sadb_address_reserved = 0; + + tlen += sizeof(*migrate_dst_address_payload); + + if (migrate_family == AF_INET) { + struct sockaddr_in *migrate_dst4 = (struct sockaddr_in *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET, migrate_dst, &migrate_dst4->sin_addr), 1, "migrate dst fail"); + migrate_dst4->sin_family = AF_INET; + migrate_dst4->sin_len = sizeof(*migrate_dst4); + uint16_t len = sizeof(*migrate_dst_address_payload) + PFKEY_ALIGN8(migrate_dst4->sin_len); + migrate_dst_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(migrate_dst4->sin_len); + } else if (migrate_family == AF_INET6) { + struct sockaddr_in6 *migrate_dst6 = (struct sockaddr_in6 *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET6, migrate_dst, &migrate_dst6->sin6_addr), 1, "migrate dst fail"); + migrate_dst6->sin6_family = AF_INET6; + migrate_dst6->sin6_len = sizeof(*migrate_dst6); + uint16_t len = sizeof(*migrate_dst_address_payload) + PFKEY_ALIGN8(migrate_dst6->sin6_len); + migrate_dst_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(migrate_dst6->sin6_len); + } else if (migrate_family == AF_CHAOS) { + struct sockaddr_in6 *migrate_dst6 = (struct sockaddr_in6 *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET6, migrate_dst, &migrate_dst6->sin6_addr), 1, "migrate dst fail"); + migrate_dst6->sin6_family = AF_INET6; + migrate_dst6->sin6_len = sizeof(*migrate_dst6) + 100; // Bad value to trigger exploit + uint16_t len = sizeof(*migrate_dst_address_payload) + PFKEY_ALIGN8(migrate_dst6->sin6_len); + migrate_dst_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(migrate_dst6->sin6_len); + } + + // Update the total length + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + T_QUIET; T_ASSERT_POSIX_SUCCESS(send(pfkey_socket, payload, (size_t)PFKEY_UNUNIT64(msg_payload->sadb_msg_len), 0), "pfkey send migrate sa"); +} + +static void +send_pfkey_get_sa_stat(int pfkey_socket, uint32_t spi, uint32_t stat_length) +{ + uint8_t payload[MCLBYTES] __attribute__ ((aligned(32))); + bzero(payload, sizeof(payload)); + uint16_t tlen = 0; + + struct sadb_msg *msg_payload = (struct sadb_msg *)payload; + msg_payload->sadb_msg_version = PF_KEY_V2; + msg_payload->sadb_msg_type = SADB_GETSASTAT; + msg_payload->sadb_msg_errno = 0; + msg_payload->sadb_msg_satype = SADB_SATYPE_UNSPEC; + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + msg_payload->sadb_msg_reserved = 0; + msg_payload->sadb_msg_seq = 0; + msg_payload->sadb_msg_pid = (u_int32_t)getpid(); + tlen += sizeof(*msg_payload); + + struct sadb_session_id *session_id_payload = (struct sadb_session_id *)(void *)(payload + tlen); + session_id_payload->sadb_session_id_len = PFKEY_UNIT64(sizeof(*session_id_payload)); + session_id_payload->sadb_session_id_exttype = SADB_EXT_SESSION_ID; + session_id_payload->sadb_session_id_v[0] = 1; + tlen += sizeof(*session_id_payload); + + struct sadb_sastat *sadb_stat_payload = (struct sadb_sastat *)(void *)(payload + tlen); + uint16_t length = sizeof(*sadb_stat_payload) + PFKEY_ALIGN8(sizeof(struct sastat)); + sadb_stat_payload->sadb_sastat_len = PFKEY_UNIT64(length); + sadb_stat_payload->sadb_sastat_exttype = SADB_EXT_SASTAT; + sadb_stat_payload->sadb_sastat_dir = IPSEC_DIR_OUTBOUND; + sadb_stat_payload->sadb_sastat_list_len = stat_length; + tlen += sizeof(*sadb_stat_payload); + + struct sastat *sastat_payload = (struct sastat *)(void *)(payload + tlen); + sastat_payload->spi = htonl(spi); + tlen += PFKEY_ALIGN8(sizeof(*sastat_payload)); + + // Update the total length + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + T_QUIET; T_ASSERT_POSIX_SUCCESS(send(pfkey_socket, payload, (size_t)PFKEY_UNUNIT64(msg_payload->sadb_msg_len), 0), "pfkey send get sa stat"); +} + +static void +send_pkey_delete_sa(int pfkey_socket, uint32_t spi) +{ + uint8_t payload[MCLBYTES] __attribute__ ((aligned(32))); + bzero(payload, sizeof(payload)); + uint16_t tlen = 0; + + struct sadb_msg *msg_payload = (struct sadb_msg *)payload; + msg_payload->sadb_msg_version = PF_KEY_V2; + msg_payload->sadb_msg_type = SADB_DELETE; + msg_payload->sadb_msg_errno = 0; + msg_payload->sadb_msg_satype = SADB_SATYPE_ESP; + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + msg_payload->sadb_msg_reserved = 0; + msg_payload->sadb_msg_seq = 0; + msg_payload->sadb_msg_pid = (u_int32_t)getpid(); + tlen += sizeof(*msg_payload); + + struct sadb_sa_2 *sa2_payload = (struct sadb_sa_2 *)(void *)(payload + tlen); + sa2_payload->sa.sadb_sa_len = PFKEY_UNIT64(sizeof(*sa2_payload)); + sa2_payload->sa.sadb_sa_exttype = SADB_EXT_SA; + sa2_payload->sa.sadb_sa_spi = htonl(spi); + tlen += sizeof(*sa2_payload); + + struct sadb_address *src_address_payload = (struct sadb_address *)(void *)(payload + tlen); + src_address_payload->sadb_address_exttype = SADB_EXT_ADDRESS_SRC & 0xffff; + src_address_payload->sadb_address_proto = IPSEC_ULPROTO_ANY & 0xff; + src_address_payload->sadb_address_prefixlen = (sizeof(struct in_addr) << 3); + src_address_payload->sadb_address_reserved = 0; + tlen += sizeof(*src_address_payload); + + struct sockaddr_in *src = (struct sockaddr_in *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET, TEST_SRC_ADDRESS_IPv4, &src->sin_addr), 1, "migrate src fail"); + src->sin_family = AF_INET; + src->sin_len = sizeof(*src); + uint16_t len = sizeof(*src_address_payload) + PFKEY_ALIGN8(src->sin_len); + src_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(src->sin_len); + + struct sadb_address *dst_address_payload = (struct sadb_address *)(void *)(payload + tlen); + dst_address_payload->sadb_address_exttype = SADB_EXT_ADDRESS_DST & 0xffff; + dst_address_payload->sadb_address_proto = IPSEC_ULPROTO_ANY & 0xff; + dst_address_payload->sadb_address_prefixlen = (sizeof(struct in_addr) << 3); + dst_address_payload->sadb_address_reserved = 0; + tlen += sizeof(*dst_address_payload); + + struct sockaddr_in *dst = (struct sockaddr_in *)(void *)(payload + tlen); + T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET, TEST_DST_ADDRESS_IPv4, &dst->sin_addr), 1, "migrate dst fail"); + dst->sin_family = AF_INET; + dst->sin_len = sizeof(*dst); + len = sizeof(*dst_address_payload) + PFKEY_ALIGN8(dst->sin_len); + dst_address_payload->sadb_address_len = PFKEY_UNIT64(len); + tlen += PFKEY_ALIGN8(dst->sin_len); + + // Update the total length + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + T_QUIET; T_ASSERT_POSIX_SUCCESS(send(pfkey_socket, payload, (size_t)PFKEY_UNUNIT64(msg_payload->sadb_msg_len), 0), "pfkey send delete sa"); +} + +static void +send_pfkey_sa_dump_message(int pfkey_socket) +{ + uint8_t payload[MCLBYTES] __attribute__ ((aligned(32))); + bzero(payload, sizeof(payload)); + uint16_t tlen = 0; + + struct sadb_msg *msg_payload = (struct sadb_msg *)(void *)payload; + msg_payload->sadb_msg_version = PF_KEY_V2; + msg_payload->sadb_msg_type = SADB_DUMP; + msg_payload->sadb_msg_errno = 0; + msg_payload->sadb_msg_satype = SADB_SATYPE_UNSPEC; + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + msg_payload->sadb_msg_reserved = 0; + msg_payload->sadb_msg_seq = 0; + msg_payload->sadb_msg_pid = (uint32_t)getpid(); + tlen += sizeof(*msg_payload); + + // Update the total length + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + T_QUIET; T_ASSERT_POSIX_SUCCESS(send(pfkey_socket, payload, (size_t)PFKEY_UNUNIT64(msg_payload->sadb_msg_len), 0), "pfkey send sa dump failed"); +} + +static void +send_pfkey_flush_sa(int pfkey_socket) +{ + uint8_t payload[MCLBYTES] __attribute__ ((aligned(32))); + bzero(payload, sizeof(payload)); + uint16_t tlen = 0; + + struct sadb_msg *msg_payload = (struct sadb_msg *)payload; + msg_payload->sadb_msg_version = PF_KEY_V2; + msg_payload->sadb_msg_type = SADB_FLUSH; + msg_payload->sadb_msg_errno = 0; + msg_payload->sadb_msg_satype = SADB_SATYPE_UNSPEC; + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + msg_payload->sadb_msg_reserved = 0; + msg_payload->sadb_msg_seq = 0; + msg_payload->sadb_msg_pid = (u_int32_t)getpid(); + tlen += sizeof(*msg_payload); + + // Update the total length + msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); + T_QUIET; T_ASSERT_POSIX_SUCCESS(send(pfkey_socket, payload, (size_t)PFKEY_UNUNIT64(msg_payload->sadb_msg_len), 0), "pfkey flush sa"); +} + +static void +pfkey_cleanup(void) +{ + if (pfkey_source != NULL) { + int pfkey_socket = (int)dispatch_source_get_handle(pfkey_source); + if (pfkey_socket > 0) { + send_pfkey_flush_sa(pfkey_socket); + send_pfkey_flush_sp(pfkey_socket); + } + dispatch_source_cancel(pfkey_source); + pfkey_source = NULL; + } +} + +static int +pfkey_setup_socket(void) +{ + int pfkey_socket = -1; + int bufsiz = 0; + const unsigned long newbufk = 1536; + unsigned long oldmax; + size_t oldmaxsize = sizeof(oldmax); + unsigned long newmax = newbufk * (1024 + 128); + + T_QUIET; T_ASSERT_POSIX_SUCCESS(pfkey_socket = socket(PF_KEY, SOCK_RAW, PF_KEY_V2), NULL); + + if (sysctlbyname("kern.ipc.maxsockbuf", &oldmax, &oldmaxsize, &newmax, sizeof(newmax)) != 0) { + bufsiz = 233016; /* Max allowed by default */ + } else { + bufsiz = newbufk * 1024; + } + + T_QUIET; T_ASSERT_POSIX_SUCCESS(setsockopt(pfkey_socket, SOL_SOCKET, SO_SNDBUF, &bufsiz, sizeof(bufsiz)), "pfkey set snd socket buf failed %d", bufsiz); + T_QUIET; T_ASSERT_POSIX_SUCCESS(setsockopt(pfkey_socket, SOL_SOCKET, SO_RCVBUF, &bufsiz, sizeof(bufsiz)), "pfkey set recv socket buf failed %d", bufsiz); + + pfkey_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, (uintptr_t)pfkey_socket, 0, dispatch_get_main_queue()); + T_QUIET; T_ASSERT_NOTNULL(pfkey_source, "dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, ...)"); + dispatch_source_set_event_handler(pfkey_source, ^{ + recv_pfkey_message(pfkey_socket); + }); + dispatch_source_set_cancel_handler(pfkey_source, ^{ + close(pfkey_socket); + }); + dispatch_resume(pfkey_source); + return pfkey_socket; +} + +static void +pfkey_process_message_test_60822136(uint8_t **mhp, int pfkey_socket) +{ + struct sadb_msg *message = (struct sadb_msg *)(void *)mhp[0]; + static int counter = 0; + static uint32_t policy_id = 0; + + if (message->sadb_msg_pid != (uint32_t)getpid()) { + return; + } + + if (message->sadb_msg_errno) { + T_QUIET; T_ASSERT_EQ(message->sadb_msg_type, SADB_X_SPDDUMP, "SADB error for type %u", message->sadb_msg_type); + pfkey_cleanup(); + T_END; + } + + switch (message->sadb_msg_type) { + case SADB_X_SPDADD: + { + struct sadb_x_policy *policy_message = (struct sadb_x_policy *)(void *)mhp[SADB_X_EXT_POLICY]; + T_QUIET; T_ASSERT_NOTNULL(policy_message, "spd add policy message is NULL"); + policy_id = policy_message->sadb_x_policy_id; + T_LOG("Added policy id %u", policy_id); + send_pfkey_spd_get_message(pfkey_socket, policy_id);; + break; + } + case SADB_X_SPDGET: + { + struct sadb_x_policy *policy_message = (struct sadb_x_policy *)(void *)mhp[SADB_X_EXT_POLICY]; + T_QUIET; T_ASSERT_NOTNULL(policy_message, "spd get policy message is NULL"); + T_QUIET; T_ASSERT_EQ(policy_id, policy_message->sadb_x_policy_id, "spd_get: spid mismatch %u != %u", policy_id, policy_message->sadb_x_policy_id); + if (counter < MAX_SPD_CHECK) { + counter++; + send_pfkey_spd_get_message(pfkey_socket, policy_id); + } else { + T_LOG("Deleting policy id %u", policy_id); + send_pfkey_spd_delete_message(pfkey_socket, policy_id); + } + break; + } + case SADB_X_SPDDELETE2: + { + struct sadb_x_policy *policy_message = (struct sadb_x_policy *)(void *)mhp[SADB_X_EXT_POLICY]; + T_QUIET; T_ASSERT_NOTNULL(policy_message, "spd delete2 policy message is NULL"); + T_QUIET; T_ASSERT_EQ(policy_id, policy_message->sadb_x_policy_id, "spd_delete2: spid mismatch %u != %u", policy_id, policy_message->sadb_x_policy_id); + T_LOG("Deleted policy id %u", policy_id); + sleep(2); + send_pfkey_spd_dump_message(pfkey_socket); + break; + } + case SADB_X_SPDDUMP: + { + struct sadb_x_policy *policy_message = (struct sadb_x_policy *)(void *)mhp[SADB_X_EXT_POLICY]; + T_QUIET; T_ASSERT_NOTNULL(policy_message, "spd dump policy message is NULL"); + T_QUIET; T_ASSERT_EQ(policy_id, policy_message->sadb_x_policy_id, "spd_dump: spid mismatch %u != %u", policy_id, policy_message->sadb_x_policy_id); + T_FAIL("Policy id %u still exists", policy_id); + pfkey_cleanup(); + T_END; + } + case SADB_FLUSH: + case SADB_X_SPDFLUSH: + break; + default: + T_FAIL("bad SADB message type %u", message->sadb_msg_type); + T_END; + } + return; +} + +static void +pfkey_process_message_test_60822924(uint8_t **mhp, int pfkey_socket) +{ + struct sadb_msg *message = (struct sadb_msg *)(void *)mhp[0]; + static int counter = 0; + static uint32_t policy_id = 0; + + if (message->sadb_msg_pid != (uint32_t)getpid()) { + return; + } + + if (message->sadb_msg_errno) { + T_QUIET; T_ASSERT_EQ(message->sadb_msg_type, SADB_X_SPDDUMP, "SADB error for type %u", message->sadb_msg_type); + pfkey_cleanup(); + T_END; + } + + switch (message->sadb_msg_type) { + case SADB_X_SPDADD: + { + struct sadb_x_policy *policy_message = (struct sadb_x_policy *)(void *)mhp[SADB_X_EXT_POLICY]; + T_QUIET; T_ASSERT_NOTNULL(policy_message, "spd add policy message is NULL"); + policy_id = policy_message->sadb_x_policy_id; + T_LOG("Added policy id %u", policy_id); + send_pfkey_spd_enable_message(pfkey_socket, policy_id);; + break; + } + case SADB_X_SPDENABLE: + { + struct sadb_x_policy *policy_message = (struct sadb_x_policy *)(void *)mhp[SADB_X_EXT_POLICY]; + T_QUIET; T_ASSERT_NOTNULL(policy_message, "spd enable policy message is NULL"); + T_QUIET; T_ASSERT_EQ(policy_id, policy_message->sadb_x_policy_id, "spd_enable: spid mismatch %u != %u", policy_id, policy_message->sadb_x_policy_id); + if (counter < MAX_SPD_CHECK) { + counter++; + send_pfkey_spd_enable_message(pfkey_socket, policy_id); + } else { + T_LOG("Deleting policy id %u", policy_id); + send_pfkey_spd_delete_message(pfkey_socket, policy_id); + } + break; + } + case SADB_X_SPDDELETE2: + { + struct sadb_x_policy *policy_message = (struct sadb_x_policy *)(void *)mhp[SADB_X_EXT_POLICY]; + T_QUIET; T_ASSERT_NOTNULL(policy_message, "spd delete2 policy message is NULL"); + T_QUIET; T_ASSERT_EQ(policy_id, policy_message->sadb_x_policy_id, "spd_delete2: spid mismatch %u != %u", policy_id, policy_message->sadb_x_policy_id); + T_LOG("Deleted policy id %u", policy_id); + sleep(2); + send_pfkey_spd_dump_message(pfkey_socket); + break; + } + case SADB_X_SPDDUMP: + { + struct sadb_x_policy *policy_message = (struct sadb_x_policy *)(void *)mhp[SADB_X_EXT_POLICY]; + T_QUIET; T_ASSERT_NOTNULL(policy_message, "spd dump policy message is NULL"); + T_QUIET; T_ASSERT_EQ(policy_id, policy_message->sadb_x_policy_id, "spd_dump: spid mismatch %u != %u", policy_id, policy_message->sadb_x_policy_id); + T_FAIL("Policy id %u still exists", policy_id); + pfkey_cleanup(); + T_END; + } + case SADB_FLUSH: + case SADB_X_SPDFLUSH: + break; + default: + T_FAIL("bad SADB message type %u", message->sadb_msg_type); + T_END; + } + return; +} + +static void +pfkey_process_message_test_60822956(uint8_t **mhp, int pfkey_socket) +{ + struct sadb_msg *message = (struct sadb_msg *)(void *)mhp[0]; + static int counter = 0; + static uint32_t policy_id = 0; + + if (message->sadb_msg_pid != (uint32_t)getpid()) { + return; + } + + if (message->sadb_msg_errno) { + T_QUIET; T_ASSERT_EQ(message->sadb_msg_type, SADB_X_SPDDUMP, "SADB error for type %u", message->sadb_msg_type); + pfkey_cleanup(); + T_END; + } + + switch (message->sadb_msg_type) { + case SADB_X_SPDADD: + { + struct sadb_x_policy *policy_message = (struct sadb_x_policy *)(void *)mhp[SADB_X_EXT_POLICY]; + T_QUIET; T_ASSERT_NOTNULL(policy_message, "spd add policy message is NULL"); + policy_id = policy_message->sadb_x_policy_id; + T_LOG("Added policy id %u", policy_id); + send_pfkey_spd_disable_message(pfkey_socket, policy_id);; + break; + } + case SADB_X_SPDDISABLE: + { + struct sadb_x_policy *policy_message = (struct sadb_x_policy *)(void *)mhp[SADB_X_EXT_POLICY]; + T_QUIET; T_ASSERT_NOTNULL(policy_message, "spd disable policy message is NULL"); + T_QUIET; T_ASSERT_EQ(policy_id, policy_message->sadb_x_policy_id, "spd_disable: spid mismatch %u != %u", policy_id, policy_message->sadb_x_policy_id); + if (counter < MAX_SPD_CHECK) { + counter++; + send_pfkey_spd_disable_message(pfkey_socket, policy_id); + } else { + T_LOG("Deleting policy id %u", policy_id); + send_pfkey_spd_delete_message(pfkey_socket, policy_id); + } + break; + } + case SADB_X_SPDDELETE2: + { + struct sadb_x_policy *policy_message = (struct sadb_x_policy *)(void *)mhp[SADB_X_EXT_POLICY]; + T_QUIET; T_ASSERT_NOTNULL(policy_message, "spd delete2 policy message is NULL"); + T_QUIET; T_ASSERT_EQ(policy_id, policy_message->sadb_x_policy_id, "spd_delete2: spid mismatch %u != %u", policy_id, policy_message->sadb_x_policy_id); + T_LOG("Deleted policy id %u", policy_id); + sleep(2); + send_pfkey_spd_dump_message(pfkey_socket); + break; + } + case SADB_X_SPDDUMP: + { + struct sadb_x_policy *policy_message = (struct sadb_x_policy *)(void *)mhp[SADB_X_EXT_POLICY]; + T_QUIET; T_ASSERT_NOTNULL(policy_message, "spd dump policy message is NULL"); + T_QUIET; T_ASSERT_EQ(policy_id, policy_message->sadb_x_policy_id, "spd_dump: spid mismatch %u != %u", policy_id, policy_message->sadb_x_policy_id); + T_FAIL("Policy id %u still exists", policy_id); + pfkey_cleanup(); + T_END; + } + case SADB_FLUSH: + case SADB_X_SPDFLUSH: + break; + default: + T_FAIL("bad SADB message type %u", message->sadb_msg_type); + T_END; + } + return; +} + +static void +pfkey_process_message_test_60679513(uint8_t **mhp, int pfkey_socket) +{ + struct sadb_msg *message = (struct sadb_msg *)(void *)mhp[0]; + static uint32_t spi = 0; + + if (message->sadb_msg_pid != (uint32_t)getpid()) { + return; + } + + if (message->sadb_msg_errno) { + T_QUIET; T_ASSERT_EQ(message->sadb_msg_type, SADB_UPDATE, "SADB error for type %u", message->sadb_msg_type); + } + + switch (message->sadb_msg_type) { + case SADB_GETSPI: + { + struct sadb_sa *sa_message = (struct sadb_sa *)(void *)mhp[SADB_EXT_SA]; + T_QUIET; T_ASSERT_NOTNULL(sa_message, "sa get spi message is NULL"); + spi = ntohl(sa_message->sadb_sa_spi); + T_LOG("get spi 0x%x", spi); + send_pkey_update_sa(pfkey_socket, spi); + break; + } + case SADB_UPDATE: + { + struct sadb_sa *sa_message = (struct sadb_sa *)(void *)mhp[SADB_EXT_SA]; + T_QUIET; T_ASSERT_NOTNULL(sa_message, "update sa message is NULL"); + T_QUIET; T_ASSERT_EQ(spi, ntohl(sa_message->sadb_sa_spi), "sadb update: spi mismatch %u != %u", spi, ntohl(sa_message->sadb_sa_spi)); + T_LOG("update sa 0x%x", spi); + send_pkey_delete_sa(pfkey_socket, spi); + break; + } + case SADB_DELETE: + { + struct sadb_sa *sa_message = (struct sadb_sa *)(void *)mhp[SADB_EXT_SA]; + T_QUIET; T_ASSERT_NOTNULL(sa_message, "delete sa message is NULL"); + T_QUIET; T_ASSERT_EQ(spi, ntohl(sa_message->sadb_sa_spi), "sadb delete: spi mismatch %u != %u", spi, ntohl(sa_message->sadb_sa_spi)); + T_LOG("delete sa 0x%x", spi); + pfkey_cleanup(); + T_END; + } + case SADB_FLUSH: + case SADB_X_SPDFLUSH: + break; + default: + T_FAIL("bad SADB message type %u", message->sadb_msg_type); + T_END; + } + return; +} + +static void +pfkey_process_message_test_60768729(uint8_t **mhp, int pfkey_socket) +{ + struct sadb_msg *message = (struct sadb_msg *)(void *)mhp[0]; + uint32_t spi = 0; + static int counter = 0; + + if (message->sadb_msg_pid != (uint32_t)getpid()) { + return; + } + + T_QUIET; T_ASSERT_EQ(message->sadb_msg_errno, 0, "SADB error for type %u", message->sadb_msg_type); + + switch (message->sadb_msg_type) { + case SADB_GETSPI: + { + struct sadb_sa *sa_message = (struct sadb_sa *)(void *)mhp[SADB_EXT_SA]; + T_QUIET; T_ASSERT_NOTNULL(sa_message, "sa get spi message is NULL"); + spi = ntohl(sa_message->sadb_sa_spi); + counter++; + if (counter <= 1000) { + send_pkey_get_spi(pfkey_socket); + } else { + T_LOG("SADB added 1000 Larval SPIs"); + send_pfkey_sa_dump_message(pfkey_socket); + } + break; + } + case SADB_DUMP: + { + counter--; + if (counter == 0) { + T_PASS("SADB dump successful"); + pfkey_cleanup(); + T_END; + } + break; + } + + case SADB_FLUSH: + case SADB_X_SPDFLUSH: + break; + default: + T_FAIL("bad SADB message type %u", message->sadb_msg_type); + T_END; + } + return; +} + +static void +pfkey_process_message_test_60769680(uint8_t **mhp, int pfkey_socket) +{ + struct sadb_msg *message = (struct sadb_msg *)(void *)mhp[0]; + static uint8_t counter = 0; + + if (message->sadb_msg_pid != (uint32_t)getpid()) { + return; + } + + T_QUIET; T_ASSERT_EQ(message->sadb_msg_errno, 0, "SADB error for type %u error %d", message->sadb_msg_type, message->sadb_msg_errno); + + switch (message->sadb_msg_type) { + case SADB_X_SPDADD: + { + struct sadb_x_policy *policy_message = (struct sadb_x_policy *)(void *)mhp[SADB_X_EXT_POLICY]; + T_QUIET; T_ASSERT_NOTNULL(policy_message, "spd add policy message is NULL"); + counter++; + if (counter <= 240) { + send_pfkey_spd_add_message(pfkey_socket, counter + 1); + } else { + T_LOG("SADB added 240 security policies"); + send_pfkey_spd_dump_message(pfkey_socket); + } + break; + } + case SADB_X_SPDDUMP: + { + counter--; + if (counter == 0) { + T_PASS("SADB policy dump successful"); + pfkey_cleanup(); + T_END; + } + break; + } + + case SADB_FLUSH: + case SADB_X_SPDFLUSH: + break; + default: + T_FAIL("bad SADB message type %u", message->sadb_msg_type); + T_END; + } + return; +} + +static void +pfkey_process_message_test_60822823(uint8_t **mhp, int pfkey_socket) +{ + struct sadb_msg *message = (struct sadb_msg *)(void *)mhp[0]; + static uint32_t spi = 0; + + if (message->sadb_msg_pid != (uint32_t)getpid()) { + return; + } + + if (message->sadb_msg_errno != 0) { + T_QUIET; T_ASSERT_EQ(message->sadb_msg_type, SADB_GETSASTAT, "SADB error for type %u error %d", message->sadb_msg_type, message->sadb_msg_errno); + T_QUIET; T_ASSERT_EQ(message->sadb_msg_errno, EINVAL, "SADB error for type %u error %d", message->sadb_msg_type, message->sadb_msg_errno); + T_PASS("SADB get SA Stat received EINVAL"); + T_END; + } + + switch (message->sadb_msg_type) { + case SADB_ADD: + { + struct sadb_sa *sa_message = (struct sadb_sa *)(void *)mhp[SADB_EXT_SA]; + T_QUIET; T_ASSERT_NOTNULL(sa_message, "add sa message is NULL"); + spi = ntohl(sa_message->sadb_sa_spi); + T_LOG("added sa 0x%x", spi); + send_pfkey_get_sa_stat(pfkey_socket, spi, 5); + break; + } + case SADB_GETSASTAT: + { + T_FAIL("get sa stat should fail %u", message->sadb_msg_type); + T_END; + } + case SADB_FLUSH: + case SADB_X_SPDFLUSH: + break; + default: + T_FAIL("bad SADB message type %u", message->sadb_msg_type); + T_END; + } + return; +} + +static void +pfkey_process_message_test_60822823_1(uint8_t **mhp, int pfkey_socket) +{ + struct sadb_msg *message = (struct sadb_msg *)(void *)mhp[0]; + static uint32_t spi = 0; + + if (message->sadb_msg_pid != (uint32_t)getpid()) { + return; + } + + T_QUIET; T_ASSERT_EQ(message->sadb_msg_errno, 0, "SADB error for type %u error %d", message->sadb_msg_type, message->sadb_msg_errno); + + switch (message->sadb_msg_type) { + case SADB_ADD: + { + struct sadb_sa *sa_message = (struct sadb_sa *)(void *)mhp[SADB_EXT_SA]; + T_QUIET; T_ASSERT_NOTNULL(sa_message, "add sa message is NULL"); + spi = ntohl(sa_message->sadb_sa_spi); + T_LOG("added sa 0x%x", spi); + send_pfkey_get_sa_stat(pfkey_socket, spi, 1); + break; + } + case SADB_GETSASTAT: + { + struct sadb_session_id *session_id = (struct sadb_session_id *)(void *)mhp[SADB_EXT_SESSION_ID]; + T_QUIET; T_ASSERT_NOTNULL(session_id, "session id is NULL"); + T_QUIET; T_EXPECT_EQ_ULLONG(session_id->sadb_session_id_v[0], 1ULL, "Session id is not equal"); + T_PASS("get sa stat success %u", message->sadb_msg_type); + T_END; + } + case SADB_FLUSH: + case SADB_X_SPDFLUSH: + break; + default: + T_FAIL("bad SADB message type %u", message->sadb_msg_type); + T_END; + } + return; +} + +static void +pfkey_process_message_test_60687183(uint8_t **mhp, int pfkey_socket) +{ + struct sadb_msg *message = (struct sadb_msg *)(void *)mhp[0]; + static uint32_t spi = 0; + + if (message->sadb_msg_pid != (uint32_t)getpid()) { + return; + } + + T_QUIET; T_ASSERT_EQ(message->sadb_msg_errno, 0, "SADB error for type %u error %d", message->sadb_msg_type, message->sadb_msg_errno); + + switch (message->sadb_msg_type) { + case SADB_ADD: + { + struct sadb_sa *sa_message = (struct sadb_sa *)(void *)mhp[SADB_EXT_SA]; + T_QUIET; T_ASSERT_NOTNULL(sa_message, "add sa message is NULL"); + spi = ntohl(sa_message->sadb_sa_spi); + T_LOG("added sa 0x%x", spi); + send_pkey_migrate_sa(pfkey_socket, spi, TEST_SRC_ADDRESS_IPv4, TEST_DST_ADDRESS_IPv4, AF_INET, + TEST_MIGRATE_SRC_ADDRESS_IPv4, TEST_MIGRATE_DST_ADDRESS_IPv4, AF_INET); + break; + } + case SADB_MIGRATE: + { + T_PASS("migrate SA success"); + T_END; + } + case SADB_FLUSH: + case SADB_X_SPDFLUSH: + break; + default: + T_FAIL("bad SADB message type %u", message->sadb_msg_type); + T_END; + } + return; +} + +static void +pfkey_process_message_test_60687183_1(uint8_t **mhp, int pfkey_socket) +{ + struct sadb_msg *message = (struct sadb_msg *)(void *)mhp[0]; + static uint32_t spi = 0; + + if (message->sadb_msg_pid != (uint32_t)getpid()) { + return; + } + + T_QUIET; T_ASSERT_EQ(message->sadb_msg_errno, 0, "SADB error for type %u error %d", message->sadb_msg_type, message->sadb_msg_errno); + + switch (message->sadb_msg_type) { + case SADB_ADD: + { + struct sadb_sa *sa_message = (struct sadb_sa *)(void *)mhp[SADB_EXT_SA]; + T_QUIET; T_ASSERT_NOTNULL(sa_message, "add sa message is NULL"); + spi = ntohl(sa_message->sadb_sa_spi); + T_LOG("added sa 0x%x", spi); + send_pkey_migrate_sa(pfkey_socket, spi, TEST_SRC_ADDRESS_IPv6, TEST_DST_ADDRESS_IPv6, AF_INET6, + TEST_MIGRATE_SRC_ADDRESS_IPv6, TEST_MIGRATE_DST_ADDRESS_IPv6, AF_INET6); + break; + } + case SADB_MIGRATE: + { + T_PASS("migrate SA success"); + T_END; + } + case SADB_FLUSH: + case SADB_X_SPDFLUSH: + break; + default: + T_FAIL("bad SADB message type %u", message->sadb_msg_type); + T_END; + } + return; +} + +static void +pfkey_process_message_test_60687183_2(uint8_t **mhp, int pfkey_socket) +{ + struct sadb_msg *message = (struct sadb_msg *)(void *)mhp[0]; + static uint32_t spi = 0; + + if (message->sadb_msg_pid != (uint32_t)getpid()) { + return; + } + + if (message->sadb_msg_errno != 0) { + T_QUIET; T_ASSERT_EQ(message->sadb_msg_type, SADB_MIGRATE, "SADB error for type %u error %d", message->sadb_msg_type, message->sadb_msg_errno); + T_QUIET; T_ASSERT_EQ(message->sadb_msg_errno, EINVAL, "SADB error for type %u error %d", message->sadb_msg_type, message->sadb_msg_errno); + T_PASS("SADB migrate SA received EINVAL"); + T_END; + } + + T_QUIET; T_ASSERT_EQ(message->sadb_msg_errno, 0, "SADB error for type %u error %d", message->sadb_msg_type, message->sadb_msg_errno); + + switch (message->sadb_msg_type) { + case SADB_ADD: + { + struct sadb_sa *sa_message = (struct sadb_sa *)(void *)mhp[SADB_EXT_SA]; + T_QUIET; T_ASSERT_NOTNULL(sa_message, "add sa message is NULL"); + spi = ntohl(sa_message->sadb_sa_spi); + T_LOG("added sa 0x%x", spi); + send_pkey_migrate_sa(pfkey_socket, spi, TEST_SRC_ADDRESS_IPv6, TEST_DST_ADDRESS_IPv6, AF_INET6, + TEST_MIGRATE_SRC_ADDRESS_IPv6, TEST_MIGRATE_DST_ADDRESS_IPv6, AF_CHAOS); + break; + } + case SADB_MIGRATE: + { + T_FAIL("migrate SA test for bad address failed"); + T_END; + } + case SADB_FLUSH: + case SADB_X_SPDFLUSH: + break; + default: + T_FAIL("bad SADB message type %u", message->sadb_msg_type); + T_END; + } + return; +} + +T_DECL(sadb_x_get_60822136, "security policy reference count overflow") +{ + test_id = TEST_SADB_X_GET_OVERFLOW_60822136; + + int pfkey_socket = pfkey_setup_socket(); + send_pfkey_flush_sa(pfkey_socket); + send_pfkey_flush_sp(pfkey_socket); + send_pfkey_spd_add_message(pfkey_socket, IPSEC_ULPROTO_ANY); + + dispatch_main(); +} + +T_DECL(sadb_x_spd_enable_60822924, "security policy reference count overflow") +{ + test_id = TEST_SADB_X_SPDENABLE_OVERFLOW_60822924; + + int pfkey_socket = pfkey_setup_socket(); + send_pfkey_flush_sa(pfkey_socket); + send_pfkey_flush_sp(pfkey_socket); + send_pfkey_spd_add_message(pfkey_socket, IPSEC_ULPROTO_ANY); + + dispatch_main(); +} + +T_DECL(sadb_x_spd_disable_60822956, "security policy reference count overflow") +{ + test_id = TEST_SADB_X_SPDDISABLE_OVERFLOW_60822956; + + int pfkey_socket = pfkey_setup_socket(); + send_pfkey_flush_sa(pfkey_socket); + send_pfkey_flush_sp(pfkey_socket); + send_pfkey_spd_add_message(pfkey_socket, IPSEC_ULPROTO_ANY); + + dispatch_main(); +} + +T_DECL(sadb_update_60679513, "security association use after free") +{ + test_id = TEST_SADB_UPDATE_USE_AFTER_FREE_60679513; + + int pfkey_socket = pfkey_setup_socket(); + send_pfkey_flush_sa(pfkey_socket); + send_pfkey_flush_sp(pfkey_socket); + send_pkey_get_spi(pfkey_socket); + + dispatch_main(); +} + +T_DECL(sadb_dump_60768729, "security association sa dump heap overflow") +{ + test_id = TEST_SADB_DUMP_HEAP_OVERFLOW_60768729; + + int pfkey_socket = pfkey_setup_socket(); + T_ATEND(pfkey_cleanup); + send_pfkey_flush_sa(pfkey_socket); + send_pfkey_flush_sp(pfkey_socket); + send_pkey_get_spi(pfkey_socket); + + dispatch_main(); +} + +T_DECL(sadb_policy_dump_60769680, "security association sa policy dump heap overflow") +{ + test_id = TEST_SADB_POLICY_DUMP_HEAP_OVERFLOW_60769680; + + int pfkey_socket = pfkey_setup_socket(); + T_ATEND(pfkey_cleanup); + send_pfkey_flush_sa(pfkey_socket); + send_pfkey_flush_sp(pfkey_socket); + send_pfkey_spd_add_message(pfkey_socket, 1); + + dispatch_main(); +} + +T_DECL(sadb_get_sastat_oob_60769680, "security association get sa stat oob read") +{ + test_id = TEST_SADB_GETSASTAT_OOB_READ_60822823; + + int pfkey_socket = pfkey_setup_socket(); + T_ATEND(pfkey_cleanup); + send_pfkey_flush_sa(pfkey_socket); + send_pfkey_flush_sp(pfkey_socket); + send_pkey_add_sa(pfkey_socket, 0x12345678, TEST_SRC_ADDRESS_IPv4, TEST_DST_ADDRESS_IPv4, AF_INET); + + dispatch_main(); +} + +T_DECL(sadb_get_sastat_success, "security association get sa stat") +{ + test_id = TEST_SADB_GETSASTAT_OOB_READ_SUCCESS; + + int pfkey_socket = pfkey_setup_socket(); + T_ATEND(pfkey_cleanup); + send_pfkey_flush_sa(pfkey_socket); + send_pfkey_flush_sp(pfkey_socket); + send_pkey_add_sa(pfkey_socket, 0x12345678, TEST_SRC_ADDRESS_IPv4, TEST_DST_ADDRESS_IPv4, AF_INET); + + dispatch_main(); +} + +T_DECL(sadb_key_migrate_address_ipv4, "security association migrate address ipv4") +{ + test_id = TEST_SADB_EXT_MIGRATE_ADDRESS_IPv4; + + int pfkey_socket = pfkey_setup_socket(); + T_ATEND(pfkey_cleanup); + send_pfkey_flush_sa(pfkey_socket); + send_pfkey_flush_sp(pfkey_socket); + send_pkey_add_sa(pfkey_socket, 0x12345678, TEST_SRC_ADDRESS_IPv4, TEST_DST_ADDRESS_IPv4, AF_INET); + + dispatch_main(); +} + +T_DECL(sadb_key_migrate_address_ipv6, "security association migrate address ipv6") +{ + test_id = TEST_SADB_EXT_MIGRATE_ADDRESS_IPv6; + + int pfkey_socket = pfkey_setup_socket(); + T_ATEND(pfkey_cleanup); + send_pfkey_flush_sa(pfkey_socket); + send_pfkey_flush_sp(pfkey_socket); + send_pkey_add_sa(pfkey_socket, 0x12345678, TEST_SRC_ADDRESS_IPv6, TEST_DST_ADDRESS_IPv6, AF_INET6); + + dispatch_main(); +} + +T_DECL(sadb_key_migrate_bad_address, "security association migrate bad address") +{ + test_id = TEST_SADB_EXT_MIGRATE_BAD_ADDRESS; + + int pfkey_socket = pfkey_setup_socket(); + T_ATEND(pfkey_cleanup); + send_pfkey_flush_sa(pfkey_socket); + send_pfkey_flush_sp(pfkey_socket); + send_pkey_add_sa(pfkey_socket, 0x12345678, TEST_SRC_ADDRESS_IPv6, TEST_DST_ADDRESS_IPv6, AF_INET6); + + dispatch_main(); +} diff --git a/tests/proc_info.c b/tests/proc_info.c index 51206a2f4..5ce0747eb 100644 --- a/tests/proc_info.c +++ b/tests/proc_info.c @@ -263,8 +263,12 @@ static child_action_handler_t proc_info_call_pidinfo_handler = ^void (proc_confi /* * Allocate a page of memory * Copy on write shared memory + * + * WARNING + * Don't add calls to T_LOG here as they can end up generating unwanted + * calls to mach_msg_send(). If curtask->messages_sent gets incremented + * at this point it will interfere with testing pti_messages_sent. */ - T_LOG("Child allocating a page of memory, and causing a copy-on-write"); retval = 0; tmp_map = mmap(0, PAGE_SIZE, PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); if (tmp_map == MAP_FAILED) { diff --git a/tests/sioc-if-addr-bounds.c b/tests/sioc-if-addr-bounds.c new file mode 100644 index 000000000..b7b124a31 --- /dev/null +++ b/tests/sioc-if-addr-bounds.c @@ -0,0 +1,662 @@ +/* + * Copyright (c) 2020 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +/* -*- compile-command: "xcrun --sdk iphoneos.internal make sioc-if-addr-bounds" -*- */ + +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +#include + +#include + +#include "ioc_str.h" + +T_GLOBAL_META(T_META_NAMESPACE("xnu.net")); + +#ifndef STRINGIFY +#define __STR(x) #x /* just a helper macro */ +#define STRINGIFY(x) __STR(x) +#endif /* STRINGIFY */ + +#define IF_NAME "bridge" + +/* On some platforms with DEBUG kernel, we need to wait a while */ +#define SIFCREATE_RETRY 600 + +#define PATTERN_SIZE 8 + +static int +ifnet_destroy(int s, const char * ifname, bool fail_on_error) +{ + int err; + struct ifreq ifr; + + bzero(&ifr, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + err = ioctl(s, SIOCIFDESTROY, &ifr); + if (fail_on_error) { + T_QUIET; + T_ASSERT_POSIX_SUCCESS(err, "SIOCSIFDESTROY %s", ifr.ifr_name); + } + if (err < 0) { + T_LOG("SIOCSIFDESTROY %s", ifr.ifr_name); + } + return err; +} + +static int +ifnet_set_flags(int s, const char * ifname, + uint16_t flags_set, uint16_t flags_clear) +{ + uint16_t flags_after; + uint16_t flags_before; + struct ifreq ifr; + int ret; + + bzero(&ifr, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr); + if (ret != 0) { + T_LOG("SIOCGIFFLAGS %s", ifr.ifr_name); + return ret; + } + flags_before = (uint16_t)ifr.ifr_flags; + ifr.ifr_flags |= flags_set; + ifr.ifr_flags &= ~(flags_clear); + flags_after = (uint16_t)ifr.ifr_flags; + if (flags_before == flags_after) { + /* nothing to do */ + ret = 0; + } else { + /* issue the ioctl */ + T_QUIET; + T_ASSERT_POSIX_SUCCESS(ioctl(s, SIOCSIFFLAGS, &ifr), + "SIOCSIFFLAGS %s 0x%x", + ifr.ifr_name, (uint16_t)ifr.ifr_flags); + } + return ret; +} + +static int +ifnet_create(int s, char * ifname, size_t ifname_size) +{ + int error = 0; + struct ifreq ifr; + + bzero(&ifr, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + + for (int i = 0; i < SIFCREATE_RETRY; i++) { + if (ioctl(s, SIOCIFCREATE, &ifr) < 0) { + error = errno; + T_LOG("SIOCSIFCREATE %s: %s", ifname, + strerror(error)); + if (error == EBUSY) { + /* interface is tearing down, try again */ + usleep(10000); + } else if (error == EEXIST) { + /* interface exists, try destroying it */ + (void)ifnet_destroy(s, ifname, false); + } else { + /* unexpected failure */ + break; + } + } else { + error = 0; + break; + } + } + if (error == 0) { + /* Copy back the interface name with unit number */ + strlcpy(ifname, ifr.ifr_name, ifname_size); + error = ifnet_set_flags(s, ifname, IFF_UP, 0); + } + return error; +} + +#define MAXBUF 32 + +static void +HexDump(void *data, size_t len) +{ + size_t i, j, k; + unsigned char *ptr = (unsigned char *)data; + unsigned char buf[3 * MAXBUF + 1]; + + for (i = 0; i < len; i += MAXBUF) { + for (j = i, k = 0; j < i + MAXBUF && j < len; j++) { + unsigned char msnbl = ptr[j] >> 4; + unsigned char lsnbl = ptr[j] & 0x0f; + + buf[k++] = msnbl < 10 ? msnbl + '0' : msnbl + 'a' - 10; + buf[k++] = lsnbl < 10 ? lsnbl + '0' : lsnbl + 'a' - 10; + if ((j % 2) == 1) { + buf[k++] = ' '; + } + if ((j % MAXBUF) == MAXBUF - 1) { + buf[k++] = ' '; + } + } + buf[k] = 0; + T_LOG("%5zd: %s\n", i, buf); + } +} + + +static int +check_rt_if_list_for_pattern(const char *label, unsigned char pattern, size_t pattern_size) +{ + size_t i; + size_t len; + int mib[6] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; + unsigned char *rt_if_list_buf = NULL; + int count = 0; + unsigned char *pattern_buf = NULL; + + T_QUIET; T_ASSERT_NOTNULL(pattern_buf = calloc(1, pattern_size), "pattern_buf calloc(1, %zd)", pattern_size); + memset(pattern_buf, pattern, pattern_size); + + T_QUIET; T_EXPECT_POSIX_SUCCESS(sysctl(mib, 6, NULL, &len, NULL, 0), "sysctl NET_RT_IFLIST"); + + T_QUIET; T_ASSERT_NOTNULL(rt_if_list_buf = calloc(1, len), "rt_if_list_buf calloc(1, %zd)", len); + + T_QUIET; T_EXPECT_POSIX_SUCCESS(sysctl(mib, 6, rt_if_list_buf, &len, NULL, 0), "sysctl NET_RT_IFLIST"); + + if (label != NULL) { + T_LOG("%s sysctl NET_RT_IFLIST buffer length %zd\n", label, len); + } + + count = 0; + for (i = 0; i < len - pattern_size; i++) { + if (memcmp(rt_if_list_buf + i, pattern_buf, pattern_size) == 0) { + count++; + i += pattern_size - 1; + } + } + + if (label != NULL) { + if (label != NULL && count > 0) { + T_LOG("%s found pattern at %zd count %d times\n", label, i, count); + HexDump(rt_if_list_buf, len); + } + } + free(rt_if_list_buf); + free(pattern_buf); + + return count; +} + +static bool +find_unused_pattern_in_rt_if_list(unsigned char *pattern, size_t pattern_size) +{ + bool found_pattern = false; + unsigned char i; + unsigned char *pattern_buf = NULL; + + T_QUIET; T_ASSERT_NOTNULL(pattern_buf = calloc(1, pattern_size), "pattern_buf calloc(1, %zd)", pattern_size); + + /* Try 10 times to find an unused pattern */ + for (i = 1; i < 255; i++) { + if (check_rt_if_list_for_pattern(NULL, i, pattern_size) == 0) { + found_pattern = true; + *pattern = i; + memset(pattern_buf, i, pattern_size); + T_LOG("PATTERN: "); + HexDump(pattern_buf, pattern_size); + break; + } + } + free(pattern_buf); + + return found_pattern; +} + +static const char * +ioc_str(unsigned long cmd) +{ +#define X(a) case a: return #a; + + switch (cmd) { + SIOC_LIST + + default: + break; + } + return ""; +} + +struct ioc_ifreq { + unsigned long ioc_cmd; + uint8_t salen; + uint8_t safamily; + const char *sastr; + int error; // 0 means no error, -1, end of list, otherwise expected errno +}; + +static struct ioc_ifreq ioc_list[] = { + { SIOCSIFADDR, sizeof(struct sockaddr_in), AF_INET6, "10.2.3.1", EINVAL }, + { SIOCDIFADDR, sizeof(struct sockaddr_in), AF_INET6, "10.2.3.1", EADDRNOTAVAIL }, + { SIOCDIFADDR, sizeof(struct sockaddr_in6), AF_INET, "10.2.3.1", EADDRNOTAVAIL }, + { SIOCDIFADDR, sizeof(struct sockaddr_in), AF_INET, "10.2.3.1", EADDRNOTAVAIL }, + + { SIOCSIFADDR, 0xf0, AF_INET6, "10.2.3.1", EINVAL }, + { SIOCDIFADDR, 0xf0, AF_INET6, "10.2.3.1", EADDRNOTAVAIL }, + { SIOCDIFADDR, 0xf0, AF_INET, "10.2.3.1", EADDRNOTAVAIL }, + { SIOCDIFADDR, 0xf0, AF_INET, "10.2.3.1", EADDRNOTAVAIL }, + + { SIOCSIFADDR, 0, AF_INET6, "10.2.3.1", EINVAL }, + { SIOCDIFADDR, 0, AF_INET6, "10.2.3.1", EADDRNOTAVAIL }, + { SIOCDIFADDR, 0, AF_INET, "10.2.3.1", EADDRNOTAVAIL }, + { SIOCDIFADDR, 0, AF_INET, "10.2.3.1", EADDRNOTAVAIL }, + + { SIOCSIFADDR, sizeof(struct sockaddr_in6), AF_INET, "10.2.3.2", 0 }, + { SIOCDIFADDR, sizeof(struct sockaddr_in), AF_INET6, "10.2.3.2", 0 }, + + { SIOCSIFADDR, sizeof(struct sockaddr_in), AF_INET, "10.2.3.3", 0 }, + { SIOCDIFADDR, sizeof(struct sockaddr_in6), AF_INET, "10.2.3.3", 0 }, + + { SIOCSIFADDR, sizeof(struct sockaddr_in6), AF_INET6, "10.2.3.4", EINVAL }, + { SIOCDIFADDR, sizeof(struct sockaddr_in6), AF_INET, "10.2.3.4", EADDRNOTAVAIL }, + + { SIOCSIFADDR, sizeof(struct sockaddr_in), AF_INET, "10.2.3.5", 0 }, + { SIOCDIFADDR, sizeof(struct sockaddr_in), AF_INET, "0.0.0.0", EADDRNOTAVAIL }, + { SIOCDIFADDR, sizeof(struct sockaddr_in), AF_INET, "10.2.3.5", 0 }, + + { SIOCSIFADDR, sizeof(struct sockaddr_in), AF_INET, "10.2.3.6", 0 }, + + { SIOCSIFNETMASK, sizeof(struct sockaddr_in), 0, "ff.00.00.00", 0 }, + { SIOCSIFNETMASK, sizeof(struct sockaddr_in), AF_INET, "ff.00.00.00", 0 }, + { SIOCSIFNETMASK, sizeof(struct sockaddr_in), AF_INET6, "ff.f.00.00", 0 }, + + { SIOCSIFNETMASK, sizeof(struct sockaddr_in6), 0, "ff.ff.00.00", 0 }, + { SIOCSIFNETMASK, sizeof(struct sockaddr_in6), AF_INET, "ff.ff.00.00", 0 }, + { SIOCSIFNETMASK, sizeof(struct sockaddr_in6), AF_INET6, "ff.ff.f0.00", 0 }, + + { SIOCSIFNETMASK, 0, 0, "ff.ff.00.00", 0 }, + { SIOCSIFNETMASK, 0, AF_INET, "ff.ff.00.00", 0 }, + { SIOCSIFNETMASK, 0, AF_INET6, "ff.ff.f0.00", 0 }, + + { SIOCSIFNETMASK, 0xf0, 0, "ff.ff.00.00", 0 }, + { SIOCSIFNETMASK, 0xf0, AF_INET, "ff.ff.00.00", 0 }, + { SIOCSIFNETMASK, 0xf0, AF_INET6, "ff.ff.f0.00", 0 }, + + { SIOCSIFBRDADDR, sizeof(struct sockaddr_in), 0, "10.255.255.255", 0 }, + { SIOCSIFBRDADDR, sizeof(struct sockaddr_in), AF_INET, "10.255.255.255", 0 }, + { SIOCSIFBRDADDR, sizeof(struct sockaddr_in), AF_INET6, "10.255.255.255", 0 }, + { SIOCSIFBRDADDR, sizeof(struct sockaddr_in6), AF_INET, "10.255.255.255", 0 }, + + { SIOCSIFBRDADDR, 0xf0, 0, "10.255.255.255", 0 }, + { SIOCSIFBRDADDR, 0xf0, AF_INET, "10.255.255.255", 0 }, + { SIOCSIFBRDADDR, 0xf0, AF_INET6, "10.255.255.255", 0 }, + { SIOCSIFBRDADDR, 0xf0, AF_INET, "10.255.255.255", 0 }, + + { SIOCSIFBRDADDR, 0, 0, "10.255.255.255", 0 }, + { SIOCSIFBRDADDR, 0, AF_INET, "10.255.255.255", 0 }, + { SIOCSIFBRDADDR, 0, AF_INET6, "10.255.255.255", 0 }, + { SIOCSIFBRDADDR, 0, AF_INET, "10.255.255.255", 0 }, + + { 0, 0, 0, "", -1 }, +}; + +static void +test_sioc_ifr_bounds(struct ioc_ifreq *ioc_ifreq, int s, const char *ifname) +{ + struct ifreq ifr = {}; + unsigned char pattern; + struct sockaddr_in *sin; + + T_LOG(""); + T_LOG("TEST CASE: %s ioctl(%s, sa_len %u, sa_family %u, %s) -> %d", __func__, + ioc_str(ioc_ifreq->ioc_cmd), ioc_ifreq->salen, ioc_ifreq->safamily, ioc_ifreq->sastr, ioc_ifreq->error); + + + if (find_unused_pattern_in_rt_if_list(&pattern, PATTERN_SIZE) == false) { + T_SKIP("Could not find unused pattern"); + } + + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + memset(&ifr.ifr_addr.sa_data, pattern, sizeof(ifr.ifr_dstaddr.sa_data)); + + sin = (struct sockaddr_in *)(void *)&ifr.ifr_addr; + sin->sin_len = ioc_ifreq->salen; + sin->sin_family = ioc_ifreq->safamily; + sin->sin_addr.s_addr = inet_addr(ioc_ifreq->sastr); + + int retval; + if (ioc_ifreq->error == 0) { + T_EXPECT_POSIX_SUCCESS(retval = ioctl(s, ioc_ifreq->ioc_cmd, &ifr), + "%s, %s: retval %d", ioc_str(ioc_ifreq->ioc_cmd), ioc_ifreq->sastr, retval); + } else { + T_EXPECT_POSIX_FAILURE(retval = ioctl(s, ioc_ifreq->ioc_cmd, &ifr), ioc_ifreq->error, + "%s, %s: retval %d errno %s", ioc_str(ioc_ifreq->ioc_cmd), ioc_ifreq->sastr, retval, strerror(errno)); + } + + T_EXPECT_EQ(check_rt_if_list_for_pattern("test_sioc_ifr_bounds", pattern, PATTERN_SIZE), 0, "pattern should not be found"); + + fflush(stdout); + fflush(stderr); +} + +T_DECL(sioc_ifr_bounds, "test bound checks on struct ifreq addresses passed to interface ioctls", + T_META_ASROOT(true)) +{ + int s = -1; + char ifname[IFNAMSIZ]; + + T_LOG("%s", __func__); + + T_QUIET; T_EXPECT_POSIX_SUCCESS(s = socket(AF_INET, SOCK_DGRAM, 0), "socket"); + + strlcpy(ifname, IF_NAME, sizeof(ifname)); + + int error = 0; + if ((error = ifnet_create(s, ifname, sizeof(ifname))) != 0) { + if (error == EINVAL) { + T_SKIP("The system does not support the %s cloning interface", IF_NAME); + } + T_SKIP("This test failed creating a %s cloning interface", IF_NAME); + } + T_LOG("created clone interface '%s'", ifname); + + struct ioc_ifreq *ioc_ifreq; + for (ioc_ifreq = ioc_list; ioc_ifreq->error != -1; ioc_ifreq++) { + test_sioc_ifr_bounds(ioc_ifreq, s, ifname); + } + (void)ifnet_destroy(s, ifname, true); + + close(s); +} + +struct ioc_ifra { + const char *description; + + uint8_t addr_len; + uint8_t addr_fam; + const char *addr_str; + + uint8_t broad_len; + uint8_t broad_fam; + const char *broad_str; + + uint8_t mask_len; + uint8_t mask_fam; + const char *mask_str; + + int error; // 0 means no error, -1, end of list, otherwise expected errno +}; + +static struct ioc_ifra ioc_ifra_list[] = { + { + .description = "fully formed", + .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.1.1.1", + .broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET, .broad_str = "1.1.1.255", + .mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET, .mask_str = "255.255.0.0", + .error = 0 + }, + { + .description = "addr_len 0", + .addr_len = 0, .addr_fam = AF_INET, .addr_str = "10.2.2.0", + .broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET, .broad_str = "10.2.2.255", + .mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET, .mask_str = "255.0.0.0", + .error = 0 + }, + { + .description = "addr_len 1", + .addr_len = 1, .addr_fam = AF_INET, .addr_str = "10.2.2.1", + .broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET, .broad_str = "10.2.2.255", + .mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET, .mask_str = "255.0.0.0", + .error = 0 + }, + { + .description = "addr_len 250", + .addr_len = 250, .addr_fam = AF_INET, .addr_str = "10.2.2.250", + .broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET, .broad_str = "10.2.2.255", + .mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET, .mask_str = "255.0.0.0", + .error = 0 + }, + { + .description = "addr_family AF_INET6", + .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET6, .addr_str = "10.3.3.3", + .broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET, .broad_str = "10.3.255.255", + .mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET, .mask_str = "255.255.255.0", + .error = EINVAL + }, + { + .description = "broadcast_len 0xf0", + .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.4.4.4", + .broad_len = 0xf0, .broad_fam = AF_INET, .broad_str = "10.4.4.255", + .mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET, .mask_str = "255.255.255.0", + .error = 0 + }, + { + .description = "broadcast_family AF_INET6", + .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.5.5.5", + .broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET6, .broad_str = "10.5.5.255", + .mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET, .mask_str = "255.255.0.0", + .error = 0 + }, + { + .description = "mask_len 0xf0", + .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.6.6.6", + .broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET, .broad_str = "1.6.6.255", + .mask_len = 0xf0, .mask_fam = AF_INET, .mask_str = "255.255.0.0", + .error = 0 + }, + { + .description = "mask_family AF_INET6", + .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.7.7.7", + .broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET, .broad_str = "10.7.7.255", + .mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET6, .mask_str = "255.255.0.0", + .error = 0 + }, + { + .description = "ifra address only", + .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.8.8.8", + .broad_len = 0, .broad_str = NULL, + .mask_len = 0, .mask_str = NULL, + .error = 0 + }, + { + .description = "ifra mask len 1", + .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.9.9.1", + .broad_len = 0, .broad_str = NULL, + .mask_len = 1, .mask_fam = AF_INET, .mask_str = "255.255.255.0", + .error = 0 + }, + { + .description = "ifra mask len 3", + .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.9.9.3", + .broad_len = 0, .broad_str = NULL, + .mask_len = 1, .mask_fam = AF_INET, .mask_str = "255.255.255.0", + .error = 0 + }, + { + .description = "ifra mask len 5", + .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.9.9.5", + .broad_len = 0, .broad_str = NULL, + .mask_len = 1, .mask_fam = AF_INET, .mask_str = "255.255.255.0", + .error = 0 + }, + { + .description = "ifra mask len 7", + .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.9.9.7", + .broad_len = 0, .broad_str = NULL, + .mask_len = 1, .mask_fam = AF_INET, .mask_str = "255.255.255.0", + .error = 0 + }, + { + .description = "ifra mask len 9", + .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.9.9.9", + .broad_len = 0, .broad_str = NULL, + .mask_len = 1, .mask_fam = AF_INET, .mask_str = "255.255.255.0", + .error = 0 + }, + { + .description = "ifra mask len 11", + .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.9.9.11", + .broad_len = 0, .broad_str = NULL, + .mask_len = 1, .mask_fam = AF_INET, .mask_str = "255.255.255.0", + .error = 0 + }, + { + .description = "ifra mask len 13", + .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.9.9.13", + .broad_len = 0, .broad_str = NULL, + .mask_len = 1, .mask_fam = AF_INET, .mask_str = "255.255.255.0", + .error = 0 + }, + { + .description = NULL, + .error = -1 + } +}; + +T_DECL(sioc_ifra_addr_bounds, "test bound checks on socket address passed to interface ioctls", + T_META_ASROOT(true)) +{ + int s = -1; + + T_QUIET; T_EXPECT_POSIX_SUCCESS(s = socket(AF_INET, SOCK_DGRAM, 0), "socket"); + + char ifname[IFNAMSIZ]; + strlcpy(ifname, IF_NAME, sizeof(ifname)); + int error = 0; + if ((error = ifnet_create(s, ifname, sizeof(ifname))) != 0) { + if (error == EINVAL) { + T_SKIP("The system does not support the %s cloning interface", IF_NAME); + } + T_SKIP("This test failed creating a %s cloning interface", IF_NAME); + } + T_LOG("created clone interface '%s'", ifname); + + struct ioc_ifra *ioc_ifra; + + for (ioc_ifra = ioc_ifra_list; ioc_ifra->error != -1; ioc_ifra++) { + struct in_aliasreq ifra = {}; + unsigned char pattern; + int retval; + + T_LOG(""); + T_LOG("TEST CASE: %s, ioctl(SIOCAIFADDR, %s)", ioc_ifra->description, ioc_ifra->addr_str != NULL ? ioc_ifra->addr_str : ""); + + if (find_unused_pattern_in_rt_if_list(&pattern, PATTERN_SIZE) == false) { + T_SKIP("Could not find unused pattern in rt_if_list"); + return; + } + + memset(&ifra, pattern, sizeof(ifra)); + + strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name)); + + ifra.ifra_addr.sin_len = ioc_ifra->addr_len; + ifra.ifra_addr.sin_family = ioc_ifra->addr_fam; + if (ioc_ifra->addr_str != NULL) { + ifra.ifra_addr.sin_addr.s_addr = inet_addr(ioc_ifra->addr_str); + } + + ifra.ifra_broadaddr.sin_len = ioc_ifra->broad_len; + ifra.ifra_broadaddr.sin_family = ioc_ifra->broad_fam; + if (ioc_ifra->broad_str != NULL) { + ifra.ifra_broadaddr.sin_addr.s_addr = inet_addr(ioc_ifra->broad_str); + } + + ifra.ifra_mask.sin_len = ioc_ifra->mask_len; + ifra.ifra_mask.sin_family = ioc_ifra->mask_fam; + if (ioc_ifra->mask_str != NULL) { + ifra.ifra_mask.sin_addr.s_addr = inet_addr(ioc_ifra->mask_str); + } + + if (ioc_ifra->error == 0) { + T_EXPECT_POSIX_SUCCESS(retval = ioctl(s, SIOCAIFADDR, &ifra), "SIOCAIFADDR retval %d", retval); + } else { + T_EXPECT_POSIX_FAILURE(retval = ioctl(s, SIOCAIFADDR, &ifra), EINVAL, "SIOCAIFADDR retval %d, %s", retval, strerror(errno)); + } + + T_EXPECT_EQ(check_rt_if_list_for_pattern("after ioctl SIOCAIFADDR", pattern, PATTERN_SIZE), 0, "pattern should not be found"); + } + + (void)ifnet_destroy(s, ifname, true); + + close(s); +} + +T_DECL(sioc_ifr_dstaddr_leak, "test bound checks on socket address passed to interface ioctls", + T_META_ASROOT(true)) +{ + int s = -1; + struct ifreq ifr = {}; + unsigned char pattern; + struct ifaddrs *ifap = NULL, *ifa; + bool found_gif0 = false; + + T_QUIET; T_EXPECT_POSIX_SUCCESS(getifaddrs(&ifap), "getifaddrs"); + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (strcmp(ifa->ifa_name, "gif0") == 0) { + found_gif0 = true; + break; + } + } + freeifaddrs(ifap); + ifap = NULL; + if (found_gif0 == false) { + T_SKIP("gif0 does not exists"); + } + + if (find_unused_pattern_in_rt_if_list(&pattern, PATTERN_SIZE) == false) { + T_SKIP("Could not find unused pattern"); + return; + } + + T_QUIET; T_EXPECT_POSIX_SUCCESS(s = socket(AF_INET, SOCK_DGRAM, 0), "socket"); + + strlcpy(ifr.ifr_name, "gif0", sizeof(ifr.ifr_name)); + ifr.ifr_dstaddr.sa_family = AF_INET6; + ifr.ifr_dstaddr.sa_len = 0xf0; + memset(&ifr.ifr_dstaddr.sa_data, pattern, PATTERN_SIZE); + + T_EXPECT_POSIX_SUCCESS(ioctl(s, SIOCSIFDSTADDR, &ifr), "ioctl(SIOCSIFDSTADDR)"); + + close(s); + + T_EXPECT_EQ(check_rt_if_list_for_pattern("AFTER", pattern, PATTERN_SIZE), 0, "pattern should not be found"); +} diff --git a/tests/unp_connect_thread_uaf.c b/tests/unp_connect_thread_uaf.c new file mode 100644 index 000000000..3d61b1394 --- /dev/null +++ b/tests/unp_connect_thread_uaf.c @@ -0,0 +1,149 @@ +/* This tests thread_t uaf vulnerability in the XNU kernel due to + * a race condition in unp_connect + */ + +#include +#include +#include +#include +#include +#include +#include + +int g_start = 0; +int g_client = 0; +int g_sever1 = 0; +int g_sever2 = 0; + +static void +server_thread1(char* path) +{ + struct sockaddr_un server_sockaddr; + memset(&server_sockaddr, 0, sizeof(struct sockaddr_un)); + server_sockaddr.sun_family = AF_UNIX; + strcpy(server_sockaddr.sun_path, path); + unlink(server_sockaddr.sun_path); + + int server_sock = socket(AF_UNIX, SOCK_STREAM, 0); + g_sever1 = server_sock; + T_ASSERT_POSIX_SUCCESS(bind(server_sock, + (struct sockaddr *) &server_sockaddr, sizeof(server_sockaddr)), NULL); + + /*********************************/ + /* Listen for any client sockets */ + /*********************************/ + T_ASSERT_POSIX_SUCCESS(listen(server_sock, -1), NULL); + + return; +} + +static void +server_thread2(char* path) +{ + struct sockaddr_un server_sockaddr; + memset(&server_sockaddr, 0, sizeof(struct sockaddr_un)); + server_sockaddr.sun_family = AF_UNIX; + strcpy(server_sockaddr.sun_path, path); + unlink(server_sockaddr.sun_path); + + int server_sock = socket(AF_UNIX, SOCK_STREAM, 0); + g_sever2 = server_sock; + T_ASSERT_POSIX_SUCCESS(bind(server_sock, + (struct sockaddr *) &server_sockaddr, sizeof(server_sockaddr)), NULL); + + /*********************************/ + /* Listen for any client sockets */ + /*********************************/ + T_ASSERT_POSIX_SUCCESS(listen(server_sock, -1), NULL); + + return; +} + +static void +try_to_connect(char* path) +{ + struct sockaddr_un server_sockaddr; + memset(&server_sockaddr, 0, sizeof(struct sockaddr_un)); + server_sockaddr.sun_family = AF_UNIX; + strcpy(server_sockaddr.sun_path, path); + //unlink(server_sockaddr.sun_path); + + while (g_start == 0) { + usleep(100); + } + int ret = connect(g_client, (struct sockaddr *)&server_sockaddr, + sizeof(server_sockaddr)); + + T_ASSERT_TRUE(ret == 0 || errno == EALREADY || errno == EISCONN, + "connect with ret: %d(%d)", ret, errno); +} + + +static void +test_unp_connect_multithread() +{ + int client_sock; + char path[] = "/tmp/"; + char path1[256]; + char path2[256]; + char path3[256]; + + strncpy(path1, path, 255); + strcat(path1, "/1"); + strncpy(path2, path, 255); + strcat(path2, "/2"); + strncpy(path3, path, 255); + strcat(path3, "/3"); + + + for (int i = 0; i < 1024; i++) { + T_SETUPBEGIN; + server_thread1(path1); + server_thread2(path2); + T_ASSERT_POSIX_SUCCESS(client_sock = socket(AF_UNIX, SOCK_STREAM, 0), NULL); + + unlink(path3); + struct sockaddr_un client_sockaddr; + client_sockaddr.sun_family = AF_UNIX; + strcpy(client_sockaddr.sun_path, path3); + T_ASSERT_POSIX_SUCCESS(bind(client_sock, (struct sockaddr *)&client_sockaddr, + sizeof(client_sockaddr)), NULL); + T_SETUPEND; + g_client = client_sock; + g_start = 0; + pthread_t runner1; + pthread_t runner2; + if (pthread_create(&runner1, 0, (void*)try_to_connect, path1)) { + T_ASSERT_FAIL("pthread_create failed"); + } + + if (pthread_create(&runner2, 0, (void*)try_to_connect, path2)) { + T_ASSERT_FAIL("pthread_create failed"); + } + usleep(300); + g_start = 1; + pthread_join(runner1, 0); + pthread_join(runner2, 0); + + usleep(3000); + + struct socket_fdinfo si_1 = {0}; + proc_pidfdinfo(getpid(), g_sever1, PROC_PIDFDSOCKETINFO, &si_1, + sizeof(si_1)); + struct socket_fdinfo si_2 = {0}; + proc_pidfdinfo(getpid(), g_sever2, PROC_PIDFDSOCKETINFO, &si_2, + sizeof(si_2)); + if (si_1.psi.soi_incqlen || si_2.psi.soi_incqlen) { + close(g_sever2); + close(g_sever1); + } + close(client_sock); + close(g_sever2); + close(g_sever1); + } +} + +T_DECL(unp_connect_thread_uaf, "Uaf due to multithreaded unp_connect") +{ + test_unp_connect_multithread(); +} diff --git a/tools/lldbmacros/sysreg.py b/tools/lldbmacros/sysreg.py index 376a0e202..b3fba544c 100755 --- a/tools/lldbmacros/sysreg.py +++ b/tools/lldbmacros/sysreg.py @@ -187,4 +187,4 @@ def _Colorify(color, msg): _SYSREG_TO_DECODE_FUNC_MAP = { 'ESR_EL1': PrintEsrEl1Explanation -} +} \ No newline at end of file diff --git a/tools/lldbmacros/zonetriage.py b/tools/lldbmacros/zonetriage.py index ef6f52dc0..fe58c09c6 100755 --- a/tools/lldbmacros/zonetriage.py +++ b/tools/lldbmacros/zonetriage.py @@ -121,4 +121,4 @@ def FindZoneBTLog(zone): if zone == "%s" % zval.zone_name: return "0x%lx" % zval.zlog_btlog return None -# EndMacro: zonetriage, zonetriage_freedelement, zonetriage_memoryleak +# EndMacro: zonetriage, zonetriage_freedelement, zonetriage_memoryleak \ No newline at end of file -- 2.45.2