다음과 같이 "echo"(또는 다른 Bash 내장 기능)를 사용하여 대상 파일(일반 Linux에서 루트로)에 안전하게 쓰고 싶습니다.
echo "foo" > /destination/dir/filename
그러나 문제는 일반 시스템 사용자가 /destination/dir에 액세스할 수 있으므로 심볼릭 링크 조건이 발생할 위험이 있다는 것입니다.
C를 사용할 때 TOC-TOU를 방지하는 방법에 대한 모든 "방법"을 읽었으므로 심볼릭 링크를 확인하거나 제거한 다음 열지 마십시오(일반적인 조언은 open()에 O_NOFOLLOW를 사용하는 것 같습니다).
그러나 이 모든 것(커널 open() 및 해당 플래그에 대한 액세스)은 Bash를 통해 가능하지 않습니다(또는 제가 틀렸습니까?).
그때 나는 생각했다
- mktemp를 사용하여 임시 파일 만들기
- chown+chmod 임시 파일을 적절히
- 임시 파일에 쓸 내용을 씁니다.
- Bash 매개변수 "-T"를 사용하여 임시 파일을 대상 디렉터리로 이동합니다.
따라서 일부 Bash 의사 코드(어떤 곳에서는 오류 검사가 없음)
TEMPFILE=$(mktemp)
chown root:root $TEMPFILE
chmod 0600 $TEMPFILE
echo "contents" > $TEMPFILE
mv -T $TEMPFILE /destination/dir/filename
방금 시스템 파일에 대한 심볼릭 링크로 "/destination/dir/filename"을 사용하여 테스트했지만 작동합니다. "mv"는 임시 파일을 "filename"으로 올바르게 이동하고 심볼릭 링크는 제거됩니다(내 의도였습니다). , 파일을 덮어쓰지 않습니다.
안전/경쟁 조건 등의 문제가 누락되었다고 생각합니까?
감사해요:-)
답변1
안전하게 존재한다고 가정해보자 /destination/dir
. (그렇지 않은 경우 루트가 아닌 사용자가 하위 디렉터리에 액세스하거나 생성할 수 없도록 충분히 제한된 권한을 사용하여 최상위 디렉터리를 만듭니다. 그런 다음 계층 구조가 완료되면 권한을 완화합니다.)
mktemp
한 가지 방법은 대상 디렉터리 내에 임시이지만 고유한 이름을 가진 파일을 만드는 것입니다. 그런 다음 해당 내용이 기록되고 마지막으로 mv
대상에 기록됩니다.
중요한 점은 mv
동일한 파일 시스템에서 소스와 대상을 사용할 때 이름 바꾸기 프로세스의 일부로 대상이 제거된다는 것입니다. 이는 rename(2)
시스템 호출을 통해 커널 자체에서 수행되는 원자적 작업입니다.
이미 존재 하는 경우
newpath
해당 항목에 액세스하려는 다른 프로세스에서 누락된 항목을 찾을 수 없도록 자동으로 교체됩니다newpath
. 그러나 이름이 바뀌는 파일을 참조하는oldpath
창이 나타날 수 있습니다 .newpath
여러분의 구현과 매우 유사한 간단한 구현은 다음과 같습니다.
base='/destination/dir' # Use '.' for current directory
file='filename'
tf=$(mktemp "$base/XXXXXXXXXX.tmp") # Created with mode 600
echo "contents" >"$tf" # Always double-quote variables when used
if ! mv -Tf "$tf" "$base/$file"
then
echo "Error writing to $base/$file" >&2
rm -f "$tf" # Clean up temporary file
fi
POSIX 세계에서는 이에 상응하는 것을 달성하는 mv -T
것이 더 어렵습니다. 여기서는 임시 디렉토리를 생성할 수 있는 능력에 의존합니다. 실제 상황에서는 성공할 때까지 다른 디렉토리 이름을 반복하는 루프에서 처리하는 것이 가장 좋을 것입니다 mkdir
. 그러나 여기서는 한 번만 생성하려고 합니다.
base='/destination/dir' # Use '.' for current directory
file='filename'
td="$base/dir.$$.tmp" # Must be unique
if mkdir -m700 "$td" # Will fail if not unique
then
echo "contents" >"$td/$file"
if ! mv -f "$td/$file" "$base/" # Overwrite/replace $base/filename, or fail
then
echo "Error writing to $base/$file" >&2
fi
rm -rf "$td" # Clean up temporary directory
else
echo "Error creating temporary directory $td" >&2
fi
이 mktemp
명령도 POSIX는 아니지만 다음이 있습니다.권장 사항 구현이를 위해 사용 가능합니다.