Create /etc/pristine/ containing unmodified copies of conffiles

Registered by James Hunt

Currently, dpkg is aware of which files in a package are conffiles, the conffiles checksums and where those conffiles live on the system once the package is installed.

However, there are problems:

(1) What if the user modifies a conffile incorrectly such that the service no longer starts or behaves erratically?
(2) What if the user modifies an Upstart job conffile such that the system no longer boots?
      (This is the same problem as (1) but results in a significantly worse outcome!)
(3) What if the user cannot remember what changes they made to invalidate the conffile (and forgot to backup the unmodified conffile)?

There are many facilities available to help with (3) including version-control systems and configuration management systems. However, the default Ubuntu system should have a *simple* way to mitigate some of the problem scenarios.

The proposal is to modify dpkg either directly or by way of triggers such that every conffile is installed as normal but an additional copy of the conffile is placed in /etc/pristine/ (or some sub-directory). The files will all be given the same owner+group as the corresponding original conffile but permissions will be set to 0440 to discourage inadvertent modification.

This gives the following benefits:

(a) Problem (1) can be solved easily since the user can use diff(1) to compare their modified conffile with the pristine version
     in /etc/pristine/.

(b) Problem (2) can be solved in the same way as Problem (1), but there is some extra magic available to help the user:

If they have modified /etc/init/*.conf directly, or even created /etc/init/*.override files to modify the .conf file indirectly, we could add a new boot option that would invoke Upstart like this:

init --confdir /etc/pristine/init/ --startup-event=emergency-boot --no-log --no-sessions --debug

Doing this would ensure that the system will boot *using the pristine conffiles* installed in /etc/pristine/init/ rather than the
potentially corrupted /etc/init/*.conf files. We could then start a job based on the 'emergency-boot' event that would guide the user to restoring their system to a normally booting one. We could just show the user which job files/override files they have changed by date and offer to revert the changes but there are a few possibilities. We could even warn the user if they leave /etc/init/ in a condition different from /etc/pristine/init/ but the expectation is that at the end of the recovery process, all future boots will behave as expected.

(c) By having a pristine copy of each conffile of the system, it would also be possible to provide 3-way merge facilities in the future when dpkg could show the user the following on package upgrade:

- the locally modified conffile
- the local pristine version of the conffile
- the new about-to-be-installed pristine conffile

The costs of creating /etc/pristine/:

- Extra disk space consumed

Taking two 12.04 systems as examples:

package count: 1751
size of conffiles: 11M

package count: 4041
size of conffiles: 16M

A basic desktop install would show slightly lower figures, but these numbers are significant enough that we might want to audit the conffiles in a default install to consider a strategy.

For example, for the first system above, of the top 15 largest conffiles, 8 come from the 'brltty' package and those 8 files account for 20% of the total conffile size (2.2M).

Additional information/thoughts:

- FreeBSD already retains pristine copies of key system configuration files in /etc/defaults/. Using this name though could be confusing to Ubuntu users where /etc/default/ is used to store files that are *intended* to be modified.

- What about the 'ucf' ("Update Configuration File") and 'etckeeper' packages?
- Might be helpful to create /etc/pristine/README with a couple of lines of description?

Blueprint information

Status:
Not started
Approver:
Colin Watson
Priority:
Low
Drafter:
James Hunt
Direction:
Needs approval
Assignee:
None
Definition:
New
Series goal:
Accepted for quantal
Implementation:
Unknown
Milestone target:
None

Related branches

Sprints

Whiteboard

2012-05-04 cjwatson: By definition, pristine conffiles don't belong in /etc, as their purpose would be defeated were users to edit them. If we do this, some other bit of the filesystem namespace should be used, probably somewhere under /var (compare /var/lib/ucf).
2012-05-04 vorlon: in fact it probably needs to be /lib, to ensure early boot availability given the stated use.
2012-05-12 zackw: Please make the files be mode 0444, not 0440.

From the etherpad...

 Welcome to Ubuntu Developer Summit!
#uds-p #track #topic
put your session notes here

 * could we mitigate disk space overhead using reflinks somehow?
   - No, unfortunately - only btrfs supports them
* use a FS that has built-in rollback functionality to avoid making an actual copy.
* use etckeeper? what is VC overhead (/etc/init/.git/, /etc/init/.bzr ~= 3-10M)
* cost for ISO image = 2.8M compressed for etckeeper and dependencies
* cost for post-install system: 17.7M.
* friendly-recovery could interface with etckeeper to revert (not uncommit!) to some arbitrary known good commit to allow the normal boot to proceed. Add tags for last-known-good-boot. Change the tag when say DM launched and /etc is writeable.
* if we want a pristine copy, should not go in /etc - put it in /lib (can't be /var as may be on a separate partition).
* implemented through a descrete pkg so for small footprint devices with no/little chance users will modify conffiles (think ubuntu phone), this can be not implement by not installing that pkg thus saving the disk footprint hit
* ability to revert user-made-changes vs packaging changes on boot in friendly-recovery.
* should this also apply to server?
* should have ability to white/black list files:
   - don't store core files, /etc/passwd, /etc/shadow, /etc/cups/printers.conf (automatically updated by BrowsePoll), binary files, etc?
     - arguably the cups thing is a bug
* use btrfs snapshot hooks for pkg upgrade changes?
* is there a generic etckeeper facility to ignore files or patterns or do we add such patterns to /etc/.bzrignore? what if etckeeper changed to git say?
* test this as part of upgrade testing.
* discuss this change with QA.
* testing the friendly recovery as well.
* should we keep the .bzr/ directory *outside* of /etc (in /lib say?)
= Actions =
* review /etc for binary files and raise bugs to get them moved to /usr
* seed changes to include etckeeper
* review apt/dpkg post-install hook
  * add tags on commit
* friendly recovery interface
* ensure friendly-recovery disallow rolling back to previous release :-)
* add upstart job to add last-known-good-boot bzr tag
* ensure do-release-upgrade/upgrade-manager adds appropriate tags.
* consider changing dpkg to add tags for each pre-inst and post-inst phase of a package install/upgrade [OPTIONAL]. Only needs to be used if dpkg invoked directly - not done if dpkg called via apt.
* check to see if etckeeper can provide a "mainline" branch which is the "pristine" set of files and offer the user the option to "revert to pristine" [adam]
* [SECURITY]: get security team to review this plan (imagine an admin changes the root password in a VM, then publishes that VM on a website: consumers of that VM could get back to original copy of /etc/passwd, /etc/shadow and brute-force attack it).
  - NetworkManager wireless passwords, CUPS printer passwords, ldap.conf -- basically anything non-world-readable in /etc comes to mind here

(?)

Work Items

Work items:
Review /etc for binary files and raise bugs to get them moved to /usr - see bug 1001334: TODO
Seed changes to include etckeeper: TODO
Review apt/dpkg post-install hook: TODO
Add tags on commit: TODO
Friendly recovery interface: TODO
Ensure friendly-recovery disallows rolling back to previous release: TODO
Add upstart job to add last-known-good-boot bzr tag: TODO
Ensure do-release-upgrade/upgrade-manager adds appropriate tags: TODO
Consider changing dpkg to add tags for each pre-inst and post-inst phase of a package install/upgrade [OPTIONAL]: TODO
[adconrad] Determine if etckeeper can provide a "mainline" branch which is the "pristine" set of files and offer the user the option to "revert to pristine": TODO
[jamesodhunt] Get security team to review this plan: DONE