Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compiling go code, inside host mounted folder prevent the binary file being executable #602

Open
matteosilv opened this issue Jan 27, 2022 · 7 comments
Labels
bug Something isn't working component/sshfs

Comments

@matteosilv
Copy link

Description

limactl version 0.8.1

After picking up a shell session on the lima vm or running from inside a docker container, building go binaries inside a mount:

go build -o $MOUNTED_HOST_FOLDER ./cmd/server/main.go

results in creating the main file not executable:

-rw-r--r-- 1 lima dialout 35264925 Jan 27 15:00 main

Same done to a vm folder:

go build -o $HOME ./cmd/server/main.go

results in:

-rwxrwxr-x 1 lima lima 35264925 Jan 27 15:03 main

This prevents us from switching from Docker Desktop to lima + docker seamlessly without modification to our workflows expecting the binary to be executable after compilation.

NOTE: chmod on the file works as intended, we have a workaround but requires us some modifications.

@matteosilv
Copy link
Author

Digging a little bit more into that running the go compiler with -x option, i believe it is loosing file permission after the cp command:

mkdir -p $WORK/b001/exe/
cd .
/usr/lib/go-1.17/pkg/tool/linux_amd64/link -o $WORK/b001/exe/a.out -importcfg $WORK/b001/importcfg.link -buildmode=exe -buildid=n0j33Z7mjXck_-cJmBhq/RTaH5kmSl0Lrw7v13rk0/d6m-_ikKkEfFSAAursPz/n0j33Z7mjXck_-cJmBhq -extld=gcc /home/lima.linux/.cache/go-build/bf/bfbafae3d8611f2f93196d75bac8f11e17f21138ba5f019995ebaeb5f6af9eee-d
/usr/lib/go-1.17/pkg/tool/linux_amd64/buildid -w $WORK/b001/exe/a.out # internal
cp $WORK/b001/exe/a.out main
rm -r $WORK/b001/

I tried to cp an executable file to a mounted dir and it lost its executable bit

@afbjorklund
Copy link
Member

I can reproduce this, on my machine. It gets 644 on sshfs, and 755 in $HOME.

@rfay
Copy link
Contributor

rfay commented Jan 27, 2022

I've seen this also.

@afbjorklund
Copy link
Member

afbjorklund commented Jan 27, 2022

Go does some kind of special trick, to try to determine the umask. Apparently it goes horribly wrong, under sshfs.

        // The perm argument is meant to be adjusted according to umask,
        // but we don't know what the umask is.
        // Create a dummy file to find out.
        // This avoids build tags and works even on systems like Plan 9
        // where the file mask computation incorporates other information.
        mode := perm
        f, err := os.OpenFile(filepath.Clean(dst)+"-go-tmp-umask", os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm)
        if err == nil {
                fi, err := f.Stat()
                if err == nil {
                        mode = fi.Mode() & 0777
                }
                name := f.Name()
                f.Close()
                os.Remove(name)
        }

        if err := os.Chmod(src, mode); err == nil {
                if err := os.Rename(src, dst); err == nil {
                        if cfg.BuildX {
                                b.Showcmd("", "mv %s %s", src, dst)
                        }
                        return nil
                }
        }

Sadly it never logs the secret chmod, but only the mv...

But it is clearly visible when using strace (as usual)

$HOME: 13189 fstat(3, {st_mode=S_IFREG|0775, st_size=0, ...}) = 0

/tmp/lima: 12680 fstat(3, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0


EDIT: That would be $HOME in the VM, not $HOME on the host

i.e. /home/anders.linux (not mounted), not /home/anders (mounted)

@afbjorklund
Copy link
Member

afbjorklund commented Jan 27, 2022

Reproducer:

package main

import (
	"fmt"
	"io/fs"
	"os"
)

func main() {
	perm := fs.FileMode(0777)
	dst := "test"

	mode := perm
	f, err := os.OpenFile(dst+"-go-tmp-umask", os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm)
	if err == nil {
		fi, err := f.Stat()
		if err == nil {
			mode = fi.Mode() & 0777
		}
		name := f.Name()
		f.Close()
		os.Remove(name)
	}

	fmt.Printf("%s: %v\n", dst, mode)
}

test: -rwxrwxr-x

test: -rw-r--r--

$ go version
go version go1.17 linux/amd64
$ umask
0002

@afbjorklund
Copy link
Member

afbjorklund commented Jan 27, 2022

This is a bug, in the SFTP server that lima is using (through sshocker):

	github.com/pkg/sftp v1.13.3 // indirect

Apparently it has been broken since day one, in the github.com/pkg/sftp server:

pkg/sftp@058e1be

        f, err := os.OpenFile(toLocalPath(p.Path), osFlags, 0644)
        if err != nil {
                return statusFromError(p.ID, err)
        }

So always uses 0644, no matter what mode the packet sends (such as 0777).

@AkihiroSuda AkihiroSuda added bug Something isn't working component/sshfs labels Jan 28, 2022
@afbjorklund
Copy link
Member

afbjorklund commented Jan 28, 2022

I fixed the code, but it sorta made it worse. There is no agreement on using umask, so now the go binary is 0777.

According to docs, sftp is supposed to apply umask and sftp-server is supposed to not apply any umask.

https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.6

Currently, neither sshfs nor github.com/pkg/sftp applies any umask at all. There is an option, to have server override it...

Maybe it should be ported to the Go package, so that you end up with some sane default like 0666 mode and 0002 umask ?

https://bugzilla.mindrot.org/show_bug.cgi?id=1844


EDIT: Here was the code: afbjorklund/sftp@244f752

	github.com/pkg/sftp v1.13.3 // indirect

stehessel added a commit to stackrox/stackrox that referenced this issue Mar 31, 2022
Lima manages virtual machines on macOS, which can be used as a
replacement to `Docker Desktop`. Currently, Lima contains a bug that
leads to go binaries not being executable if they have been built inside
a mounted volume (lima-vm/lima#602).

As a workaround, add execution to the file permissions explicitly. This
should be a no-op when Lima is not used, for example on Linux systems.
stehessel added a commit to stackrox/stackrox that referenced this issue Apr 21, 2022
Lima manages virtual machines on macOS, which can be used as a
replacement to `Docker Desktop`. Currently, Lima contains a bug that
leads to go binaries not being executable if they have been built inside
a mounted volume (lima-vm/lima#602).

As a workaround, add execution to the file permissions explicitly. This
should be a no-op when Lima is not used, for example on Linux systems.
stehessel added a commit to stackrox/stackrox that referenced this issue Apr 21, 2022
Lima manages virtual machines on macOS, which can be used as a
replacement to `Docker Desktop`. Currently, Lima contains a bug that
leads to go binaries not being executable if they have been built inside
a mounted volume (lima-vm/lima#602).

As a workaround, add execution to the file permissions explicitly. This
should be a no-op when Lima is not used, for example on Linux systems.
stehessel added a commit to stackrox/stackrox that referenced this issue Apr 21, 2022
Lima manages virtual machines on macOS, which can be used as a
replacement to `Docker Desktop`. Currently, Lima contains a bug that
leads to go binaries not being executable if they have been built inside
a mounted volume (lima-vm/lima#602).

As a workaround, add execution to the file permissions explicitly. This
should be a no-op when Lima is not used, for example on Linux systems.
stehessel added a commit to stackrox/stackrox that referenced this issue Apr 21, 2022
Lima manages virtual machines on macOS, which can be used as a
replacement to `Docker Desktop`. Currently, Lima contains a bug that
leads to go binaries not being executable if they have been built inside
a mounted volume (lima-vm/lima#602).

As a workaround, add execution to the file permissions explicitly. This
should be a no-op when Lima is not used, for example on Linux systems.
stehessel added a commit to stackrox/stackrox that referenced this issue Apr 21, 2022
Lima manages virtual machines on macOS, which can be used as a
replacement to `Docker Desktop`. Currently, Lima contains a bug that
leads to go binaries not being executable if they have been built inside
a mounted volume (lima-vm/lima#602).

As a workaround, add execution to the file permissions explicitly. This
should be a no-op when Lima is not used, for example on Linux systems.
stehessel added a commit to stackrox/stackrox that referenced this issue Apr 22, 2022
Lima manages virtual machines on macOS, which can be used as a
replacement to `Docker Desktop`. Currently, Lima contains a bug that
leads to go binaries not being executable if they have been built inside
a mounted volume (lima-vm/lima#602).

As a workaround, add execution to the file permissions explicitly. This
should be a no-op when Lima is not used, for example on Linux systems.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working component/sshfs
Projects
None yet
Development

No branches or pull requests

4 participants