Skip to content

Commit

Permalink
Use libarchive instead of calling out to tar
Browse files Browse the repository at this point in the history
Use libarchive in order to make use of its security features and avoid
calling out to tar via a shell. The TAR_COMMAND is still used in
staging.c to complete the copy when a hardlink fails.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
  • Loading branch information
matthewrsj committed Oct 31, 2017
1 parent ba9e0f2 commit 338034d
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 40 deletions.
5 changes: 3 additions & 2 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ check_PROGRAMS = \
swupd_sig_verifytest

SWUPD_COMMON_SOURCES = \
src/archives.c \
src/curl.c \
src/delta.c \
src/download.c \
Expand Down Expand Up @@ -82,9 +83,9 @@ swupd_locktest_SOURCES = test/locktest.c
swupd_sig_verifytest_SOURCES = test/signature_verify_test.c


AM_CPPFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/include
AM_CPPFLAGS = $(AM_CFLAGS) $(libarchive_CFLAGS) -I$(top_srcdir)/include
SWUPD_COMPRESSION_LIBS = $(lzma_LIBS) $(zlib_LIBS) $(bzip2_LIBS)
SWUPD_CORE_LIBS = libswupd.la ${curl_LIBS} $(openssl_LIBS) $(SWUPD_COMPRESSION_LIBS) $(bsdiff_LIBS)
SWUPD_CORE_LIBS = libswupd.la ${curl_LIBS} $(openssl_LIBS) $(libarchive_LIBS) $(SWUPD_COMPRESSION_LIBS) $(bsdiff_LIBS)

swupd_LDADD = $(SWUPD_CORE_LIBS) $(pthread_LIBS)

Expand Down
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ PKG_CHECK_MODULES([lzma], [liblzma])
PKG_CHECK_MODULES([zlib], [zlib])
PKG_CHECK_MODULES([curl], [libcurl])
PKG_CHECK_MODULES([openssl], [libcrypto >= 1.0.1])
PKG_CHECK_MODULES([libarchive], [libarchive])
AC_CHECK_LIB([pthread], [pthread_create])


Expand Down
2 changes: 2 additions & 0 deletions include/swupd.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ extern int get_value_from_path(char **contents, const char *path, bool is_abs_pa
extern int get_version_from_path(const char *abs_path);
extern timelist init_timelist(void);

extern int extract(const char *filename, const char *target);

extern int swupd_stats[];
static inline void account_new_file(void)
{
Expand Down
138 changes: 138 additions & 0 deletions src/archives.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
* Software Updater - client side
*
* Copyright © 2012-2016 Intel Corporation.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 or later of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Matthew Johnson <mathew.johnson@intel.com>
*
*/

#include <stdlib.h>
#include <archive.h>
#include <archive_entry.h>

#include "swupd.h"

static int copy_data(struct archive *ar, struct archive *aw)
{
int r;
const void *buffer;
size_t size;
la_int64_t offset;

for(;;) {
r = archive_read_data_block(ar, &buffer, &size, &offset);
if (r == ARCHIVE_EOF) {
return ARCHIVE_OK;
} else if (r < ARCHIVE_OK) {
return r;
}

r = archive_write_data_block(aw, buffer, size, offset);
if (r < ARCHIVE_OK) {
fprintf(stderr, "Error: %s\n", archive_error_string(aw));
return r;
}
}
}

int extract(const char *filename, const char *target)
{
struct archive *a, *ext;
struct archive_entry *entry;
int flags, r;

/* set which attributes we want to restore */
flags = ARCHIVE_EXTRACT_TIME;
flags |= ARCHIVE_EXTRACT_PERM;
flags |= ARCHIVE_EXTRACT_ACL;
flags |= ARCHIVE_EXTRACT_FFLAGS;
flags |= ARCHIVE_EXTRACT_XATTR;

/* set security flags */
flags |= ARCHIVE_EXTRACT_SECURE_SYMLINKS;
flags |= ARCHIVE_EXTRACT_SECURE_NODOTDOT;
//flags |= ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS;

a = archive_read_new();
archive_read_support_format_all(a);
archive_read_support_filter_all(a);

ext = archive_write_disk_new();
archive_write_disk_set_options(ext, flags);
archive_write_disk_set_standard_lookup(ext);
r = archive_read_open_filename(a, filename, 10240);
if (r) {
return r;
}

for (;;) {
r = archive_read_next_header(a, &entry);
if (r == ARCHIVE_EOF) {
break;
}

if (r < ARCHIVE_OK) {
fprintf(stderr, "%s\n", archive_error_string(ext));
}

if (r < ARCHIVE_WARN) {
return r;
}

// Default to state directory if target is NULL
char *fullpath;
if (target != NULL) {
string_or_die(&fullpath, "%s/%s", target, archive_entry_pathname(entry));
} else {
string_or_die(&fullpath, "%s/%s", state_dir, archive_entry_pathname(entry));
}

archive_entry_set_pathname(entry, fullpath);
free(fullpath);

r = archive_write_header(ext, entry);
if (r < ARCHIVE_OK) {
fprintf(stderr, "%s\n", archive_error_string(ext));
} else if (archive_entry_size(entry) > 0) {
r = copy_data(a, ext);
if (r < ARCHIVE_OK) {
fprintf(stderr, "%s\n", archive_error_string(ext));
return r;
}

if (r < ARCHIVE_WARN) {
return r;
}
}

r = archive_write_finish_entry(ext);
if (r < ARCHIVE_OK) {
fprintf(stderr, "%s\n", archive_error_string(ext));
return r;
}

if (r < ARCHIVE_WARN) {
return r;
}
}

archive_read_close(a);
archive_read_free(a);
archive_write_close(ext);
archive_write_free(ext);
return 0;
}
13 changes: 4 additions & 9 deletions src/download.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,6 @@ int untar_full_download(void *data)
char *targetfile;
struct stat stat;
int err;
char *tarcommand;

string_or_die(&tar_dotfile, "%s/download/.%s.tar", state_dir, file->hash);
string_or_die(&tarfile, "%s/download/%s.tar", state_dir, file->hash);
Expand Down Expand Up @@ -293,14 +292,10 @@ int untar_full_download(void *data)
}

/* modern tar will automatically determine the compression type used */
string_or_die(&tarcommand, TAR_COMMAND " -C %s/staged/ " TAR_PERM_ATTR_ARGS " -xf %s 2> /dev/null",
state_dir, tarfile);

err = system(tarcommand);
if (WIFEXITED(err)) {
err = WEXITSTATUS(err);
}
free(tarcommand);
char *target;
string_or_die(&target, "%s/staged", state_dir);
err = extract(tarfile, target);
free(target);
if (err) {
fprintf(stderr, "ignoring tar extract failure for fullfile %s.tar (ret %d)\n",
file->hash, err);
Expand Down
12 changes: 2 additions & 10 deletions src/hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,6 @@ int verify_bundle_hash(struct manifest *manifest, struct file *bundle)
/* missing bundle manifest - attempt to download it */
char *filename;
char *url;
char *tar;

fprintf(stderr, "Warning: Downloading missing manifest for bundle %s version %d.\n",
current->filename, current->last_change);
Expand All @@ -319,17 +318,10 @@ int verify_bundle_hash(struct manifest *manifest, struct file *bundle)
free(filename);
break;
}
free(filename);

string_or_die(&tar, TAR_COMMAND " -C %s/%i -xf %s/%i/Manifest.%s.tar 2> /dev/null",
state_dir, current->last_change, state_dir,
current->last_change, current->filename);
ret = extract(filename, NULL);
free(filename);

ret = system(tar);
free(tar);
if (WIFEXITED(ret)) {
ret = WEXITSTATUS(ret);
}
if (ret != 0) {
break;
}
Expand Down
13 changes: 2 additions & 11 deletions src/manifest.c
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,6 @@ static int retrieve_manifests(int current, int version, char *component, struct
char *filename;
char *dir;
int ret = 0;
char *tar;
struct stat sb;

/* Check for fullfile only, we will not be keeping the .tar around */
Expand All @@ -530,7 +529,6 @@ static int retrieve_manifests(int current, int version, char *component, struct
if ((ret != 0) && (errno != EEXIST)) {
goto out;
}
free(dir);

/* FILE is not set for a MoM, only for bundle manifests */
if (file && current < version) {
Expand All @@ -547,15 +545,8 @@ static int retrieve_manifests(int current, int version, char *component, struct
goto out;
}

string_or_die(&tar, TAR_COMMAND " -C %s/%i -xf %s/%i/Manifest.%s.tar 2> /dev/null",
state_dir, version, state_dir, version, component);

/* this is is historically a point of odd errors */
ret = system(tar);
if (WIFEXITED(ret)) {
ret = WEXITSTATUS(ret);
}
free(tar);
ret = extract(filename, dir);
free(dir);
if (ret != 0) {
goto out;
} else {
Expand Down
9 changes: 1 addition & 8 deletions src/packs.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
static int download_pack(int oldversion, int newversion, char *module)
{
FILE *tarfile = NULL;
char *tar = NULL;
char *url = NULL;
int err = -1;
char *filename;
Expand Down Expand Up @@ -67,14 +66,8 @@ static int download_pack(int oldversion, int newversion, char *module)
free(url);

fprintf(stderr, "\nExtracting %s pack for version %i\n", module, newversion);
string_or_die(&tar, TAR_COMMAND " -C %s " TAR_PERM_ATTR_ARGS " -xf %s/pack-%s-from-%i-to-%i.tar 2> /dev/null",
state_dir, state_dir, module, oldversion, newversion);
err = extract(filename, NULL);

err = system(tar);
if (WIFEXITED(err)) {
err = WEXITSTATUS(err);
}
free(tar);
unlink(filename);
/* make a zero sized file to prevent redownload */
tarfile = fopen(filename, "w");
Expand Down

0 comments on commit 338034d

Please sign in to comment.