次のように、「echo」(または他のBash組み込み機能)を使用してターゲットファイル(通常のLinuxではrootとして)に安全に書きたいと思います。
echo "foo" > /destination/dir/filename
ただし、問題は、通常のシステムユーザーが/ detination / 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
。 (そうでない場合は、root以外のユーザーがサブディレクトリにアクセスまたは作成できないように十分に制限された権限を使用して最上位ディレクトリを作成します。階層が完了したら権限を軽減します。)
mktemp
1つの方法は、ターゲットディレクトリ内に一時的ですが、一意の名前を持つファイルを作成することです。その後、その内容が記録され、最後にターゲット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ではありませんが、次のものがあります。推奨事項の実装これには利用可能です。