The cn_namelen member is a signed type.
sys/sys/namei.h:
struct componentname { ... long cn_namelen; /* length of looked up component */ };
There are no casts to unsigned for any of the values it is compared against:
sys/kern/uipc_mqueue.c:
#define MQFS_NAMELEN NAME_MAX
sys/sys/syslimits.h:
#define NAME_MAX 255 /* max bytes in a file name */
sys/fs/pseudofs/pseudofs.h:
#define PFS_NAMELEN 24
Since signed comparisons will be used, negative lengths will be incorrectly accepted, which could lead to out of bounds reads in later parts of the code. For example in mqfs_search:
sys/kern/uipc_mqueue.c:
static struct mqfs_node * mqfs_search(struct mqfs_node *pd, const char *name, int len) { struct mqfs_node *pn; sx_assert(&pd->mn_info->mi_lock, SX_LOCKED); LIST_FOREACH(pn, &pd->mn_children, mn_sibling) { if (strncmp(pn->mn_name, name, len) == 0 && pn->mn_name[len] == '\0') return (pn); } return (NULL); }
However, there is more serious potential if this negative length were to be passed to mqfs_create_node:
sys/kern/uipc_mqueue.c:
static __inline struct mqfs_node * mqnode_alloc(void) { return uma_zalloc(mqnode_zone, M_WAITOK | M_ZERO); } static struct mqfs_node * mqfs_create_node(const char *name, int namelen, struct ucred *cred, int mode, int nodetype) { struct mqfs_node *node; node = mqnode_alloc(); strncpy(node->mn_name, name, namelen); node->mn_type = nodetype; node->mn_refcount = 1; vfs_timestamp(&node->mn_birth); node->mn_ctime = node->mn_atime = node->mn_mtime = node->mn_birth; node->mn_uid = cred->cr_uid; node->mn_gid = cred->cr_gid; node->mn_mode = mode; return (node); }
Negative namelen will be converted to unsigned for strcpy which would then overflow fixed buffer:
sys/kern/uipc_mqueue.c:
struct mqfs_node { char mn_name[MQFS_NAMELEN+1]; ...