fix: add symlink handling in createFirejailedBinary (#108)
All checks were successful
Update alr-git / changelog (push) Successful in 30s
All checks were successful
Update alr-git / changelog (push) Successful in 30s
closes #107 Reviewed-on: #108 Co-authored-by: Maxim Slipenko <no-reply@maxim.slipenko.com> Co-committed-by: Maxim Slipenko <no-reply@maxim.slipenko.com>
This commit is contained in:
@ -28,7 +28,6 @@ import (
|
||||
"github.com/goreleaser/nfpm/v2/files"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
|
||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/osutils"
|
||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh"
|
||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types"
|
||||
)
|
||||
@ -51,6 +50,92 @@ var binaryDirectories = []string{
|
||||
"/usr/local/bin/",
|
||||
}
|
||||
|
||||
func moveWithSymlinkHandling(src, dst string) error {
|
||||
srcInfo, err := os.Lstat(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get source info: %w", err)
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0o755); err != nil {
|
||||
return fmt.Errorf("failed to create destination directory: %w", err)
|
||||
}
|
||||
|
||||
if srcInfo.Mode()&os.ModeSymlink != 0 {
|
||||
return moveSymlink(src, dst)
|
||||
}
|
||||
|
||||
if err := os.Rename(src, dst); err != nil {
|
||||
return copyAndRemove(src, dst)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func moveSymlink(src, dst string) error {
|
||||
target, err := os.Readlink(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read symlink: %w", err)
|
||||
}
|
||||
|
||||
if err := os.Symlink(target, dst); err != nil {
|
||||
return fmt.Errorf("failed to create symlink: %w", err)
|
||||
}
|
||||
|
||||
if err := os.Remove(src); err != nil {
|
||||
os.Remove(dst)
|
||||
return fmt.Errorf("failed to remove original symlink: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyAndRemove(src, dst string) error {
|
||||
srcFile, err := os.Open(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open source: %w", err)
|
||||
}
|
||||
defer srcFile.Close()
|
||||
|
||||
dstFile, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create destination: %w", err)
|
||||
}
|
||||
defer dstFile.Close()
|
||||
|
||||
if _, err := io.Copy(dstFile, srcFile); err != nil {
|
||||
return fmt.Errorf("failed to copy content: %w", err)
|
||||
}
|
||||
|
||||
srcInfo, err := srcFile.Stat()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get source stats: %w", err)
|
||||
}
|
||||
|
||||
if err := dstFile.Chmod(srcInfo.Mode()); err != nil {
|
||||
return fmt.Errorf("failed to set permissions: %w", err)
|
||||
}
|
||||
|
||||
if err := os.Remove(src); err != nil {
|
||||
return fmt.Errorf("failed to remove source: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func moveFileWithErrorHandling(src, dst string) error {
|
||||
err := moveWithSymlinkHandling(src, dst)
|
||||
if err != nil {
|
||||
if os.IsPermission(err) {
|
||||
return fmt.Errorf("permission denied: %w", err)
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return fmt.Errorf("source file does not exist: %w", err)
|
||||
}
|
||||
return fmt.Errorf("failed to move file: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyFirejailIntegration(
|
||||
vars *alrsh.Package,
|
||||
dirs types.Directories,
|
||||
@ -143,12 +228,15 @@ func createFirejailedBinary(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := osutils.Move(content.Source, filepath.Join(dirs.PkgDir, origFilePath)); err != nil {
|
||||
if err := moveFileWithErrorHandling(filepath.Join(dirs.PkgDir, content.Destination), filepath.Join(dirs.PkgDir, origFilePath)); err != nil {
|
||||
return nil, fmt.Errorf("failed to move original binary: %w", err)
|
||||
}
|
||||
|
||||
content.Type = "file"
|
||||
content.Source = filepath.Join(dirs.PkgDir, content.Destination)
|
||||
|
||||
// Create wrapper script
|
||||
if err := createWrapperScript(content.Source, origFilePath, dest); err != nil {
|
||||
if err := createWrapperScript(filepath.Join(dirs.PkgDir, content.Destination), origFilePath, dest); err != nil {
|
||||
return nil, fmt.Errorf("failed to create wrapper script: %w", err)
|
||||
}
|
||||
|
||||
|
@ -138,7 +138,10 @@ func TestCreateFirejailedBinary(t *testing.T) {
|
||||
os.MkdirAll(pkgDir, 0o755)
|
||||
os.MkdirAll(scriptDir, 0o755)
|
||||
|
||||
srcBinary := filepath.Join(tmpDir, "test-binary")
|
||||
binDir := filepath.Join(pkgDir, "usr", "bin")
|
||||
os.MkdirAll(binDir, 0o755)
|
||||
|
||||
srcBinary := filepath.Join(binDir, "test-binary")
|
||||
os.WriteFile(srcBinary, []byte("#!/bin/bash\necho test"), 0o755)
|
||||
|
||||
defaultProfile := filepath.Join(scriptDir, "default.profile")
|
||||
@ -154,7 +157,7 @@ func TestCreateFirejailedBinary(t *testing.T) {
|
||||
|
||||
content := &files.Content{
|
||||
Source: srcBinary,
|
||||
Destination: "./usr/bin/test-binary",
|
||||
Destination: "/usr/bin/test-binary",
|
||||
Type: "file",
|
||||
}
|
||||
|
||||
@ -172,7 +175,10 @@ func TestCreateFirejailedBinary(t *testing.T) {
|
||||
os.MkdirAll(pkgDir, 0o755)
|
||||
os.MkdirAll(scriptDir, 0o755)
|
||||
|
||||
srcBinary := filepath.Join(tmpDir, "special-binary")
|
||||
binDir := filepath.Join(pkgDir, "usr", "bin")
|
||||
os.MkdirAll(binDir, 0o755)
|
||||
|
||||
srcBinary := filepath.Join(binDir, "special-binary")
|
||||
os.WriteFile(srcBinary, []byte("#!/bin/bash\necho special"), 0o755)
|
||||
|
||||
defaultProfile := filepath.Join(scriptDir, "default.profile")
|
||||
@ -191,7 +197,7 @@ func TestCreateFirejailedBinary(t *testing.T) {
|
||||
|
||||
content := &files.Content{
|
||||
Source: srcBinary,
|
||||
Destination: "./usr/bin/special-binary",
|
||||
Destination: "/usr/bin/special-binary",
|
||||
Type: "file",
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user