This file contains the errors that Andrey Karpov has found in a XNU kernel using a PVS-Studio static code analyzer. PVS-Studio is a tool for bug detection in the source code of programs, written in C, C++, and C#. https://www.viva64.com/en/pvs-studio/ Andrey Karpov is going to write an article at the time of release of the first version of PVS-Studio for macOS. The article will be dedicated to the XNU kernel check, and demonstrate the abilities of PVS-Studio in identifying various errors and potential vulnerabilities. PVS-Studio team often writes similar articles: https://www.viva64.com/en/inspections/ Andrey Karpov has prepared this file where he cited fragments of code with errors that he noticed and which will be used when writing the article so that XNU developers could fix the bugs in advance. P.S. These are not all the errors that can be detected using PVS-Studio. Andrey Karpov faces the challenge to write an article, dealing with to the release of PVS-Studio for macOS. Therefore, he did not strive to find as many bugs as possible and put together only the most obvious and interesting ones that will be enough to write an article. That’s why it is much better for XNU developers not to be limited by only those bugs that are described here, but also to analyze the project themselves. ----------------------------------------------------------------- V501 CWE-570 There are identical sub-expressions 'm->M_dat.MH.MH_pkthdr.len' to the left and to the right of the '!=' operator. key.c 9442 int key_parse( struct mbuf *m, struct socket *so) { .... if ((m->m_flags & M_PKTHDR) == 0 || m->m_pkthdr.len != m->m_pkthdr.len) { ipseclog((LOG_DEBUG, "key_parse: invalid message length.\n")); PFKEY_STAT_INCREMENT(pfkeystat.out_invlen); error = EINVAL; goto senderror; } .... } #info Apparently, it’s a typo. The member m->m_pkthdr.len is compared with itself. ----------------------------------------------------------------- V512 CWE-119 A call of the 'snprintf' function will lead to overflow of the buffer 'interface_names[index]'. necp.c 4376 V512 CWE-119 A call of the 'memset' function will lead to overflow of the buffer 'interface_names[index]'. necp.c 4378 #define IFNAMSIZ 16 #define IFXNAMSIZ (IFNAMSIZ + 8) #define MAX_ROUTE_RULE_INTERFACES 10 static inline const char * necp_get_result_description(....) { .... char interface_names[IFXNAMSIZ][MAX_ROUTE_RULE_INTERFACES]; .... for (index = 0; index < MAX_ROUTE_RULE_INTERFACES; index++) { if (route_rule->exception_if_indices[index] != 0) { ifnet_t interface = ifindex2ifnet[....]; snprintf(interface_names[index], IFXNAMSIZ, "%s%d", ifnet_name(interface), ifnet_unit(interface)); } else { memset(interface_names[index], 0, IFXNAMSIZ); } } .... } #info Most likely, the array was declared incorrectly and it should be written as follows: char interface_names[MAX_ROUTE_RULE_INTERFACES][IFXNAMSIZ]; ----------------------------------------------------------------- V512 CWE-119 A call of the '__builtin___memcpy_chk' function will lead to a buffer overflow. - ADDITIONAL IN CURRENT necp_client.c 1459 V557 CWE-787 Array overrun is possible. The value of 'length - 1' index could reach 23. - ADDITIONAL IN CURRENT necp_client.c 1460 #define IFNAMSIZ 16 #define IFXNAMSIZ (IFNAMSIZ + 8) #define NECP_MAX_PARSED_PARAMETERS 16 struct necp_client_parsed_parameters { .... char prohibited_interfaces[IFXNAMSIZ] [NECP_MAX_PARSED_PARAMETERS]; .... }; static int necp_client_parse_parameters(...., struct necp_client_parsed_parameters *parsed_parameters) { .... u_int32_t length = ....; .... if (length <= IFXNAMSIZ && length > 0) { memcpy(parsed_parameters->prohibited_interfaces[ num_prohibited_interfaces], value, length); parsed_parameters->prohibited_interfaces[ num_prohibited_interfaces][length - 1] = 0; .... } #info Most likely, the array was declared incorrectly and it should be written as follows: char prohibited_interfaces[NECP_MAX_PARSED_PARAMETERS][IFXNAMSIZ]; ----------------------------------------------------------------- V517 CWE-570 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 340, 343. pf_pbuf.c 340 void pbuf_copy_back(pbuf_t *pbuf, int off, int len, void *src) { VERIFY(off >= 0); VERIFY(len >= 0); VERIFY((u_int)(off + len) <= pbuf->pb_packet_len); if (pbuf->pb_type == PBUF_TYPE_MBUF) m_copyback(pbuf->pb_mbuf, off, len, src); else if (pbuf->pb_type == PBUF_TYPE_MBUF) { if (len) memcpy(&((uint8_t *)pbuf->pb_data)[off], src, len); } else panic("%s: bad pb_type: %d", __func__, pbuf->pb_type); } #info The code contains a logical error. It seems to me that the first key word 'else' is superfluous. ----------------------------------------------------------------- V517 CWE-570 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 358, 361. pf_pbuf.c 358 void pbuf_copy_data(pbuf_t *pbuf, int off, int len, void *dst) { VERIFY(off >= 0); VERIFY(len >= 0); VERIFY((u_int)(off + len) <= pbuf->pb_packet_len); if (pbuf->pb_type == PBUF_TYPE_MBUF) m_copydata(pbuf->pb_mbuf, off, len, dst); else if (pbuf->pb_type == PBUF_TYPE_MBUF) { if (len) memcpy(dst, &((uint8_t *)pbuf->pb_data)[off], len); } else panic("%s: bad pb_type: %d", __func__, pbuf->pb_type); } #info The code is very similar to the previous one. Most likely, this function is written using a Copy-Paste method. The code contains a logical error. It seems to me that the first key word 'else' is superfluous. ----------------------------------------------------------------- V519 CWE-563 The 'wrap.Seal_Alg[0]' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 2070, 2071. gss_krb5_mech.c 2071 uint32_t gss_krb5_3des_unwrap_mbuf(....) { .... for (cflag = 1; cflag >= 0; cflag--) { *minor = gss_krb5_3des_token_get( ctx, &itoken, wrap, &hash, &offset, &length, reverse); if (*minor == 0) break; wrap.Seal_Alg[0] = 0xff; wrap.Seal_Alg[0] = 0xff; } .... } #info The value is written in the same element of the array twice. I looked through the near code and now I think that this was actually supposed to be written as follows: wrap.Seal_Alg[0] = 0xff; wrap.Seal_Alg[1] = 0xff; ----------------------------------------------------------------- V522 CWE-628 Dereferencing of the null pointer 'session' might take place. The null pointer is passed into 'netagent_send_error_response' function. Inspect the first argument. Check lines: 427, 972. network_agent.c 427 static int netagent_send_error_response( struct netagent_session *session, u_int8_t message_type, u_int32_t message_id, u_int32_t error_code) { int error = 0; u_int8_t *response = NULL; size_t response_size = sizeof(struct netagent_message_header); MALLOC(response, u_int8_t *, response_size, M_NETAGENT, M_WAITOK); if (response == NULL) { return (ENOMEM); } (void)netagent_buffer_write_message_header(.....); if ((error = netagent_send_ctl_data(session->control_unit, (u_int8_t *)response, response_size))) { NETAGENTLOG0(LOG_ERR, "Failed to send response"); } FREE(response, M_NETAGENT); return (error); } static void netagent_handle_unregister_message( struct netagent_session *session, ....) #pragma unused(payload_length, packet, offset) u_int32_t response_error = NETAGENT_MESSAGE_ERROR_INTERNAL; if (session == NULL) { NETAGENTLOG0(LOG_ERR, "Failed to find session"); response_error = NETAGENT_MESSAGE_ERROR_INTERNAL; goto fail; } netagent_unregister_session_wrapper(session); netagent_send_success_response(session, .....); return; fail: netagent_send_error_response( session, NETAGENT_MESSAGE_TYPE_UNREGISTER, message_id, response_error); } #info If in the function netagent_handle_unregister_message a transition to the fail label occurs, then the null pointer dereferencing will occur in the function netagent_send_error_response. ----------------------------------------------------------------- V522 CWE-628 Dereferencing of the null pointer 'pbuf' might take place. The null pointer is passed into 'pf_lazy_makewritable' function. Inspect the second argument. Check lines: 349, 7460. pf.c 349 void * pf_lazy_makewritable(struct pf_pdesc *pd, pbuf_t *pbuf, int len) { void *p; if (pd->lmw < 0) return (NULL); VERIFY(pbuf == pd->mp); p = pbuf->pb_data; if (len > pd->lmw) { .... } static int pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, pbuf_t *pbuf, int off, void *h, struct pf_pdesc *pd, u_short *reason) { .... if (pf_lazy_makewritable(pd, NULL, off + sizeof (struct icmp6_hdr)) == NULL) return (PF_DROP); .... } #info Incorrect call of the pf_lazy_makewritable function. Null pointer dereference might occur. ----------------------------------------------------------------- V547 CWE-571 Expression is always true. mtrr.c 692 void pat_init(void) { boolean_t istate; uint64_t pat; if (!(cpuid_features() & CPUID_FEATURE_PAT)) return; istate = ml_set_interrupts_enabled(FALSE); pat = rdmsr64(MSR_IA32_CR_PAT); DBG("CPU%d PAT: was 0x%016llx\n", get_cpu_number(), pat); /* Change PA6 attribute field to WC if required */ if ((pat & ~(0x0FULL << 48)) != (0x01ULL << 48)) { mtrr_update_action(CACHE_CONTROL_PAT); } ml_set_interrupts_enabled(istate); } #info ~(0x0FULL << 48) = 0xFFF0FFFFFFFFFFFF (0x01ULL << 48) = 0x0001000000000000 The expression pat & [0xFFF0FFFFFFFFFFFF] can not result in the value 0x0001000000000000. So, the condition is always true. And the function mtrr_update_action is always called. ----------------------------------------------------------------- V568 It's odd that 'sizeof()' operator evaluates the size of a pointer to a class, but not the size of the 'thread_template.overrides' class object. thread.c 377 extern void bzero(void *, size_t); static struct thread thread_template, init_thread; struct thread { .... struct thread_qos_override { struct thread_qos_override *override_next; uint32_t override_contended_resource_count; int16_t override_qos; int16_t override_resource_type; user_addr_t override_resource; } *overrides; .... }; void thread_bootstrap(void) { .... bzero(&thread_template.overrides, sizeof(thread_template.overrides)); .... } #info One took a pointer to a pointer and nullified it. A very strange unnatural way to reset the value of the variable. It is much easier to write: thread_template.overrides = NULL; We can conclude that a developer wanted to reset the buffer, but nullified a pointer. ----------------------------------------------------------------- V593 CWE-783 Consider reviewing the expression of the 'A = B != C' kind. The expression is calculated as following: 'A = (B != C)'. kern_memorystatus.c 4554 static void memorystatus_init_snapshot_vmstats( memorystatus_jetsam_snapshot_t *snapshot) { kern_return_t kr = KERN_SUCCESS; mach_msg_type_number_t count = HOST_VM_INFO64_COUNT; vm_statistics64_data_t vm_stat; if ((kr = host_statistics64(.....) != KERN_SUCCESS)) { printf("memorystatus_init_jetsam_snapshot_stats: " "host_statistics64 failed with %d\n", kr); memset(&snapshot->stats, 0, sizeof(snapshot->stats)); } else { .... } #info Parentheses are skipped. Incorrect information about the error will be issued. The value of the variable kr, equal to 1 will be issued. ----------------------------------------------------------------- V593 CWE-783 Consider reviewing the expression of the 'A = B != C' kind. The expression is calculated as following: 'A = (B != C)'. vfs_syscalls.c 10574 int getxattr(....) { .... if ((error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen) != 0)) { goto out; } .... out: .... return (error); } #info Parentheses are skipped. In case of an error, the function will return a status which is always equal to 1. Similar errors: #add V593 CWE-783 Consider reviewing the expression of the 'A = B != C' kind. The expression is calculated as following: 'A = (B != C)'. vfs_syscalls.c 10654 V593 CWE-783 Consider reviewing the expression of the 'A = B != C' kind. The expression is calculated as following: 'A = (B != C)'. vfs_syscalls.c 10700 V593 CWE-783 Consider reviewing the expression of the 'A = B != C' kind. The expression is calculated as following: 'A = (B != C)'. vfs_syscalls.c 10759 V593 CWE-783 Consider reviewing the expression of the 'A = B != C' kind. The expression is calculated as following: 'A = (B != C)'. kern_exec.c 2297 ----------------------------------------------------------------- V595 CWE-476 The 'sym' pointer was utilized before it was verified against nullptr. Check lines: 889, 896. IORegistryEntry.cpp 889 bool IORegistryEntry::compareName(....) const { const OSSymbol * sym = copyName(); bool isEqual; isEqual = sym->isEqualTo( name ); if( isEqual && matched) { name->retain(); *matched = name; } if( sym) sym->release(); return( isEqual ); } #info Everybody writes comparison functions incorrectly ;). The Evil within the Comparison Functions: https://www.viva64.com/en/b/0509/ ----------------------------------------------------------------- One forgot to dereference (indirectly detect an error) V595 CWE-476 The 'list_ptr' pointer was utilized before it was verified against nullptr. Check lines: 7175, 7176. kern_memorystatus.c 7175 static int memorystatus_get_priority_list( memorystatus_priority_entry_t **list_ptr, size_t *buffer_size, size_t *list_size, boolean_t size_only) { .... *list_ptr = (memorystatus_priority_entry_t*)kalloc(*list_size); if (!list_ptr) { return ENOMEM; } .... } #info Most likely, it is a forgotten dereferencing of a pointer and it should be as follows: if (!*list_ptr) { ----------------------------------------------------------------- V595 CWE-476 The 'so' pointer was utilized before it was verified against nullptr. Check lines: 3450, 3453. in_pcb.c 3450 inline void inp_decr_sndbytes_unsent(struct socket *so, int32_t len) { struct inpcb *inp = (struct inpcb *)so->so_pcb; struct ifnet *ifp = inp->inp_last_outifp; if (so == NULL || !(so->so_snd.sb_flags & SB_SNDBYTE_CNT)) return; if (ifp != NULL) { if (ifp->if_sndbyte_unsent >= len) OSAddAtomic64(-len, &ifp->if_sndbyte_unsent); else ifp->if_sndbyte_unsent = 0; } } #info In the beginning the so pointer is dereferenced in the expression so->so_pcb. The check below so == NULL tells us that the pointer can be null. There are quite a lot of such errors. Here are some of them: #add V595 CWE-476 The 'startDict' pointer was utilized before it was verified against nullptr. Check lines: 3369, 3373. IOService.cpp 3369 V595 CWE-476 The 'job' pointer was utilized before it was verified against nullptr. Check lines: 4083, 4085. IOService.cpp 4083 V595 CWE-476 The 'typeinst' pointer was utilized before it was verified against nullptr. Check lines: 176, 177. OSMetaClass.cpp 176 V595 CWE-476 The 'name' pointer was utilized before it was verified against nullptr. Check lines: 385, 392. devfs_tree.c 385 V595 CWE-476 The 'collection' pointer was utilized before it was verified against nullptr. Check lines: 71, 75. OSCollectionIterator.cpp 71 V595 CWE-476 The 'ifp' pointer was utilized before it was verified against nullptr. Check lines: 2014, 2018. dlil.c 2014 V595 CWE-476 The 'fakeif' pointer was utilized before it was verified against nullptr. Check lines: 561, 566. if_fake.c 561 V595 CWE-476 The 'sb' pointer was utilized before it was verified against nullptr. Check lines: 138, 140. in_pcblist.c 138 V595 CWE-476 The 'tp' pointer was utilized before it was verified against nullptr. Check lines: 2603, 2610. tcp_subr.c 2603 V595 CWE-476 The 'str_id' pointer was utilized before it was verified against nullptr. Check lines: 1812, 1817. kdebug.c 1812 V595 CWE-476 The 'sessp' pointer was utilized before it was verified against nullptr. Check lines: 191, 194. subr_prf.c 191 V595 CWE-476 The 'sessp' pointer was utilized before it was verified against nullptr. Check lines: 1463, 1469. tty.c 1463 V595 CWE-476 The 'so' pointer was utilized before it was verified against nullptr. Check lines: 6714, 6719. uipc_socket.c 6714 V595 CWE-476 The 'uap' pointer was utilized before it was verified against nullptr. Check lines: 314, 320. nfs_upcall.c 314 V595 CWE-476 The 'xfromname' pointer was utilized before it was verified against nullptr. Check lines: 3986, 4006. kpi_vfs.c 3986 There were other warnings of this type, but it was not fun to deal with them in detail. ----------------------------------------------------------------- V597 CWE-14 The compiler could delete the 'memset' function call, which is used to flush 'finalcount' buffer. The memset_s() function should be used to erase the private data. sha1mod.c 188 __private_extern__ void YSHA1Final(unsigned char digest[20], YSHA1_CTX* context) { u_int32_t i, j; unsigned char finalcount[8]; .... /* Wipe variables */ i = j = 0; memset(context->buffer, 0, 64); memset(context->state, 0, 20); memset(context->count, 0, 8); memset(finalcount, 0, 8); #ifdef SHA1HANDSOFF YSHA1Transform(context->state, context->buffer); #endif } #info The compiler will delete memset(finalcount, 0, 8); in terms of optimization. ----------------------------------------------------------------- V610 CWE-758 Undefined behavior. Check the shift operator '<<'. The left operand '-1' is negative. pf_table.c 976 static void pfr_prepare_network(union sockaddr_union *sa, int af, int net) { .... sa->sin.sin_addr.s_addr = net ? htonl(-1 << (32-net)) : 0; .... } #info Negative values shift is undefined behavior. Similar errors: #add V610 CWE-758 Undefined behavior. Check the shift operator '<<'. The left operand '-1' is negative. pf_table.c 983 ----------------------------------------------------------------- V617 CWE-480 Consider inspecting the condition. The '0x0001' argument of the '|' bitwise operation contains a non-zero value. nfs_upcall.c 331 #define NFS_UC_QUEUE_SLEEPING 0x0001 static void nfsrv_uc_proxy(socket_t so, void *arg, int waitflag) { .... if (myqueue->ucq_flags | NFS_UC_QUEUE_SLEEPING) wakeup(myqueue); .... } ----------------------------------------------------------------- V646 CWE-670 Consider inspecting the application's logic. It's possible that 'else' keyword is missing. in.c 2010 static void in_ifaddr_free(struct ifaddr *ifa) { IFA_LOCK_ASSERT_HELD(ifa); if (ifa->ifa_refcnt != 0) { panic("%s: ifa %p bad ref cnt", __func__, ifa); /* NOTREACHED */ } if (!(ifa->ifa_debug & IFD_ALLOC)) { panic("%s: ifa %p cannot be freed", __func__, ifa); /* NOTREACHED */ } if (ifa->ifa_debug & IFD_DEBUG) { .... } #info Not sure if this is a bug. Perhaps, one forgot to write 'else'. Similar warnings: #add V646 CWE-670 Consider inspecting the application's logic. It's possible that 'else' keyword is missing. kern_malloc.c 836 V646 CWE-670 Consider inspecting the application's logic. It's possible that 'else' keyword is missing. ipc_kmsg.c 4229 ----------------------------------------------------------------- V705 CWE-691 It is possible that 'else' block was forgotten or commented out, thus altering the program's operation logics. vm_resident.c 1248 void vm_page_release_startup(vm_page_t mem); void pmap_startup( vm_offset_t *startp, vm_offset_t *endp) { .... // -debug code remove if (2 == vm_himemory_mode) { for (i = 1; i <= pages_initialized; i++) { .... } } else // debug code remove- /* * Release pages in reverse order so that physical pages * initially get allocated in ascending addresses. This keeps * the devices (which must address physical memory) happy if * they require several consecutive pages. */ for (i = pages_initialized; i > 0; i--) { if(fill) fillPage(....); vm_page_release_startup(&vm_pages[i - 1]); } .... } #info A very suspicious 'else' keyword. Maybe it is superfluous and it changes the logic of the program. ----------------------------------------------------------------- V773 CWE-401 The 'nub' pointer was assigned values twice without releasing the memory. A memory leak is possible. IOPlatformExpert.cpp 1287 IOService * IODTPlatformExpert::createNub(IORegistryEntry * from) { IOService * nub; nub = new IOPlatformDevice; if (nub) { if( !nub->init( from, gIODTPlane )) { nub->free(); nub = 0; } } return (nub); } #info I’m not sure if it is an error or not. If the function free() removes the object, then all is well. And if not, then here is a memory leak, because there is no call of a delete operator. #add V773 CWE-401 The 'inst' pointer was assigned values twice without releasing the memory. A memory leak is possible. IOUserClient.cpp 246 V773 CWE-401 The 'myself' pointer was assigned values twice without releasing the memory. A memory leak is possible. IOPMrootDomain.cpp 9151 ----------------------------------------------------------------- V781 CWE-129 The value of the 'channel_index' variable is checked after it was used. Perhaps there is a mistake in program logic. Check lines: 852, 855. IOStateReporter.cpp 852 IOReturn IOStateReporter::updateChannelValues(int channel_index) { .... state_index = _currentStates[channel_index]; if (channel_index < 0 || channel_index > (_nElements - state_index) / _channelDimension) { result = kIOReturnOverrun; goto finish; } .... } #info It is very suspicious that the variable channel_index is used as an array index. And only after that a check occurs, that the variable does not exceed certain limits values. Similar errors: #add V781 CWE-129 The value of the 'channel_index' variable is checked after it was used. Perhaps there is a mistake in program logic. Check lines: 651, 654. IOStateReporter.cpp 651 V781 CWE-129 The value of the 'pri' variable is checked after it was used. Perhaps there is a mistake in program logic. Check lines: 267, 269. pktsched_fq_codel.c 267 V781 CWE-129 The value of the 'pcid' variable is checked after it was used. Perhaps there is a mistake in program logic. Check lines: 224, 225. pmap_pcid.c 224 ----------------------------------------------------------------- V519 CWE-563 The 'm->M_dat.MH.MH_pkthdr.csum_flags' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 758, 759. pf_norm.c 759 static struct mbuf * pf_reassemble(struct mbuf *m0, struct pf_fragment **frag, struct pf_frent *frent, int mff) { .... m->m_pkthdr.csum_flags &= ~CSUM_PARTIAL; m->m_pkthdr.csum_flags = CSUM_DATA_VALID | CSUM_PSEUDO_HDR | CSUM_IP_CHECKED | CSUM_IP_VALID; .... } #info The value of the variable m->m_pkthdr.csum_flags is reset. Similar errors: #add V519 CWE-563 The 'm->M_dat.MH.MH_pkthdr.csum_flags' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 1349, 1350. pf_norm.c 1350 V519 CWE-563 The 'm->M_dat.MH.MH_pkthdr.csum_flags' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 2984, 2985. ip_input.c 2985 V519 CWE-563 The 'm->M_dat.MH.MH_pkthdr.csum_flags' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 773, 774. frag6.c 774 ----------------------------------------------------------------- V768 CWE-571 The expression 'new_codec = CMODE_HYB' is of enum type. It is odd that it is used as an expression of a Boolean-type. vm_compressor_algorithms.c 419 typedef enum { CMODE_WK = 0, CMODE_LZ4 = 1, CMODE_HYB = 2, VM_COMPRESSOR_DEFAULT_CODEC = 3, CMODE_INVALID = 4 } vm_compressor_mode_t; void vm_compressor_algorithm_init(void) { .... assertf(((new_codec == VM_COMPRESSOR_DEFAULT_CODEC) || (new_codec == CMODE_WK) || (new_codec == CMODE_LZ4) || (new_codec = CMODE_HYB)), "Invalid VM compression codec: %u", new_codec); .... } #info In the expression the value 2 is assigned to the variable new_codec. Because of this the condition is always true and assertf will check nothing. The value of the variable new_codec is additionally spoiled. ----------------------------------------------------------------- V1004 CWE-476 The 'fakeif' pointer was used unsafely after it was verified against nullptr. Check lines: 566, 572. if_fake.c 572 static void feth_start(ifnet_t ifp) { .... if_fake_ref fakeif; .... if (fakeif != NULL) { peer = fakeif->iff_peer; flags = fakeif->iff_flags; } /* check for pending TX */ m = fakeif->iff_pending_tx_packet; .... } #info The check "if (fakeif != NULL)" tells us that the pointer fakeif can be null. However, further the pointer is dereferenced before the preliminary check. Similar errors: #add V1004 CWE-476 The 'rt->rt_ifp' pointer was used unsafely after it was verified against nullptr. Check lines: 138, 140. netsrc.c 140 ----------------------------------------------------------------- V522 CWE-690 There might be dereferencing of a potential null pointer 'dp'. vfs_cache.c 1449 typedef struct vnode * vnode_t; int cache_lookup_path(...., vnode_t dp, ....) { .... if (dp && (dp->v_flag & VISHARDLINK)) { break; } if ((dp->v_flag & VROOT) || dp == ndp->ni_rootdir || dp->v_parent == NULLVP) break; .... } #info The pointer dp can be null. However, further the pointer is dereferenced before the preliminary check. ----------------------------------------------------------------- V1001 CWE-563 The 'a' variable is assigned but is not used until the end of the function. sha1mod.c 120 __private_extern__ void YSHA1Transform(u_int32_t state[5], const unsigned char buffer[64]) { u_int32_t a, b, c, d, e; .... state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; /* Wipe variables */ a = b = c = d = e = 0; } #info The compiler can delete code in terms of optimization. ----------------------------------------------------------------- V612 CWE-670 An unconditional 'goto' within a loop. kern_descrip.c 628 int dup2(proc_t p, struct dup2_args *uap, int32_t *retval) { .... while ((fdp->fd_ofileflags[new] & UF_RESERVED) == UF_RESERVED) { fp_drop(p, old, fp, 1); procfdtbl_waitfd(p, new); #if DIAGNOSTIC proc_fdlock_assert(p, LCK_MTX_ASSERT_OWNED); #endif goto startover; } .... startover: .... } #info Strange loop body at the end of which there is an unconditional transition to the label startover. Similar errors: #add V612 CWE-670 An unconditional 'goto' within a loop. tty.c 1084 V612 CWE-670 An unconditional 'goto' within a loop. vm_purgeable.c 842 V612 CWE-670 An unconditional 'return' within a loop. kern_credential.c 930 ----------------------------------------------------------------- V560 CWE-570 A part of conditional expression is always false: ((* state & 3) > 3). vm_user.c 3415 #define VM_PURGABLE_STATE_MASK 3 kern_return_t memory_entry_purgeable_control_internal(...., int *state) { .... if ((control == VM_PURGABLE_SET_STATE || control == VM_PURGABLE_SET_STATE_FROM_KERNEL) && (((*state & ~(VM_PURGABLE_ALL_MASKS)) != 0) || ((*state & VM_PURGABLE_STATE_MASK) > VM_PURGABLE_STATE_MASK))) return(KERN_INVALID_ARGUMENT); .... } #info Let’s leave the main point: ((* state & 3) > 3). The expression has no sense. Similar errors: #add V560 CWE-570 A part of conditional expression is always false: ((* state & 3) > 3). vm_map.c 15809 -----------------------------------------------------------------