예제 #1
0
파일: clear.go 프로젝트: contester/runlib
func (s *Contester) Clear(request *contester_proto.ClearSandboxRequest, response *contester_proto.EmptyMessage) error {
	ec := tools.ErrorContext("Clear")
	sandbox, err := getSandboxById(s.Sandboxes, request.GetSandbox())
	if err != nil {
		return ec.NewError(err, "getSandboxById")
	}

	sandbox.Mutex.Lock()
	defer sandbox.Mutex.Unlock()

	repeat := true

	for retries := 10; retries > 0 && repeat; retries-- {
		repeat, err = tryClearPath(sandbox.Path)
		if repeat && err != nil {
			log.Error(err)
			time.Sleep(time.Second / 2)
		}
	}

	if err != nil {
		return ec.NewError(err, "tryClearPath")
	}
	return nil
}
예제 #2
0
// Login and load user profile. Also, set finalizer on s to logout() above.
func (s *LoginInfo) Prepare() error {
	var err error
	if s.Username == "" {
		return nil
	}

	ec := tools.ErrorContext("LoginInfo.Prepare")

	s.HUser, err = win32.LogonUser(
		syscall.StringToUTF16Ptr(s.Username),
		syscall.StringToUTF16Ptr("."),
		syscall.StringToUTF16Ptr(s.Password),
		win32.LOGON32_LOGON_INTERACTIVE,
		win32.LOGON32_PROVIDER_DEFAULT)

	if err != nil {
		return ec.NewError(err)
	}

	s.HProfile, err = loadProfile(s.HUser, s.Username)

	if err != nil {
		syscall.CloseHandle(s.HUser)
		s.HUser = syscall.InvalidHandle
		return ec.NewError(err)
	}

	runtime.SetFinalizer(s, logout)
	return nil
}
예제 #3
0
func (sub *Subprocess) CreateFrozen() (*SubprocessData, error) {
	ec := tools.ErrorContext("CreateFrozen")

	if sub.Cmd.ApplicationName == nil {
		return nil, ec.NewError(fmt.Errorf("Application name must be present"), "init")
	}
	d := &SubprocessData{}
	var stdh linux.StdHandles
	err := d.wAllRedirects(sub, &stdh)
	defer stdh.Close()
	if err != nil {
		return nil, ec.NewError(err, "Redirects")
	}
	var uid int
	if sub.Login != nil {
		uid = sub.Login.Uid
	}
	d.platformData.params, err = linux.CreateCloneParams(
		*sub.Cmd.ApplicationName, sub.Cmd.Parameters, sub.Environment, sub.CurrentDirectory, uid, stdh)
	if err != nil {
		return nil, ec.NewError(err, "CreateCloneParams")
	}
	syscall.ForkLock.Lock()
	d.platformData.Pid, err = d.platformData.params.CloneFrozen()
	closeDescriptors(d.closeAfterStart)
	syscall.ForkLock.Unlock()
	if err != nil {
		return nil, ec.NewError(err, "CloneFrozen")
	}
	err = SetupControlGroup(sub, d)
	if err != nil {
		return nil, ec.NewError(err, "SetupControlGroup")
	}
	return d, nil
}
예제 #4
0
func Interconnect(s1, s2 *Subprocess, d1, d2 *os.File) error {
	ec := tools.ErrorContext("Interconnect")

	read1, write1, err := RecordingPipe(d1)
	if err != nil {
		return ec.NewError(err, "RecordingPipe")
	}

	read2, write2, err := RecordingPipe(d2)
	if err != nil {
		read1.Close()
		write1.Close()
		return ec.NewError(err, "RecordingPipe")
	}

	s1.StdIn = &Redirect{
		Mode: REDIRECT_PIPE,
		Pipe: read1,
	}
	s2.StdOut = &Redirect{
		Mode: REDIRECT_PIPE,
		Pipe: write1,
	}
	s1.StdOut = &Redirect{
		Mode: REDIRECT_PIPE,
		Pipe: write2,
	}
	s2.StdIn = &Redirect{
		Mode: REDIRECT_PIPE,
		Pipe: read2,
	}
	return nil
}
예제 #5
0
func CreateJob(s *Subprocess, d *SubprocessData) error {
	var e error
	ec := tools.ErrorContext("CreateJob")
	d.platformData.hJob, e = win32.CreateJobObject(nil, nil)
	if e != nil {
		return ec.NewError(e, "CreateJobObject")
	}

	if s.RestrictUi {
		var info win32.JobObjectBasicUiRestrictions
		info.UIRestrictionClass = (win32.JOB_OBJECT_UILIMIT_DESKTOP |
			win32.JOB_OBJECT_UILIMIT_DISPLAYSETTINGS |
			win32.JOB_OBJECT_UILIMIT_EXITWINDOWS |
			win32.JOB_OBJECT_UILIMIT_GLOBALATOMS |
			win32.JOB_OBJECT_UILIMIT_HANDLES |
			win32.JOB_OBJECT_UILIMIT_READCLIPBOARD |
			win32.JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS |
			win32.JOB_OBJECT_UILIMIT_WRITECLIPBOARD)

		e = win32.SetJobObjectBasicUiRestrictions(d.platformData.hJob, &info)
		if e != nil {
			return ec.NewError(e, "SetJobObjectBasicUiRestrictions")
		}
	}

	var einfo win32.JobObjectExtendedLimitInformation
	einfo.BasicLimitInformation.LimitFlags = win32.JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION | win32.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE

	if s.HardTimeLimit > 0 {
		einfo.BasicLimitInformation.PerJobUserTimeLimit = uint64(s.HardTimeLimit.Nanoseconds() / 100)
		einfo.BasicLimitInformation.PerProcessUserTimeLimit = uint64(s.HardTimeLimit.Nanoseconds() / 100)
		einfo.BasicLimitInformation.LimitFlags |= win32.JOB_OBJECT_LIMIT_PROCESS_TIME | win32.JOB_OBJECT_LIMIT_JOB_TIME
	}

	if s.ProcessLimit > 0 {
		einfo.BasicLimitInformation.ActiveProcessLimit = s.ProcessLimit
		einfo.BasicLimitInformation.LimitFlags |= win32.JOB_OBJECT_LIMIT_ACTIVE_PROCESS
	}

	if s.HardMemoryLimit > 0 {
		einfo.ProcessMemoryLimit = uintptr(s.HardMemoryLimit)
		einfo.JobMemoryLimit = uintptr(s.HardMemoryLimit)
		einfo.BasicLimitInformation.MaximumWorkingSetSize = uintptr(s.HardMemoryLimit)
		einfo.BasicLimitInformation.LimitFlags |= win32.JOB_OBJECT_LIMIT_JOB_MEMORY | win32.JOB_OBJECT_LIMIT_PROCESS_MEMORY | win32.JOB_OBJECT_LIMIT_WORKINGSET
	}

	// If we don't create job then we need to set process affinity on the process handle after its creation.
	// if s.ProcessAffinityMask != 0 {
	//	einfo.BasicLimitInformation.Affinity = uintptr(s.ProcessAffinityMask)
	//	einfo.BasicLimitInformation.LimitFlags |= win32.JOB_OBJECT_LIMIT_AFFINITY
	//}

	e = win32.SetJobObjectExtendedLimitInformation(d.platformData.hJob, &einfo)
	if e != nil {
		return ec.NewError(e, "SetJobObjectExtendedLimitInformation")
	}
	return nil
}
예제 #6
0
func NewLoginInfo(username, password string) (*LoginInfo, error) {
	ec := tools.ErrorContext("NewLoginInfo")
	u, err := user.Lookup(username)
	if err != nil {
		return nil, ec.NewError(err, "user.Lookup")
	}
	uid, err := strconv.Atoi(u.Uid)
	if err != nil {
		return nil, ec.NewError(err, "strconv.Atoi")
	}
	return &LoginInfo{
		Uid: uid,
	}, nil
}
예제 #7
0
func filerUpload(localName, remoteName, checksum, moduleType, authToken string) (stat *contester_proto.FileStat, err error) {
	ec := tools.ErrorContext("upload")
	if stat, err = tools.StatFile(localName, true); err != nil || stat == nil {
		return stat, err
	}
	if checksum != "" && stat.GetChecksum() != checksum {
		return nil, fmt.Errorf("Checksum mismatch, local %s != %s", stat.GetChecksum(), checksum)
	}
	checksum = stat.GetChecksum()

	local, err := os.Open(localName)
	if err != nil {
		return nil, ec.NewError(err, "local.Open")
	}
	defer local.Close()

	req, err := http.NewRequest("PUT", remoteName, local)
	if err != nil {
		return nil, err
	}
	if moduleType != "" {
		req.Header.Add("X-FS-Module-Type", moduleType)
	}
	if authToken != "" {
		req.Header.Add("Authorization", "bearer "+authToken)
	}
	req.Header.Add("X-FS-Content-Length", strconv.FormatUint(stat.GetSize_(), 10))
	var base64sha1 string
	if checksum != "" && strings.HasPrefix(checksum, "sha1:") {
		if data, err := hex.DecodeString(strings.TrimPrefix(checksum, "sha1:")); err == nil {
			base64sha1 = base64.StdEncoding.EncodeToString(data)
			req.Header.Add("Digest", "SHA="+base64sha1)
		}
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var st uploadStatus
	err = json.NewDecoder(resp.Body).Decode(&st)
	if err != nil {
		return nil, err
	}
	if st.Size != int64(stat.GetSize_()) || (base64sha1 != "" && base64sha1 != st.Digests["SHA"]) {
		return nil, fmt.Errorf("upload integrity verification failed")
	}
	return stat, nil
}
예제 #8
0
파일: putget.go 프로젝트: petemoore/runlib
func (s *Contester) Put(request *contester_proto.FileBlob, response *contester_proto.FileStat) error {
	ec := tools.ErrorContext("Put")

	resolved, sandbox, err := resolvePath(s.Sandboxes, *request.Name, true)
	if err != nil {
		return ec.NewError(err, "resolvePath")
	}

	if sandbox != nil {
		sandbox.Mutex.Lock()
		defer sandbox.Mutex.Unlock()
	}

	var destination *os.File

	for {
		destination, err = os.Create(resolved)
		loop, err := OnOsCreateError(err)

		if err != nil {
			return ec.NewError(err, "os.Create")
		}
		if !loop {
			break
		}
	}
	data, err := request.Data.Bytes()
	if err != nil {
		return ec.NewError(err, "request.Data.Bytes")
	}
	_, err = destination.Write(data)
	if err != nil {
		return ec.NewError(err, "destination.Write")
	}
	destination.Close()
	if sandbox != nil {
		return sandbox.Own(resolved)
	}

	stat, err := tools.StatFile(resolved, true)
	if err != nil {
		return ec.NewError(err, "statFile")
	}

	*response = *stat
	return nil
}
예제 #9
0
// Loads user profile, using handle and username.
func loadProfile(user syscall.Handle, username string) (syscall.Handle, error) {
	ec := tools.ErrorContext("loadProfile")
	var pinfo win32.ProfileInfo
	var err error
	pinfo.Size = uint32(unsafe.Sizeof(pinfo))
	pinfo.Flags = win32.PI_NOUI
	pinfo.Username, err = syscall.UTF16PtrFromString(username)
	if err != nil {
		return syscall.InvalidHandle, ec.NewError(err, ERR_USER, "UTF16PtrFromString")
	}

	err = win32.LoadUserProfile(user, &pinfo)
	if err != nil {
		log.Debug("Error loading profile for %d/%s", user, username)
		return syscall.InvalidHandle, ec.NewError(err, "LoadUserProfile")
	}
	return pinfo.Profile, nil
}
예제 #10
0
파일: fileops.go 프로젝트: petemoore/runlib
func (s *Contester) Stat(request *contester_proto.StatRequest, response *contester_proto.FileStats) error {
	ec := tools.ErrorContext("Stat")
	if request.SandboxId != nil {
		sandbox, err := getSandboxById(s.Sandboxes, *request.SandboxId)
		if err != nil {
			return ec.NewError(err, "getSandboxById")
		}
		sandbox.Mutex.RLock()
		defer sandbox.Mutex.RUnlock()
	}

	response.Entries = make([]*contester_proto.FileStat, 0, len(request.Name))
	for _, name := range request.Name {
		resolved, _, err := resolvePath(s.Sandboxes, name, false)
		if err != nil {
			return ec.NewError(err, "resolvePath")
		}
		var expanded []string
		if request.GetExpand() {
			expanded, err = filepath.Glob(resolved)
			if err != nil {
				return ec.NewError(err, "filepath.Glob")
			}
		} else {
			expanded = []string{resolved}
		}

		for _, name := range expanded {
			stat, err := tools.StatFile(name, request.GetCalculateChecksum())
			if err != nil {
				return ec.NewError(err, "statFile")
			}
			if stat != nil {
				response.Entries = append(response.Entries, stat)
			}
		}

	}
	return nil
}
예제 #11
0
파일: putget.go 프로젝트: petemoore/runlib
func (s *Contester) Get(request *contester_proto.GetRequest, response *contester_proto.FileBlob) error {
	ec := tools.ErrorContext("Get")
	resolved, sandbox, err := resolvePath(s.Sandboxes, *request.Name, false)
	if err != nil {
		return ec.NewError(err, "resolvePath")
	}

	if sandbox != nil {
		sandbox.Mutex.RLock()
		defer sandbox.Mutex.RUnlock()
	}

	source, err := os.Open(resolved)
	if err != nil {
		return ec.NewError(err, "os.Open")
	}
	defer source.Close()

	response.Name = &resolved
	response.Data, err = contester_proto.BlobFromStream(source)
	return err
}
예제 #12
0
func InjectDll(d *SubprocessData, loadLibraryW uintptr, dll string) error {
	if int(loadLibraryW) == 0 {
		return nil
	}

	ec := tools.ErrorContext("InjectDll")

	log.Debug("InjectDll: Injecting library %s with call to %d", dll, loadLibraryW)
	name, err := syscall.UTF16FromString(dll)
	if err != nil {
		return ec.NewError(err, ERR_USER, "UTF16FromString")
	}
	nameLen := uint32((len(name) + 1) * 2)
	remoteName, err := win32.VirtualAllocEx(d.platformData.hProcess, 0, nameLen, win32.MEM_COMMIT, win32.PAGE_READWRITE)
	if err != nil {
		return ec.NewError(err)
	}
	defer win32.VirtualFreeEx(d.platformData.hProcess, remoteName, 0, win32.MEM_RELEASE)

	_, err = win32.WriteProcessMemory(d.platformData.hProcess, remoteName, unsafe.Pointer(&name[0]), nameLen)
	if err != nil {
		return ec.NewError(err)
	}
	thread, _, err := win32.CreateRemoteThread(d.platformData.hProcess, win32.MakeInheritSa(), 0, loadLibraryW, remoteName, 0)
	if err != nil {
		return ec.NewError(err)
	}
	defer syscall.CloseHandle(thread)
	wr, err := syscall.WaitForSingleObject(thread, syscall.INFINITE)
	if err != nil {
		return ec.NewError(os.NewSyscallError("WaitForSingleObject", err))
	}
	if wr != syscall.WAIT_OBJECT_0 {
		return ec.NewError(fmt.Errorf("Unexpected wait result %s", wr))
	}

	return nil
}
예제 #13
0
파일: clear.go 프로젝트: contester/runlib
func tryClearPath(path string) (bool, error) {
	ec := tools.ErrorContext("tryClearPath")
	files, err := ioutil.ReadDir(path)
	if err != nil {
		return false, ec.NewError(err, "ioutil.ReadDir")
	}

	if len(files) == 0 {
		return false, nil
	}

	for _, info := range files {
		if info.Name() == "." || info.Name() == ".." {
			continue
		}
		fullpath := filepath.Join(path, info.Name())
		err = os.RemoveAll(fullpath)
		if err != nil {
			return true, ec.NewError(err, "os.RemoveAll")
		}
	}
	return true, nil
}
예제 #14
0
func (sub *Subprocess) CreateFrozen() (*SubprocessData, error) {
	d := &SubprocessData{}

	si := &syscall.StartupInfo{}
	si.Cb = uint32(unsafe.Sizeof(*si))
	si.Flags = win32.STARTF_FORCEOFFFEEDBACK | syscall.STARTF_USESHOWWINDOW
	si.ShowWindow = syscall.SW_SHOWMINNOACTIVE

	useCreateProcessWithLogonW := sub.NoJob || win32.IsWindows8OrGreater()

	if !useCreateProcessWithLogonW && sub.Options != nil && sub.Options.Desktop != "" {
		si.Desktop = syscall.StringToUTF16Ptr(sub.Options.Desktop)
	}

	ec := tools.ErrorContext("CreateFrozen")

	e := d.wAllRedirects(sub, si)
	if e != nil {
		return nil, e
	}

	pi := &syscall.ProcessInformation{}

	applicationName := win32.StringPtrToUTF16Ptr(sub.Cmd.ApplicationName)
	commandLine := win32.StringPtrToUTF16Ptr(sub.Cmd.CommandLine)
	environment := win32.ListToEnvironmentBlock(sub.Environment)
	currentDirectory := win32.StringPtrToUTF16Ptr(sub.CurrentDirectory)

	var syscallName string

	syscall.ForkLock.Lock()
	wSetInherit(si)

	if sub.Login != nil {
		if useCreateProcessWithLogonW {
			syscallName = "CreateProcessWithLogonW"
			e = win32.CreateProcessWithLogonW(
				syscall.StringToUTF16Ptr(sub.Login.Username),
				syscall.StringToUTF16Ptr("."),
				syscall.StringToUTF16Ptr(sub.Login.Password),
				win32.LOGON_WITH_PROFILE,
				applicationName,
				commandLine,
				win32.CREATE_SUSPENDED|syscall.CREATE_UNICODE_ENVIRONMENT,
				environment,
				currentDirectory,
				si,
				pi)
		} else {
			syscallName = "CreateProcessAsUser"
			e = win32.CreateProcessAsUser(
				sub.Login.HUser,
				applicationName,
				commandLine,
				nil,
				nil,
				true,
				win32.CREATE_NEW_PROCESS_GROUP|win32.CREATE_NEW_CONSOLE|win32.CREATE_SUSPENDED|
					syscall.CREATE_UNICODE_ENVIRONMENT|win32.CREATE_BREAKAWAY_FROM_JOB,
				environment,
				currentDirectory,
				si,
				pi)
		}
	} else {
		syscallName = "CreateProcess"
		e = syscall.CreateProcess(
			applicationName,
			commandLine,
			nil,
			nil,
			true,
			win32.CREATE_NEW_PROCESS_GROUP|win32.CREATE_NEW_CONSOLE|win32.CREATE_SUSPENDED|
				syscall.CREATE_UNICODE_ENVIRONMENT|win32.CREATE_BREAKAWAY_FROM_JOB,
			environment,
			currentDirectory,
			si,
			pi)
	}

	closeDescriptors(d.closeAfterStart)
	syscall.ForkLock.Unlock()

	if e != nil {
		if errno, ok := e.(syscall.Errno); ok && errno == syscall.Errno(136) {
			e = tools.NewError(e, ERR_USER)
		}
		return nil, ec.NewError(e, syscallName)
	}

	d.platformData.hProcess = pi.Process
	d.platformData.hThread = pi.Thread
	d.platformData.hJob = syscall.InvalidHandle

	for _, dll := range sub.Options.InjectDLL {
		if e = InjectDll(d, sub.Options.LoadLibraryW, dll); e != nil {
			break
		}
	}

	if e != nil {
		// Terminate process/thread here.
		d.platformData.terminateAndClose()
		return nil, ec.NewError(e, "InjectDll")
	}

	if sub.ProcessAffinityMask != 0 {
		e = win32.SetProcessAffinityMask(d.platformData.hProcess, sub.ProcessAffinityMask)
		if e != nil {
			d.platformData.terminateAndClose()

			return nil, ec.NewError(e, "SetProcessAffinityMask")
		}
	}

	if !sub.NoJob {
		e = CreateJob(sub, d)
		if e != nil {
			if sub.FailOnJobCreationFailure {
				d.platformData.terminateAndClose()

				return nil, ec.NewError(e, "CreateJob")
			}
			log.Error("CreateFrozen/CreateJob: %s", e)
		} else {
			e = win32.AssignProcessToJobObject(d.platformData.hJob, d.platformData.hProcess)
			if e != nil {
				syscall.CloseHandle(d.platformData.hJob)
				d.platformData.hJob = syscall.InvalidHandle
				if sub.FailOnJobCreationFailure {
					d.platformData.terminateAndClose()

					return nil, ec.NewError(e, "AssignProcessToJobObject")
				}
				log.Error("CreateFrozen/AssignProcessToJobObject: %s", e)
			}
		}
	}

	return d, nil
}
예제 #15
0
파일: mongodb.go 프로젝트: petemoore/runlib
func (s *mongodbStorage) Copy(localName, remoteName string, toRemote bool, checksum, moduleType string) (stat *contester_proto.FileStat, err error) {
	ec := tools.ErrorContext("mongodb.Copy")

	if toRemote {
		stat, err = tools.StatFile(localName, true)
		if err != nil {
			err = ec.NewError(err, "local.CalculateChecksum")
		}
		// If file doesn't exist then stat == nil.
		if err != nil || stat == nil {
			return
		}

		if checksum != "" && *stat.Checksum != checksum {
			return nil, ec.NewError(fmt.Errorf("Checksum mismatch, local %s != %s", stat.Checksum, checksum))
		}

		checksum = *stat.Checksum
	}

	var local *os.File
	if toRemote {
		local, err = os.Open(localName)
	} else {
		local, err = os.Create(localName)
	}

	if err != nil {
		return nil, ec.NewError(err, "local.Open")
	}
	defer local.Close()

	var remote *mgo.GridFile
	if toRemote {
		// Remove all files with the same remoteName.
		if err = s.GridFS.Remove(remoteName); err != nil {
			return nil, ec.NewError(err, "remote.Remove")
		}
		remote, err = s.GridFS.Create(remoteName)
	} else {
		remote, err = s.GridFS.Open(remoteName)
	}
	if err != nil {
		return nil, ec.NewError(err, "remote.Open")
	}
	defer remote.Close()

	var source io.ReadCloser
	if toRemote {
		source = local
	} else {
		source = remote
		var meta fileMetadata
		if err = remote.GetMeta(&meta); err != nil {
			return nil, ec.NewError(err, "remote.GetMeta")
		}
		if meta.CompressionType == "ZLIB" {
			source, err = zlib.NewReader(source)
			if err != nil {
				return nil, ec.NewError(err, "zlib.NewReader")
			}
		}
	}

	var destination io.WriteCloser
	if toRemote {
		destination = zlib.NewWriter(remote)
	} else {
		destination = local
	}

	size, err := io.Copy(destination, source)
	if err != nil {
		return nil, ec.NewError(err, "io.Copy")
	}

	if toRemote {
		var meta fileMetadata
		meta.OriginalSize = uint64(size)
		meta.CompressionType = "ZLIB"
		meta.Checksum = *stat.Checksum
		meta.ModuleType = moduleType

		remote.SetMeta(meta)
	}

	if err = destination.Close(); err != nil {
		return nil, ec.NewError(err, "destination.Close")
	}

	if err = source.Close(); err != nil {
		return nil, ec.NewError(err, "source.Close")
	}

	if !toRemote {
		stat, err = tools.StatFile(localName, true)
		if err != nil {
			return nil, ec.NewError(err, "StatFile")
		}
	}

	return stat, nil
}