Home | History | Annotate | Download | only in windows
      1 // Copyright 2017 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // +build windows
      6 
      7 package windows_test
      8 
      9 import (
     10 	"fmt"
     11 	"internal/syscall/windows"
     12 	"os"
     13 	"os/exec"
     14 	"syscall"
     15 	"testing"
     16 	"unsafe"
     17 )
     18 
     19 func TestRunAtLowIntegrity(t *testing.T) {
     20 	if isWindowsXP(t) {
     21 		t.Skip("Windows XP does not support windows integrity levels")
     22 	}
     23 
     24 	if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
     25 		wil, err := getProcessIntegrityLevel()
     26 		if err != nil {
     27 			fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
     28 			os.Exit(9)
     29 			return
     30 		}
     31 		fmt.Printf("%s", wil)
     32 		os.Exit(0)
     33 		return
     34 	}
     35 
     36 	cmd := exec.Command(os.Args[0], "-test.run=TestRunAtLowIntegrity", "--")
     37 	cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
     38 
     39 	token, err := getIntegrityLevelToken(sidWilLow)
     40 	if err != nil {
     41 		t.Fatal(err)
     42 	}
     43 	defer token.Close()
     44 
     45 	cmd.SysProcAttr = &syscall.SysProcAttr{
     46 		Token: token,
     47 	}
     48 
     49 	out, err := cmd.CombinedOutput()
     50 	if err != nil {
     51 		t.Fatal(err)
     52 	}
     53 
     54 	if string(out) != sidWilLow {
     55 		t.Fatalf("Child process did not run as low integrity level: %s", string(out))
     56 	}
     57 }
     58 
     59 func isWindowsXP(t *testing.T) bool {
     60 	v, err := syscall.GetVersion()
     61 	if err != nil {
     62 		t.Fatalf("GetVersion failed: %v", err)
     63 	}
     64 	major := byte(v)
     65 	return major < 6
     66 }
     67 
     68 const (
     69 	sidWilLow = `S-1-16-4096`
     70 )
     71 
     72 func getProcessIntegrityLevel() (string, error) {
     73 	procToken, err := syscall.OpenCurrentProcessToken()
     74 	if err != nil {
     75 		return "", err
     76 	}
     77 	defer procToken.Close()
     78 
     79 	p, err := tokenGetInfo(procToken, syscall.TokenIntegrityLevel, 64)
     80 	if err != nil {
     81 		return "", err
     82 	}
     83 
     84 	tml := (*windows.TOKEN_MANDATORY_LABEL)(p)
     85 
     86 	sid := (*syscall.SID)(unsafe.Pointer(tml.Label.Sid))
     87 
     88 	return sid.String()
     89 }
     90 
     91 func tokenGetInfo(t syscall.Token, class uint32, initSize int) (unsafe.Pointer, error) {
     92 	n := uint32(initSize)
     93 	for {
     94 		b := make([]byte, n)
     95 		e := syscall.GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
     96 		if e == nil {
     97 			return unsafe.Pointer(&b[0]), nil
     98 		}
     99 		if e != syscall.ERROR_INSUFFICIENT_BUFFER {
    100 			return nil, e
    101 		}
    102 		if n <= uint32(len(b)) {
    103 			return nil, e
    104 		}
    105 	}
    106 }
    107 
    108 func getIntegrityLevelToken(wns string) (syscall.Token, error) {
    109 	var procToken, token syscall.Token
    110 
    111 	proc, err := syscall.GetCurrentProcess()
    112 	if err != nil {
    113 		return 0, err
    114 	}
    115 	defer syscall.CloseHandle(proc)
    116 
    117 	err = syscall.OpenProcessToken(proc,
    118 		syscall.TOKEN_DUPLICATE|
    119 			syscall.TOKEN_ADJUST_DEFAULT|
    120 			syscall.TOKEN_QUERY|
    121 			syscall.TOKEN_ASSIGN_PRIMARY,
    122 		&procToken)
    123 	if err != nil {
    124 		return 0, err
    125 	}
    126 	defer procToken.Close()
    127 
    128 	sid, err := syscall.StringToSid(wns)
    129 	if err != nil {
    130 		return 0, err
    131 	}
    132 
    133 	tml := &windows.TOKEN_MANDATORY_LABEL{}
    134 	tml.Label.Attributes = windows.SE_GROUP_INTEGRITY
    135 	tml.Label.Sid = sid
    136 
    137 	err = windows.DuplicateTokenEx(procToken, 0, nil, windows.SecurityImpersonation,
    138 		windows.TokenPrimary, &token)
    139 	if err != nil {
    140 		return 0, err
    141 	}
    142 
    143 	err = windows.SetTokenInformation(token,
    144 		syscall.TokenIntegrityLevel,
    145 		uintptr(unsafe.Pointer(tml)),
    146 		tml.Size())
    147 	if err != nil {
    148 		token.Close()
    149 		return 0, err
    150 	}
    151 	return token, nil
    152 }
    153