Subject: Re: [PATCH v2 23/35] net/tcp: Add getsockopt(TCP_AO_GET)

From: kernel test robot <[email-masked]>
Date: Sat, 24 Sep 2022 14:44:08 +0800

Hi Dmitry,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on bf682942cd26ce9cd5e87f73ae099b383041e782]

url:    https://github.com/intel-lab-lkp/linux/commits/Dmitry-Safonov/net-tcp-Add-TCP-AO-support/20220924-042311
base:   bf682942cd26ce9cd5e87f73ae099b383041e782
config: um-x86_64_defconfig
compiler: gcc-11 (Debian 11.3.0-5) 11.3.0
reproduce (this is a W=1 build):
        # https://github.com/intel-lab-lkp/linux/commit/464de48068a05d5b8690ca346f382b74914e5ce3
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Dmitry-Safonov/net-tcp-Add-TCP-AO-support/20220924-042311
        git checkout 464de48068a05d5b8690ca346f382b74914e5ce3
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        make W=1 O=build_dir ARCH=um SUBARCH=x86_64 SHELL=/bin/bash net/ipv4/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email-masked]>

All warnings (new ones prefixed by >>):

   net/ipv4/tcp_ao.c:113:20: warning: no previous prototype for 'tcp_ao_do_lookup_keyid' [-Wmissing-prototypes]
     113 | struct tcp_ao_key *tcp_ao_do_lookup_keyid(struct tcp_ao_info *ao,
         |                    ^~~~~~~~~~~~~~~~~~~~~~
   net/ipv4/tcp_ao.c:270:20: warning: no previous prototype for 'tcp_ao_copy_key' [-Wmissing-prototypes]
     270 | struct tcp_ao_key *tcp_ao_copy_key(struct sock *sk, struct tcp_ao_key *key)
         |                    ^~~~~~~~~~~~~~~
>> net/ipv4/tcp_ao.c:1778:5: warning: no previous prototype for 'tcp_ao_copy_mkts_to_user' [-Wmissing-prototypes]
    1778 | int tcp_ao_copy_mkts_to_user(struct tcp_ao_info *ao_info,
         |     ^~~~~~~~~~~~~~~~~~~~~~~~

vim +/tcp_ao_copy_mkts_to_user +1778 net/ipv4/tcp_ao.c

  1742	
  1743	/* tcp_ao_copy_mkts_to_user(ao_info, optval, optlen)
  1744	 *
  1745	 * @ao_info:	struct tcp_ao_info on the socket that
  1746	 *		socket getsockopt(TCP_AO_GET) is executed on
  1747	 * @optval:	pointer to array of tcp_ao_getsockopt structures in user space.
  1748	 *		Must be != NULL.
  1749	 * @optlen:	pointer to size of tcp_ao_getsockopt structure.
  1750	 *		Must be != NULL.
  1751	 *
  1752	 * Return value: 0 on success, a negative error number otherwise.
  1753	 *
  1754	 * optval points to an array of tcp_ao_getsockopt structures in user space.
  1755	 * optval[0] is used as both input and output to getsockopt. It determines
  1756	 * which keys are returned by the kernel.
  1757	 * optval[0].nkeys is the size of the array in user space. On return it contains
  1758	 * the number of keys matching the search criteria.
  1759	 * If TCP_AO_GET_ALL is set in "flags", then all keys in the socket are
  1760	 * returned, otherwise only keys matching <addr, prefix, sndid, rcvid>
  1761	 * in optval[0] are returned.
  1762	 * optlen is also used as both input and output. The user provides the size
  1763	 * of struct tcp_ao_getsockopt in user space, and the kernel returns the size
  1764	 * of the structure in kernel space.
  1765	 * The size of struct tcp_ao_getsockopt may differ between user and kernel.
  1766	 * There are three cases to consider:
  1767	 *  * If usize == ksize, then keys are copied verbatim.
  1768	 *  * If usize < ksize, then the userspace has passed an old struct to a
  1769	 *    newer kernel. The rest of the trailing bytes in optval[0]
  1770	 *    (ksize - usize) are interpreted as 0 by the kernel.
  1771	 *  * If usize > ksize, then the userspace has passed a new struct to an
  1772	 *    older kernel. The trailing bytes unknown to the kernel (usize - ksize)
  1773	 *    are checked to ensure they are zeroed, otherwise -E2BIG is returned.
  1774	 * On return the kernel fills in min(usize, ksize) in each entry of the array.
  1775	 * The layout of the fields in the user and kernel structures is expected to
  1776	 * be the same (including in the 32bit vs 64bit case).
  1777	 */
> 1778	int tcp_ao_copy_mkts_to_user(struct tcp_ao_info *ao_info,
  1779				     char __user *optval, int __user *optlen)
  1780	{
  1781		struct tcp_ao_getsockopt opt_in;
  1782		struct tcp_ao_getsockopt opt_out;
  1783		struct tcp_ao_getsockopt __user *optval_in;
  1784		int user_len;
  1785		unsigned int max_keys;	/* maximum number of keys to copy to user */
  1786		u32 copied_keys;	/* keys copied to user so far */
  1787		int matched_keys;	/* keys from ao_info matched so far */
  1788		int bytes_to_write;	/* number of bytes to write to user level */
  1789		struct tcp_ao_key *key;
  1790		struct sockaddr_in *sin;   /* (struct sockaddr_in *)&opt_in.addr */
  1791		struct sockaddr_in6 *sin6; /* (struct sockaddr_in6 *)&opt_in.addr */
  1792		struct in6_addr *addr6;    /* &sin6->sin6_addr */
  1793		__kernel_sa_family_t ss_family;
  1794		union tcp_ao_addr *addr;
  1795		int optlen_out;
  1796		u8 prefix_in;
  1797		u16 port = 0;
  1798		bool copy_all, copy_current, copy_next;
  1799		int err;
  1800	
  1801		if (get_user(user_len, optlen))
  1802			return -EFAULT;
  1803	
  1804		if (user_len <= 0)
  1805			return -EINVAL;
  1806	
  1807		memset(&opt_in, 0, sizeof(struct tcp_ao_getsockopt));
  1808		err = copy_struct_from_user(&opt_in, sizeof(struct tcp_ao_getsockopt),
  1809					    optval, user_len);
  1810		if (err < 0)
  1811			return err;
  1812	
  1813		optval_in = (struct tcp_ao_getsockopt __user *)optval;
  1814		ss_family = opt_in.addr.ss_family;
  1815	
  1816		BUILD_BUG_ON(TCP_AO_GET_ALL & (TCP_AO_GET_CURR | TCP_AO_GET_NEXT));
  1817		if (opt_in.flags & ~TCP_AO_GETF_VALID)
  1818			return -EINVAL;
  1819	
  1820		max_keys = opt_in.nkeys;
  1821		copy_all = !!(opt_in.flags & TCP_AO_GET_ALL);
  1822		copy_current = !!(opt_in.flags & TCP_AO_GET_CURR);
  1823		copy_next = !!(opt_in.flags & TCP_AO_GET_NEXT);
  1824	
  1825		if (!(copy_all || copy_current || copy_next)) {
  1826			prefix_in = opt_in.prefix;
  1827	
  1828			switch (ss_family) {
  1829			case AF_INET: {
  1830				sin = (struct sockaddr_in *)&opt_in.addr;
  1831				port = sin->sin_port;
  1832				addr = (union tcp_ao_addr *)&sin->sin_addr;
  1833	
  1834				if (prefix_in > 32)
  1835					return -EINVAL;
  1836	
  1837				if (sin->sin_addr.s_addr == INADDR_ANY &&
  1838				    prefix_in != 0)
  1839					return -EINVAL;
  1840	
  1841				break;
  1842			}
  1843			case AF_INET6: {
  1844				sin6 = (struct sockaddr_in6 *)&opt_in.addr;
  1845				addr = (union tcp_ao_addr *)&sin6->sin6_addr;
  1846				addr6 = &sin6->sin6_addr;
  1847				port = sin6->sin6_port;
  1848	
  1849				if (prefix_in != 0) {
  1850					if (ipv6_addr_v4mapped(addr6)) {
  1851						__be32 addr4 = addr6->s6_addr32[3];
  1852	
  1853						if (prefix_in > 32 ||
  1854						    addr4 == INADDR_ANY)
  1855							return -EINVAL;
  1856					} else {
  1857						if (ipv6_addr_any(addr6) ||
  1858						    prefix_in > 128)
  1859							return -EINVAL;
  1860					}
  1861				} else if (!ipv6_addr_any(addr6)) {
  1862					return -EINVAL;
  1863				}
  1864	
  1865				break;
  1866			}
  1867			default:
  1868				return -EINVAL;
  1869			}
  1870		}
  1871	
  1872		bytes_to_write = min(user_len, (int)sizeof(struct tcp_ao_getsockopt));
  1873		copied_keys = 0;
  1874		matched_keys = 0;
  1875	
  1876		hlist_for_each_entry_rcu(key, &ao_info->head, node) {
  1877			if (copy_all)
  1878				goto match;
  1879	
  1880			if (copy_current || copy_next) {
  1881				if (copy_current && key == ao_info->current_key)
  1882					goto match;
  1883				if (copy_next && key == ao_info->rnext_key)
  1884					goto match;
  1885				continue;
  1886			}
  1887	
  1888			if (tcp_ao_key_cmp(key, addr, opt_in.prefix,
  1889					   opt_in.addr.ss_family,
  1890					   opt_in.sndid, opt_in.rcvid, port) != 0)
  1891				continue;
  1892	match:
  1893			matched_keys++;
  1894			if (copied_keys >= max_keys)
  1895				continue;
  1896	
  1897			memset(&opt_out, 0, sizeof(struct tcp_ao_getsockopt));
  1898	
  1899			if (key->family == AF_INET) {
  1900				struct sockaddr_in *sin_out = (struct sockaddr_in *)&opt_out.addr;
  1901	
  1902				sin_out->sin_family = key->family;
  1903				sin_out->sin_port = ntohs(key->port);
  1904				memcpy(&sin_out->sin_addr, &key->addr, sizeof(struct in_addr));
  1905			} else {
  1906				struct sockaddr_in6 *sin6_out = (struct sockaddr_in6 *)&opt_out.addr;
  1907	
  1908				sin6_out->sin6_family = key->family;
  1909				sin6_out->sin6_port = ntohs(key->port);
  1910				memcpy(&sin6_out->sin6_addr, &key->addr, sizeof(struct in6_addr));
  1911			}
  1912			opt_out.sndid = key->sndid;
  1913			opt_out.rcvid = key->rcvid;
  1914			opt_out.prefix = key->prefixlen;
  1915			opt_out.keyflags = key->keyflags;
  1916			opt_out.flags = 0;
  1917			if (key == ao_info->current_key)
  1918				opt_out.flags |= TCP_AO_GET_CURR;
  1919			if (key == ao_info->rnext_key)
  1920				opt_out.flags |= TCP_AO_GET_NEXT;
  1921			opt_out.nkeys = 0;
  1922			opt_out.maclen = key->maclen;
  1923			opt_out.keylen = key->keylen;
  1924			memcpy(&opt_out.key, key->key, key->keylen);
  1925			crypto_pool_algo(key->crypto_pool_id, opt_out.alg_name, 64);
  1926	
  1927			/* Copy key to user */
  1928			if (copy_to_user(optval, &opt_out, bytes_to_write))
  1929				return -EFAULT;
  1930			optval += user_len;
  1931			copied_keys++;
  1932		}
  1933	
  1934		optlen_out = (int)sizeof(struct tcp_ao_getsockopt);
  1935		if (copy_to_user(optlen, &optlen_out, sizeof(int)))
  1936			return -EFAULT;
  1937	
  1938		if (copy_to_user(&optval_in->nkeys, &matched_keys, sizeof(u32)))
  1939			return -EFAULT;
  1940	
  1941		return 0;
  1942	}
  1943	

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp