mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
Merge pull request #65 from andreimedar:libarchive
PiperOrigin-RevId: 343290002 Change-Id: I1f29e4acfc7d423be63fd52e7a78ceb209d29115
This commit is contained in:
commit
fbf3e84799
|
@ -18,10 +18,10 @@ project(libarchive_sapi CXX)
|
|||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED 17)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
|
||||
|
||||
# Build SAPI library
|
||||
#set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree")
|
||||
set(SAPI_ROOT "/usr/local/google/home/amedar/internship/sandboxed-api" CACHE PATH "Path to the Sandboxed API source tree")
|
||||
set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree")
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
|
@ -58,4 +58,4 @@ target_include_directories(libarchive_sapi INTERFACE
|
|||
|
||||
add_subdirectory(examples)
|
||||
add_subdirectory(test)
|
||||
|
||||
add_subdirectory(ld_preload_example)
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
add_library(minitar_lib SHARED
|
||||
minitar.cc
|
||||
minitar.h
|
||||
)
|
||||
|
||||
target_link_libraries(minitar_lib PRIVATE
|
||||
archive
|
||||
)
|
||||
|
||||
add_executable(minitar_original
|
||||
minitar_main.cc
|
||||
)
|
||||
|
||||
target_link_libraries(minitar_original PRIVATE
|
||||
minitar_lib
|
||||
)
|
||||
|
||||
add_library(sapi_minitar_lib_shared SHARED
|
||||
../examples/sapi_minitar.cc
|
||||
../examples/sapi_minitar.h
|
||||
../examples/sandbox.h
|
||||
)
|
||||
|
||||
target_link_libraries(sapi_minitar_lib_shared PUBLIC
|
||||
glog::glog
|
||||
libarchive_sapi
|
||||
sandbox2::executor
|
||||
sandbox2::fileops
|
||||
sandbox2::file_base
|
||||
sandbox2::util
|
||||
sandbox2::temp_file
|
||||
sapi::sapi
|
||||
)
|
||||
|
||||
target_include_directories(sapi_minitar_lib_shared INTERFACE
|
||||
"${PROJECT_SOURCE_DIR}/examples"
|
||||
)
|
||||
|
||||
add_library(minitar_preload SHARED
|
||||
sapi_minitar.cc
|
||||
)
|
||||
|
||||
target_link_libraries(minitar_preload PRIVATE
|
||||
sapi_minitar_lib_shared
|
||||
)
|
25
oss-internship-2020/libarchive/ld_preload_example/README.md
Normal file
25
oss-internship-2020/libarchive/ld_preload_example/README.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Sandboxing the minitar example (only the extraction function) using LD_PRELOAD
|
||||
|
||||
## Description
|
||||
Using `LD_PRELOAD` we can create our own functions with the same signatures as the ones from the libarchive that are called in the original code and call those instead.
|
||||
This example only implements the extract part of the original tool.
|
||||
|
||||
## Structure
|
||||
- **minitar_main.cc** - the original main function.
|
||||
- **minitar.cc** and **minitar.h** - original functions called from main, built into a shared library.
|
||||
- The three files mentioned above are taken from the original minitar [example](https://github.com/libarchive/libarchive/tree/master/examples/minitar). The only difference to the code is that the main function was separated from the rest in order to build a shared library so that when `LD_PRELOAD` is used we can call our custom functions.
|
||||
- **sapi_minitar.cc** - libarchive functions with our own implementation, built into a shared library which will be used with `LD_PRELOAD`.
|
||||
|
||||
Most of the functions simply convert the arguments to sapi::v objects and calls the sandboxed version of the function. Also, there is a custom *extract* implementation that also created the sandbox object. If the sandbox could be created without special arguments then this would not be needed and could be done inside of the first function called. However, in our case, the sandbox requires the file path and so we do this in the *create* function where we have access to that path. Aftert this, we call the original function (the "next" function symbol).
|
||||
|
||||
## Files changed from the original libarchive sandboxed version
|
||||
The only changes are in the root CMakeLists.txt:
|
||||
|
||||
- `add_subdirectory(ld_preload_example)` to add this current folder to the build process.
|
||||
|
||||
- `set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)` to make sure that shared libraries are built with position independent code.
|
||||
|
||||
## Usage
|
||||
`LD_PRELOAD= build/ld_preload_example/libminitar_preload.so build/ld_preload_example/minitar_original -xvf archive_file`
|
||||
|
||||
Instead of the *x* option, *t* can be used as well only to print the archive entries.
|
312
oss-internship-2020/libarchive/ld_preload_example/minitar.cc
Normal file
312
oss-internship-2020/libarchive/ld_preload_example/minitar.cc
Normal file
|
@ -0,0 +1,312 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// clang-format off
|
||||
#include "minitar.h" // NOLINT(build/include)
|
||||
|
||||
/*
|
||||
* NO_CREATE implies NO_BZIP2_CREATE and NO_GZIP_CREATE and NO_COMPRESS_CREATE.
|
||||
*/
|
||||
#ifdef NO_CREATE
|
||||
#undef NO_BZIP2_CREATE
|
||||
#define NO_BZIP2_CREATE
|
||||
#undef NO_COMPRESS_CREATE
|
||||
#define NO_COMPRESS_CREATE
|
||||
#undef NO_GZIP_CREATE
|
||||
#define NO_GZIP_CREATE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The combination of NO_BZIP2_CREATE and NO_BZIP2_EXTRACT is
|
||||
* equivalent to NO_BZIP2.
|
||||
*/
|
||||
#ifdef NO_BZIP2_CREATE
|
||||
#ifdef NO_BZIP2_EXTRACT
|
||||
#undef NO_BZIP2
|
||||
#define NO_BZIP2
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef NO_BZIP2
|
||||
#undef NO_BZIP2_EXTRACT
|
||||
#define NO_BZIP2_EXTRACT
|
||||
#undef NO_BZIP2_CREATE
|
||||
#define NO_BZIP2_CREATE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The combination of NO_COMPRESS_CREATE and NO_COMPRESS_EXTRACT is
|
||||
* equivalent to NO_COMPRESS.
|
||||
*/
|
||||
#ifdef NO_COMPRESS_CREATE
|
||||
#ifdef NO_COMPRESS_EXTRACT
|
||||
#undef NO_COMPRESS
|
||||
#define NO_COMPRESS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef NO_COMPRESS
|
||||
#undef NO_COMPRESS_EXTRACT
|
||||
#define NO_COMPRESS_EXTRACT
|
||||
#undef NO_COMPRESS_CREATE
|
||||
#define NO_COMPRESS_CREATE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The combination of NO_GZIP_CREATE and NO_GZIP_EXTRACT is
|
||||
* equivalent to NO_GZIP.
|
||||
*/
|
||||
#ifdef NO_GZIP_CREATE
|
||||
#ifdef NO_GZIP_EXTRACT
|
||||
#undef NO_GZIP
|
||||
#define NO_GZIP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef NO_GZIP
|
||||
#undef NO_GZIP_EXTRACT
|
||||
#define NO_GZIP_EXTRACT
|
||||
#undef NO_GZIP_CREATE
|
||||
#define NO_GZIP_CREATE
|
||||
#endif
|
||||
|
||||
#ifndef NO_CREATE
|
||||
void create(const char* filename, int compress, const char** argv);
|
||||
#endif
|
||||
void errmsg(const char*);
|
||||
void extract(const char* filename, int do_extract, int flags);
|
||||
int copy_data(struct archive*, struct archive*);
|
||||
void msg(const char*);
|
||||
void usage(void);
|
||||
|
||||
#ifndef NO_CREATE
|
||||
|
||||
void create(const char* filename, int compress, const char** argv,
|
||||
int verbose) {
|
||||
struct archive* a;
|
||||
struct archive_entry* entry;
|
||||
ssize_t len;
|
||||
int fd;
|
||||
|
||||
a = archive_write_new();
|
||||
switch (compress) {
|
||||
#ifndef NO_BZIP2_CREATE
|
||||
case 'j':
|
||||
case 'y':
|
||||
archive_write_add_filter_bzip2(a);
|
||||
break;
|
||||
#endif
|
||||
#ifndef NO_COMPRESS_CREATE
|
||||
case 'Z':
|
||||
archive_write_add_filter_compress(a);
|
||||
break;
|
||||
#endif
|
||||
#ifndef NO_GZIP_CREATE
|
||||
case 'z':
|
||||
archive_write_add_filter_gzip(a);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
archive_write_add_filter_none(a);
|
||||
break;
|
||||
}
|
||||
archive_write_set_format_ustar(a);
|
||||
if (filename != NULL && strcmp(filename, "-") == 0) filename = NULL;
|
||||
archive_write_open_filename(a, filename);
|
||||
|
||||
while (*argv != NULL) {
|
||||
struct archive* disk = archive_read_disk_new();
|
||||
#ifndef NO_LOOKUP
|
||||
archive_read_disk_set_standard_lookup(disk);
|
||||
#endif
|
||||
int r;
|
||||
|
||||
r = archive_read_disk_open(disk, *argv);
|
||||
if (r != ARCHIVE_OK) {
|
||||
errmsg(archive_error_string(disk));
|
||||
errmsg("\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
int needcr = 0;
|
||||
|
||||
entry = archive_entry_new();
|
||||
r = archive_read_next_header2(disk, entry);
|
||||
if (r == ARCHIVE_EOF) break;
|
||||
if (r != ARCHIVE_OK) {
|
||||
errmsg(archive_error_string(disk));
|
||||
errmsg("\n");
|
||||
exit(1);
|
||||
}
|
||||
archive_read_disk_descend(disk);
|
||||
if (verbose) {
|
||||
msg("a ");
|
||||
msg(archive_entry_pathname(entry));
|
||||
needcr = 1;
|
||||
}
|
||||
r = archive_write_header(a, entry);
|
||||
if (r < ARCHIVE_OK) {
|
||||
errmsg(": ");
|
||||
errmsg(archive_error_string(a));
|
||||
needcr = 1;
|
||||
}
|
||||
if (r == ARCHIVE_FATAL) exit(1);
|
||||
if (r > ARCHIVE_FAILED) {
|
||||
static char buff[16384];
|
||||
fd = open(archive_entry_sourcepath(entry), O_RDONLY);
|
||||
len = read(fd, buff, sizeof(buff));
|
||||
while (len > 0) {
|
||||
archive_write_data(a, buff, len);
|
||||
len = read(fd, buff, sizeof(buff));
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
archive_entry_free(entry);
|
||||
if (needcr) msg("\n");
|
||||
}
|
||||
archive_read_close(disk);
|
||||
archive_read_free(disk);
|
||||
argv++;
|
||||
}
|
||||
archive_write_close(a);
|
||||
archive_write_free(a);
|
||||
}
|
||||
#endif
|
||||
|
||||
void extract(const char* filename, int do_extract, int flags, int verbose) {
|
||||
struct archive* a;
|
||||
struct archive* ext;
|
||||
struct archive_entry* entry;
|
||||
int r;
|
||||
|
||||
a = archive_read_new();
|
||||
ext = archive_write_disk_new();
|
||||
archive_write_disk_set_options(ext, flags);
|
||||
#ifndef NO_BZIP2_EXTRACT
|
||||
archive_read_support_filter_bzip2(a);
|
||||
#endif
|
||||
#ifndef NO_GZIP_EXTRACT
|
||||
archive_read_support_filter_gzip(a);
|
||||
#endif
|
||||
#ifndef NO_COMPRESS_EXTRACT
|
||||
archive_read_support_filter_compress(a);
|
||||
#endif
|
||||
#ifndef NO_TAR_EXTRACT
|
||||
archive_read_support_format_tar(a);
|
||||
#endif
|
||||
#ifndef NO_CPIO_EXTRACT
|
||||
archive_read_support_format_cpio(a);
|
||||
#endif
|
||||
#ifndef NO_LOOKUP
|
||||
archive_write_disk_set_standard_lookup(ext);
|
||||
#endif
|
||||
if (filename != NULL && strcmp(filename, "-") == 0) filename = NULL;
|
||||
if ((r = archive_read_open_filename(a, filename, 10240))) {
|
||||
errmsg(archive_error_string(a));
|
||||
errmsg("\n");
|
||||
exit(r);
|
||||
}
|
||||
for (;;) {
|
||||
int needcr = 0;
|
||||
r = archive_read_next_header(a, &entry);
|
||||
if (r == ARCHIVE_EOF) break;
|
||||
if (r != ARCHIVE_OK) {
|
||||
errmsg(archive_error_string(a));
|
||||
errmsg("\n");
|
||||
exit(1);
|
||||
}
|
||||
if (verbose && do_extract) msg("x ");
|
||||
|
||||
if (verbose || !do_extract) {
|
||||
std::cout << archive_entry_pathname(entry) << std::endl;
|
||||
msg(" ");
|
||||
needcr = 1;
|
||||
}
|
||||
if (do_extract) {
|
||||
r = archive_write_header(ext, entry);
|
||||
if (r != ARCHIVE_OK) {
|
||||
errmsg(archive_error_string(a));
|
||||
needcr = 1;
|
||||
} else {
|
||||
r = copy_data(a, ext);
|
||||
if (r != ARCHIVE_OK) needcr = 1;
|
||||
}
|
||||
}
|
||||
if (needcr) msg("\n");
|
||||
}
|
||||
archive_read_close(a);
|
||||
archive_read_free(a);
|
||||
|
||||
archive_write_close(ext);
|
||||
archive_write_free(ext);
|
||||
}
|
||||
|
||||
int copy_data(struct archive* ar, struct archive* aw) {
|
||||
int r;
|
||||
const void* buff;
|
||||
size_t size;
|
||||
int64_t offset;
|
||||
|
||||
for (;;) {
|
||||
r = archive_read_data_block(ar, &buff, &size, &offset);
|
||||
if (r == ARCHIVE_EOF) return (ARCHIVE_OK);
|
||||
if (r != ARCHIVE_OK) {
|
||||
errmsg(archive_error_string(ar));
|
||||
return (r);
|
||||
}
|
||||
r = archive_write_data_block(aw, buff, size, offset);
|
||||
if (r != ARCHIVE_OK) {
|
||||
errmsg(archive_error_string(ar));
|
||||
return (r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void msg(const char* m) { write(1, m, strlen(m)); }
|
||||
|
||||
void errmsg(const char* m) {
|
||||
if (m == NULL) {
|
||||
m = "Error: No error description provided.\n";
|
||||
}
|
||||
write(2, m, strlen(m));
|
||||
}
|
||||
|
||||
void usage(void) {
|
||||
/* Many program options depend on compile options. */
|
||||
const char* m =
|
||||
"Usage: minitar [-"
|
||||
#ifndef NO_CREATE
|
||||
"c"
|
||||
#endif
|
||||
#ifndef NO_BZIP2
|
||||
"j"
|
||||
#endif
|
||||
"tvx"
|
||||
#ifndef NO_BZIP2
|
||||
"y"
|
||||
#endif
|
||||
#ifndef NO_COMPRESS
|
||||
"Z"
|
||||
#endif
|
||||
#ifndef NO_GZIP
|
||||
"z"
|
||||
#endif
|
||||
"] [-f file] [file]\n";
|
||||
|
||||
errmsg(m);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// clang-format on
|
112
oss-internship-2020/libarchive/ld_preload_example/minitar.h
Normal file
112
oss-internship-2020/libarchive/ld_preload_example/minitar.h
Normal file
|
@ -0,0 +1,112 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef LIBARCHIVE_LD_PRELOAD_EXAMPLE_MINITAR_H_
|
||||
#define LIBARCHIVE_LD_PRELOAD_EXAMPLE_MINITAR_H_
|
||||
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
// The declarations below have been extracted from upstream's minitar.c, hence
|
||||
// the formatting.
|
||||
//
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
* NO_CREATE implies NO_BZIP2_CREATE and NO_GZIP_CREATE and NO_COMPRESS_CREATE.
|
||||
*/
|
||||
#ifdef NO_CREATE
|
||||
#undef NO_BZIP2_CREATE
|
||||
#define NO_BZIP2_CREATE
|
||||
#undef NO_COMPRESS_CREATE
|
||||
#define NO_COMPRESS_CREATE
|
||||
#undef NO_GZIP_CREATE
|
||||
#define NO_GZIP_CREATE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The combination of NO_BZIP2_CREATE and NO_BZIP2_EXTRACT is
|
||||
* equivalent to NO_BZIP2.
|
||||
*/
|
||||
#ifdef NO_BZIP2_CREATE
|
||||
#ifdef NO_BZIP2_EXTRACT
|
||||
#undef NO_BZIP2
|
||||
#define NO_BZIP2
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef NO_BZIP2
|
||||
#undef NO_BZIP2_EXTRACT
|
||||
#define NO_BZIP2_EXTRACT
|
||||
#undef NO_BZIP2_CREATE
|
||||
#define NO_BZIP2_CREATE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The combination of NO_COMPRESS_CREATE and NO_COMPRESS_EXTRACT is
|
||||
* equivalent to NO_COMPRESS.
|
||||
*/
|
||||
#ifdef NO_COMPRESS_CREATE
|
||||
#ifdef NO_COMPRESS_EXTRACT
|
||||
#undef NO_COMPRESS
|
||||
#define NO_COMPRESS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef NO_COMPRESS
|
||||
#undef NO_COMPRESS_EXTRACT
|
||||
#define NO_COMPRESS_EXTRACT
|
||||
#undef NO_COMPRESS_CREATE
|
||||
#define NO_COMPRESS_CREATE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The combination of NO_GZIP_CREATE and NO_GZIP_EXTRACT is
|
||||
* equivalent to NO_GZIP.
|
||||
*/
|
||||
#ifdef NO_GZIP_CREATE
|
||||
#ifdef NO_GZIP_EXTRACT
|
||||
#undef NO_GZIP
|
||||
#define NO_GZIP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef NO_GZIP
|
||||
#undef NO_GZIP_EXTRACT
|
||||
#define NO_GZIP_EXTRACT
|
||||
#undef NO_GZIP_CREATE
|
||||
#define NO_GZIP_CREATE
|
||||
#endif
|
||||
|
||||
#ifndef NO_CREATE
|
||||
void create(const char *filename, int compress, const char **argv,
|
||||
int verbose = 1);
|
||||
#endif
|
||||
void errmsg(const char *);
|
||||
void extract(const char *filename, int do_extract, int flags, int verbose = 1);
|
||||
int copy_data(struct archive *, struct archive *);
|
||||
void msg(const char *);
|
||||
void usage(void);
|
||||
|
||||
// clang-format on
|
||||
#endif // LIBARCHIVE_LD_PRELOAD_EXAMPLE_MINITAR_H_
|
|
@ -0,0 +1,207 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// clang-format off
|
||||
/*-
|
||||
* This is a compact "tar" program whose primary goal is small size.
|
||||
* Statically linked, it can be very small indeed. This serves a number
|
||||
* of goals:
|
||||
* o a testbed for libarchive (to check for link pollution),
|
||||
* o a useful tool for space-constrained systems (boot floppies, etc),
|
||||
* o a place to experiment with new implementation ideas for bsdtar,
|
||||
* o a small program to demonstrate libarchive usage.
|
||||
*
|
||||
* Use the following macros to suppress features:
|
||||
* NO_BZIP2 - Implies NO_BZIP2_CREATE and NO_BZIP2_EXTRACT
|
||||
* NO_BZIP2_CREATE - Suppress bzip2 compression support.
|
||||
* NO_BZIP2_EXTRACT - Suppress bzip2 auto-detection and decompression.
|
||||
* NO_COMPRESS - Implies NO_COMPRESS_CREATE and NO_COMPRESS_EXTRACT
|
||||
* NO_COMPRESS_CREATE - Suppress compress(1) compression support
|
||||
* NO_COMPRESS_EXTRACT - Suppress compress(1) auto-detect and decompression.
|
||||
* NO_CREATE - Suppress all archive creation support.
|
||||
* NO_CPIO_EXTRACT - Suppress auto-detect and dearchiving of cpio archives.
|
||||
* NO_GZIP - Implies NO_GZIP_CREATE and NO_GZIP_EXTRACT
|
||||
* NO_GZIP_CREATE - Suppress gzip compression support.
|
||||
* NO_GZIP_EXTRACT - Suppress gzip auto-detection and decompression.
|
||||
* NO_LOOKUP - Try to avoid getpw/getgr routines, which can be very large
|
||||
* NO_TAR_EXTRACT - Suppress tar extraction
|
||||
*
|
||||
* With all of the above macros defined (except NO_TAR_EXTRACT), you
|
||||
* get a very small program that can recognize and extract essentially
|
||||
* any uncompressed tar archive. On FreeBSD 5.1, this minimal program
|
||||
* is under 64k, statically linked, which compares rather favorably to
|
||||
* main(){printf("hello, world");}
|
||||
* which is over 60k statically linked on the same operating system.
|
||||
* Without any of the above macros, you get a static executable of
|
||||
* about 180k with a lot of very sophisticated modern features.
|
||||
* Obviously, it's trivial to add support for ISO, Zip, mtree,
|
||||
* lzma/xz, etc. Just fill in the appropriate setup calls.
|
||||
*/
|
||||
|
||||
#include "minitar.h" // NOLINT(build/include)
|
||||
|
||||
/*
|
||||
* NO_CREATE implies NO_BZIP2_CREATE and NO_GZIP_CREATE and NO_COMPRESS_CREATE.
|
||||
*/
|
||||
#ifdef NO_CREATE
|
||||
#undef NO_BZIP2_CREATE
|
||||
#define NO_BZIP2_CREATE
|
||||
#undef NO_COMPRESS_CREATE
|
||||
#define NO_COMPRESS_CREATE
|
||||
#undef NO_GZIP_CREATE
|
||||
#define NO_GZIP_CREATE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The combination of NO_BZIP2_CREATE and NO_BZIP2_EXTRACT is
|
||||
* equivalent to NO_BZIP2.
|
||||
*/
|
||||
#ifdef NO_BZIP2_CREATE
|
||||
#ifdef NO_BZIP2_EXTRACT
|
||||
#undef NO_BZIP2
|
||||
#define NO_BZIP2
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef NO_BZIP2
|
||||
#undef NO_BZIP2_EXTRACT
|
||||
#define NO_BZIP2_EXTRACT
|
||||
#undef NO_BZIP2_CREATE
|
||||
#define NO_BZIP2_CREATE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The combination of NO_COMPRESS_CREATE and NO_COMPRESS_EXTRACT is
|
||||
* equivalent to NO_COMPRESS.
|
||||
*/
|
||||
#ifdef NO_COMPRESS_CREATE
|
||||
#ifdef NO_COMPRESS_EXTRACT
|
||||
#undef NO_COMPRESS
|
||||
#define NO_COMPRESS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef NO_COMPRESS
|
||||
#undef NO_COMPRESS_EXTRACT
|
||||
#define NO_COMPRESS_EXTRACT
|
||||
#undef NO_COMPRESS_CREATE
|
||||
#define NO_COMPRESS_CREATE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The combination of NO_GZIP_CREATE and NO_GZIP_EXTRACT is
|
||||
* equivalent to NO_GZIP.
|
||||
*/
|
||||
#ifdef NO_GZIP_CREATE
|
||||
#ifdef NO_GZIP_EXTRACT
|
||||
#undef NO_GZIP
|
||||
#define NO_GZIP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef NO_GZIP
|
||||
#undef NO_GZIP_EXTRACT
|
||||
#define NO_GZIP_EXTRACT
|
||||
#undef NO_GZIP_CREATE
|
||||
#define NO_GZIP_CREATE
|
||||
#endif
|
||||
|
||||
int main(int unused_argc, const char** argv) {
|
||||
const char* filename = nullptr;
|
||||
int compress;
|
||||
int flags;
|
||||
int mode;
|
||||
int opt;
|
||||
|
||||
mode = 'x';
|
||||
int verbose = 0;
|
||||
compress = '\0';
|
||||
flags = ARCHIVE_EXTRACT_TIME;
|
||||
|
||||
/* Among other sins, getopt(3) pulls in printf(3). */
|
||||
while (*++argv != nullptr && **argv == '-') {
|
||||
const char* p = *argv + 1;
|
||||
|
||||
while ((opt = *p++) != '\0') {
|
||||
switch (opt) {
|
||||
#ifndef NO_CREATE
|
||||
case 'c':
|
||||
mode = opt;
|
||||
break;
|
||||
#endif
|
||||
case 'f':
|
||||
if (*p != '\0')
|
||||
filename = p;
|
||||
else
|
||||
filename = *++argv;
|
||||
p += strlen(p);
|
||||
break;
|
||||
#ifndef NO_BZIP2_CREATE
|
||||
case 'j':
|
||||
compress = opt;
|
||||
break;
|
||||
#endif
|
||||
case 'p':
|
||||
flags |= ARCHIVE_EXTRACT_PERM;
|
||||
flags |= ARCHIVE_EXTRACT_ACL;
|
||||
flags |= ARCHIVE_EXTRACT_FFLAGS;
|
||||
break;
|
||||
case 't':
|
||||
mode = opt;
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
case 'x':
|
||||
mode = opt;
|
||||
break;
|
||||
#ifndef NO_BZIP2_CREATE
|
||||
case 'y':
|
||||
compress = opt;
|
||||
break;
|
||||
#endif
|
||||
#ifndef NO_COMPRESS_CREATE
|
||||
case 'Z':
|
||||
compress = opt;
|
||||
break;
|
||||
#endif
|
||||
#ifndef NO_GZIP_CREATE
|
||||
case 'z':
|
||||
compress = opt;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
#ifndef NO_CREATE
|
||||
case 'c':
|
||||
create(filename, compress, argv, verbose);
|
||||
break;
|
||||
#endif
|
||||
case 't':
|
||||
extract(filename, 0, flags, verbose);
|
||||
break;
|
||||
case 'x':
|
||||
extract(filename, 1, flags, verbose);
|
||||
break;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
// clang-format on
|
|
@ -0,0 +1,229 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "sapi_minitar.h" // NOLINT(build/include)
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include "libarchive_sapi.sapi.h" // NOLINT(build/include)
|
||||
#include "sandbox.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/var_array.h"
|
||||
#include "sandboxed_api/var_ptr.h"
|
||||
|
||||
SapiLibarchiveSandboxExtract* sandbox_extract;
|
||||
LibarchiveApi* api;
|
||||
char* c_str_tmp = nullptr;
|
||||
|
||||
typedef void (*real_extract)(const char*, int, int, int);
|
||||
|
||||
void extract(const char* filename, int do_extract, int flags, int verbose) {
|
||||
// Here we initialize the sandbox and other objects.
|
||||
std::string tmp_dir;
|
||||
if (do_extract) {
|
||||
tmp_dir = CreateTempDirAtCWD().value();
|
||||
}
|
||||
|
||||
std::string filename_absolute = MakeAbsolutePathAtCWD(filename);
|
||||
|
||||
// Initialize sandbox and api objects.
|
||||
sandbox_extract =
|
||||
new SapiLibarchiveSandboxExtract(filename_absolute, do_extract, tmp_dir);
|
||||
CHECK(sandbox_extract->Init().ok()) << "Error during sandbox initialization";
|
||||
api = new LibarchiveApi(sandbox_extract);
|
||||
|
||||
// After everything is set up, call the original function (next symbol).
|
||||
|
||||
// TODO getting the mangled name of the function at runtime does not work
|
||||
// as intended. At the moment just use the symbol directly.
|
||||
const char* y = "_Z7extractPKciii";
|
||||
void* x = dlsym(RTLD_NEXT, y);
|
||||
|
||||
CHECK(x != nullptr) << "dlsym call could not find function symbol";
|
||||
((real_extract)x)(filename_absolute.c_str(), do_extract, flags, verbose);
|
||||
|
||||
// clean up
|
||||
if (c_str_tmp != nullptr) {
|
||||
delete[] c_str_tmp;
|
||||
}
|
||||
|
||||
// This is the last function called so we can delete the temporary directory
|
||||
// here
|
||||
if (do_extract) {
|
||||
sandbox2::file_util::fileops::DeleteRecursively(tmp_dir);
|
||||
}
|
||||
|
||||
delete api;
|
||||
delete sandbox_extract;
|
||||
}
|
||||
|
||||
archive* archive_read_new() {
|
||||
archive* ret = api->archive_read_new().value();
|
||||
CHECK(ret != nullptr) << "Failed to create archive";
|
||||
return ret;
|
||||
}
|
||||
|
||||
archive* archive_write_disk_new() {
|
||||
archive* ret = api->archive_write_disk_new().value();
|
||||
CHECK(ret != nullptr) << "Failed to create archive";
|
||||
return ret;
|
||||
}
|
||||
|
||||
int archive_write_disk_set_options(archive* ext, int flags) {
|
||||
sapi::v::RemotePtr ext_ptr(ext);
|
||||
|
||||
return api->archive_write_disk_set_options(&ext_ptr, flags).value();
|
||||
}
|
||||
|
||||
int archive_read_support_filter_bzip2(archive* a) {
|
||||
sapi::v::RemotePtr a_ptr(a);
|
||||
return api->archive_read_support_filter_bzip2(&a_ptr).value();
|
||||
}
|
||||
|
||||
int archive_read_support_filter_gzip(archive* a) {
|
||||
sapi::v::RemotePtr a_ptr(a);
|
||||
return api->archive_read_support_filter_gzip(&a_ptr).value();
|
||||
}
|
||||
|
||||
int archive_read_support_filter_compress(archive* a) {
|
||||
sapi::v::RemotePtr a_ptr(a);
|
||||
return api->archive_read_support_filter_compress(&a_ptr).value();
|
||||
}
|
||||
int archive_read_support_format_tar(archive* a) {
|
||||
sapi::v::RemotePtr a_ptr(a);
|
||||
return api->archive_read_support_format_tar(&a_ptr).value();
|
||||
}
|
||||
|
||||
int archive_read_support_format_cpio(archive* a) {
|
||||
sapi::v::RemotePtr a_ptr(a);
|
||||
return api->archive_read_support_format_cpio(&a_ptr).value();
|
||||
}
|
||||
|
||||
int archive_write_disk_set_standard_lookup(archive* ext) {
|
||||
sapi::v::RemotePtr ext_ptr(ext);
|
||||
|
||||
return api->archive_write_disk_set_standard_lookup(&ext_ptr).value();
|
||||
}
|
||||
|
||||
int archive_read_open_filename(archive* a, const char* _filename,
|
||||
size_t _block_size) {
|
||||
sapi::v::RemotePtr a_ptr(a);
|
||||
|
||||
return api
|
||||
->archive_read_open_filename(
|
||||
&a_ptr, sapi::v::ConstCStr(_filename).PtrBefore(), _block_size)
|
||||
.value();
|
||||
}
|
||||
|
||||
int archive_read_next_header(archive* a, archive_entry** entry) {
|
||||
sapi::v::IntBase<archive_entry*> entry_ptr_tmp(0);
|
||||
sapi::v::RemotePtr a_ptr(a);
|
||||
int rc =
|
||||
api->archive_read_next_header(&a_ptr, entry_ptr_tmp.PtrAfter()).value();
|
||||
*entry = entry_ptr_tmp.GetValue();
|
||||
return rc;
|
||||
}
|
||||
|
||||
// In the following two functions we need to transfer a string from the
|
||||
// sandboxed process to the client process. However, this string would
|
||||
// go out of scope after this function so we use a global char * to make
|
||||
// sure it does not get automatically deleted before it is used.
|
||||
const char* archive_error_string(archive* a) {
|
||||
sapi::v::RemotePtr a_ptr(a);
|
||||
char* str = api->archive_error_string(&a_ptr).value();
|
||||
CHECK(str != nullptr) << "Could not get error message";
|
||||
|
||||
std::string str_tmp =
|
||||
sandbox_extract->GetCString(sapi::v::RemotePtr(str)).value();
|
||||
|
||||
if (c_str_tmp != nullptr) {
|
||||
delete[] c_str_tmp;
|
||||
}
|
||||
|
||||
c_str_tmp = new char[str_tmp.length() + 1];
|
||||
strcpy(c_str_tmp, str_tmp.c_str()); // NOLINT(runtime/printf)
|
||||
|
||||
return c_str_tmp;
|
||||
}
|
||||
|
||||
const char* archive_entry_pathname(archive_entry* entry) {
|
||||
sapi::v::RemotePtr entry_ptr(entry);
|
||||
char* str = api->archive_entry_pathname(&entry_ptr).value();
|
||||
CHECK(str != nullptr) << "Could not get pathname";
|
||||
|
||||
std::string str_tmp =
|
||||
sandbox_extract->GetCString(sapi::v::RemotePtr(str)).value();
|
||||
|
||||
if (c_str_tmp != nullptr) {
|
||||
delete[] c_str_tmp;
|
||||
}
|
||||
|
||||
c_str_tmp = new char[str_tmp.length() + 1];
|
||||
strcpy(c_str_tmp, str_tmp.c_str()); // NOLINT(runtime/printf)
|
||||
|
||||
return c_str_tmp;
|
||||
}
|
||||
|
||||
int archive_read_close(archive* a) {
|
||||
sapi::v::RemotePtr a_ptr(a);
|
||||
return api->archive_read_close(&a_ptr).value();
|
||||
}
|
||||
|
||||
int archive_read_free(archive* a) {
|
||||
sapi::v::RemotePtr a_ptr(a);
|
||||
return api->archive_read_free(&a_ptr).value();
|
||||
}
|
||||
|
||||
int archive_write_close(archive* a) {
|
||||
sapi::v::RemotePtr a_ptr(a);
|
||||
return api->archive_write_close(&a_ptr).value();
|
||||
}
|
||||
|
||||
int archive_write_free(archive* a) {
|
||||
sapi::v::RemotePtr a_ptr(a);
|
||||
return api->archive_write_free(&a_ptr).value();
|
||||
}
|
||||
|
||||
int archive_write_header(archive* a, archive_entry* entry) {
|
||||
sapi::v::RemotePtr a_ptr(a), entry_ptr(entry);
|
||||
return api->archive_write_header(&a_ptr, &entry_ptr).value();
|
||||
}
|
||||
|
||||
int archive_read_data_block(archive* a, const void** buff, size_t* size,
|
||||
la_int64_t* offset) {
|
||||
sapi::v::IntBase<archive_entry*> buff_ptr_tmp(0);
|
||||
sapi::v::ULLong size_tmp;
|
||||
sapi::v::SLLong offset_tmp;
|
||||
sapi::v::RemotePtr a_ptr(a);
|
||||
|
||||
int rv =
|
||||
api->archive_read_data_block(&a_ptr, buff_ptr_tmp.PtrAfter(),
|
||||
size_tmp.PtrAfter(), offset_tmp.PtrAfter())
|
||||
.value();
|
||||
*buff = buff_ptr_tmp.GetValue();
|
||||
*size = size_tmp.GetValue();
|
||||
*offset = offset_tmp.GetValue();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
la_ssize_t archive_write_data_block(archive* a, const void* buff, size_t s,
|
||||
la_int64_t o) {
|
||||
sapi::v::RemotePtr buff_ptr((void*)(buff));
|
||||
sapi::v::RemotePtr a_ptr(a);
|
||||
|
||||
return api->archive_write_data_block(&a_ptr, &buff_ptr, s, o).value();
|
||||
}
|
Loading…
Reference in New Issue
Block a user