убрана лишняя зависимость bindfs и избыточное использование дополнительного пользователя alr
This commit is contained in:
		| @@ -44,9 +44,9 @@ var HandshakeConfig = plugin.HandshakeConfig{ | ||||
|  | ||||
| func setCommonCmdEnv(cmd *exec.Cmd) { | ||||
| 	cmd.Env = []string{ | ||||
| 		"HOME=/var/cache/alr", | ||||
| 		"LOGNAME=alr", | ||||
| 		"USER=alr", | ||||
| 		"HOME=" + os.Getenv("HOME"), | ||||
| 		"LOGNAME=" + os.Getenv("USER"), | ||||
| 		"USER=" + os.Getenv("USER"), | ||||
| 		"PATH=/usr/bin:/bin:/usr/local/bin", | ||||
| 	} | ||||
| 	for _, env := range os.Environ() { | ||||
| @@ -102,9 +102,7 @@ func getSafeExecutor[T any](subCommand, pluginName string) (T, func(), error) { | ||||
| 		Cmd:             cmd, | ||||
| 		Logger:          logger.GetHCLoggerAdapter(), | ||||
| 		SkipHostEnv:     true, | ||||
| 		UnixSocketConfig: &plugin.UnixSocketConfig{ | ||||
| 			Group: "alr", | ||||
| 		}, | ||||
| 		UnixSocketConfig: &plugin.UnixSocketConfig{}, | ||||
| 		SyncStderr: os.Stderr, | ||||
| 	}) | ||||
| 	rpcClient, err := client.Client() | ||||
|   | ||||
| @@ -23,6 +23,7 @@ import ( | ||||
| 	"os" | ||||
| 	"strings" | ||||
|  | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/constants" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/dl" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/dlcache" | ||||
| ) | ||||
| @@ -74,7 +75,9 @@ func (s *SourceDownloader) DownloadSources( | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		opts.DlCache = dlcache.New(s.cfg.GetPaths().CacheDir) | ||||
| 		// Используем временную директорию для загрузок | ||||
| 		// dlcache.New добавит свой подкаталог "dl" внутри | ||||
| 		opts.DlCache = dlcache.New(constants.TempDir) | ||||
|  | ||||
| 		err := dl.Download(ctx, opts) | ||||
| 		if err != nil { | ||||
|   | ||||
| @@ -40,6 +40,7 @@ import ( | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/cpu" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/overrides" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/utils" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types" | ||||
| @@ -47,15 +48,21 @@ import ( | ||||
|  | ||||
| // Функция prepareDirs подготавливает директории для сборки. | ||||
| func prepareDirs(dirs types.Directories) error { | ||||
| 	err := os.RemoveAll(dirs.BaseDir) // Удаляем базовую директорию, если она существует | ||||
| 	// Пробуем удалить базовую директорию, если она существует | ||||
| 	err := os.RemoveAll(dirs.BaseDir) | ||||
| 	if err != nil { | ||||
| 		// Если не можем удалить (например, принадлежит root), игнорируем | ||||
| 		// и попробуем создать новые директории | ||||
| 	} | ||||
| 	 | ||||
| 	// Создаем директории с правильным владельцем для /tmp/alr с setgid битом | ||||
| 	err = utils.EnsureTempDirWithRootOwner(dirs.SrcDir, 0o2775) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	err = os.MkdirAll(dirs.SrcDir, 0o755) // Создаем директорию для источников | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return os.MkdirAll(dirs.PkgDir, 0o755) // Создаем директорию для пакетов | ||||
| 	 | ||||
| 	// Создаем директорию для пакетов с setgid битом | ||||
| 	return utils.EnsureTempDirWithRootOwner(dirs.PkgDir, 0o2775) | ||||
| } | ||||
|  | ||||
| // Функция buildContents создает секцию содержимого пакета, которая содержит файлы, | ||||
|   | ||||
| @@ -21,6 +21,7 @@ package config | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
|  | ||||
| 	"github.com/goccy/go-yaml" | ||||
| @@ -55,7 +56,12 @@ func defaultConfigKoanf() *koanf.Koanf { | ||||
| 		"ignorePkgUpdates": []string{}, | ||||
| 		"logLevel":         "info", | ||||
| 		"autoPull":         true, | ||||
| 		"repos":            []types.Repo{}, | ||||
| 		"repos": []types.Repo{ | ||||
| 			{ | ||||
| 				Name: "alr-default", | ||||
| 				URL:  "https://gitea.plemya-x.ru/Plemya-x/alr-default.git", | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	if err := k.Load(confmap.Provider(defaults, "."), nil); err != nil { | ||||
| 		panic(k) | ||||
| @@ -98,8 +104,15 @@ func (c *ALRConfig) Load() error { | ||||
| 	c.paths.UserConfigPath = constants.SystemConfigPath | ||||
| 	c.paths.CacheDir = constants.SystemCachePath | ||||
| 	c.paths.RepoDir = filepath.Join(c.paths.CacheDir, "repo") | ||||
| 	c.paths.PkgsDir = filepath.Join(c.paths.CacheDir, "pkgs") | ||||
| 	c.paths.DBPath = filepath.Join(c.paths.CacheDir, "db") | ||||
| 	c.paths.PkgsDir = filepath.Join(constants.TempDir, "pkgs")  // Перемещаем в /tmp/alr/pkgs | ||||
| 	c.paths.DBPath = filepath.Join(c.paths.CacheDir, "alr.db") | ||||
|  | ||||
| 	// Проверяем существование кэш-директории, но не пытаемся создать | ||||
| 	if _, err := os.Stat(c.paths.CacheDir); err != nil { | ||||
| 		if !os.IsNotExist(err) { | ||||
| 			return fmt.Errorf("failed to check cache directory: %w", err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
| @@ -19,6 +19,6 @@ package constants | ||||
| const ( | ||||
| 	SystemConfigPath = "/etc/alr/alr.toml" | ||||
| 	SystemCachePath  = "/var/cache/alr" | ||||
| 	AlrRunDir        = "/var/run/alr" | ||||
| 	TempDir          = "/tmp/alr" | ||||
| 	PrivilegedGroup  = "wheel" | ||||
| ) | ||||
|   | ||||
| @@ -21,7 +21,10 @@ package db | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"log/slog" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
|  | ||||
| 	"github.com/leonelquinteros/gotext" | ||||
| 	_ "modernc.org/sqlite" | ||||
| @@ -54,6 +57,21 @@ func New(config Config) *Database { | ||||
|  | ||||
| func (d *Database) Connect() error { | ||||
| 	dsn := d.config.GetPaths().DBPath | ||||
| 	 | ||||
| 	// Проверяем директорию для БД | ||||
| 	dbDir := filepath.Dir(dsn) | ||||
| 	if _, err := os.Stat(dbDir); err != nil { | ||||
| 		if os.IsNotExist(err) { | ||||
| 			// Директория не существует - пытаемся создать | ||||
| 			if mkErr := os.MkdirAll(dbDir, 0775); mkErr != nil { | ||||
| 				// Не смогли создать - вернём ошибку, пользователь должен использовать alr fix | ||||
| 				return fmt.Errorf("cache directory does not exist, please run 'alr fix' to create it: %w", mkErr) | ||||
| 			} | ||||
| 		} else { | ||||
| 			return fmt.Errorf("failed to check database directory: %w", err) | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	engine, err := xorm.NewEngine("sqlite", dsn) | ||||
| 	// engine.SetLogLevel(log.LOG_DEBUG) | ||||
| 	// engine.ShowSQL(true) | ||||
|   | ||||
| @@ -17,12 +17,9 @@ | ||||
| package utils | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"os/user" | ||||
| 	"strconv" | ||||
| 	"syscall" | ||||
|  | ||||
| 	"github.com/leonelquinteros/gotext" | ||||
| 	"github.com/urfave/cli/v2" | ||||
| @@ -32,114 +29,12 @@ import ( | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/constants" | ||||
| ) | ||||
|  | ||||
| func GetUidGidAlrUserString() (string, string, error) { | ||||
| 	u, err := user.Lookup("alr") | ||||
| 	if err != nil { | ||||
| 		return "", "", err | ||||
| 	} | ||||
|  | ||||
| 	return u.Uid, u.Gid, nil | ||||
| } | ||||
|  | ||||
| func GetUidGidAlrUser() (int, int, error) { | ||||
| 	strUid, strGid, err := GetUidGidAlrUserString() | ||||
| 	if err != nil { | ||||
| 		return 0, 0, err | ||||
| 	} | ||||
|  | ||||
| 	uid, err := strconv.Atoi(strUid) | ||||
| 	if err != nil { | ||||
| 		return 0, 0, err | ||||
| 	} | ||||
| 	gid, err := strconv.Atoi(strGid) | ||||
| 	if err != nil { | ||||
| 		return 0, 0, err | ||||
| 	} | ||||
|  | ||||
| 	return uid, gid, nil | ||||
| } | ||||
|  | ||||
| func DropCapsToAlrUser() error { | ||||
| 	uid, gid, err := GetUidGidAlrUser() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	err = syscall.Setgid(gid) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	err = syscall.Setuid(uid) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return EnsureIsAlrUser() | ||||
| } | ||||
|  | ||||
| func ExitIfCantDropGidToAlr() cli.ExitCoder { | ||||
| 	_, gid, err := GetUidGidAlrUser() | ||||
| 	if err != nil { | ||||
| 		return cliutils.FormatCliExit("cannot get gid alr", err) | ||||
| 	} | ||||
| 	err = syscall.Setgid(gid) | ||||
| 	if err != nil { | ||||
| 		return cliutils.FormatCliExit("cannot get setgid alr", err) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // ExitIfCantDropCapsToAlrUser attempts to drop capabilities to the already | ||||
| // running user. Returns a cli.ExitCoder with an error if the operation fails. | ||||
| // See also [ExitIfCantDropCapsToAlrUserNoPrivs] for a version that also applies | ||||
| // no-new-privs. | ||||
| func ExitIfCantDropCapsToAlrUser() cli.ExitCoder { | ||||
| 	err := DropCapsToAlrUser() | ||||
| 	if err != nil { | ||||
| 		return cliutils.FormatCliExit(gotext.Get("Error on dropping capabilities"), err) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func ExitIfCantSetNoNewPrivs() cli.ExitCoder { | ||||
| 	if err := NoNewPrivs(); err != nil { | ||||
| 		return cliutils.FormatCliExit("error on NoNewPrivs", err) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // ExitIfCantDropCapsToAlrUserNoPrivs combines [ExitIfCantDropCapsToAlrUser] with [ExitIfCantSetNoNewPrivs] | ||||
| func ExitIfCantDropCapsToAlrUserNoPrivs() cli.ExitCoder { | ||||
| 	if err := ExitIfCantDropCapsToAlrUser(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if err := ExitIfCantSetNoNewPrivs(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // IsNotRoot проверяет, что текущий пользователь не является root | ||||
| func IsNotRoot() bool { | ||||
| 	return os.Getuid() != 0 | ||||
| } | ||||
|  | ||||
| func EnsureIsAlrUser() error { | ||||
| 	uid, gid, err := GetUidGidAlrUser() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	newUid := syscall.Getuid() | ||||
| 	if newUid != uid { | ||||
| 		return errors.New("uid don't matches requested") | ||||
| 	} | ||||
| 	newGid := syscall.Getgid() | ||||
| 	if newGid != gid { | ||||
| 		return errors.New("gid don't matches requested") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // EnuseIsPrivilegedGroupMember проверяет, что пользователь является членом привилегированной группы (wheel) | ||||
| func EnuseIsPrivilegedGroupMember() error { | ||||
| 	currentUser, err := user.Current() | ||||
| 	if err != nil { | ||||
| @@ -164,26 +59,6 @@ func EnuseIsPrivilegedGroupMember() error { | ||||
| 	return cliutils.FormatCliExit(gotext.Get("You need to be a %s member to perform this action", constants.PrivilegedGroup), nil) | ||||
| } | ||||
|  | ||||
| func EscalateToRootGid() error { | ||||
| 	return syscall.Setgid(0) | ||||
| } | ||||
|  | ||||
| func EscalateToRootUid() error { | ||||
| 	return syscall.Setuid(0) | ||||
| } | ||||
|  | ||||
| func EscalateToRoot() error { | ||||
| 	err := EscalateToRootUid() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	err = EscalateToRootGid() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func RootNeededAction(f cli.ActionFunc) cli.ActionFunc { | ||||
| 	return func(ctx *cli.Context) error { | ||||
| 		deps, err := appbuilder. | ||||
|   | ||||
| @@ -16,8 +16,44 @@ | ||||
|  | ||||
| package utils | ||||
|  | ||||
| import "golang.org/x/sys/unix" | ||||
| import ( | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"strings" | ||||
|  | ||||
| 	"golang.org/x/sys/unix" | ||||
| ) | ||||
|  | ||||
| func NoNewPrivs() error { | ||||
| 	return unix.Prctl(unix.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) | ||||
| } | ||||
|  | ||||
| // EnsureTempDirWithRootOwner создает каталог в /tmp/alr с правами для группы wheel | ||||
| // Все каталоги в /tmp/alr принадлежат root:wheel с правами 775 | ||||
| // Для других каталогов использует стандартные права | ||||
| func EnsureTempDirWithRootOwner(path string, mode os.FileMode) error { | ||||
| 	if strings.HasPrefix(path, "/tmp/alr") { | ||||
| 		// Сначала создаем директорию обычным способом | ||||
| 		err := os.MkdirAll(path, mode) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		 | ||||
| 		// Все каталоги в /tmp/alr доступны для группы wheel | ||||
| 		// Устанавливаем setgid бит (2775), чтобы новые файлы наследовали группу | ||||
| 		permissions := "2775" | ||||
| 		group := "wheel" | ||||
| 		 | ||||
| 		// Устанавливаем права с setgid битом | ||||
| 		err = exec.Command("sudo", "chmod", permissions, path).Run() | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		 | ||||
| 		// Устанавливаем владельца root:wheel | ||||
| 		return exec.Command("sudo", "chown", "root:"+group, path).Run() | ||||
| 	} | ||||
| 	 | ||||
| 	// Для остальных каталогов обычное создание | ||||
| 	return os.MkdirAll(path, mode) | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user