Skip to content

Commit

Permalink
ctlsock: delete colliding orphaned socket file
Browse files Browse the repository at this point in the history
Detect and delete an orphaned socket file that collides with
the ctlsock we want to create.

Fixes #776
  • Loading branch information
rfjakob committed Sep 3, 2024
1 parent 40abf96 commit 2c01b1a
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 0 deletions.
35 changes: 35 additions & 0 deletions internal/ctlsocksrv/ctlsock_listen.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,44 @@
package ctlsocksrv

import (
"errors"
"io/fs"
"net"
"os"
"syscall"
"time"

"github.com/rfjakob/gocryptfs/v2/internal/tlog"
)

// cleanupOrphanedSocket deletes an orphaned socket file at `path`.
// The file at `path` will only be deleted if:
// 1) It is a socket file
// 2) Connecting to it results in ECONNREFUSED
func cleanupOrphanedSocket(path string) {
fi, err := os.Stat(path)
if err != nil {
return
}
if fi.Mode().Type() != fs.ModeSocket {
return
}
conn, err := net.DialTimeout("unix", path, time.Second)
if err == nil {
// This socket file is still active. Don't delete it.
conn.Close()
return
}
if errors.Is(err, syscall.ECONNREFUSED) {
tlog.Info.Printf("ctlsock: deleting orphaned socket file %q\n", path)
err = os.Remove(path)
if err != nil {
tlog.Warn.Printf("ctlsock: deleting socket file failed: %v", path)
}
}
}

func Listen(path string) (net.Listener, error) {
cleanupOrphanedSocket(path)
return net.Listen("unix", path)
}
37 changes: 37 additions & 0 deletions tests/cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package cli
import (
"bytes"
"encoding/hex"
"errors"
"fmt"
"io/ioutil"
"os"
Expand Down Expand Up @@ -1033,3 +1034,39 @@ func TestMountCreat(t *testing.T) {
test_helpers.UnmountPanic(mnt)
}
}

// https://github.com/rfjakob/gocryptfs/issues/776
func TestOrphanedSocket(t *testing.T) {
cDir := test_helpers.InitFS(t)
ctlSock := cDir + ".sock"
mnt := cDir + ".mnt"
test_helpers.MountOrFatal(t, cDir, mnt, "-extpass", "echo test", "-wpanic=false", "-ctlsock", ctlSock)

mnt2 := cDir + ".mnt2"
err := test_helpers.Mount(cDir, mnt2, false, "-extpass", "echo test", "-wpanic=false", "-ctlsock", ctlSock)
exitCode := test_helpers.ExtractCmdExitCode(err)
if exitCode != exitcodes.CtlSock {
t.Errorf("wrong exit code: want=%d, have=%d", exitcodes.CtlSock, exitCode)
}
test_helpers.UnmountPanic(mnt)

// Unmount returns before the gocryptfs process has terminated and before the
// socket file has been deleted. Wait out the deletion.
for i := 0; i < 100; i++ {
_, err := os.Stat(ctlSock)
if errors.Is(err, os.ErrNotExist) {
break
}
time.Sleep(time.Millisecond)
}

// Create orphaned socket file
err = syscall.Mknod(ctlSock, syscall.S_IFSOCK|0666, 0)
if err != nil {
t.Fatal(err)
}

// Should delete the socket file automatically and the mount should work
test_helpers.MountOrFatal(t, cDir, mnt, "-extpass", "echo test", "-wpanic=false", "-ctlsock", ctlSock)
test_helpers.UnmountPanic(mnt)
}

0 comments on commit 2c01b1a

Please sign in to comment.