Browse Source

don't change owner/perms/times through file:// symlinks

If we have files in partial/ from a previous invocation or similar such
those could be symlinks created by file:// sources. The code is
expecting only real files through and happily changes owner,
modification times and permission on the file the symlink points to
which tend to be files we have no business in touching in this way.
Permissions of symlinks shouldn't be changed, changing owner is usually
pointless to, but just to be sure we pick the easy way out and use
lchown, check for symlinks before chmod/utimes.

Reported-By: Mattia Rizzolo on IRC
tags/debian/1.3_pre1
David Kalnischkies 5 years ago
parent
commit
3465138575
7 changed files with 60 additions and 23 deletions
  1. +4
    -1
      apt-pkg/contrib/fileutl.cc
  2. +31
    -0
      methods/aptmethod.h
  3. +2
    -7
      methods/copy.cc
  4. +2
    -14
      methods/store.cc
  5. +9
    -0
      test/integration/framework
  6. +5
    -1
      test/integration/test-apt-update-file
  7. +7
    -0
      test/integration/test-apt-update-ims

+ 4
- 1
apt-pkg/contrib/fileutl.cc View File

@@ -916,9 +916,12 @@ bool ChangeOwnerAndPermissionOfFile(char const * const requester, char const * c
// ensure the file is owned by root and has good permissions
struct passwd const * const pw = getpwnam(user);
struct group const * const gr = getgrnam(group);
if (pw != NULL && gr != NULL && chown(file, pw->pw_uid, gr->gr_gid) != 0)
if (pw != NULL && gr != NULL && lchown(file, pw->pw_uid, gr->gr_gid) != 0)
Res &= _error->WarningE(requester, "chown to %s:%s of file %s failed", user, group, file);
}
struct stat Buf;
if (lstat(file, &Buf) != 0 || S_ISLNK(Buf.st_mode))
return Res;
if (chmod(file, mode) != 0)
Res &= _error->WarningE(requester, "chmod 0%o of file %s failed", mode, file);
return Res;


+ 31
- 0
methods/aptmethod.h View File

@@ -3,10 +3,18 @@

#include <apt-pkg/acquire-method.h>
#include <apt-pkg/configuration.h>
#include <apt-pkg/error.h>

#include <locale>
#include <string>

#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include <apti18n.h>

class aptMethod : public pkgAcqMethod
{
char const * const Binary;
@@ -43,6 +51,29 @@ public:
va_end(args);
}

bool TransferModificationTimes(char const * const From, char const * const To, time_t &LastModified)
{
if (strcmp(To, "/dev/null") == 0)
return true;

struct stat Buf2;
if (lstat(To, &Buf2) != 0 || S_ISLNK(Buf2.st_mode))
return true;

struct stat Buf;
if (stat(From, &Buf) != 0)
return _error->Errno("stat",_("Failed to stat"));

// we don't use utimensat here for compatibility reasons: #738567
struct timeval times[2];
times[0].tv_sec = Buf.st_atime;
LastModified = times[1].tv_sec = Buf.st_mtime;
times[0].tv_usec = times[1].tv_usec = 0;
if (utimes(To, times) != 0)
return _error->Errno("utimes",_("Failed to set modification time"));
return true;
}

aptMethod(char const * const Binary, char const * const Ver, unsigned long const Flags) :
pkgAcqMethod(Ver, Flags), Binary(Binary)
{


+ 2
- 7
methods/copy.cc View File

@@ -78,13 +78,8 @@ bool CopyMethod::Fetch(FetchItem *Itm)
From.Close();
To.Close();

// Transfer the modification times
struct timeval times[2];
times[0].tv_sec = Buf.st_atime;
times[1].tv_sec = Buf.st_mtime;
times[0].tv_usec = times[1].tv_usec = 0;
if (utimes(Res.Filename.c_str(), times) != 0)
return _error->Errno("utimes",_("Failed to set modification time"));
if (TransferModificationTimes(File.c_str(), Res.Filename.c_str(), Res.LastModified) == false)
return false;

CalculateHashes(Itm, Res);
URIDone(Res);


+ 2
- 14
methods/store.cc View File

@@ -126,20 +126,8 @@ bool StoreMethod::Fetch(FetchItem *Itm) /*{{{*/
if (Failed == true)
return false;

// Transfer the modification times
if (Itm->DestFile != "/dev/null")
{
struct stat Buf;
if (stat(Path.c_str(),&Buf) != 0)
return _error->Errno("stat",_("Failed to stat"));

struct timeval times[2];
times[0].tv_sec = Buf.st_atime;
Res.LastModified = times[1].tv_sec = Buf.st_mtime;
times[0].tv_usec = times[1].tv_usec = 0;
if (utimes(Itm->DestFile.c_str(), times) != 0)
return _error->Errno("utimes",_("Failed to set modification time"));
}
if (TransferModificationTimes(Path.c_str(), Itm->DestFile.c_str(), Res.LastModified) == false)
return false;

// Return a Done response
Res.TakeHashes(Hash);


+ 9
- 0
test/integration/framework View File

@@ -1886,6 +1886,11 @@ pause() {
read IGNORE
}

logcurrentarchivedirectory() {
find "${TMPWORKINGDIRECTORY}/aptarchive/dists" -type f | while read line; do
stat --format '%U:%G:%a:%n' "$line"
done | sort > "${TMPWORKINGDIRECTORY}/rootdir/var/log/aptgetupdate.before.lst"
}
listcurrentlistsdirectory() {
{
find rootdir/var/lib/apt/lists -maxdepth 1 -type d | while read line; do
@@ -1964,6 +1969,10 @@ aptautotest_aptget_update() {
# failure cases can retain partial files and such
testempty find "${TMPWORKINGDIRECTORY}/rootdir/var/lib/apt/lists/partial" -mindepth 1 ! \( -name 'lock' -o -name '*.FAILED' \)
fi
if [ -s "${TMPWORKINGDIRECTORY}/rootdir/var/log/aptgetupdate.before.lst" ]; then
testfileequal "${TMPWORKINGDIRECTORY}/rootdir/var/log/aptgetupdate.before.lst" \
"$(find "${TMPWORKINGDIRECTORY}/aptarchive/dists" -type f | while read line; do stat --format '%U:%G:%a:%n' "$line"; done | sort)"
fi
}
aptautotest_apt_update() { aptautotest_aptget_update "$@"; }
aptautotest_aptcdrom_add() { aptautotest_aptget_update "$@"; }


+ 5
- 1
test/integration/test-apt-update-file View File

@@ -18,6 +18,7 @@ insertpackage 'unstable' 'bar' 'amd64' '1'
insertsource 'unstable' 'foo' 'all' '1'

setupaptarchive --no-update
logcurrentarchivedirectory

# ensure the archive is not writable
addtrap 'prefix' 'chmod 755 aptarchive/dists/unstable/main/binary-all;'
@@ -37,8 +38,11 @@ if [ "$(id -u)" = '0' ]; then
rm -rf rootdir/var/lib/apt/lists
chmod 500 aptarchive/dists/
testsuccesswithnotice aptget update
exit
chmod 755 aptarchive/dists/
else
testsuccess aptget update
fi
mv rootdir/var/lib/apt/lists/_* rootdir/var/lib/apt/lists/partial
chmod 555 aptarchive/dists/unstable/main/binary-all
testsuccess aptget update -o Debug::pkgAcquire::Worker=1
cp -a rootdir/tmp/testsuccess.output rootdir/tmp/update.output


+ 7
- 0
test/integration/test-apt-update-ims View File

@@ -12,6 +12,7 @@ insertsource 'unstable' 'unrelated' 'all' '0.5~squeeze1'

export APT_DONT_SIGN=""
setupaptarchive --no-update
logcurrentarchivedirectory
changetowebserver

runtest() {
@@ -71,6 +72,7 @@ EXPECT="Ign:1 http://localhost:${APTHTTPPORT} unstable InRelease
Hit:2 http://localhost:${APTHTTPPORT} unstable Release
Reading package lists..."
find aptarchive -name 'InRelease' -delete
logcurrentarchivedirectory
echo 'Acquire::GzipIndexes "0";' > rootdir/etc/apt/apt.conf.d/02compressindex
runtest
echo 'Acquire::GzipIndexes "1";' > rootdir/etc/apt/apt.conf.d/02compressindex
@@ -87,6 +89,7 @@ W: The repository 'http://localhost:${APTHTTPPORT} unstable Release' is not sign
N: Data from such a repository can't be authenticated and is therefore potentially dangerous to use.
N: See apt-secure(8) manpage for repository creation and user configuration details."
find aptarchive -name 'Release.gpg' -delete
logcurrentarchivedirectory
echo 'Acquire::GzipIndexes "0";' > rootdir/etc/apt/apt.conf.d/02compressindex
runtest 'warning'
echo 'Acquire::GzipIndexes "1";' > rootdir/etc/apt/apt.conf.d/02compressindex
@@ -99,6 +102,7 @@ find aptarchive -name '*Release' -exec sed -i \
-e '/^Valid-Until: / d' -e "/^Date: / a\
Valid-Until: $(date -ud '-1 weeks' '+%a, %d %b %Y %H:%M:%S %Z')" '{}' \;
signreleasefiles
logcurrentarchivedirectory

msgmsg 'expired InRelease'
EXPECT="Hit:1 http://localhost:${APTHTTPPORT} unstable InRelease
@@ -116,6 +120,7 @@ Hit:2 http://localhost:${APTHTTPPORT} unstable Release
Reading package lists...
E: Release file for http://localhost:${APTHTTPPORT}/dists/unstable/Release is expired (invalid since). Updates for this repository will not be applied."
find aptarchive -name 'InRelease' -delete
logcurrentarchivedirectory
echo 'Acquire::GzipIndexes "0";' > rootdir/etc/apt/apt.conf.d/02compressindex
runtest 'failure'
echo 'Acquire::GzipIndexes "1";' > rootdir/etc/apt/apt.conf.d/02compressindex
@@ -133,6 +138,7 @@ N: Data from such a repository can't be authenticated and is therefore potential
N: See apt-secure(8) manpage for repository creation and user configuration details.
E: Release file for http://localhost:${APTHTTPPORT}/dists/unstable/Release is expired (invalid since). Updates for this repository will not be applied."
find aptarchive -name 'Release.gpg' -delete
logcurrentarchivedirectory
echo 'Acquire::GzipIndexes "0";' > rootdir/etc/apt/apt.conf.d/02compressindex
runtest 'failure' 'warning'
echo 'Acquire::GzipIndexes "1";' > rootdir/etc/apt/apt.conf.d/02compressindex
@@ -177,6 +183,7 @@ W: The repository 'http://localhost:${APTHTTPPORT} unstable Release' does not ha
N: Data from such a repository can't be authenticated and is therefore potentially dangerous to use.
N: See apt-secure(8) manpage for repository creation and user configuration details."
find aptarchive -name '*Release*' -delete
logcurrentarchivedirectory
echo 'Acquire::GzipIndexes "0";
Acquire::PDiffs "0";' > rootdir/etc/apt/apt.conf.d/02compressindex
runtest 'warning'


Loading…
Cancel
Save