Bug Investigation: Debian Bug #901952


I was inspired by Niels Thykier’s blog post asking for help with Debian RC bugs to see if I could help. I’m not a Debian Developer, so I was looking for bugs where that wasn’t much of a hurdle.

Searching udd (the “Ultimate Debian Database”) for RC bugs, sorted by most popular projects put a nice tar bug at the top, #901952.

Investigation

Whenever I look into a bug that has previous work, I will review but not trust those efforts.

I like to first understand as much context as possible from scratch. Too much is better than too little. In this case, the key error messages in the bug report meant nothing to me:

gbp:error: Error creating fdroidserver_1.0.6.orig.tar.gz: 
Pristine-tar couldn't checkout "fdroidserver_1.0.6.orig.tar.gz": 
xdelta: expected from file (/tmp/pristine-tar.SljdkfANnj/recreatetarball) of length 7557120 bytes

so I had a lot of investigation to do.

The bug had been filed against pristine-tar and reassigned to tar, though it was not clear that the fix would lie there.

In this case, since I wasn’t familiar with any of the software involved, there was quite a bit of poking around to get context.

First, I downloaded the source to gbp (git-buildpackage) to sort out what it was trying to do and where things were breaking.

The failing step was a pristine-tar checkout, which “regenerates a copy of the specified tarball”, per the man page. Basically, an earlier tar file and xdelta patch have been saved to the git repository for fdroidserver. The call to pristine-tar checkout verifies that it can create an identical tar file.

pristine-tar

pristine-tar helpfully has -v and -d options to show details of what it is doing. Unfortunately, neither showed enough of the command path for me to understand exactly what was going on. All the work is done in temporary directories and the debugging output wasn’t showing the setup of the contents of those directories.

Also making things tricky was that pristine-tar is very good at cleaning up all of those temporary directories, so I couldn’t debug after the fact.

On the positive side, pristine-tar’s main logic is in a single perl script. It is very easy to read, breakpoint, and step through. I simply had to breakpoint once everything was set up for the tar command in question. Then I could run a slightly modified command line and save the tar output somewhere I could review later.

tar has changed

Currently, Debian’s tar policy (on my machine) looks like:

tar:
  Installed: 1.30+dfsg-2
  Candidate: 1.30+dfsg-2
  Version table:
 *** 1.30+dfsg-2 700
        700 https://deb.debian.org/debian testing/main amd64 Packages
        600 https://deb.debian.org/debian unstable/main amd64 Packages
        100 /var/lib/dpkg/status
     1.29b-1.1 500
        500 https://deb.debian.org/debian stable/main amd64 Packages

This is perfect, because 1.30 was breaking things and 1.29 was not, according to the bug details. I could easily swap back and forth between them to test.

After doing so, the tar files were in fact different. The files with tricky Unicode characters in their names were zero-length when using 1.30.

Zero length? What the hell? It’s actually nothing too surprising. This was expected when the file in question is not found. The pristine-tar process makes sure that files in the manifest that are missing are saved as zero-length files.

The bug (or at least the changed behavior) was definitely in tar, no longer managing to find files mentioned in the manifest if they have weird characters. The next step was to figure out why.

Upstream tar

I headed to the upstream repo, specifically to the change log.

The only really likely change between 1.29 and 1.30 was:

2017-11-09	Fix --verbatim-files-from

since this is the option that pristine-tar is using to make sure the manifest is read without unwanted processing.

The change message for that commit includes

* src/names.c (read_next_name): Don't unquote name read from the
file, if --verbatim-files-from option is in effect.

which would definitely break our use case. Using a new rule for unescaping file names with --verbatim-files-from would keep files that needed escaping from matching the manifest. Which is exactly what I was seeing.

All Done?

Okay, now I can update the bug report and move on? No, just to be safe I wanted to verify, even though the answer seemed clear.

Verify the cause

Time to build my own tar binary.

The process, basically:

sudo apt-get build-dep tar
apt-get source tar
wget -O p1  'http://git.savannah.gnu.org/cgit/tar.git/patch/?id=dee7e3f16e74e07504bb8f4d80426005fe4364ae'
cd tar-1.29b
patch -p1 <../p1

dpkg-buildpackage -us -uc2
[fails complaining that there are local changes, needs 'dpkg-source --commit']

dpkg-source --commit
dpkg-buildpackage -us -uc
[wait for very large tar test suite]

After installing the generated .deb file and regenerating the tar file (again, by breakpointing pristine-tar at the right point), the zero-length files are seen. This matches the buggy behavior, so the responsible patch has (probably) been identified.

Update the bug

With a verification that I had the right answer, I updated the bug. I intentionally didn’t include much background, as I definitely don’t have the full context. I just answered the maintainer’s existing question about which change caused the issue.

I subscribed to the bug in the Debian bug tracker, in case more questions arose.

Next Steps

I could leave the Debian and upstream tar maintainers to figure out what is the right outcome. But I wanted to spend a little time trying to figure it out.

The NEWS file for GNU Tar doesn’t explain the change in detail. However, I do see that --verbatim-files-from was new in 1.29. It’s not too surprising the behavior is changing. But is the 1.30 behavior correct? What are the pros and cons? Also, is there a clean pristine-tar workaround?

On the tar side, allowing the file list to have a level of quoting seems like it would be safe to allow. I can’t find an explanation for the change that made --unquote and --verbatim-files-from not work together, so I’ll assume there is a good reason.

On the pristine-tar side, perhaps using this tar option is the way forward:

--null Instruct  subsequent -T options to read null-terminated names
    verbatim (disables special handling of names that start with a dash).

Null-separating the file names may do a better job of removing ambiguity, but just switching to this isn’t simple, as old manifests need to be correctly handled.

Making this change would be a big job for me, since I don’t know pristine-tar well. Since I’m not sure which way Debian wants to go with this, I will leave things here.