Sometimes, Bash scripts need to create temporary files or temporary directories.

The common practice is to generate a file inside the /tmp directory yourself, which has many drawbacks. This article describes how to safely handle temporary files.

Security of temporary files

Creating temporary files directly, especially in the /tmp directory, often leads to security problems.

First, the /tmp directory is readable by everyone and any user can write to it. The temporary files created are also readable by everyone.

1
2
3
$ touch /tmp/info.txt
$ ls -l /tmp/info.txt
-rw-r--r-- 1 ruanyf ruanyf 0 12月 28 17:12 /tmp/info.txt

The above command creates a file directly in the /tmp directory, which is readable by everyone by default.

Second, if the attacker knows the file name of the temporary file, he can create a symbolic link to the temporary file, which may cause the system to run abnormally. The attacker may also provide some malicious data to the script. Therefore, it is better to use unpredictable and different file names for temporary files every time.

Finally, temporary files should be deleted when they are finished being used. However, scripts often neglect to clean up temporary files when they exit unexpectedly.

Best practices for temporary files

The script generates temporary files and should follow the following rules.

  • Check if the file already exists before creating it.
  • Make sure the temporary file has been created successfully.
  • Temporary files must have permission restrictions.
  • Temporary files are to use unpredictable file names.
  • To delete temporary files when the script exits (use the trap command).

Usage of the mktemp command

The mktemp command is designed to create temporary files securely. Although it does not check for the existence of a temporary file before creating it, it supports unique file names and a purge mechanism, thus mitigating the risk of security attacks.

Run the mktemp command directly to generate a temporary file.

1
2
3
4
5
6

$ mktemp
/tmp/tmp.4GcsWSG4vj

$ ls -l /tmp/tmp.4GcsWSG4vj
-rw------- 1 ruanyf ruanyf 0 12月 28 12:49 /tmp/tmp.4GcsWSG4vj

In the above command, the mktemp command generates temporary files with random names and permissions that only the user can read and write.

The Bash script uses the mktemp command as follows.

1
2
3
4
#!/bin/bash

TMPFILE=$(mktemp)
echo "Our temp file is $TMPFILE"

To ensure that the temporary file is created successfully, it is a good idea to use the OR operator (||) after the mktemp command to specify that the script will exit if the creation fails.

1
2
3
4
#!/bin/bash

TMPFILE=$(mktemp) || exit 1
echo "Our temp file is $TMPFILE"

To ensure that temporary files are deleted when the script exits, you can use the trap command to specify a purge operation on exit (see later for details).

1
2
3
4
5
6
7

#!/bin/bash

trap 'rm -f "$TMPFILE"' EXIT

TMPFILE=$(mktemp) || exit 1
echo "Our temp file is $TMPFILE"

Parameters of the mktemp command

The -d parameter creates a temporary directory.

1
2
3

$ mktemp -d
/tmp/tmp.Wcau5UjmN6

The -p argument specifies the directory where the temporary files are located. The default is to use the directory specified by the $TMPDIR environment variable, if this variable is not set, then the /tmp directory is used.

1
2
3

$ mktemp -p /home/ruanyf/
/home/ruanyf/tmp.FOKEtvs2H3

The -t argument specifies a file name template for temporary files, which must contain at least three consecutive X characters at the end, indicating random characters; a minimum of six X is recommended. The default filename template is tmp. followed by ten random characters.

1
2
$ mktemp -t mytemp.XXXXXXX
/tmp/mytemp.yZ1HgZV

Usage of the trap command

The trap command is used to respond to system signals in Bash scripts.

The most common system signal is SIGINT (interrupt), which is the signal generated by pressing Ctrl + C. The -trap command has a -l argument, which lists all system signals.

1
2
3
4
$ trap -l
 1) SIGHUP   2) SIGINT   3) SIGQUIT
 4) SIGILL   5) SIGTRAP  6) SIGABRT
 ... ...

The command format of trap is as follows.

1
$ trap [action] [signal]

In the above code, the “action” is a Bash command and the “signal” is commonly used as follows.

  • HUP: number 1, the script is disconnected from the terminal where it is running.
  • INT: number 2, the user presses Ctrl + C with the intention of aborting the script.
  • QUIT: number 3, the user presses Ctrl + slash with the intention of exiting the script.
  • KILL: number 9, this signal is used to kill the process.
  • TERM: number 15, this is the default signal issued by the kill command.
  • EXIT: number 0, this is not a system signal, but a Bash script-specific signal that is generated whenever the script is exited, regardless of the situation.

The trap command is written in response to the EXIT signal as follows.

1
$ trap 'rm -f "$TMPFILE"' EXIT

In the above command, the script executes rm -f "$TMPFILE" when it encounters the EXIT signal.

A common usage scenario for the trap command is to specify the cleanup command to be executed on exit in a Bash script.

1
2
3
4
5
6
7
8
9
#!/bin/bash

trap 'rm -f "$TMPFILE"' EXIT

TMPFILE=$(mktemp) || exit 1
ls /etc > $TMPFILE
if grep -qi "kernel" $TMPFILE; then
  echo 'find'
fi

In the above code, the EXIT signal is generated whether the script ends normally or the user presses Ctrl + C to terminate, thus triggering the deletion of the temporary file.

Note that the trap command must be placed at the beginning of the script. Otherwise, any command above it that causes the script to exit will not be caught by it.

If trap needs to trigger multiple commands, you can wrap a Bash function.

1
2
3
4
5
6
7
8

function egress {
  command1
  command2
  command3
}

trap egress EXIT

Reference https://www.ruanyifeng.com/blog/2019/12/mktemp.html