Author: Ben Hutchings Description: Remote DoS on Linux 2.6.32 (Closes: #629373). --- sysdeputil.c +++ sysdeputil.c @@ -25,6 +25,11 @@ #define _LARGEFILE64_SOURCE 1 #endif +#ifdef __linux__ + #include + #include +#endif + /* For INT_MAX */ #include @@ -1262,11 +1267,36 @@ vsf_set_term_if_parent_dies() #endif } +#ifdef VSF_SYSDEP_HAVE_LINUX_CLONE +/* On Linux versions <2.6.35, netns cleanup may be so slow that + * creating a netns per connection allows a remote denial-of-service. + * We therefore do not use CLONE_NEWNET on these versions. + */ +static int +vsf_sysutil_netns_cleanup_is_fast(void) +{ +#ifdef __linux__ + struct utsname utsname; + int r1, r2, r3 = 0; + return (uname(&utsname) == 0 && + sscanf(utsname.release, "%d.%d.%d", &r1, &r2, &r3) >= 2 && + ((r1 << 16) | (r2 << 8) | r3) >= ((2 << 16) | (6 << 8) | 35)); +#else + /* Assume any other kernel that has the feature don't have this problem */ + return 1; +#endif +} +#endif + int vsf_sysutil_fork_isolate_all_failok() { #ifdef VSF_SYSDEP_HAVE_LINUX_CLONE - static int cloneflags_work = 1; + static int cloneflags_work = -1; + if (cloneflags_work < 0) + { + cloneflags_work = vsf_sysutil_netns_cleanup_is_fast(); + } if (cloneflags_work) { int ret = syscall(__NR_clone, @@ -1312,7 +1342,11 @@ int vsf_sysutil_fork_newnet() { #ifdef VSF_SYSDEP_HAVE_LINUX_CLONE - static int cloneflags_work = 1; + static int cloneflags_work = -1; + if (cloneflags_work < 0) + { + cloneflags_work = vsf_sysutil_netns_cleanup_is_fast(); + } if (cloneflags_work) { int ret = syscall(__NR_clone, CLONE_NEWNET | SIGCHLD, NULL);