Commit a108369c authored by Alexey Borzenkov's avatar Alexey Borzenkov Committed by Russ Cox

syscall: return EINVAL when string arguments have NUL characters

Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.

R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
parent 8efb70f9
......@@ -98,9 +98,13 @@ func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) e
// checkChainSSLServerPolicy checks that the certificate chain in chainCtx is valid for
// use as a certificate chain for a SSL/TLS server.
func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) error {
servernamep, err := syscall.UTF16PtrFromString(opts.DNSName)
if err != nil {
return err
}
sslPara := &syscall.SSLExtraCertChainPolicyPara{
AuthType: syscall.AUTHTYPE_SERVER,
ServerName: syscall.StringToUTF16Ptr(opts.DNSName),
ServerName: servernamep,
}
sslPara.Size = uint32(unsafe.Sizeof(*sslPara))
......@@ -110,7 +114,7 @@ func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContex
para.Size = uint32(unsafe.Sizeof(*para))
status := syscall.CertChainPolicyStatus{}
err := syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, para, &status)
err = syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, para, &status)
if err != nil {
return err
}
......
......@@ -156,7 +156,11 @@ func (w *Watcher) wakeupReader() error {
}
func getDir(pathname string) (dir string, err error) {
attr, e := syscall.GetFileAttributes(syscall.StringToUTF16Ptr(pathname))
pathnamep, e := syscall.UTF16PtrFromString(pathname)
if e != nil {
return "", e
}
attr, e := syscall.GetFileAttributes(pathnamep)
if e != nil {
return "", os.NewSyscallError("GetFileAttributes", e)
}
......@@ -170,7 +174,11 @@ func getDir(pathname string) (dir string, err error) {
}
func getIno(path string) (ino *inode, err error) {
h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(path),
pathp, e := syscall.UTF16PtrFromString(path)
if e != nil {
return nil, e
}
h, e := syscall.CreateFile(pathp,
syscall.FILE_LIST_DIRECTORY,
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
nil, syscall.OPEN_EXISTING,
......
......@@ -11,7 +11,8 @@ import (
func initMime() {
var root syscall.Handle
if syscall.RegOpenKeyEx(syscall.HKEY_CLASSES_ROOT, syscall.StringToUTF16Ptr(`\`),
rootpathp, _ := syscall.UTF16PtrFromString(`\`)
if syscall.RegOpenKeyEx(syscall.HKEY_CLASSES_ROOT, rootpathp,
0, syscall.KEY_READ, &root) != nil {
return
}
......@@ -31,15 +32,17 @@ func initMime() {
continue
}
var h syscall.Handle
extpathp, _ := syscall.UTF16PtrFromString(`\` + ext)
if syscall.RegOpenKeyEx(
syscall.HKEY_CLASSES_ROOT, syscall.StringToUTF16Ptr(`\`+ext),
syscall.HKEY_CLASSES_ROOT, extpathp,
0, syscall.KEY_READ, &h) != nil {
continue
}
var typ uint32
n = uint32(len(buf) * 2) // api expects array of bytes, not uint16
contenttypep, _ := syscall.UTF16PtrFromString("Content Type")
if syscall.RegQueryValueEx(
h, syscall.StringToUTF16Ptr("Content Type"),
h, contenttypep,
nil, &typ, (*byte)(unsafe.Pointer(&buf[0])), &n) != nil {
syscall.RegCloseKey(h)
continue
......
......@@ -106,3 +106,27 @@ func TestIsExist(t *testing.T) {
}
}
}
func TestErrPathNUL(t *testing.T) {
f, err := ioutil.TempFile("", "_Go_ErrPathNUL\x00")
if err == nil {
f.Close()
t.Fatal("TempFile should have failed")
}
f, err = ioutil.TempFile("", "_Go_ErrPathNUL")
if err != nil {
t.Fatalf("open ErrPathNUL tempfile: %s", err)
}
defer os.Remove(f.Name())
defer f.Close()
f2, err := os.OpenFile(f.Name(), os.O_RDWR, 0600)
if err != nil {
t.Fatalf("open ErrPathNUL: %s", err)
}
f2.Close()
f2, err = os.OpenFile(f.Name()+"\x00", os.O_RDWR, 0600)
if err == nil {
f2.Close()
t.Fatal("Open should have failed")
}
}
......@@ -77,8 +77,12 @@ func openFile(name string, flag int, perm FileMode) (file *File, err error) {
}
func openDir(name string) (file *File, err error) {
maskp, e := syscall.UTF16PtrFromString(name + `\*`)
if e != nil {
return nil, &PathError{"open", name, e}
}
d := new(dirInfo)
r, e := syscall.FindFirstFile(syscall.StringToUTF16Ptr(name+`\*`), &d.data)
r, e := syscall.FindFirstFile(maskp, &d.data)
if e != nil {
return nil, &PathError{"open", name, e}
}
......@@ -284,11 +288,14 @@ func Truncate(name string, size int64) error {
// Remove removes the named file or directory.
// If there is an error, it will be of type *PathError.
func Remove(name string) error {
p := &syscall.StringToUTF16(name)[0]
p, e := syscall.UTF16PtrFromString(name)
if e != nil {
return &PathError{"remove", name, e}
}
// Go file interface forces us to know whether
// name is a file or directory. Try both.
e := syscall.DeleteFile(p)
e = syscall.DeleteFile(p)
if e == nil {
return nil
}
......
......@@ -48,7 +48,11 @@ func Stat(name string) (fi FileInfo, err error) {
return statDevNull()
}
var d syscall.Win32FileAttributeData
e := syscall.GetFileAttributesEx(syscall.StringToUTF16Ptr(name), syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&d)))
namep, e := syscall.UTF16PtrFromString(name)
if e != nil {
return nil, &PathError{"Stat", name, e}
}
e = syscall.GetFileAttributesEx(namep, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&d)))
if e != nil {
return nil, &PathError{"GetFileAttributesEx", name, e}
}
......@@ -221,7 +225,11 @@ func (s *winSys) loadFileId() error {
}
s.Lock()
defer s.Unlock()
h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(s.path), 0, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
pathp, e := syscall.UTF16PtrFromString(s.path)
if e != nil {
return e
}
h, e := syscall.CreateFile(pathp, 0, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
if e != nil {
return e
}
......
......@@ -16,10 +16,16 @@ func lookupFullName(domain, username, domainAndUser string) (string, error) {
syscall.NameSamCompatible, syscall.NameDisplay, 50)
if e != nil {
// domain lookup failed, perhaps this pc is not part of domain
d := syscall.StringToUTF16Ptr(domain)
u := syscall.StringToUTF16Ptr(username)
d, e := syscall.UTF16PtrFromString(domain)
if e != nil {
return "", e
}
u, e := syscall.UTF16PtrFromString(username)
if e != nil {
return "", e
}
var p *byte
e := syscall.NetUserGetInfo(d, u, 10, &p)
e = syscall.NetUserGetInfo(d, u, 10, &p)
if e != nil {
return "", e
}
......
......@@ -9,7 +9,10 @@ import (
)
func toShort(path string) (string, error) {
p := syscall.StringToUTF16(path)
p, err := syscall.UTF16FromString(path)
if err != nil {
return "", err
}
b := p // GetShortPathName says we can reuse buffer
n, err := syscall.GetShortPathName(&p[0], &b[0], uint32(len(b)))
if err != nil {
......@@ -26,7 +29,10 @@ func toShort(path string) (string, error) {
}
func toLong(path string) (string, error) {
p := syscall.StringToUTF16(path)
p, err := syscall.UTF16FromString(path)
if err != nil {
return "", err
}
b := p // GetLongPathName says we can reuse buffer
n, err := syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
if err != nil {
......
......@@ -112,9 +112,10 @@ func Test64BitReturnStdCall(t *testing.T) {
func TestCDecl(t *testing.T) {
var buf [50]byte
fmtp, _ := syscall.BytePtrFromString("%d %d %d")
a, _, _ := GetDLL(t, "user32.dll").Proc("wsprintfA").Call(
uintptr(unsafe.Pointer(&buf[0])),
uintptr(unsafe.Pointer(syscall.StringBytePtr("%d %d %d"))),
uintptr(unsafe.Pointer(fmtp)),
1000, 2000, 3000)
if string(buf[:a]) != "1000 2000 3000" {
t.Error("cdecl USER32.wsprintfA returns", a, "buf=", buf[:a])
......
......@@ -34,7 +34,11 @@ type DLL struct {
// LoadDLL loads DLL file into memory.
func LoadDLL(name string) (dll *DLL, err error) {
h, e := loadlibrary(StringToUTF16Ptr(name))
namep, err := UTF16PtrFromString(name)
if err != nil {
return nil, err
}
h, e := loadlibrary(namep)
if e != 0 {
return nil, &DLLError{
Err: e,
......@@ -61,7 +65,11 @@ func MustLoadDLL(name string) *DLL {
// FindProc searches DLL d for procedure named name and returns *Proc
// if found. It returns an error if search fails.
func (d *DLL) FindProc(name string) (proc *Proc, err error) {
a, e := getprocaddress(uintptr(d.Handle), StringBytePtr(name))
namep, err := BytePtrFromString(name)
if err != nil {
return nil, err
}
a, e := getprocaddress(uintptr(d.Handle), namep)
if e != 0 {
return nil, &DLLError{
Err: e,
......
......@@ -12,14 +12,18 @@ import (
)
func Getenv(key string) (value string, found bool) {
keyp, err := UTF16PtrFromString(key)
if err != nil {
return "", false
}
b := make([]uint16, 100)
n, e := GetEnvironmentVariable(StringToUTF16Ptr(key), &b[0], uint32(len(b)))
n, e := GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
if n == 0 && e == ERROR_ENVVAR_NOT_FOUND {
return "", false
}
if n > uint32(len(b)) {
b = make([]uint16, n)
n, e = GetEnvironmentVariable(StringToUTF16Ptr(key), &b[0], uint32(len(b)))
n, e = GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
if n > uint32(len(b)) {
n = 0
}
......@@ -32,10 +36,18 @@ func Getenv(key string) (value string, found bool) {
func Setenv(key, value string) error {
var v *uint16
var err error
if len(value) > 0 {
v = StringToUTF16Ptr(value)
v, err = UTF16PtrFromString(value)
if err != nil {
return err
}
}
keyp, err := UTF16PtrFromString(key)
if err != nil {
return err
}
e := SetEnvironmentVariable(StringToUTF16Ptr(key), v)
e := SetEnvironmentVariable(keyp, v)
if e != nil {
return e
}
......
......@@ -60,8 +60,9 @@ import (
var ForkLock sync.RWMutex
// Convert array of string to array
// of NUL-terminated byte pointer.
// StringSlicePtr is deprecated. Use SlicePtrFromStrings instead.
// If any string contains a NUL byte this function panics instead
// of returning an error.
func StringSlicePtr(ss []string) []*byte {
bb := make([]*byte, len(ss)+1)
for i := 0; i < len(ss); i++ {
......@@ -71,6 +72,22 @@ func StringSlicePtr(ss []string) []*byte {
return bb
}
// SlicePtrFromStrings converts a slice of strings to a slice of
// pointers to NUL-terminated byte slices. If any string contains
// a NUL byte, it returns (nil, EINVAL).
func SlicePtrFromStrings(ss []string) ([]*byte, error) {
var err error
bb := make([]*byte, len(ss)+1)
for i := 0; i < len(ss); i++ {
bb[i], err = BytePtrFromString(ss[i])
if err != nil {
return nil, err
}
}
bb[len(ss)] = nil
return bb, nil
}
// gbit16 reads a 16-bit numeric value from a 9P protocol message stored in b,
// returning the value and the remaining slice of b.
func gbit16(b []byte) (uint16, []byte) {
......@@ -373,12 +390,21 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
p[1] = -1
// Convert args to C form.
argv0p := StringBytePtr(argv0)
argvp := StringSlicePtr(argv)
argv0p, err := BytePtrFromString(argv0)
if err != nil {
return 0, err
}
argvp, err := SlicePtrFromStrings(argv)
if err != nil {
return 0, err
}
var dir *byte
if attr.Dir != "" {
dir = StringBytePtr(attr.Dir)
dir, err = BytePtrFromString(attr.Dir)
if err != nil {
return 0, err
}
}
var envvParsed []envItem
if attr.Env != nil {
......@@ -389,7 +415,15 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
i++
}
envvParsed = append(envvParsed, envItem{StringBytePtr("/env/" + v[:i]), StringBytePtr(v[i+1:]), len(v) - i})
envname, err := BytePtrFromString("/env/" + v[:i])
if err != nil {
return 0, err
}
envvalue, err := BytePtrFromString(v[i+1:])
if err != nil {
return 0, err
}
envvParsed = append(envvParsed, envItem{envname, envvalue, len(v) - i})
}
}
......@@ -511,9 +545,17 @@ func Exec(argv0 string, argv []string, envv []string) (err error) {
}
}
argv0p, err := BytePtrFromString(argv0)
if err != nil {
return err
}
argvp, err := SlicePtrFromStrings(argv)
if err != nil {
return err
}
_, _, e1 := Syscall(SYS_EXEC,
uintptr(unsafe.Pointer(StringBytePtr(argv0))),
uintptr(unsafe.Pointer(&StringSlicePtr(argv)[0])),
uintptr(unsafe.Pointer(argv0p)),
uintptr(unsafe.Pointer(&argvp[0])),
0)
return e1
......
......@@ -63,8 +63,9 @@ import (
var ForkLock sync.RWMutex
// Convert array of string to array
// of NUL-terminated byte pointer.
// StringSlicePtr is deprecated. Use SlicePtrFromStrings instead.
// If any string contains a NUL byte this function panics instead
// of returning an error.
func StringSlicePtr(ss []string) []*byte {
bb := make([]*byte, len(ss)+1)
for i := 0; i < len(ss); i++ {
......@@ -74,6 +75,22 @@ func StringSlicePtr(ss []string) []*byte {
return bb
}
// SlicePtrFromStrings converts a slice of strings to a slice of
// pointers to NUL-terminated byte slices. If any string contains
// a NUL byte, it returns (nil, EINVAL).
func SlicePtrFromStrings(ss []string) ([]*byte, error) {
var err error
bb := make([]*byte, len(ss)+1)
for i := 0; i < len(ss); i++ {
bb[i], err = BytePtrFromString(ss[i])
if err != nil {
return nil, err
}
}
bb[len(ss)] = nil
return bb, nil
}
func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) }
func SetNonblock(fd int, nonblocking bool) (err error) {
......@@ -128,9 +145,18 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
p[1] = -1
// Convert args to C form.
argv0p := StringBytePtr(argv0)
argvp := StringSlicePtr(argv)
envvp := StringSlicePtr(attr.Env)
argv0p, err := BytePtrFromString(argv0)
if err != nil {
return 0, err
}
argvp, err := SlicePtrFromStrings(argv)
if err != nil {
return 0, err
}
envvp, err := SlicePtrFromStrings(attr.Env)
if err != nil {
return 0, err
}
if runtime.GOOS == "freebsd" && len(argv[0]) > len(argv0) {
argvp[0] = argv0p
......@@ -138,11 +164,17 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
var chroot *byte
if sys.Chroot != "" {
chroot = StringBytePtr(sys.Chroot)
chroot, err = BytePtrFromString(sys.Chroot)
if err != nil {
return 0, err
}
}
var dir *byte
if attr.Dir != "" {
dir = StringBytePtr(attr.Dir)
dir, err = BytePtrFromString(attr.Dir)
if err != nil {
return 0, err
}
}
// Acquire the fork lock so that no other threads
......@@ -215,9 +247,21 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
// Ordinary exec.
func Exec(argv0 string, argv []string, envv []string) (err error) {
argv0p, err := BytePtrFromString(argv0)
if err != nil {
return err
}
argvp, err := SlicePtrFromStrings(argv)
if err != nil {
return err
}
envvp, err := SlicePtrFromStrings(envv)
if err != nil {
return err
}
_, _, err1 := RawSyscall(SYS_EXECVE,
uintptr(unsafe.Pointer(StringBytePtr(argv0))),
uintptr(unsafe.Pointer(&StringSlicePtr(argv)[0])),
uintptr(unsafe.Pointer(&StringSlicePtr(envv)[0])))
uintptr(unsafe.Pointer(argv0p)),
uintptr(unsafe.Pointer(&argvp[0])),
uintptr(unsafe.Pointer(&envvp[0])))
return Errno(err1)
}
......@@ -132,7 +132,10 @@ func SetNonblock(fd Handle, nonblocking bool) (err error) {
// getFullPath retrieves the full path of the specified file.
// Just a wrapper for Windows GetFullPathName api.
func getFullPath(name string) (path string, err error) {
p := StringToUTF16Ptr(name)
p, err := UTF16PtrFromString(name)
if err != nil {
return "", err
}
buf := make([]uint16, 100)
n, err := GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
if err != nil {
......@@ -262,7 +265,10 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
return 0, 0, err
}
}
argv0p := StringToUTF16Ptr(argv0)
argv0p, err := UTF16PtrFromString(argv0)
if err != nil {
return 0, 0, err
}
var cmdline string
// Windows CreateProcess takes the command line as a single string:
......@@ -276,12 +282,18 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
var argvp *uint16
if len(cmdline) != 0 {
argvp = StringToUTF16Ptr(cmdline)
argvp, err = UTF16PtrFromString(cmdline)
if err != nil {
return 0, 0, err
}
}
var dirp *uint16
if len(attr.Dir) != 0 {
dirp = StringToUTF16Ptr(attr.Dir)
dirp, err = UTF16PtrFromString(attr.Dir)
if err != nil {
return 0, 0, err
}
}
// Acquire the fork lock so that no other threads
......
......@@ -110,6 +110,16 @@ while(<>) {
my $out_decl = @out ? sprintf(" (%s)", join(', ', @out)) : "";
$text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out_decl;
# Check if err return available
my $errvar = "";
foreach my $p (@out) {
my ($name, $type) = parseparam($p);
if($type eq "error") {
$errvar = $name;
last;
}
}
# Prepare arguments to Syscall.
my @args = ();
my $n = 0;
......@@ -117,8 +127,18 @@ while(<>) {
my ($name, $type) = parseparam($p);
if($type =~ /^\*/) {
push @args, "uintptr(unsafe.Pointer($name))";
} elsif($type eq "string" && $errvar ne "") {
$text .= "\tvar _p$n *byte\n";
$text .= "\t_p$n, $errvar = BytePtrFromString($name)\n";
$text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n";
push @args, "uintptr(unsafe.Pointer(_p$n))";
$n++;
} elsif($type eq "string") {
push @args, "uintptr(unsafe.Pointer(StringBytePtr($name)))";
print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n";
$text .= "\tvar _p$n *byte\n";
$text .= "\t_p$n, _ = BytePtrFromString($name)\n";
push @args, "uintptr(unsafe.Pointer(_p$n))";
$n++;
} elsif($type =~ /^\[\](.*)/) {
# Convert slice into pointer, length.
# Have to be careful not to take address of &a[0] if len == 0:
......
......@@ -118,7 +118,8 @@ while(<>) {
}
# Decide which version of api is used: ascii or unicode.
my $strconvfunc = $sysname !~ /W$/ ? "StringBytePtr" : "StringToUTF16Ptr";
my $strconvfunc = $sysname !~ /W$/ ? "BytePtrFromString" : "UTF16PtrFromString";
my $strconvtype = $sysname !~ /W$/ ? "*byte" : "*uint16";
# Winapi proc address variable.
$vars .= "\t$sysvarname = $modvname.NewProc(\"$sysname\")\n";
......@@ -133,6 +134,16 @@ while(<>) {
}
$text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out;
# Check if err return available
my $errvar = "";
foreach my $p (@out) {
my ($name, $type) = parseparam($p);
if($type eq "error") {
$errvar = $name;
last;
}
}
# Prepare arguments to Syscall.
my @args = ();
my $n = 0;
......@@ -141,8 +152,18 @@ while(<>) {
my ($name, $type) = parseparam($p);
if($type =~ /^\*/) {
push @args, "uintptr(unsafe.Pointer($name))";
} elsif($type eq "string" && $errvar ne "") {
$text .= "\tvar _p$n $strconvtype\n";
$text .= "\t_p$n, $errvar = $strconvfunc($name)\n";
$text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n";
push @args, "uintptr(unsafe.Pointer(_p$n))";
$n++;
} elsif($type eq "string") {
push @args, "uintptr(unsafe.Pointer($strconvfunc($name)))";
print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n";
$text .= "\tvar _p$n $strconvtype\n";
$text .= "\t_p$n, _ = $strconvfunc($name)\n";
push @args, "uintptr(unsafe.Pointer(_p$n))";
$n++;
} elsif($type =~ /^\[\](.*)/) {
# Convert slice into pointer, length.
# Have to be careful not to take address of &a[0] if len == 0:
......
......@@ -37,10 +37,13 @@ const (
// TranslateAccountName converts a directory service
// object name from one format to another.
func TranslateAccountName(username string, from, to uint32, initSize int) (string, error) {
u := StringToUTF16Ptr(username)
u, e := UTF16PtrFromString(username)
if e != nil {
return "", e
}
b := make([]uint16, 50)
n := uint32(len(b))
e := TranslateName(u, from, to, &b[0], &n)
e = TranslateName(u, from, to, &b[0], &n)
if e != nil {
if e != ERROR_INSUFFICIENT_BUFFER {
return "", e
......@@ -94,7 +97,11 @@ type SID struct{}
// sid into a valid, functional sid.
func StringToSid(s string) (*SID, error) {
var sid *SID
e := ConvertStringSidToSid(StringToUTF16Ptr(s), &sid)
p, e := UTF16PtrFromString(s)
if e != nil {
return nil, e
}
e = ConvertStringSidToSid(p, &sid)
if e != nil {
return nil, e
}
......@@ -109,17 +116,23 @@ func LookupSID(system, account string) (sid *SID, domain string, accType uint32,
if len(account) == 0 {
return nil, "", 0, EINVAL
}
acc := StringToUTF16Ptr(account)
acc, e := UTF16PtrFromString(account)
if e != nil {
return nil, "", 0, e
}
var sys *uint16
if len(system) > 0 {
sys = StringToUTF16Ptr(system)
sys, e = UTF16PtrFromString(system)
if e != nil {
return nil, "", 0, e
}
}
db := make([]uint16, 50)
dn := uint32(len(db))
b := make([]byte, 50)
n := uint32(len(b))
sid = (*SID)(unsafe.Pointer(&b[0]))
e := LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
if e != nil {
if e != ERROR_INSUFFICIENT_BUFFER {
return nil, "", 0, e
......@@ -170,7 +183,10 @@ func (sid *SID) Copy() (*SID, error) {
func (sid *SID) LookupAccount(system string) (account, domain string, accType uint32, err error) {
var sys *uint16
if len(system) > 0 {
sys = StringToUTF16Ptr(system)
sys, err = UTF16PtrFromString(system)
if err != nil {
return "", "", 0, err
}
}
b := make([]uint16, 50)
n := uint32(len(b))
......
......@@ -14,18 +14,47 @@
// On most systems, that error has type syscall.Errno.
package syscall
// StringByteSlice returns a NUL-terminated slice of bytes
// containing the text of s.
// StringByteSlice is deprecated. Use ByteSliceFromString instead.
// If s contains a NUL byte this function panics instead of
// returning an error.
func StringByteSlice(s string) []byte {
a, err := ByteSliceFromString(s)
if err != nil {
panic("syscall: string with NUL passed to StringByteSlice")
}
return a
}
// ByteSliceFromString returns a NUL-terminated slice of bytes
// containing the text of s. If s contains a NUL byte at any
// location, it returns (nil, EINVAL).
func ByteSliceFromString(s string) ([]byte, error) {
for i := 0; i < len(s); i++ {
if s[i] == 0 {
return nil, EINVAL
}
}
a := make([]byte, len(s)+1)
copy(a, s)
return a
return a, nil
}
// StringBytePtr returns a pointer to a NUL-terminated array of bytes
// containing the text of s.
// StringBytePtr is deprecated. Use BytePtrFromString instead.
// If s contains a NUL byte this function panics instead of
// returning an error.
func StringBytePtr(s string) *byte { return &StringByteSlice(s)[0] }
// BytePtrFromString returns a pointer to a NUL-terminated array of
// bytes containing the text of s. If s contains a NUL byte at any
// location, it returns (nil, EINVAL).
func BytePtrFromString(s string) (*byte, error) {
a, err := ByteSliceFromString(s)
if err != nil {
return nil, err
}
return &a[0], nil
}
// Single-word zero for use when we need a valid pointer to 0 bytes.
// See mksyscall.pl.
var _zero uintptr
......
......@@ -41,7 +41,10 @@ func nametomib(name string) (mib []_C_int, err error) {
n := uintptr(CTL_MAXNAME) * siz
p := (*byte)(unsafe.Pointer(&buf[0]))
bytes := StringByteSlice(name)
bytes, err := ByteSliceFromString(name)
if err != nil {
return nil, err
}
// Magic sysctl: "setting" 0.3 to a string name
// lets you read back the array of integers form.
......
......@@ -41,7 +41,10 @@ func nametomib(name string) (mib []_C_int, err error) {
n := uintptr(CTL_MAXNAME) * siz
p := (*byte)(unsafe.Pointer(&buf[0]))
bytes := StringByteSlice(name)
bytes, err := ByteSliceFromString(name)
if err != nil {
return nil, err
}
// Magic sysctl: "setting" 0.3 to a string name
// lets you read back the array of integers form.
......
......@@ -52,7 +52,11 @@ func Futimesat(dirfd int, path string, tv []Timeval) (err error) {
if len(tv) != 2 {
return EINVAL
}
return futimesat(dirfd, StringBytePtr(path), (*[2]Timeval)(unsafe.Pointer(&tv[0])))
pathp, err := BytePtrFromString(path)
if err != nil {
return err
}
return futimesat(dirfd, pathp, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
}
func Futimes(fd int, tv []Timeval) (err error) {
......@@ -783,7 +787,11 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri
if data == "" {
return mount(source, target, fstype, flags, nil)
}
return mount(source, target, fstype, flags, StringBytePtr(data))
datap, err := BytePtrFromString(data)
if err != nil {
return err
}
return mount(source, target, fstype, flags, datap)
}
// Sendto
......
......@@ -306,7 +306,11 @@ func Fstatfs(fd int, buf *Statfs_t) (err error) {
}
func Statfs(path string, buf *Statfs_t) (err error) {
_, _, e := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(StringBytePtr(path))), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
pathp, err := BytePtrFromString(path)
if err != nil {
return err
}
_, _, e := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(pathp)), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
if e != 0 {
err = e
}
......
......@@ -237,16 +237,24 @@ func Await(w *Waitmsg) (err error) {
}
func Unmount(name, old string) (err error) {
oldp := uintptr(unsafe.Pointer(StringBytePtr(old)))
oldp, err := BytePtrFromString(old)
if err != nil {
return err
}
oldptr := uintptr(unsafe.Pointer(oldp))
var r0 uintptr
var e ErrorString
// bind(2) man page: If name is zero, everything bound or mounted upon old is unbound or unmounted.
if name == "" {
r0, _, e = Syscall(SYS_UNMOUNT, _zero, oldp, 0)
r0, _, e = Syscall(SYS_UNMOUNT, _zero, oldptr, 0)
} else {
r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(name))), oldp, 0)
namep, err := BytePtrFromString(name)
if err != nil {
return err
}
r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(namep)), oldptr, 0)
}
if int(r0) == -1 {
......
......@@ -52,9 +52,28 @@ func main() {
*/
// StringToUTF16 returns the UTF-16 encoding of the UTF-8 string s,
// with a terminating NUL added.
func StringToUTF16(s string) []uint16 { return utf16.Encode([]rune(s + "\x00")) }
// StringToUTF16 is deprecated. Use UTF16FromString instead.
// If s contains a NUL byte this function panics instead of
// returning an error.
func StringToUTF16(s string) []uint16 {
a, err := UTF16FromString(s)
if err != nil {
panic("syscall: string with NUL passed to StringToUTF16")
}
return a
}
// UTF16FromString returns the UTF-16 encoding of the UTF-8 string
// s, with a terminating NUL added. If s contains a NUL byte at any
// location, it returns (nil, EINVAL).
func UTF16FromString(s string) ([]uint16, error) {
for i := 0; i < len(s); i++ {
if s[i] == 0 {
return nil, EINVAL
}
}
return utf16.Encode([]rune(s + "\x00")), nil
}
// UTF16ToString returns the UTF-8 encoding of the UTF-16 sequence s,
// with a terminating NUL removed.
......@@ -68,10 +87,22 @@ func UTF16ToString(s []uint16) string {
return string(utf16.Decode(s))
}
// StringToUTF16Ptr returns pointer to the UTF-16 encoding of
// the UTF-8 string s, with a terminating NUL added.
// StringToUTF16Ptr is deprecated. Use UTF16PtrFromString instead.
// If s contains a NUL byte this function panics instead of
// returning an error.
func StringToUTF16Ptr(s string) *uint16 { return &StringToUTF16(s)[0] }
// UTF16PtrFromString returns pointer to the UTF-16 encoding of
// the UTF-8 string s, with a terminating NUL added. If s
// contains a NUL byte at any location, it returns (nil, EINVAL).
func UTF16PtrFromString(s string) (*uint16, error) {
a, err := UTF16FromString(s)
if err != nil {
return nil, err
}
return &a[0], nil
}
func Getpagesize() int { return 4096 }
// Errno is the Windows error number.
......@@ -218,6 +249,10 @@ func Open(path string, mode int, perm uint32) (fd Handle, err error) {
if len(path) == 0 {
return InvalidHandle, ERROR_FILE_NOT_FOUND
}
pathp, err := UTF16PtrFromString(path)
if err != nil {
return InvalidHandle, err
}
var access uint32
switch mode & (O_RDONLY | O_WRONLY | O_RDWR) {
case O_RDONLY:
......@@ -252,7 +287,7 @@ func Open(path string, mode int, perm uint32) (fd Handle, err error) {
default:
createmode = OPEN_EXISTING
}
h, e := CreateFile(StringToUTF16Ptr(path), access, sharemode, sa, createmode, FILE_ATTRIBUTE_NORMAL, 0)
h, e := CreateFile(pathp, access, sharemode, sa, createmode, FILE_ATTRIBUTE_NORMAL, 0)
return h, e
}
......@@ -330,24 +365,46 @@ func Getwd() (wd string, err error) {
}
func Chdir(path string) (err error) {
return SetCurrentDirectory(&StringToUTF16(path)[0])
pathp, err := UTF16PtrFromString(path)
if err != nil {
return err
}
return SetCurrentDirectory(pathp)
}
func Mkdir(path string, mode uint32) (err error) {
return CreateDirectory(&StringToUTF16(path)[0], nil)
pathp, err := UTF16PtrFromString(path)
if err != nil {
return err
}
return CreateDirectory(pathp, nil)
}
func Rmdir(path string) (err error) {
return RemoveDirectory(&StringToUTF16(path)[0])
pathp, err := UTF16PtrFromString(path)
if err != nil {
return err
}
return RemoveDirectory(pathp)
}
func Unlink(path string) (err error) {
return DeleteFile(&StringToUTF16(path)[0])
pathp, err := UTF16PtrFromString(path)
if err != nil {
return err
}
return DeleteFile(pathp)
}
func Rename(oldpath, newpath string) (err error) {
from := &StringToUTF16(oldpath)[0]
to := &StringToUTF16(newpath)[0]
from, err := UTF16PtrFromString(oldpath)
if err != nil {
return err
}
to, err := UTF16PtrFromString(newpath)
if err != nil {
return err
}
return MoveFile(from, to)
}
......@@ -403,7 +460,11 @@ func Utimes(path string, tv []Timeval) (err error) {
if len(tv) != 2 {
return EINVAL
}
h, e := CreateFile(StringToUTF16Ptr(path),
pathp, e := UTF16PtrFromString(path)
if e != nil {
return e
}
h, e := CreateFile(pathp,
FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
if e != nil {
......@@ -423,7 +484,10 @@ func Chmod(path string, mode uint32) (err error) {
if mode == 0 {
return EINVAL
}
p := StringToUTF16Ptr(path)
p, e := UTF16PtrFromString(path)
if e != nil {
return e
}
attrs, e := GetFileAttributes(p)
if e != nil {
return e
......
......@@ -35,7 +35,8 @@ func TestWin32finddata(t *testing.T) {
var want byte = 2 // it is unlikely to have this character in the filename
x := X{got: want}
h, err := syscall.FindFirstFile(syscall.StringToUTF16Ptr(path), &(x.fd))
pathp, _ := syscall.UTF16PtrFromString(path)
h, err := syscall.FindFirstFile(pathp, &(x.fd))
if err != nil {
t.Fatalf("FindFirstFile failed: %v", err)
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -7,13 +7,6 @@ import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func exits(msg *byte) {
Syscall(SYS_EXITS, uintptr(unsafe.Pointer(msg)), 0, 0)
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func fd2path(fd int, buf []byte) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
......@@ -69,7 +62,12 @@ func Dup(oldfd int, newfd int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Open(path string, mode int) (fd int, err error) {
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
fd = int(r0)
if int(r0) == -1 {
err = e1
......@@ -80,7 +78,12 @@ func Open(path string, mode int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Create(path string, mode int, perm uint32) (fd int, err error) {
r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
fd = int(r0)
if int(r0) == -1 {
err = e1
......@@ -91,7 +94,12 @@ func Create(path string, mode int, perm uint32) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Remove(path string) (err error) {
r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0)
if int(r0) == -1 {
err = e1
}
......@@ -145,7 +153,12 @@ func Close(fd int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Chdir(path string) (err error) {
r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
if int(r0) == -1 {
err = e1
}
......@@ -155,7 +168,17 @@ func Chdir(path string) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Bind(name string, old string, flag int) (err error) {
r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(StringBytePtr(name))), uintptr(unsafe.Pointer(StringBytePtr(old))), uintptr(flag))
var _p0 *byte
_p0, err = BytePtrFromString(name)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(old)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag))
if int(r0) == -1 {
err = e1
}
......@@ -165,7 +188,17 @@ func Bind(name string, old string, flag int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(StringBytePtr(old))), uintptr(flag), uintptr(unsafe.Pointer(StringBytePtr(aname))), 0)
var _p0 *byte
_p0, err = BytePtrFromString(old)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(aname)
if err != nil {
return
}
r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0)
if int(r0) == -1 {
err = e1
}
......@@ -175,13 +208,18 @@ func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Stat(path string, edir []byte) (n int, err error) {
var _p0 unsafe.Pointer
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
var _p1 unsafe.Pointer
if len(edir) > 0 {
_p0 = unsafe.Pointer(&edir[0])
_p1 = unsafe.Pointer(&edir[0])
} else {
_p0 = unsafe.Pointer(&_zero)
_p1 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(edir)))
r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
n = int(r0)
if int(r0) == -1 {
err = e1
......@@ -209,13 +247,18 @@ func Fstat(fd int, edir []byte) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Wstat(path string, edir []byte) (err error) {
var _p0 unsafe.Pointer
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
var _p1 unsafe.Pointer
if len(edir) > 0 {
_p0 = unsafe.Pointer(&edir[0])
_p1 = unsafe.Pointer(&edir[0])
} else {
_p0 = unsafe.Pointer(&_zero)
_p1 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(edir)))
r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
if int(r0) == -1 {
err = e1
}
......
......@@ -155,7 +155,12 @@ func GetLastError() (lasterr error) {
}
func LoadLibrary(libname string) (handle Handle, err error) {
r0, _, e1 := Syscall(procLoadLibraryW.Addr(), 1, uintptr(unsafe.Pointer(StringToUTF16Ptr(libname))), 0, 0)
var _p0 *uint16
_p0, err = UTF16PtrFromString(libname)
if err != nil {
return
}
r0, _, e1 := Syscall(procLoadLibraryW.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0)
handle = Handle(r0)
if handle == 0 {
if e1 != 0 {
......@@ -180,7 +185,12 @@ func FreeLibrary(handle Handle) (err error) {
}
func GetProcAddress(module Handle, procname string) (proc uintptr, err error) {
r0, _, e1 := Syscall(procGetProcAddress.Addr(), 2, uintptr(module), uintptr(unsafe.Pointer(StringBytePtr(procname))), 0)
var _p0 *byte
_p0, err = BytePtrFromString(procname)
if err != nil {
return
}
r0, _, e1 := Syscall(procGetProcAddress.Addr(), 2, uintptr(module), uintptr(unsafe.Pointer(_p0)), 0)
proc = uintptr(r0)
if proc == 0 {
if e1 != 0 {
......@@ -1406,7 +1416,12 @@ func WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32
}
func GetHostByName(name string) (h *Hostent, err error) {
r0, _, e1 := Syscall(procgethostbyname.Addr(), 1, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
var _p0 *byte
_p0, err = BytePtrFromString(name)
if err != nil {
return
}
r0, _, e1 := Syscall(procgethostbyname.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0)
h = (*Hostent)(unsafe.Pointer(r0))
if h == nil {
if e1 != 0 {
......@@ -1419,7 +1434,17 @@ func GetHostByName(name string) (h *Hostent, err error) {
}
func GetServByName(name string, proto string) (s *Servent, err error) {
r0, _, e1 := Syscall(procgetservbyname.Addr(), 2, uintptr(unsafe.Pointer(StringBytePtr(name))), uintptr(unsafe.Pointer(StringBytePtr(proto))), 0)
var _p0 *byte
_p0, err = BytePtrFromString(name)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(proto)
if err != nil {
return
}
r0, _, e1 := Syscall(procgetservbyname.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
s = (*Servent)(unsafe.Pointer(r0))
if s == nil {
if e1 != 0 {
......@@ -1438,7 +1463,12 @@ func Ntohs(netshort uint16) (u uint16) {
}
func GetProtoByName(name string) (p *Protoent, err error) {
r0, _, e1 := Syscall(procgetprotobyname.Addr(), 1, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
var _p0 *byte
_p0, err = BytePtrFromString(name)
if err != nil {
return
}
r0, _, e1 := Syscall(procgetprotobyname.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0)
p = (*Protoent)(unsafe.Pointer(r0))
if p == nil {
if e1 != 0 {
......@@ -1451,7 +1481,12 @@ func GetProtoByName(name string) (p *Protoent, err error) {
}
func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) {
r0, _, _ := Syscall6(procDnsQuery_W.Addr(), 6, uintptr(unsafe.Pointer(StringToUTF16Ptr(name))), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr)))
var _p0 *uint16
_p0, status = UTF16PtrFromString(name)
if status != nil {
return
}
r0, _, _ := Syscall6(procDnsQuery_W.Addr(), 6, uintptr(unsafe.Pointer(_p0)), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr)))
if r0 != 0 {
status = Errno(r0)
}
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment