Monday, February 27, 2023

Reverse Engineering Notes - CVE-2020-7460


static int
freebsd32_copyin_control(struct mbuf **mp, caddr_t buf, u_int buflen)
{
	struct mbuf *m;
	void *md;
	u_int idx, len, msglen;
	int error;

	buflen = FREEBSD32_ALIGN(buflen);

	if (buflen > MCLBYTES)
		return (EINVAL); 

This is a function named freebsd32_copyin_control that takes three arguments: a pointer to a pointer of struct mbuf, a caddr_t buffer, and an u_int value representing the length of the buffer. The function returns an integer value.

Here's what each line of the function does:

  • struct mbuf *m; This line declares a pointer to an mbuf structure. The pointer is used later to traverse the mbuf chain and copy the data from the buffer into the mbuf structure.
  • void *md; This line declares a void pointer to be used later. This pointer is used to temporarily store a pointer to the md field of the mbuf structure.
  • u_int idx, len, msglen; This line declares three unsigned integers to be used later. These integers are used to keep track of the current index, the remaining length of the data to be copied, and the length of each mbuf segment.
  • int error; This line declares an integer variable to be used later. This variable is used to store the error code if the operation fails.
  • buflen = FREEBSD32_ALIGN(buflen); This line aligns the buflen parameter to a multiple of the alignment value specified by the FREEBSD32_ALIGN macro. This is done to ensure that the buffer length is aligned properly for efficient memory access.
  • if (buflen > MCLBYTES) return (EINVAL); This line checks if buflen is greater than the maximum length allowed for a single mbuf structure. If it is, the function returns an error code indicating that the operation is invalid.
  • msglen = MCLBYTES; This line sets the value of msglen to the maximum segment length allowed for an mbuf structure.
  • for (idx = 0, len = buflen; len > 0; idx++, len -= msglen, mp = &(*mp)->m_next) { This line starts a loop that iterates through the mbuf chain and copies the data from the buffer into each segment of the chain. The loop initializes idx to zero and len to the total length of the buffer. It also sets the value of mp to a pointer to the first mbuf structure in the chain.
  • if (*mp == NULL) { This line checks if the current mbuf structure is NULL. If it is, the function returns an error code indicating that the operation has failed.
  • if ((*mp)->m_flags & M_EXT) { This line checks if the M_EXT flag is set for the current mbuf structure. This flag indicates that the mbuf structure is part of an mbuf cluster, which is a group of contiguous mbuf structures used to represent larger data segments.
  • md = &(*mp)->m_ext.ext_buf[(idx * msglen) & (*mp)->m_ext.ext_size]; This line sets the value of md to a pointer to the current segment of the mbuf cluster. The pointer is calculated using the current segment index idx, the segment length msglen, and the size of the mbuf cluster.
  • } else { This line starts an else block for the case where the M_EXT flag is not set.
  • md = &(*mp)->m_dat[off]; This line sets the value of md to a pointer to the md field of the current mbuf structure. The md field is a pointer to the data segment of the mbuf structure.
  • off = idx * MCLBYTES; This line sets the value of
  •  This line of code is checking whether the value of the variable buflen is greater than the constant MCLBYTES.
  • If buflen is greater than MCLBYTES, the function returns the EINVAL error code indicating that the input parameters to the function are invalid.
  • EINVAL is a standard error code in Unix-based operating systems that indicates an invalid argument.

The overall purpose of this function is to perform a copy operation from a caddr_t buffer to a struct mbuf data structure, while ensuring that the buffer length is within a certain limit. The function first rounds up the buffer length to a multiple of a specific alignment value, and then checks if the rounded-up length exceeds a maximum value. If the length is within limits, the function proceeds with the copy operation and returns 0 to indicate success. Otherwise, it returns an error code to indicate failure.

 idx = 0; len = 0; while (idx < buflen) { error = copyin(buf + idx, &msglen, sizeof(msglen)); if (error) return (error); if (msglen < sizeof(struct cmsghdr)) return (EINVAL); msglen = FREEBSD32_ALIGN(msglen); if (idx + msglen > buflen) return (EINVAL); idx += msglen; msglen += CMSG_ALIGN(sizeof(struct cmsghdr)) - FREEBSD32_ALIGN(sizeof(struct cmsghdr)); len += CMSG_ALIGN(msglen); } 

This code block starts a while loop that iterates through the buffer specified by the buf pointer. The loop initializes the idx and len variables to 0.

Inside the loop, the copyin() function is called to copy the next 4 bytes of data from the buffer into the msglen variable. If an error occurs during the copy, the function returns the error code.

The code then checks if the value of msglen is less than the size of the cmsghdr structure. If it is, the function returns an error code indicating that the input parameters to the function are invalid.

The code then aligns the value of msglen to a multiple of the alignment value specified by the FREEBSD32_ALIGN macro. This is done to ensure that the length of the data to be copied is aligned properly for efficient memory access.

Next, the code checks if the value of idx plus the aligned value of msglen exceeds the total length of the buffer. If it does, the function returns an error code indicating that the input parameters to the function are invalid.

If none of the error conditions are met, the code updates the values of idx and len, and calculates the aligned length of the data segment using the CMSG_ALIGN macro. The loop continues until all the data in the buffer has been processed.

 

 

No comments:

Post a Comment

A Guide to Multi-Level Pointer Analysis

  A Comprehensive Guide to Multi-Level Pointer Analysis   A regular pointer points to only one address, but when it's accompanied by a l...