logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma git clone https://anongit.hacktivis.me/git/pleroma.git/
commit: 00d536d9e2c6c76d88724e5c75cc82a857519c65
parent bc75bb35fac172c021f6caa3ee8624cbc5325c9c
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Thu, 30 Jan 2025 15:50:50 +0100

backports: Copy mkdir_p TOCTOU fix from elixir PR 14242

See: https://github.com/elixir-lang/elixir/pull/14242

Diffstat:

Achangelog.d/toctou-mkdir.fix2++
Alib/pleroma/backports.ex72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 74 insertions(+), 0 deletions(-)

diff --git a/changelog.d/toctou-mkdir.fix b/changelog.d/toctou-mkdir.fix @@ -0,0 +1 @@ +Backport [Elixir PR 14242](https://github.com/elixir-lang/elixir/pull/14242) fixing racy mkdir and lack of error handling of parent directory creation +\ No newline at end of file diff --git a/lib/pleroma/backports.ex b/lib/pleroma/backports.ex @@ -0,0 +1,72 @@ +# Copyright 2012 Plataformatec +# Copyright 2021 The Elixir Team +# SPDX-License-Identifier: Apache-2.0 + +defmodule Pleroma.Backports do + import File, only: [dir?: 1] + + # <https://github.com/elixir-lang/elixir/pull/14242> + # To be removed when we require Elixir 1.19 + @doc """ + Tries to create the directory `path`. + + Missing parent directories are created. Returns `:ok` if successful, or + `{:error, reason}` if an error occurs. + + Typical error reasons are: + + * `:eacces` - missing search or write permissions for the parent + directories of `path` + * `:enospc` - there is no space left on the device + * `:enotdir` - a component of `path` is not a directory + + """ + @spec mkdir_p(Path.t()) :: :ok | {:error, File.posix() | :badarg} + def mkdir_p(path) do + do_mkdir_p(IO.chardata_to_string(path)) + end + + defp do_mkdir_p("/") do + :ok + end + + defp do_mkdir_p(path) do + parent = Path.dirname(path) + + if parent == path do + :ok + else + case do_mkdir_p(parent) do + :ok -> + case :file.make_dir(path) do + {:error, :eexist} -> + if dir?(path), do: :ok, else: {:error, :enotdir} + + other -> + other + end + + e -> + e + end + end + end + + @doc """ + Same as `mkdir_p/1`, but raises a `File.Error` exception in case of failure. + Otherwise `:ok`. + """ + @spec mkdir_p!(Path.t()) :: :ok + def mkdir_p!(path) do + case mkdir_p(path) do + :ok -> + :ok + + {:error, reason} -> + raise File.Error, + reason: reason, + action: "make directory (with -p)", + path: IO.chardata_to_string(path) + end + end +end