As a follow-up question to this one, I thought of another approach which builds off of @caf's answer for the case where I want to append to file name
and create it if it does not exist.
Here is what I came up with:
- Create a temporary directory with mode 0700 in a system temporary directory on the same filesystem as file
name
. Open filename
for reading only andO_CREAT
. The OS may followname
if it is a symbolic link.Usemkstemp
to create a temporary file in the temporary directory and attempt torename
the temporary file that was created bymkstemp
to filename
.
Open filename
for reading only andO_CREAT | O_EXCL
.- Iteratively attempt to make a hard link to
name
at a temporary name within the temporary directory. If ever thelink
call fails due to an error other than "the link target exists" (errnoEEXIST
), then exit. (Maybe someone has come along and removed the file atname
, who knows?) - Use
lstat
ontemp_name
(the hard link). IfS_ISLNK(lst.st_mode)
, then exit. open
temp_name
for writing & append (O_WRONLY | O_APPEND
).- Write everything out. Close the file descriptor.
unlink
the hard link.- Remove the temporary directory.
(All of this, by the way, is for an open source project that I am working on. You can view the source of my implementation of this approach here.)
Is this procedure safe against symbolic link attacks? For example, is it possible for a malicious process to ensure that the inode for name
represents a regular file for the duration of the lstat
check, then make the inode a symbolic link with the temp_name
hard link now pointing to the new, symbolic link?
I am assuming that a malicious process cannot affect temp_name
.
EDIT: link
does not overwrite the target so creating a "placeholder" temporary file is not what I wanted to do. I have since updated my code and have updated the steps above.
EDIT2: I am now using an alternate procedure for step 2 to create file name
if it does not exist which I do not think is susceptible to this problem.
EDIT3: Even better than renaming a temporary, empty, regular file to name
, which also has the effect of unlinking name
, then renaming, I can open the file O_RDONLY | O_CREAT | O_EXCL
.
The POSIX standard for open
states:
If
O_EXCL
andO_CREAT
are set, andpath
names a symbolic link,open()
shall fail and seterrno
toEEXIST
, regardless of the contents of the symbolic link.