Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save PeterJRiches/00e2cb72bb42536ea7c3234763e80da7 to your computer and use it in GitHub Desktop.

Select an option

Save PeterJRiches/00e2cb72bb42536ea7c3234763e80da7 to your computer and use it in GitHub Desktop.
Prevent unintentional self-modification of executing Bash script

Prevent unintentional self-modification of executing Bash script

Rationale

I have a script that downloads and synchronises a project from a web service (where I co-edit this project) to my local machine, where I have the project's Git repo.1

Bash does not read a whole script file in at once, rather reading it in chunks as needed for interpretation. Therefore, it is possible for the file to be modified2 while the script is running. This is seldom useful, unless you want to be really esoteric!

My particular project is downloaded as a zipfile and then unzipped. I do not know whether unzip updates existing files in place (leading to the problem) or deletes and replaces them (sidestepping it). However, I was intrigued by the problem and got to thinking about how I would protect a script against accidentally altering itself and therefore going wrong.

Concept for solution

  • At the start of the script, copy self to a tempfile under a new name.
  • exec that file, killing the original (vulnerable) process and transferring control to the copy. The original script file may now safely be updated by the new process.

Wrinkles

  1. You may have spotted the major flaw in my concept: what's to stop an infinite loop of creating new files and transferring control to them until the disk is full?

  2. The current working directory will change between the original invocation and that of the safe copy.

Termination options

The script needs to know the difference between the first invocation, when it needs to protect itself, and the second, when it needs to get down to work!

  • Use $0, the name the script was executed as, to distinguish between the initial invocation and that of the safe copy, or
  • Set an environment variable when invoking the safe copy of the script, to flag that it is the safe copy.

Options to preserve current working directory (CWD)

Note: My initial script takes no parameters, and operates on the current working directory.

  • Pass the directory to be worked on as an optional parameter, with the CWD as default. Definitely pass it when invoking the safe copy of the script, but the user can choose whether to pass a path.
  • Set an environment variable for the CWD when invoking the safe copy of the script.

Footnotes

  1. The web service does have paid options for Git or GitHub integration, but this project is not generating any income, so although I'd love to follow best practice, I have to fudge it for now.

  2. --modified in place, not replaced with a new file of the same name: Were the file to be replaced, the script would continue reading the original file from the original inode, and the new file would be assigned a new inode by the operating system, despite it having the same name.

#!/bin/env bash
# Protection part
# Work part
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment