Message ID | 1508269854.31614.114.camel@edumazet-glaptop3.roam.corp.google.com |
---|---|
State | Superseded, archived |
Delegated to: | David Miller |
Headers | show |
Series | [net] dccp/tcp: fix ireq->opt races | expand |
On Tue, 2017-10-17 at 12:50 -0700, Eric Dumazet wrote: > From: Eric Dumazet <edumazet@google.com> > > syzkaller found another bug in DCCP/TCP stacks [1] > > For the reasons explained in commit ce1050089c96 ("tcp/dccp: fix > ireq->pktopts race"), we need to make sure we do not access > ireq->opt unless we own the request sock. Arg, I will send a v2 without the silly lines that confuse patchwork.
Hi Eric, [auto build test WARNING on net/master] url: https://github.com/0day-ci/linux/commits/Eric-Dumazet/dccp-tcp-fix-ireq-opt-races/20171021-001234 config: ia64-allmodconfig (attached as .config) compiler: ia64-linux-gcc (GCC) 6.2.0 reproduce: wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree make.cross ARCH=ia64 All warnings (new ones prefixed by >>): In file included from arch/ia64/include/uapi/asm/intrinsics.h:21:0, from arch/ia64/include/asm/intrinsics.h:10, from arch/ia64/include/asm/atomic.h:17, from include/linux/atomic.h:4, from include/linux/rcupdate.h:38, from net/ipv4/cipso_ipv4.c:40: net/ipv4/cipso_ipv4.c: In function 'cipso_v4_req_setattr': net/ipv4/cipso_ipv4.c:1954:22: error: 'struct inet_request_sock' has no member named 'opt' opt = xchg(&req_inet->opt, opt); ^ arch/ia64/include/uapi/asm/cmpxchg.h:56:16: note: in definition of macro 'xchg' ((__typeof__(*(ptr))) __xchg((unsigned long) (x), (ptr), sizeof(*(ptr)))) ^~~ net/ipv4/cipso_ipv4.c:1954:22: error: 'struct inet_request_sock' has no member named 'opt' opt = xchg(&req_inet->opt, opt); ^ arch/ia64/include/uapi/asm/cmpxchg.h:33:10: note: in definition of macro '__xchg' switch (size) { \ ^~~~ >> net/ipv4/cipso_ipv4.c:1954:8: note: in expansion of macro 'xchg' opt = xchg(&req_inet->opt, opt); ^~~~ In file included from arch/ia64/include/asm/gcc_intrin.h:9:0, from arch/ia64/include/uapi/asm/intrinsics.h:19, from arch/ia64/include/asm/intrinsics.h:10, from arch/ia64/include/asm/atomic.h:17, from include/linux/atomic.h:4, from include/linux/rcupdate.h:38, from net/ipv4/cipso_ipv4.c:40: net/ipv4/cipso_ipv4.c:1954:22: error: 'struct inet_request_sock' has no member named 'opt' opt = xchg(&req_inet->opt, opt); ^ arch/ia64/include/uapi/asm/gcc_intrin.h:279:40: note: in definition of macro 'ia64_xchg1' : "=r" (ia64_intri_res) : "r" (ptr), "r" (x) : "memory"); \ ^~~ >> arch/ia64/include/uapi/asm/cmpxchg.h:56:23: note: in expansion of macro '__xchg' ((__typeof__(*(ptr))) __xchg((unsigned long) (x), (ptr), sizeof(*(ptr)))) ^~~~~~ >> net/ipv4/cipso_ipv4.c:1954:8: note: in expansion of macro 'xchg' opt = xchg(&req_inet->opt, opt); ^~~~ net/ipv4/cipso_ipv4.c:1954:22: error: 'struct inet_request_sock' has no member named 'opt' opt = xchg(&req_inet->opt, opt); ^ arch/ia64/include/uapi/asm/gcc_intrin.h:287:16: note: in definition of macro 'ia64_xchg2' : "r" (ptr), "r" (x) : "memory"); \ ^~~ >> arch/ia64/include/uapi/asm/cmpxchg.h:56:23: note: in expansion of macro '__xchg' ((__typeof__(*(ptr))) __xchg((unsigned long) (x), (ptr), sizeof(*(ptr)))) ^~~~~~ >> net/ipv4/cipso_ipv4.c:1954:8: note: in expansion of macro 'xchg' opt = xchg(&req_inet->opt, opt); ^~~~ net/ipv4/cipso_ipv4.c:1954:22: error: 'struct inet_request_sock' has no member named 'opt' opt = xchg(&req_inet->opt, opt); ^ arch/ia64/include/uapi/asm/gcc_intrin.h:295:16: note: in definition of macro 'ia64_xchg4' : "r" (ptr), "r" (x) : "memory"); \ ^~~ >> arch/ia64/include/uapi/asm/cmpxchg.h:56:23: note: in expansion of macro '__xchg' ((__typeof__(*(ptr))) __xchg((unsigned long) (x), (ptr), sizeof(*(ptr)))) ^~~~~~ >> net/ipv4/cipso_ipv4.c:1954:8: note: in expansion of macro 'xchg' opt = xchg(&req_inet->opt, opt); ^~~~ net/ipv4/cipso_ipv4.c:1954:22: error: 'struct inet_request_sock' has no member named 'opt' opt = xchg(&req_inet->opt, opt); ^ arch/ia64/include/uapi/asm/gcc_intrin.h:303:16: note: in definition of macro 'ia64_xchg8' : "r" (ptr), "r" (x) : "memory"); \ ^~~ >> arch/ia64/include/uapi/asm/cmpxchg.h:56:23: note: in expansion of macro '__xchg' ((__typeof__(*(ptr))) __xchg((unsigned long) (x), (ptr), sizeof(*(ptr)))) ^~~~~~ >> net/ipv4/cipso_ipv4.c:1954:8: note: in expansion of macro 'xchg' opt = xchg(&req_inet->opt, opt); ^~~~ net/ipv4/cipso_ipv4.c: In function 'cipso_v4_req_delattr': net/ipv4/cipso_ipv4.c:2073:16: error: 'struct inet_request_sock' has no member named 'opt' opt = req_inet->opt; ^~ net/ipv4/cipso_ipv4.c:2077:27: error: 'struct inet_request_sock' has no member named 'opt' cipso_v4_delopt(&req_inet->opt); ^~ -- In file included from arch/ia64/include/uapi/asm/intrinsics.h:21:0, from arch/ia64/include/asm/intrinsics.h:10, from arch/ia64/include/asm/atomic.h:17, from include/linux/atomic.h:4, from include/linux/rcupdate.h:38, from net//ipv4/cipso_ipv4.c:40: net//ipv4/cipso_ipv4.c: In function 'cipso_v4_req_setattr': net//ipv4/cipso_ipv4.c:1954:22: error: 'struct inet_request_sock' has no member named 'opt' opt = xchg(&req_inet->opt, opt); ^ arch/ia64/include/uapi/asm/cmpxchg.h:56:16: note: in definition of macro 'xchg' ((__typeof__(*(ptr))) __xchg((unsigned long) (x), (ptr), sizeof(*(ptr)))) ^~~ net//ipv4/cipso_ipv4.c:1954:22: error: 'struct inet_request_sock' has no member named 'opt' opt = xchg(&req_inet->opt, opt); ^ arch/ia64/include/uapi/asm/cmpxchg.h:33:10: note: in definition of macro '__xchg' switch (size) { \ ^~~~ net//ipv4/cipso_ipv4.c:1954:8: note: in expansion of macro 'xchg' opt = xchg(&req_inet->opt, opt); ^~~~ In file included from arch/ia64/include/asm/gcc_intrin.h:9:0, from arch/ia64/include/uapi/asm/intrinsics.h:19, from arch/ia64/include/asm/intrinsics.h:10, from arch/ia64/include/asm/atomic.h:17, from include/linux/atomic.h:4, from include/linux/rcupdate.h:38, from net//ipv4/cipso_ipv4.c:40: net//ipv4/cipso_ipv4.c:1954:22: error: 'struct inet_request_sock' has no member named 'opt' opt = xchg(&req_inet->opt, opt); ^ arch/ia64/include/uapi/asm/gcc_intrin.h:279:40: note: in definition of macro 'ia64_xchg1' : "=r" (ia64_intri_res) : "r" (ptr), "r" (x) : "memory"); \ ^~~ >> arch/ia64/include/uapi/asm/cmpxchg.h:56:23: note: in expansion of macro '__xchg' ((__typeof__(*(ptr))) __xchg((unsigned long) (x), (ptr), sizeof(*(ptr)))) ^~~~~~ net//ipv4/cipso_ipv4.c:1954:8: note: in expansion of macro 'xchg' opt = xchg(&req_inet->opt, opt); ^~~~ net//ipv4/cipso_ipv4.c:1954:22: error: 'struct inet_request_sock' has no member named 'opt' opt = xchg(&req_inet->opt, opt); ^ arch/ia64/include/uapi/asm/gcc_intrin.h:287:16: note: in definition of macro 'ia64_xchg2' : "r" (ptr), "r" (x) : "memory"); \ ^~~ >> arch/ia64/include/uapi/asm/cmpxchg.h:56:23: note: in expansion of macro '__xchg' ((__typeof__(*(ptr))) __xchg((unsigned long) (x), (ptr), sizeof(*(ptr)))) ^~~~~~ net//ipv4/cipso_ipv4.c:1954:8: note: in expansion of macro 'xchg' opt = xchg(&req_inet->opt, opt); ^~~~ net//ipv4/cipso_ipv4.c:1954:22: error: 'struct inet_request_sock' has no member named 'opt' opt = xchg(&req_inet->opt, opt); ^ arch/ia64/include/uapi/asm/gcc_intrin.h:295:16: note: in definition of macro 'ia64_xchg4' : "r" (ptr), "r" (x) : "memory"); \ ^~~ >> arch/ia64/include/uapi/asm/cmpxchg.h:56:23: note: in expansion of macro '__xchg' ((__typeof__(*(ptr))) __xchg((unsigned long) (x), (ptr), sizeof(*(ptr)))) ^~~~~~ net//ipv4/cipso_ipv4.c:1954:8: note: in expansion of macro 'xchg' opt = xchg(&req_inet->opt, opt); ^~~~ net//ipv4/cipso_ipv4.c:1954:22: error: 'struct inet_request_sock' has no member named 'opt' opt = xchg(&req_inet->opt, opt); ^ arch/ia64/include/uapi/asm/gcc_intrin.h:303:16: note: in definition of macro 'ia64_xchg8' : "r" (ptr), "r" (x) : "memory"); \ ^~~ >> arch/ia64/include/uapi/asm/cmpxchg.h:56:23: note: in expansion of macro '__xchg' ((__typeof__(*(ptr))) __xchg((unsigned long) (x), (ptr), sizeof(*(ptr)))) ^~~~~~ net//ipv4/cipso_ipv4.c:1954:8: note: in expansion of macro 'xchg' opt = xchg(&req_inet->opt, opt); ^~~~ net//ipv4/cipso_ipv4.c: In function 'cipso_v4_req_delattr': net//ipv4/cipso_ipv4.c:2073:16: error: 'struct inet_request_sock' has no member named 'opt' opt = req_inet->opt; ^~ net//ipv4/cipso_ipv4.c:2077:27: error: 'struct inet_request_sock' has no member named 'opt' cipso_v4_delopt(&req_inet->opt); ^~ vim +/xchg +1954 net/ipv4/cipso_ipv4.c 446fda4f2 Paul Moore 2006-08-03 1898 446fda4f2 Paul Moore 2006-08-03 1899 /** 389fb800a Paul Moore 2009-03-27 1900 * cipso_v4_req_setattr - Add a CIPSO option to a connection request socket 389fb800a Paul Moore 2009-03-27 1901 * @req: the connection request socket 389fb800a Paul Moore 2009-03-27 1902 * @doi_def: the CIPSO DOI to use 389fb800a Paul Moore 2009-03-27 1903 * @secattr: the specific security attributes of the socket 014ab19a6 Paul Moore 2008-10-10 1904 * 014ab19a6 Paul Moore 2008-10-10 1905 * Description: 389fb800a Paul Moore 2009-03-27 1906 * Set the CIPSO option on the given socket using the DOI definition and 389fb800a Paul Moore 2009-03-27 1907 * security attributes passed to the function. Returns zero on success and 389fb800a Paul Moore 2009-03-27 1908 * negative values on failure. 014ab19a6 Paul Moore 2008-10-10 1909 * 014ab19a6 Paul Moore 2008-10-10 1910 */ 389fb800a Paul Moore 2009-03-27 1911 int cipso_v4_req_setattr(struct request_sock *req, 389fb800a Paul Moore 2009-03-27 1912 const struct cipso_v4_doi *doi_def, 389fb800a Paul Moore 2009-03-27 1913 const struct netlbl_lsm_secattr *secattr) 014ab19a6 Paul Moore 2008-10-10 1914 { 389fb800a Paul Moore 2009-03-27 1915 int ret_val = -EPERM; 389fb800a Paul Moore 2009-03-27 1916 unsigned char *buf = NULL; 389fb800a Paul Moore 2009-03-27 1917 u32 buf_len; 389fb800a Paul Moore 2009-03-27 1918 u32 opt_len; f6d8bd051 Eric Dumazet 2011-04-21 1919 struct ip_options_rcu *opt = NULL; 389fb800a Paul Moore 2009-03-27 1920 struct inet_request_sock *req_inet; 014ab19a6 Paul Moore 2008-10-10 1921 389fb800a Paul Moore 2009-03-27 1922 /* We allocate the maximum CIPSO option size here so we are probably 389fb800a Paul Moore 2009-03-27 1923 * being a little wasteful, but it makes our life _much_ easier later 389fb800a Paul Moore 2009-03-27 1924 * on and after all we are only talking about 40 bytes. */ 389fb800a Paul Moore 2009-03-27 1925 buf_len = CIPSO_V4_OPT_LEN_MAX; 389fb800a Paul Moore 2009-03-27 1926 buf = kmalloc(buf_len, GFP_ATOMIC); 51456b291 Ian Morris 2015-04-03 1927 if (!buf) { 389fb800a Paul Moore 2009-03-27 1928 ret_val = -ENOMEM; 389fb800a Paul Moore 2009-03-27 1929 goto req_setattr_failure; 389fb800a Paul Moore 2009-03-27 1930 } 389fb800a Paul Moore 2009-03-27 1931 389fb800a Paul Moore 2009-03-27 1932 ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr); 389fb800a Paul Moore 2009-03-27 1933 if (ret_val < 0) 389fb800a Paul Moore 2009-03-27 1934 goto req_setattr_failure; 389fb800a Paul Moore 2009-03-27 1935 buf_len = ret_val; 389fb800a Paul Moore 2009-03-27 1936 389fb800a Paul Moore 2009-03-27 1937 /* We can't use ip_options_get() directly because it makes a call to 389fb800a Paul Moore 2009-03-27 1938 * ip_options_get_alloc() which allocates memory with GFP_KERNEL and 389fb800a Paul Moore 2009-03-27 1939 * we won't always have CAP_NET_RAW even though we _always_ want to 389fb800a Paul Moore 2009-03-27 1940 * set the IPOPT_CIPSO option. */ 389fb800a Paul Moore 2009-03-27 1941 opt_len = (buf_len + 3) & ~3; 389fb800a Paul Moore 2009-03-27 1942 opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC); 51456b291 Ian Morris 2015-04-03 1943 if (!opt) { 389fb800a Paul Moore 2009-03-27 1944 ret_val = -ENOMEM; 389fb800a Paul Moore 2009-03-27 1945 goto req_setattr_failure; 389fb800a Paul Moore 2009-03-27 1946 } f6d8bd051 Eric Dumazet 2011-04-21 1947 memcpy(opt->opt.__data, buf, buf_len); f6d8bd051 Eric Dumazet 2011-04-21 1948 opt->opt.optlen = opt_len; f6d8bd051 Eric Dumazet 2011-04-21 1949 opt->opt.cipso = sizeof(struct iphdr); 389fb800a Paul Moore 2009-03-27 1950 kfree(buf); 389fb800a Paul Moore 2009-03-27 1951 buf = NULL; 389fb800a Paul Moore 2009-03-27 1952 389fb800a Paul Moore 2009-03-27 1953 req_inet = inet_rsk(req); 389fb800a Paul Moore 2009-03-27 @1954 opt = xchg(&req_inet->opt, opt); f6d8bd051 Eric Dumazet 2011-04-21 1955 if (opt) 4f9c8c1b0 Paul E. McKenney 2012-01-06 1956 kfree_rcu(opt, rcu); 389fb800a Paul Moore 2009-03-27 1957 389fb800a Paul Moore 2009-03-27 1958 return 0; 389fb800a Paul Moore 2009-03-27 1959 389fb800a Paul Moore 2009-03-27 1960 req_setattr_failure: 389fb800a Paul Moore 2009-03-27 1961 kfree(buf); 389fb800a Paul Moore 2009-03-27 1962 kfree(opt); 389fb800a Paul Moore 2009-03-27 1963 return ret_val; 389fb800a Paul Moore 2009-03-27 1964 } 389fb800a Paul Moore 2009-03-27 1965 :::::: The code at line 1954 was first introduced by commit :::::: 389fb800ac8be2832efedd19978a2b8ced37eb61 netlabel: Label incoming TCP connections correctly in SELinux :::::: TO: Paul Moore <paul.moore@hp.com> :::::: CC: James Morris <jmorris@namei.org> --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hi Eric, [auto build test ERROR on net/master] url: https://github.com/0day-ci/linux/commits/Eric-Dumazet/dccp-tcp-fix-ireq-opt-races/20171021-001234 config: blackfin-allyesconfig (attached as .config) compiler: bfin-uclinux-gcc (GCC) 6.2.0 reproduce: wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree make.cross ARCH=blackfin All errors (new ones prefixed by >>): In file included from arch/blackfin/include/asm/atomic.h:10:0, from include/linux/atomic.h:4, from include/linux/rcupdate.h:38, from net/ipv4/cipso_ipv4.c:40: net/ipv4/cipso_ipv4.c: In function 'cipso_v4_req_setattr': >> net/ipv4/cipso_ipv4.c:1954:22: error: 'struct inet_request_sock' has no member named 'opt' opt = xchg(&req_inet->opt, opt); ^ arch/blackfin/include/asm/cmpxchg.h:130:37: note: in definition of macro 'xchg' #define xchg(ptr, x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr)))) ^~~ >> net/ipv4/cipso_ipv4.c:1954:22: error: 'struct inet_request_sock' has no member named 'opt' opt = xchg(&req_inet->opt, opt); ^ arch/blackfin/include/asm/cmpxchg.h:130:71: note: in definition of macro 'xchg' #define xchg(ptr, x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr)))) ^~~ >> net/ipv4/cipso_ipv4.c:1954:22: error: 'struct inet_request_sock' has no member named 'opt' opt = xchg(&req_inet->opt, opt); ^ arch/blackfin/include/asm/cmpxchg.h:130:86: note: in definition of macro 'xchg' #define xchg(ptr, x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr)))) ^~~ net/ipv4/cipso_ipv4.c: In function 'cipso_v4_req_delattr': net/ipv4/cipso_ipv4.c:2073:16: error: 'struct inet_request_sock' has no member named 'opt' opt = req_inet->opt; ^~ net/ipv4/cipso_ipv4.c:2077:27: error: 'struct inet_request_sock' has no member named 'opt' cipso_v4_delopt(&req_inet->opt); ^~ vim +1954 net/ipv4/cipso_ipv4.c 446fda4f2 Paul Moore 2006-08-03 1898 446fda4f2 Paul Moore 2006-08-03 1899 /** 389fb800a Paul Moore 2009-03-27 1900 * cipso_v4_req_setattr - Add a CIPSO option to a connection request socket 389fb800a Paul Moore 2009-03-27 1901 * @req: the connection request socket 389fb800a Paul Moore 2009-03-27 1902 * @doi_def: the CIPSO DOI to use 389fb800a Paul Moore 2009-03-27 1903 * @secattr: the specific security attributes of the socket 014ab19a6 Paul Moore 2008-10-10 1904 * 014ab19a6 Paul Moore 2008-10-10 1905 * Description: 389fb800a Paul Moore 2009-03-27 1906 * Set the CIPSO option on the given socket using the DOI definition and 389fb800a Paul Moore 2009-03-27 1907 * security attributes passed to the function. Returns zero on success and 389fb800a Paul Moore 2009-03-27 1908 * negative values on failure. 014ab19a6 Paul Moore 2008-10-10 1909 * 014ab19a6 Paul Moore 2008-10-10 1910 */ 389fb800a Paul Moore 2009-03-27 1911 int cipso_v4_req_setattr(struct request_sock *req, 389fb800a Paul Moore 2009-03-27 1912 const struct cipso_v4_doi *doi_def, 389fb800a Paul Moore 2009-03-27 1913 const struct netlbl_lsm_secattr *secattr) 014ab19a6 Paul Moore 2008-10-10 1914 { 389fb800a Paul Moore 2009-03-27 1915 int ret_val = -EPERM; 389fb800a Paul Moore 2009-03-27 1916 unsigned char *buf = NULL; 389fb800a Paul Moore 2009-03-27 1917 u32 buf_len; 389fb800a Paul Moore 2009-03-27 1918 u32 opt_len; f6d8bd051 Eric Dumazet 2011-04-21 1919 struct ip_options_rcu *opt = NULL; 389fb800a Paul Moore 2009-03-27 1920 struct inet_request_sock *req_inet; 014ab19a6 Paul Moore 2008-10-10 1921 389fb800a Paul Moore 2009-03-27 1922 /* We allocate the maximum CIPSO option size here so we are probably 389fb800a Paul Moore 2009-03-27 1923 * being a little wasteful, but it makes our life _much_ easier later 389fb800a Paul Moore 2009-03-27 1924 * on and after all we are only talking about 40 bytes. */ 389fb800a Paul Moore 2009-03-27 1925 buf_len = CIPSO_V4_OPT_LEN_MAX; 389fb800a Paul Moore 2009-03-27 1926 buf = kmalloc(buf_len, GFP_ATOMIC); 51456b291 Ian Morris 2015-04-03 1927 if (!buf) { 389fb800a Paul Moore 2009-03-27 1928 ret_val = -ENOMEM; 389fb800a Paul Moore 2009-03-27 1929 goto req_setattr_failure; 389fb800a Paul Moore 2009-03-27 1930 } 389fb800a Paul Moore 2009-03-27 1931 389fb800a Paul Moore 2009-03-27 1932 ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr); 389fb800a Paul Moore 2009-03-27 1933 if (ret_val < 0) 389fb800a Paul Moore 2009-03-27 1934 goto req_setattr_failure; 389fb800a Paul Moore 2009-03-27 1935 buf_len = ret_val; 389fb800a Paul Moore 2009-03-27 1936 389fb800a Paul Moore 2009-03-27 1937 /* We can't use ip_options_get() directly because it makes a call to 389fb800a Paul Moore 2009-03-27 1938 * ip_options_get_alloc() which allocates memory with GFP_KERNEL and 389fb800a Paul Moore 2009-03-27 1939 * we won't always have CAP_NET_RAW even though we _always_ want to 389fb800a Paul Moore 2009-03-27 1940 * set the IPOPT_CIPSO option. */ 389fb800a Paul Moore 2009-03-27 1941 opt_len = (buf_len + 3) & ~3; 389fb800a Paul Moore 2009-03-27 1942 opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC); 51456b291 Ian Morris 2015-04-03 1943 if (!opt) { 389fb800a Paul Moore 2009-03-27 1944 ret_val = -ENOMEM; 389fb800a Paul Moore 2009-03-27 1945 goto req_setattr_failure; 389fb800a Paul Moore 2009-03-27 1946 } f6d8bd051 Eric Dumazet 2011-04-21 1947 memcpy(opt->opt.__data, buf, buf_len); f6d8bd051 Eric Dumazet 2011-04-21 1948 opt->opt.optlen = opt_len; f6d8bd051 Eric Dumazet 2011-04-21 1949 opt->opt.cipso = sizeof(struct iphdr); 389fb800a Paul Moore 2009-03-27 1950 kfree(buf); 389fb800a Paul Moore 2009-03-27 1951 buf = NULL; 389fb800a Paul Moore 2009-03-27 1952 389fb800a Paul Moore 2009-03-27 1953 req_inet = inet_rsk(req); 389fb800a Paul Moore 2009-03-27 @1954 opt = xchg(&req_inet->opt, opt); f6d8bd051 Eric Dumazet 2011-04-21 1955 if (opt) 4f9c8c1b0 Paul E. McKenney 2012-01-06 1956 kfree_rcu(opt, rcu); 389fb800a Paul Moore 2009-03-27 1957 389fb800a Paul Moore 2009-03-27 1958 return 0; 389fb800a Paul Moore 2009-03-27 1959 389fb800a Paul Moore 2009-03-27 1960 req_setattr_failure: 389fb800a Paul Moore 2009-03-27 1961 kfree(buf); 389fb800a Paul Moore 2009-03-27 1962 kfree(opt); 389fb800a Paul Moore 2009-03-27 1963 return ret_val; 389fb800a Paul Moore 2009-03-27 1964 } 389fb800a Paul Moore 2009-03-27 1965 :::::: The code at line 1954 was first introduced by commit :::::: 389fb800ac8be2832efedd19978a2b8ced37eb61 netlabel: Label incoming TCP connections correctly in SELinux :::::: TO: Paul Moore <paul.moore@hp.com> :::::: CC: James Morris <jmorris@namei.org> --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
On Sat, 2017-10-21 at 00:53 +0800, kbuild test robot wrote: > Hi Eric, > > [auto build test WARNING on net/master] > > url: https://github.com/0day-ci/linux/commits/Eric-Dumazet/dccp-tcp-fix-ireq-opt-races/20171021-001234 > config: ia64-allmodconfig (attached as .config) > compiler: ia64-linux-gcc (GCC) 6.2.0 > reproduce: > wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross > chmod +x ~/bin/make.cross > # save the attached .config to linux build tree > make.cross ARCH=ia64 Thanks, v4 of the patch should fix this. https://patchwork.ozlabs.org/patch/828713/
Hi Eric, [auto build test WARNING on net/master] url: https://github.com/0day-ci/linux/commits/Eric-Dumazet/dccp-tcp-fix-ireq-opt-races/20171021-001234 reproduce: # apt-get install sparse make ARCH=x86_64 allmodconfig make C=1 CF=-D__CHECK_ENDIAN__ sparse warnings: (new ones prefixed by >>) vim +1954 net/ipv4/cipso_ipv4.c 446fda4f2 Paul Moore 2006-08-03 1898 446fda4f2 Paul Moore 2006-08-03 1899 /** 389fb800a Paul Moore 2009-03-27 1900 * cipso_v4_req_setattr - Add a CIPSO option to a connection request socket 389fb800a Paul Moore 2009-03-27 1901 * @req: the connection request socket 389fb800a Paul Moore 2009-03-27 1902 * @doi_def: the CIPSO DOI to use 389fb800a Paul Moore 2009-03-27 1903 * @secattr: the specific security attributes of the socket 014ab19a6 Paul Moore 2008-10-10 1904 * 014ab19a6 Paul Moore 2008-10-10 1905 * Description: 389fb800a Paul Moore 2009-03-27 1906 * Set the CIPSO option on the given socket using the DOI definition and 389fb800a Paul Moore 2009-03-27 1907 * security attributes passed to the function. Returns zero on success and 389fb800a Paul Moore 2009-03-27 1908 * negative values on failure. 014ab19a6 Paul Moore 2008-10-10 1909 * 014ab19a6 Paul Moore 2008-10-10 1910 */ 389fb800a Paul Moore 2009-03-27 1911 int cipso_v4_req_setattr(struct request_sock *req, 389fb800a Paul Moore 2009-03-27 1912 const struct cipso_v4_doi *doi_def, 389fb800a Paul Moore 2009-03-27 1913 const struct netlbl_lsm_secattr *secattr) 014ab19a6 Paul Moore 2008-10-10 1914 { 389fb800a Paul Moore 2009-03-27 1915 int ret_val = -EPERM; 389fb800a Paul Moore 2009-03-27 1916 unsigned char *buf = NULL; 389fb800a Paul Moore 2009-03-27 1917 u32 buf_len; 389fb800a Paul Moore 2009-03-27 1918 u32 opt_len; f6d8bd051 Eric Dumazet 2011-04-21 1919 struct ip_options_rcu *opt = NULL; 389fb800a Paul Moore 2009-03-27 1920 struct inet_request_sock *req_inet; 014ab19a6 Paul Moore 2008-10-10 1921 389fb800a Paul Moore 2009-03-27 1922 /* We allocate the maximum CIPSO option size here so we are probably 389fb800a Paul Moore 2009-03-27 1923 * being a little wasteful, but it makes our life _much_ easier later 389fb800a Paul Moore 2009-03-27 1924 * on and after all we are only talking about 40 bytes. */ 389fb800a Paul Moore 2009-03-27 1925 buf_len = CIPSO_V4_OPT_LEN_MAX; 389fb800a Paul Moore 2009-03-27 1926 buf = kmalloc(buf_len, GFP_ATOMIC); 51456b291 Ian Morris 2015-04-03 1927 if (!buf) { 389fb800a Paul Moore 2009-03-27 1928 ret_val = -ENOMEM; 389fb800a Paul Moore 2009-03-27 1929 goto req_setattr_failure; 389fb800a Paul Moore 2009-03-27 1930 } 389fb800a Paul Moore 2009-03-27 1931 389fb800a Paul Moore 2009-03-27 1932 ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr); 389fb800a Paul Moore 2009-03-27 1933 if (ret_val < 0) 389fb800a Paul Moore 2009-03-27 1934 goto req_setattr_failure; 389fb800a Paul Moore 2009-03-27 1935 buf_len = ret_val; 389fb800a Paul Moore 2009-03-27 1936 389fb800a Paul Moore 2009-03-27 1937 /* We can't use ip_options_get() directly because it makes a call to 389fb800a Paul Moore 2009-03-27 1938 * ip_options_get_alloc() which allocates memory with GFP_KERNEL and 389fb800a Paul Moore 2009-03-27 1939 * we won't always have CAP_NET_RAW even though we _always_ want to 389fb800a Paul Moore 2009-03-27 1940 * set the IPOPT_CIPSO option. */ 389fb800a Paul Moore 2009-03-27 1941 opt_len = (buf_len + 3) & ~3; 389fb800a Paul Moore 2009-03-27 1942 opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC); 51456b291 Ian Morris 2015-04-03 1943 if (!opt) { 389fb800a Paul Moore 2009-03-27 1944 ret_val = -ENOMEM; 389fb800a Paul Moore 2009-03-27 1945 goto req_setattr_failure; 389fb800a Paul Moore 2009-03-27 1946 } f6d8bd051 Eric Dumazet 2011-04-21 1947 memcpy(opt->opt.__data, buf, buf_len); f6d8bd051 Eric Dumazet 2011-04-21 1948 opt->opt.optlen = opt_len; f6d8bd051 Eric Dumazet 2011-04-21 1949 opt->opt.cipso = sizeof(struct iphdr); 389fb800a Paul Moore 2009-03-27 1950 kfree(buf); 389fb800a Paul Moore 2009-03-27 1951 buf = NULL; 389fb800a Paul Moore 2009-03-27 1952 389fb800a Paul Moore 2009-03-27 1953 req_inet = inet_rsk(req); 389fb800a Paul Moore 2009-03-27 @1954 opt = xchg(&req_inet->opt, opt); f6d8bd051 Eric Dumazet 2011-04-21 1955 if (opt) 4f9c8c1b0 Paul E. McKenney 2012-01-06 1956 kfree_rcu(opt, rcu); 389fb800a Paul Moore 2009-03-27 1957 389fb800a Paul Moore 2009-03-27 1958 return 0; 389fb800a Paul Moore 2009-03-27 1959 389fb800a Paul Moore 2009-03-27 1960 req_setattr_failure: 389fb800a Paul Moore 2009-03-27 1961 kfree(buf); 389fb800a Paul Moore 2009-03-27 1962 kfree(opt); 389fb800a Paul Moore 2009-03-27 1963 return ret_val; 389fb800a Paul Moore 2009-03-27 1964 } 389fb800a Paul Moore 2009-03-27 1965 :::::: The code at line 1954 was first introduced by commit :::::: 389fb800ac8be2832efedd19978a2b8ced37eb61 netlabel: Label incoming TCP connections correctly in SELinux :::::: TO: Paul Moore <paul.moore@hp.com> :::::: CC: James Morris <jmorris@namei.org> --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
================================================================== Fixes: e994b2f0fb92 ("tcp: do not lock listener to process SYN packets") Fixes: 079096f103fa ("tcp/dccp: install syn_recv requests into ehash table") Signed-off-by: Eric Dumazet <edumazet@google.com> --- include/net/inet_sock.h | 2 +- net/dccp/ipv4.c | 13 ++++++++----- net/ipv4/inet_connection_sock.c | 8 +++----- net/ipv4/syncookies.c | 2 +- net/ipv4/tcp_input.c | 2 +- net/ipv4/tcp_ipv4.c | 22 +++++++++++++--------- 6 files changed, 27 insertions(+), 22 deletions(-) diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index aa95053dfc78d35d04aef276e2a5dce7343f72a0..425752f768d2f1a0efb13964204e07f27609e9db 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -96,7 +96,7 @@ struct inet_request_sock { kmemcheck_bitfield_end(flags); u32 ir_mark; union { - struct ip_options_rcu *opt; + struct ip_options_rcu __rcu *ireq_opt; #if IS_ENABLED(CONFIG_IPV6) struct { struct ipv6_txoptions *ipv6_opt; diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 001c08696334bba0ceb896c116e595b814af0667..0490916864f93d5466e87f5b97dc524b3ee57a2e 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -414,8 +414,7 @@ struct sock *dccp_v4_request_recv_sock(const struct sock *sk, sk_daddr_set(newsk, ireq->ir_rmt_addr); sk_rcv_saddr_set(newsk, ireq->ir_loc_addr); newinet->inet_saddr = ireq->ir_loc_addr; - newinet->inet_opt = ireq->opt; - ireq->opt = NULL; + RCU_INIT_POINTER(newinet->inet_opt, rcu_dereference(ireq->ireq_opt)); newinet->mc_index = inet_iif(skb); newinet->mc_ttl = ip_hdr(skb)->ttl; newinet->inet_id = jiffies; @@ -430,7 +429,10 @@ struct sock *dccp_v4_request_recv_sock(const struct sock *sk, if (__inet_inherit_port(sk, newsk) < 0) goto put_and_exit; *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash)); - + if (*own_req) + ireq->ireq_opt = NULL; + else + newinet->inet_opt = NULL; return newsk; exit_overflow: @@ -441,6 +443,7 @@ struct sock *dccp_v4_request_recv_sock(const struct sock *sk, __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENDROPS); return NULL; put_and_exit: + newinet->inet_opt = NULL; inet_csk_prepare_forced_close(newsk); dccp_done(newsk); goto exit; @@ -492,7 +495,7 @@ static int dccp_v4_send_response(const struct sock *sk, struct request_sock *req ireq->ir_rmt_addr); err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr, ireq->ir_rmt_addr, - ireq->opt); + rcu_dereference(ireq->ireq_opt)); err = net_xmit_eval(err); } @@ -548,7 +551,7 @@ static void dccp_v4_ctl_send_reset(const struct sock *sk, struct sk_buff *rxskb) static void dccp_v4_reqsk_destructor(struct request_sock *req) { dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg); - kfree(inet_rsk(req)->opt); + kfree(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1)); } void dccp_syn_ack_timeout(const struct request_sock *req) diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 67aec7a106860b26c929fea1624d652c87972f04..5ec9136a7c36933cb36e5cd50058eb6cf189a7c3 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -540,9 +540,10 @@ struct dst_entry *inet_csk_route_req(const struct sock *sk, { const struct inet_request_sock *ireq = inet_rsk(req); struct net *net = read_pnet(&ireq->ireq_net); - struct ip_options_rcu *opt = ireq->opt; + struct ip_options_rcu *opt; struct rtable *rt; + opt = rcu_dereference(ireq->ireq_opt); flowi4_init_output(fl4, ireq->ir_iif, ireq->ir_mark, RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, sk->sk_protocol, inet_sk_flowi_flags(sk), @@ -576,10 +577,9 @@ struct dst_entry *inet_csk_route_child_sock(const struct sock *sk, struct flowi4 *fl4; struct rtable *rt; + opt = rcu_dereference(ireq->ireq_opt); fl4 = &newinet->cork.fl.u.ip4; - rcu_read_lock(); - opt = rcu_dereference(newinet->inet_opt); flowi4_init_output(fl4, ireq->ir_iif, ireq->ir_mark, RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, sk->sk_protocol, inet_sk_flowi_flags(sk), @@ -592,13 +592,11 @@ struct dst_entry *inet_csk_route_child_sock(const struct sock *sk, goto no_route; if (opt && opt->opt.is_strictroute && rt->rt_uses_gateway) goto route_err; - rcu_read_unlock(); return &rt->dst; route_err: ip_rt_put(rt); no_route: - rcu_read_unlock(); __IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); return NULL; } diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index b1bb1b3a108232d56aa82383422d68b5ff9da3ed..77cf32a80952fcf3ceff4ada946cc2d0df2411d9 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -355,7 +355,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) /* We throwed the options of the initial SYN away, so we hope * the ACK carries the same options again (see RFC1122 4.2.3.8) */ - ireq->opt = tcp_v4_save_options(sock_net(sk), skb); + RCU_INIT_POINTER(ireq->ireq_opt, tcp_v4_save_options(sock_net(sk), skb)); if (security_inet_conn_request(sk, skb, req)) { reqsk_free(req); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index c5d7656beeee29b3c92e1c8824dbf00d3fa32d28..7eec3383702bbab497a12095b55d255532ad5f60 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -6196,7 +6196,7 @@ struct request_sock *inet_reqsk_alloc(const struct request_sock_ops *ops, struct inet_request_sock *ireq = inet_rsk(req); kmemcheck_annotate_bitfield(ireq, flags); - ireq->opt = NULL; + ireq->ireq_opt = NULL; #if IS_ENABLED(CONFIG_IPV6) ireq->pktopts = NULL; #endif diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 85164d4d3e537537c87d74c00172592c860d4dfb..4c43365c374c8bf868fc0b862333244ca26d5016 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -877,7 +877,7 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr, ireq->ir_rmt_addr, - ireq->opt); + rcu_dereference(ireq->ireq_opt)); err = net_xmit_eval(err); } @@ -889,7 +889,7 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, */ static void tcp_v4_reqsk_destructor(struct request_sock *req) { - kfree(inet_rsk(req)->opt); + kfree(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1)); } #ifdef CONFIG_TCP_MD5SIG @@ -1265,10 +1265,11 @@ static void tcp_v4_init_req(struct request_sock *req, struct sk_buff *skb) { struct inet_request_sock *ireq = inet_rsk(req); + struct net *net = sock_net(sk_listener); sk_rcv_saddr_set(req_to_sk(req), ip_hdr(skb)->daddr); sk_daddr_set(req_to_sk(req), ip_hdr(skb)->saddr); - ireq->opt = tcp_v4_save_options(sock_net(sk_listener), skb); + RCU_INIT_POINTER(ireq->ireq_opt, tcp_v4_save_options(net, skb)); } static struct dst_entry *tcp_v4_route_req(const struct sock *sk, @@ -1355,10 +1356,9 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, sk_daddr_set(newsk, ireq->ir_rmt_addr); sk_rcv_saddr_set(newsk, ireq->ir_loc_addr); newsk->sk_bound_dev_if = ireq->ir_iif; - newinet->inet_saddr = ireq->ir_loc_addr; - inet_opt = ireq->opt; - rcu_assign_pointer(newinet->inet_opt, inet_opt); - ireq->opt = NULL; + newinet->inet_saddr = ireq->ir_loc_addr; + inet_opt = rcu_dereference(ireq->ireq_opt); + RCU_INIT_POINTER(newinet->inet_opt, inet_opt); newinet->mc_index = inet_iif(skb); newinet->mc_ttl = ip_hdr(skb)->ttl; newinet->rcv_tos = ip_hdr(skb)->tos; @@ -1403,9 +1403,12 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, if (__inet_inherit_port(sk, newsk) < 0) goto put_and_exit; *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash)); - if (*own_req) + if (likely(*own_req)) { tcp_move_syn(newtp, req); - + ireq->ireq_opt = NULL; + } else { + newinet->inet_opt = NULL; + } return newsk; exit_overflow: @@ -1416,6 +1419,7 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, tcp_listendrop(sk); return NULL; put_and_exit: + newinet->inet_opt = NULL; inet_csk_prepare_forced_close(newsk); tcp_done(newsk); goto exit;