shadow1ng/fscan · error

Unable to create persistence directory

Error message

Unable to create persistence directory

What it means

copyToPersistPath tries a list of candidate persistence directories (via os.MkdirAll) and, if it could not create or use any of them (targetDir stays empty), returns this error. It typically means every candidate path was unwritable or failed to be created due to permissions or a full filesystem.

Source

Thrown at plugins/local/crontask.go:169

	// 获取用户目录
	if usr, err := user.Current(); err == nil {
		userDirs := []string{
			filepath.Join(usr.HomeDir, ".local", "bin"),
			filepath.Join(usr.HomeDir, ".cache"),
		}
		persistDirs = append(userDirs, persistDirs...)
	}

	var targetDir string
	for _, dir := range persistDirs {
		if err := os.MkdirAll(dir, 0755); err == nil {
			targetDir = dir
			break
		}
	}

	if targetDir == "" {
		return "", fmt.Errorf("%s", i18n.GetText("persistence_dir_create_failed"))
	}

	// 生成隐藏文件名
	basename := filepath.Base(p.targetFile)
	hiddenName := "." + strings.TrimSuffix(basename, filepath.Ext(basename))
	if p.isScriptFile() {
		hiddenName += ".sh"
	}

	targetPath := filepath.Join(targetDir, hiddenName)

	// 复制文件
	err := p.copyFile(p.targetFile, targetPath)
	if err != nil {
		return "", err
	}

	// 设置执行权限

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Re-run as root (or with CAP_DAC_OVERRIDE) so the persistence directories can be created.
  2. Pre-create one of the candidate directories and grant the current user write permission.
  3. Point the persistence location at a user-writable path (e.g. user crontab area) if root is unavailable.
  4. Check disk space / mount flags (ro) if permissions look correct.

Example fix

// before
$ ./agent --plugin crontask   # running as low-priv user
// after
$ sudo ./agent --plugin crontask
# or, pre-provision:
$ sudo mkdir -p /var/spool/cron && sudo chown agent /var/spool/cron
Defensive patterns

Strategy: try-catch

Validate before calling

for _, dir := range candidateDirs {
    if info, err := os.Stat(dir); err == nil && info.IsDir() {
        if f, err := os.CreateTemp(dir, ".w"); err == nil { f.Close(); os.Remove(f.Name()); break }
    }
}

Try / catch

res := plugin.Scan(ctx, cfg)
if !res.Success && strings.Contains(res.Error.Error(), "persistence directory") {
    return fmt.Errorf("needs root or writable persistence dir: %w", res.Error)
}

Prevention

When it happens

Trigger: Running the crontask plugin as a non-root user when all candidate persistence directories require root; read-only root filesystem (containers); MkdirAll failing on every candidate due to permission or disk errors.

Common situations: Persistence attempted on a hardened/minimal container without write access to standard cron locations; running the agent under a restricted service account; immutable or read-only /etc, /var, or $HOME.

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06). Data as JSON: /api/errors/47f745677d99811c. Report an issue: GitHub.