[PATCH] Implement support for PAX Extended Header
From: Stefan Berger <stefanb@us.ibm.com>
Implement support for the pax extended header found in tar files. From all
the collected pax header entries we set the security.ima extended attribute
associate with the extracted file.
---
apt-inst/contrib/extracttar.cc | 170 ++++++++++++++++++++++++++++++++++++++++-
apt-inst/contrib/extracttar.h | 39 +++++++++-
2 files changed, 207 insertions(+), 2 deletions(-)
diff --git a/apt-inst/contrib/extracttar.cc b/apt-inst/contrib/extracttar.cc
index 6036005..6fde00c 100644
--- a/apt-inst/contrib/extracttar.cc
+++ b/apt-inst/contrib/extracttar.cc
@@ -32,12 +32,152 @@
#include <signal.h>
#include <fcntl.h>
#include <iostream>
+#include <sys/xattr.h>
#include <apti18n.h>
/*}}}*/
using namespace std;
-
+
+// PaxEntry::PaxEntry - Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+PaxEntry::PaxEntry(const char *Key, const unsigned char *Value, size_t ValueLen)
+{
+ this->Key = strdup(Key);
+ this->Value = new unsigned char[ValueLen]();
+ memcpy(this->Value, Value, ValueLen);
+ this->ValueLen = ValueLen;
+}
+ /*}}}*/
+// PaxEntry::PaxEntry - Copy Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+PaxEntry::PaxEntry(const PaxEntry &pd)
+{
+ this->Key = strdup(pd.Key);
+ this->Value = new unsigned char[pd.ValueLen]();
+ memcpy(this->Value, pd.Value, pd.ValueLen);
+ this->ValueLen = pd.ValueLen;
+}
+ /*}}}*/
+// PaxEntry::~PaxEntry - Destructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+PaxEntry::~PaxEntry()
+{
+ free(this->Key);
+ delete [] this->Value;
+}
+ /*}}}*/
+// PaxEntry::Apply - Apply the extended attributes /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool PaxEntry::Apply(const char *Filename)
+{
+ /* apply only security.ima */
+ if (strcmp(this->Key, "SCHILY.xattr.security.ima"))
+ setxattr(Filename, &this->Key[13], this->Value, this->ValueLen, 0);
+
+ return true;
+}
+ /*}}}*/
+// PaxData::Apply - Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+PaxData::PaxData(char *Buffer, unsigned long long BufferLength)
+ : Buffer(Buffer), BufferLength(BufferLength)
+{
+}
+ /*}}}*/
+// PaxData::~PaxData - Destructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+PaxData::~PaxData()
+{
+ Entries.clear();
+ free(Buffer);
+}
+ /*}}}*/
+// PaxData::AddEntry - Add an entry /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void PaxData::AddEntry(const char *Key, const unsigned char *Value, size_t ValueLen)
+{
+ Entries.push_back(PaxEntry(Key, Value, ValueLen));
+}
+ /*}}}*/
+// PaxData::Apply - Apply all extended attributes /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool PaxData::Apply(const char *Filename)
+{
+ std::vector<PaxEntry>::iterator iter;
+ bool ret = true;
+
+ for (iter = this->Entries.begin(); iter != this->Entries.end(); iter++) {
+ ret = iter->Apply(Filename);
+ if (!ret)
+ break;
+ }
+ return ret;
+}
+ /*}}}*/
+// PaxData::Parse - Parse the PAX data /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool PaxData::Parse(void)
+{
+ int n;
+ unsigned int Len;
+ char *KeyStart, *KeyEnd, *Current, Space;
+ unsigned char *Value;
+ size_t ValueLen;
+
+ Current = Buffer;
+
+ while (Current - Buffer < (long long)BufferLength) {
+ /* parse 'untrusted' len */
+ n = sscanf(Current, "%u%c", &Len, &Space);
+ if (n != 2 || Space != ' ' || Len == 0)
+ break;
+
+ KeyStart = index(Current, ' ');
+ if (!KeyStart)
+ break;
+
+ KeyStart++;
+ KeyEnd = index(KeyStart, '=');
+ if (!KeyEnd)
+ break;
+
+ /* check 'untrusted' Len: beyond buffer ? */
+ Current += Len;
+ if (Current > Buffer + BufferLength || Current[-1] != '\n')
+ break;
+
+ /* Value starts after the '='; value can be binary data */
+ Value = (unsigned char *)KeyEnd + 1;
+ ValueLen = Current - 1 - (char *)Value;
+ /* overwrite terminating '\n' */
+ Value[ValueLen] = 0;
+
+ try {
+ AddEntry(KeyStart, Value, ValueLen);
+ } catch (bad_alloc) {
+ _error->Error(_("Out of memory"));
+ return false;
+ }
+ }
+
+ if (Current - Buffer != (long long)BufferLength) {
+ _error->Error(_("Could not parse PAX header"));
+ return false;
+ }
+
+ return true;
+}
+ /*}}}*/
// The on disk header for a tar file.
struct ExtractTar::TarHeader
{
@@ -125,6 +265,7 @@ bool ExtractTar::Go(pkgDirStream &Stream)
// Loop over all blocks
string LastLongLink, ItemLink;
string LastLongName, ItemName;
+ PaxData *pd = NULL;
while (1)
{
bool BadRecord = false;
@@ -256,6 +397,28 @@ bool ExtractTar::Go(pkgDirStream &Stream)
}
continue;
}
+
+ case PAX_Extended_Header:
+ {
+ unsigned long long BufferLength = (Itm.Size + 511) & ~511;
+ char *Buffer = (char *)malloc(BufferLength + 1);
+
+ if (!Buffer) {
+ _error->Warning(_("Out of memory trying to allocate %llu bytes for PAX header"), BufferLength);
+ return false;
+ }
+ if (InFd.Read(Buffer, BufferLength,true) == false) {
+ free(Buffer);
+ return false;
+ }
+ pd = new PaxData(Buffer, Itm.Size);
+ if (!pd->Parse()) {
+ delete pd;
+ return false;
+ }
+
+ continue;
+ }
default:
BadRecord = true;
@@ -304,6 +467,11 @@ bool ExtractTar::Go(pkgDirStream &Stream)
LastLongName.erase();
LastLongLink.erase();
+
+ if (Tar->LinkFlag != PAX_Extended_Header) {
+ delete pd;
+ pd = NULL;
+ }
}
return Done();
diff --git a/apt-inst/contrib/extracttar.h b/apt-inst/contrib/extracttar.h
index edd3cec..005bbef 100644
--- a/apt-inst/contrib/extracttar.h
+++ b/apt-inst/contrib/extracttar.h
@@ -27,6 +27,42 @@ using std::min;
class pkgDirStream;
+class PaxEntry
+{
+ private:
+
+ char *Key;
+ unsigned char *Value;
+ size_t ValueLen;
+
+ public:
+
+ PaxEntry(const char *Key, const unsigned char *Value, size_t ValueLen);
+ PaxEntry(const PaxEntry &pe);
+ bool Apply(const char *Filename);
+ virtual ~PaxEntry();
+};
+
+class PaxData
+{
+ private:
+
+ char *Buffer;
+ unsigned long long BufferLength;
+
+ std::vector<PaxEntry> Entries;
+
+ public:
+
+ PaxData(char *Buffer, unsigned long long BufferLength);
+ bool Parse(void);
+
+ void AddEntry(const char *Key, const unsigned char *Value, size_t ValueLen);
+ bool Apply(const char *Filename);
+
+ virtual ~PaxData();
+};
+
class ExtractTar
{
protected:
@@ -37,7 +73,8 @@ class ExtractTar
enum ItemType {NormalFile0 = '\0',NormalFile = '0',HardLink = '1',
SymbolicLink = '2',CharacterDevice = '3',
BlockDevice = '4',Directory = '5',FIFO = '6',
- GNU_LongLink = 'K',GNU_LongName = 'L'};
+ GNU_LongLink = 'K',GNU_LongName = 'L',
+ PAX_Extended_Header = 'x'};
FileFd &File;
unsigned long long MaxInSize;
--
1.9.1
Reply to: