rework unpacking of packages and harden package file format requirements
A crafted .apk file could to trick apk writing unverified data to an unexpected file during temporary file creation due to bugs in handling long link target name and the way a regular file is extracted. Several hardening steps are implemented to avoid this: - the temporary file is now always first unlinked (apk thus reserved all filenames .apk.* to be it's working files) - the temporary file is after that created with O_EXCL to avoid races - the temporary file is no longer directly the archive entry name and thus directly controlled by potentially untrusted data - long file names and link target names are now rejected - hard link targets are now more rigorously checked - various additional checks added for the extraction process to error out early in case of malformed (or old legacy) file Reported-by: Max Justicz <max@justi.cz>cute-signatures
parent
b11f9aa928
commit
6484ed9849
|
@ -28,7 +28,8 @@ int apk_tar_write_entry(struct apk_ostream *, const struct apk_file_info *ae,
|
||||||
int apk_tar_write_padding(struct apk_ostream *, const struct apk_file_info *ae);
|
int apk_tar_write_padding(struct apk_ostream *, const struct apk_file_info *ae);
|
||||||
|
|
||||||
int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae,
|
int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae,
|
||||||
const char *suffix, struct apk_istream *is,
|
const char *extract_name, const char *hardlink_name,
|
||||||
|
struct apk_istream *is,
|
||||||
apk_progress_cb cb, void *cb_ctx);
|
apk_progress_cb cb, void *cb_ctx);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -317,6 +317,12 @@ int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strnlen(entry.name, PATH_MAX) >= PATH_MAX-10 ||
|
||||||
|
(entry.link_target && strnlen(entry.link_target, PATH_MAX) >= PATH_MAX-10)) {
|
||||||
|
r = -ENAMETOOLONG;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
teis.bytes_left = entry.size;
|
teis.bytes_left = entry.size;
|
||||||
if (entry.mode & S_IFMT) {
|
if (entry.mode & S_IFMT) {
|
||||||
/* callback parser function */
|
/* callback parser function */
|
||||||
|
@ -428,23 +434,15 @@ int apk_tar_write_padding(struct apk_ostream *os, const struct apk_file_info *ae
|
||||||
}
|
}
|
||||||
|
|
||||||
int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae,
|
int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae,
|
||||||
const char *suffix, struct apk_istream *is,
|
const char *extract_name, const char *link_target,
|
||||||
|
struct apk_istream *is,
|
||||||
apk_progress_cb cb, void *cb_ctx)
|
apk_progress_cb cb, void *cb_ctx)
|
||||||
{
|
{
|
||||||
struct apk_xattr *xattr;
|
struct apk_xattr *xattr;
|
||||||
char *fn = ae->name;
|
const char *fn = extract_name ?: ae->name;
|
||||||
int fd, r = -1, atflags = 0, ret = 0;
|
int fd, r = -1, atflags = 0, ret = 0;
|
||||||
|
|
||||||
if (suffix != NULL) {
|
if (unlinkat(atfd, fn, 0) != 0 && errno != ENOENT) return -errno;
|
||||||
fn = alloca(PATH_MAX);
|
|
||||||
snprintf(fn, PATH_MAX, "%s%s", ae->name, suffix);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((!S_ISDIR(ae->mode) && !S_ISREG(ae->mode)) ||
|
|
||||||
(ae->link_target != NULL)) {
|
|
||||||
/* non-standard entries need to be deleted first */
|
|
||||||
unlinkat(atfd, fn, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ae->mode & S_IFMT) {
|
switch (ae->mode & S_IFMT) {
|
||||||
case S_IFDIR:
|
case S_IFDIR:
|
||||||
|
@ -454,7 +452,7 @@ int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae,
|
||||||
break;
|
break;
|
||||||
case S_IFREG:
|
case S_IFREG:
|
||||||
if (ae->link_target == NULL) {
|
if (ae->link_target == NULL) {
|
||||||
int flags = O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC;
|
int flags = O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC | O_EXCL;
|
||||||
|
|
||||||
fd = openat(atfd, fn, flags, ae->mode & 07777);
|
fd = openat(atfd, fn, flags, ae->mode & 07777);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
|
@ -465,18 +463,12 @@ int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae,
|
||||||
if (r != ae->size) ret = r < 0 ? r : -ENOSPC;
|
if (r != ae->size) ret = r < 0 ? r : -ENOSPC;
|
||||||
close(fd);
|
close(fd);
|
||||||
} else {
|
} else {
|
||||||
char *link_target = ae->link_target;
|
r = linkat(atfd, link_target ?: ae->link_target, atfd, fn, 0);
|
||||||
if (suffix != NULL) {
|
|
||||||
link_target = alloca(PATH_MAX);
|
|
||||||
snprintf(link_target, PATH_MAX, "%s%s",
|
|
||||||
ae->link_target, suffix);
|
|
||||||
}
|
|
||||||
r = linkat(atfd, link_target, atfd, fn, 0);
|
|
||||||
if (r < 0) ret = -errno;
|
if (r < 0) ret = -errno;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case S_IFLNK:
|
case S_IFLNK:
|
||||||
r = symlinkat(ae->link_target, atfd, fn);
|
r = symlinkat(link_target ?: ae->link_target, atfd, fn);
|
||||||
if (r < 0) ret = -errno;
|
if (r < 0) ret = -errno;
|
||||||
atflags |= AT_SYMLINK_NOFOLLOW;
|
atflags |= AT_SYMLINK_NOFOLLOW;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -232,8 +232,8 @@ static int run_commit_hook(void *ctx, int dirfd, const char *file)
|
||||||
struct apk_database *db = hook->db;
|
struct apk_database *db = hook->db;
|
||||||
char fn[PATH_MAX], *argv[] = { fn, (char *) commit_hook_str[hook->type], NULL };
|
char fn[PATH_MAX], *argv[] = { fn, (char *) commit_hook_str[hook->type], NULL };
|
||||||
|
|
||||||
if ((apk_flags & (APK_NO_SCRIPTS | APK_SIMULATE)) != 0)
|
if (file[0] == '.') return 0;
|
||||||
return 0;
|
if ((apk_flags & (APK_NO_SCRIPTS | APK_SIMULATE)) != 0) return 0;
|
||||||
|
|
||||||
snprintf(fn, sizeof(fn), "etc/apk/commit_hooks.d" "/%s", file);
|
snprintf(fn, sizeof(fn), "etc/apk/commit_hooks.d" "/%s", file);
|
||||||
if ((apk_flags & APK_NO_COMMIT_HOOKS) != 0) {
|
if ((apk_flags & APK_NO_COMMIT_HOOKS) != 0) {
|
||||||
|
|
156
src/database.c
156
src/database.c
|
@ -828,8 +828,9 @@ int apk_db_index_read(struct apk_database *db, struct apk_bstream *bs, int repo)
|
||||||
case 'F':
|
case 'F':
|
||||||
if (diri) apk_db_dir_apply_diri_permissions(diri);
|
if (diri) apk_db_dir_apply_diri_permissions(diri);
|
||||||
if (pkg->name == NULL) goto bad_entry;
|
if (pkg->name == NULL) goto bad_entry;
|
||||||
diri = apk_db_diri_new(db, pkg, l, &diri_node);
|
diri = find_diri(ipkg, l, NULL, &diri_node);
|
||||||
file_diri_node = &diri->owned_files.first;
|
if (!diri) diri = apk_db_diri_new(db, pkg, l, &diri_node);
|
||||||
|
file_diri_node = hlist_tail_ptr(&diri->owned_files);
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
if (file == NULL) goto bad_entry;
|
if (file == NULL) goto bad_entry;
|
||||||
|
@ -2358,6 +2359,31 @@ static struct apk_db_dir_instance *apk_db_install_directory_entry(struct install
|
||||||
return diri;
|
return diri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define TMPNAME_MAX (PATH_MAX + 64)
|
||||||
|
|
||||||
|
static const char *format_tmpname(struct apk_package *pkg, struct apk_db_file *f, char tmpname[static TMPNAME_MAX])
|
||||||
|
{
|
||||||
|
EVP_MD_CTX mdctx;
|
||||||
|
unsigned char md[EVP_MAX_MD_SIZE];
|
||||||
|
apk_blob_t b = APK_BLOB_PTR_LEN(tmpname, TMPNAME_MAX);
|
||||||
|
|
||||||
|
if (!f) return NULL;
|
||||||
|
|
||||||
|
EVP_DigestInit(&mdctx, EVP_sha256());
|
||||||
|
EVP_DigestUpdate(&mdctx, pkg->name->name, strlen(pkg->name->name) + 1);
|
||||||
|
EVP_DigestUpdate(&mdctx, f->diri->dir->name, f->diri->dir->namelen);
|
||||||
|
EVP_DigestUpdate(&mdctx, "/", 1);
|
||||||
|
EVP_DigestUpdate(&mdctx, f->name, f->namelen);
|
||||||
|
EVP_DigestFinal(&mdctx, md, NULL);
|
||||||
|
|
||||||
|
apk_blob_push_blob(&b, APK_BLOB_PTR_LEN(f->diri->dir->name, f->diri->dir->namelen));
|
||||||
|
apk_blob_push_blob(&b, APK_BLOB_STR("/.apk."));
|
||||||
|
apk_blob_push_hexdump(&b, APK_BLOB_PTR_LEN((char *)md, 24));
|
||||||
|
apk_blob_push_blob(&b, APK_BLOB_PTR_LEN("", 1));
|
||||||
|
|
||||||
|
return tmpname;
|
||||||
|
}
|
||||||
|
|
||||||
static int apk_db_install_archive_entry(void *_ctx,
|
static int apk_db_install_archive_entry(void *_ctx,
|
||||||
const struct apk_file_info *ae,
|
const struct apk_file_info *ae,
|
||||||
struct apk_istream *is)
|
struct apk_istream *is)
|
||||||
|
@ -2369,8 +2395,9 @@ static int apk_db_install_archive_entry(void *_ctx,
|
||||||
struct apk_installed_package *ipkg = pkg->ipkg;
|
struct apk_installed_package *ipkg = pkg->ipkg;
|
||||||
apk_blob_t name = APK_BLOB_STR(ae->name), bdir, bfile;
|
apk_blob_t name = APK_BLOB_STR(ae->name), bdir, bfile;
|
||||||
struct apk_db_dir_instance *diri = ctx->diri;
|
struct apk_db_dir_instance *diri = ctx->diri;
|
||||||
struct apk_db_file *file;
|
struct apk_db_file *file, *link_target_file = NULL;
|
||||||
int ret = 0, r, type = APK_SCRIPT_INVALID;
|
int ret = 0, r, type = APK_SCRIPT_INVALID;
|
||||||
|
char tmpname_file[TMPNAME_MAX], tmpname_link_target[TMPNAME_MAX];
|
||||||
|
|
||||||
r = apk_sign_ctx_process_file(&ctx->sctx, ae, is);
|
r = apk_sign_ctx_process_file(&ctx->sctx, ae, is);
|
||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
|
@ -2437,6 +2464,40 @@ static int apk_db_install_archive_entry(void *_ctx,
|
||||||
diri = apk_db_install_directory_entry(ctx, bdir);
|
diri = apk_db_install_directory_entry(ctx, bdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check hard link target to exist in this package */
|
||||||
|
if (S_ISREG(ae->mode) && ae->link_target) {
|
||||||
|
do {
|
||||||
|
struct apk_db_file *lfile;
|
||||||
|
struct apk_db_dir_instance *ldiri;
|
||||||
|
struct hlist_node *n;
|
||||||
|
apk_blob_t hldir, hlfile;
|
||||||
|
|
||||||
|
if (!apk_blob_rsplit(APK_BLOB_STR(ae->link_target),
|
||||||
|
'/', &hldir, &hlfile))
|
||||||
|
break;
|
||||||
|
|
||||||
|
ldiri = find_diri(ipkg, hldir, diri, NULL);
|
||||||
|
if (ldiri == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
hlist_for_each_entry(lfile, n, &ldiri->owned_files,
|
||||||
|
diri_files_list) {
|
||||||
|
if (apk_blob_compare(APK_BLOB_PTR_LEN(lfile->name, lfile->namelen),
|
||||||
|
hlfile) == 0) {
|
||||||
|
link_target_file = lfile;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
if (!link_target_file) {
|
||||||
|
apk_error(PKG_VER_FMT": "BLOB_FMT": no hard link target (%s) in archive",
|
||||||
|
PKG_VER_PRINTF(pkg), BLOB_PRINTF(name), ae->link_target);
|
||||||
|
ipkg->broken_files = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
opkg = NULL;
|
opkg = NULL;
|
||||||
file = apk_db_file_query(db, bdir, bfile);
|
file = apk_db_file_query(db, bdir, bfile);
|
||||||
if (file != NULL) {
|
if (file != NULL) {
|
||||||
|
@ -2495,41 +2556,21 @@ static int apk_db_install_archive_entry(void *_ctx,
|
||||||
if (apk_verbosity >= 3)
|
if (apk_verbosity >= 3)
|
||||||
apk_message("%s", ae->name);
|
apk_message("%s", ae->name);
|
||||||
|
|
||||||
/* Extract the file as name.apk-new */
|
/* Extract the file with temporary name */
|
||||||
file->acl = apk_db_acl_atomize(ae->mode, ae->uid, ae->gid, &ae->xattr_csum);
|
file->acl = apk_db_acl_atomize(ae->mode, ae->uid, ae->gid, &ae->xattr_csum);
|
||||||
r = apk_archive_entry_extract(db->root_fd, ae, ".apk-new", is,
|
r = apk_archive_entry_extract(
|
||||||
extract_cb, ctx);
|
db->root_fd, ae,
|
||||||
|
format_tmpname(pkg, file, tmpname_file),
|
||||||
|
format_tmpname(pkg, link_target_file, tmpname_link_target),
|
||||||
|
is, extract_cb, ctx);
|
||||||
|
|
||||||
switch (r) {
|
switch (r) {
|
||||||
case 0:
|
case 0:
|
||||||
/* Hardlinks need special care for checksum */
|
/* Hardlinks need special care for checksum */
|
||||||
if (ae->csum.type == APK_CHECKSUM_NONE &&
|
if (link_target_file)
|
||||||
ae->link_target != NULL) {
|
memcpy(&file->csum, &link_target_file->csum, sizeof file->csum);
|
||||||
do {
|
else
|
||||||
struct apk_db_file *lfile;
|
memcpy(&file->csum, &ae->csum, sizeof file->csum);
|
||||||
struct apk_db_dir_instance *ldiri;
|
|
||||||
struct hlist_node *n;
|
|
||||||
|
|
||||||
if (!apk_blob_rsplit(APK_BLOB_STR(ae->link_target),
|
|
||||||
'/', &bdir, &bfile))
|
|
||||||
break;
|
|
||||||
|
|
||||||
ldiri = find_diri(ipkg, bdir, diri, NULL);
|
|
||||||
if (ldiri == NULL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
hlist_for_each_entry(lfile, n, &ldiri->owned_files,
|
|
||||||
diri_files_list) {
|
|
||||||
if (apk_blob_compare(APK_BLOB_PTR_LEN(lfile->name, lfile->namelen),
|
|
||||||
bfile) == 0) {
|
|
||||||
memcpy(&file->csum, &lfile->csum,
|
|
||||||
sizeof(file->csum));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (0);
|
|
||||||
} else
|
|
||||||
memcpy(&file->csum, &ae->csum, sizeof(file->csum));
|
|
||||||
break;
|
break;
|
||||||
case -ENOTSUP:
|
case -ENOTSUP:
|
||||||
ipkg->broken_xattr = 1;
|
ipkg->broken_xattr = 1;
|
||||||
|
@ -2547,8 +2588,11 @@ static int apk_db_install_archive_entry(void *_ctx,
|
||||||
if (name.ptr[name.len-1] == '/')
|
if (name.ptr[name.len-1] == '/')
|
||||||
name.len--;
|
name.len--;
|
||||||
|
|
||||||
|
diri = ctx->diri = find_diri(ipkg, name, NULL, &ctx->file_diri_node);
|
||||||
|
if (!diri) {
|
||||||
diri = apk_db_install_directory_entry(ctx, name);
|
diri = apk_db_install_directory_entry(ctx, name);
|
||||||
apk_db_dir_prepare(db, diri->dir, ae->mode);
|
apk_db_dir_prepare(db, diri->dir, ae->mode);
|
||||||
|
}
|
||||||
apk_db_diri_set(diri, apk_db_acl_atomize(ae->mode, ae->uid, ae->gid, &ae->xattr_csum));
|
apk_db_diri_set(diri, apk_db_acl_atomize(ae->mode, ae->uid, ae->gid, &ae->xattr_csum));
|
||||||
}
|
}
|
||||||
ctx->installed_size += ctx->current_file_size;
|
ctx->installed_size += ctx->current_file_size;
|
||||||
|
@ -2558,7 +2602,7 @@ static int apk_db_install_archive_entry(void *_ctx,
|
||||||
|
|
||||||
static void apk_db_purge_pkg(struct apk_database *db,
|
static void apk_db_purge_pkg(struct apk_database *db,
|
||||||
struct apk_installed_package *ipkg,
|
struct apk_installed_package *ipkg,
|
||||||
const char *exten)
|
int is_installed)
|
||||||
{
|
{
|
||||||
struct apk_db_dir_instance *diri;
|
struct apk_db_dir_instance *diri;
|
||||||
struct apk_db_file *file;
|
struct apk_db_file *file;
|
||||||
|
@ -2566,17 +2610,16 @@ static void apk_db_purge_pkg(struct apk_database *db,
|
||||||
struct apk_file_info fi;
|
struct apk_file_info fi;
|
||||||
struct hlist_node *dc, *dn, *fc, *fn;
|
struct hlist_node *dc, *dn, *fc, *fn;
|
||||||
unsigned long hash;
|
unsigned long hash;
|
||||||
char name[PATH_MAX];
|
char name[TMPNAME_MAX];
|
||||||
|
|
||||||
hlist_for_each_entry_safe(diri, dc, dn, &ipkg->owned_dirs, pkg_dirs_list) {
|
hlist_for_each_entry_safe(diri, dc, dn, &ipkg->owned_dirs, pkg_dirs_list) {
|
||||||
if (exten == NULL)
|
if (is_installed) diri->dir->modified = 1;
|
||||||
diri->dir->modified = 1;
|
|
||||||
|
|
||||||
hlist_for_each_entry_safe(file, fc, fn, &diri->owned_files, diri_files_list) {
|
hlist_for_each_entry_safe(file, fc, fn, &diri->owned_files, diri_files_list) {
|
||||||
snprintf(name, sizeof(name),
|
if (is_installed)
|
||||||
DIR_FILE_FMT "%s",
|
snprintf(name, sizeof name, DIR_FILE_FMT, DIR_FILE_PRINTF(diri->dir, file));
|
||||||
DIR_FILE_PRINTF(diri->dir, file),
|
else
|
||||||
exten ?: "");
|
format_tmpname(ipkg->pkg, file, name);
|
||||||
|
|
||||||
key = (struct apk_db_file_hash_key) {
|
key = (struct apk_db_file_hash_key) {
|
||||||
.dirname = APK_BLOB_PTR_LEN(diri->dir->name, diri->dir->namelen),
|
.dirname = APK_BLOB_PTR_LEN(diri->dir->name, diri->dir->namelen),
|
||||||
|
@ -2592,7 +2635,7 @@ static void apk_db_purge_pkg(struct apk_database *db,
|
||||||
if (apk_verbosity >= 3)
|
if (apk_verbosity >= 3)
|
||||||
apk_message("%s", name);
|
apk_message("%s", name);
|
||||||
__hlist_del(fc, &diri->owned_files.first);
|
__hlist_del(fc, &diri->owned_files.first);
|
||||||
if (exten == NULL) {
|
if (is_installed) {
|
||||||
apk_hash_delete_hashed(&db->installed.files, APK_BLOB_BUF(&key), hash);
|
apk_hash_delete_hashed(&db->installed.files, APK_BLOB_BUF(&key), hash);
|
||||||
db->installed.stats.files--;
|
db->installed.stats.files--;
|
||||||
}
|
}
|
||||||
|
@ -2613,7 +2656,7 @@ static void apk_db_migrate_files(struct apk_database *db,
|
||||||
struct apk_file_info fi;
|
struct apk_file_info fi;
|
||||||
struct hlist_node *dc, *dn, *fc, *fn;
|
struct hlist_node *dc, *dn, *fc, *fn;
|
||||||
unsigned long hash;
|
unsigned long hash;
|
||||||
char name[PATH_MAX], tmpname[PATH_MAX];
|
char name[PATH_MAX], tmpname[TMPNAME_MAX];
|
||||||
int cstype, r;
|
int cstype, r;
|
||||||
|
|
||||||
hlist_for_each_entry_safe(diri, dc, dn, &ipkg->owned_dirs, pkg_dirs_list) {
|
hlist_for_each_entry_safe(diri, dc, dn, &ipkg->owned_dirs, pkg_dirs_list) {
|
||||||
|
@ -2621,10 +2664,8 @@ static void apk_db_migrate_files(struct apk_database *db,
|
||||||
dir->modified = 1;
|
dir->modified = 1;
|
||||||
|
|
||||||
hlist_for_each_entry_safe(file, fc, fn, &diri->owned_files, diri_files_list) {
|
hlist_for_each_entry_safe(file, fc, fn, &diri->owned_files, diri_files_list) {
|
||||||
snprintf(name, sizeof(name), DIR_FILE_FMT,
|
snprintf(name, sizeof(name), DIR_FILE_FMT, DIR_FILE_PRINTF(diri->dir, file));
|
||||||
DIR_FILE_PRINTF(diri->dir, file));
|
format_tmpname(ipkg->pkg, file, tmpname);
|
||||||
snprintf(tmpname, sizeof(tmpname), DIR_FILE_FMT ".apk-new",
|
|
||||||
DIR_FILE_PRINTF(diri->dir, file));
|
|
||||||
|
|
||||||
key = (struct apk_db_file_hash_key) {
|
key = (struct apk_db_file_hash_key) {
|
||||||
.dirname = APK_BLOB_PTR_LEN(dir->name, dir->namelen),
|
.dirname = APK_BLOB_PTR_LEN(dir->name, dir->namelen),
|
||||||
|
@ -2665,8 +2706,21 @@ static void apk_db_migrate_files(struct apk_database *db,
|
||||||
APK_FI_NOFOLLOW | file->csum.type, &fi);
|
APK_FI_NOFOLLOW | file->csum.type, &fi);
|
||||||
if ((apk_flags & APK_CLEAN_PROTECTED) ||
|
if ((apk_flags & APK_CLEAN_PROTECTED) ||
|
||||||
(file->csum.type != APK_CHECKSUM_NONE &&
|
(file->csum.type != APK_CHECKSUM_NONE &&
|
||||||
apk_checksum_compare(&file->csum, &fi.csum) == 0))
|
apk_checksum_compare(&file->csum, &fi.csum) == 0)) {
|
||||||
unlinkat(db->root_fd, tmpname, 0);
|
unlinkat(db->root_fd, tmpname, 0);
|
||||||
|
} else {
|
||||||
|
snprintf(name, sizeof name,
|
||||||
|
DIR_FILE_FMT ".apk-new",
|
||||||
|
DIR_FILE_PRINTF(diri->dir, file));
|
||||||
|
if (renameat(db->root_fd, tmpname,
|
||||||
|
db->root_fd, name) != 0) {
|
||||||
|
apk_error(PKG_VER_FMT": failed to rename %s to %s.",
|
||||||
|
PKG_VER_PRINTF(ipkg->pkg),
|
||||||
|
tmpname, name);
|
||||||
|
ipkg->broken_files = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* Overwrite the old file */
|
/* Overwrite the old file */
|
||||||
if (renameat(db->root_fd, tmpname,
|
if (renameat(db->root_fd, tmpname,
|
||||||
|
@ -2799,7 +2853,7 @@ int apk_db_install_pkg(struct apk_database *db, struct apk_package *oldpkg,
|
||||||
if (ipkg == NULL)
|
if (ipkg == NULL)
|
||||||
goto ret_r;
|
goto ret_r;
|
||||||
apk_ipkg_run_script(ipkg, db, APK_SCRIPT_PRE_DEINSTALL, script_args);
|
apk_ipkg_run_script(ipkg, db, APK_SCRIPT_PRE_DEINSTALL, script_args);
|
||||||
apk_db_purge_pkg(db, ipkg, NULL);
|
apk_db_purge_pkg(db, ipkg, TRUE);
|
||||||
apk_ipkg_run_script(ipkg, db, APK_SCRIPT_POST_DEINSTALL, script_args);
|
apk_ipkg_run_script(ipkg, db, APK_SCRIPT_POST_DEINSTALL, script_args);
|
||||||
apk_pkg_uninstall(db, oldpkg);
|
apk_pkg_uninstall(db, oldpkg);
|
||||||
goto ret_r;
|
goto ret_r;
|
||||||
|
@ -2822,7 +2876,7 @@ int apk_db_install_pkg(struct apk_database *db, struct apk_package *oldpkg,
|
||||||
cb, cb_ctx, script_args);
|
cb, cb_ctx, script_args);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
if (oldpkg != newpkg)
|
if (oldpkg != newpkg)
|
||||||
apk_db_purge_pkg(db, ipkg, ".apk-new");
|
apk_db_purge_pkg(db, ipkg, FALSE);
|
||||||
apk_pkg_uninstall(db, newpkg);
|
apk_pkg_uninstall(db, newpkg);
|
||||||
goto ret_r;
|
goto ret_r;
|
||||||
}
|
}
|
||||||
|
@ -2830,7 +2884,7 @@ int apk_db_install_pkg(struct apk_database *db, struct apk_package *oldpkg,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldpkg != NULL && oldpkg != newpkg && oldpkg->ipkg != NULL) {
|
if (oldpkg != NULL && oldpkg != newpkg && oldpkg->ipkg != NULL) {
|
||||||
apk_db_purge_pkg(db, oldpkg->ipkg, NULL);
|
apk_db_purge_pkg(db, oldpkg->ipkg, TRUE);
|
||||||
apk_pkg_uninstall(db, oldpkg);
|
apk_pkg_uninstall(db, oldpkg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
35
src/gunzip.c
35
src/gunzip.c
|
@ -37,6 +37,16 @@ static void gzi_get_meta(void *stream, struct apk_file_meta *meta)
|
||||||
apk_bstream_get_meta(gis->bs, meta);
|
apk_bstream_get_meta(gis->bs, meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int gzi_boundary_change(struct apk_gzip_istream *gis)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = gis->cb(gis->cbctx, gis->err ? APK_MPART_END : APK_MPART_BOUNDARY, gis->cbarg);
|
||||||
|
if (r > 0) r = -ECANCELED;
|
||||||
|
if (r != 0) gis->err = r;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t gzi_read(void *stream, void *ptr, size_t size)
|
static ssize_t gzi_read(void *stream, void *ptr, size_t size)
|
||||||
{
|
{
|
||||||
struct apk_gzip_istream *gis =
|
struct apk_gzip_istream *gis =
|
||||||
|
@ -57,15 +67,8 @@ static ssize_t gzi_read(void *stream, void *ptr, size_t size)
|
||||||
|
|
||||||
while (gis->zs.avail_out != 0 && gis->err == 0) {
|
while (gis->zs.avail_out != 0 && gis->err == 0) {
|
||||||
if (!APK_BLOB_IS_NULL(gis->cbarg)) {
|
if (!APK_BLOB_IS_NULL(gis->cbarg)) {
|
||||||
r = gis->cb(gis->cbctx,
|
if (gzi_boundary_change(gis))
|
||||||
gis->err ? APK_MPART_END : APK_MPART_BOUNDARY,
|
|
||||||
gis->cbarg);
|
|
||||||
if (r > 0)
|
|
||||||
r = -ECANCELED;
|
|
||||||
if (r != 0) {
|
|
||||||
gis->err = r;
|
|
||||||
goto ret;
|
goto ret;
|
||||||
}
|
|
||||||
gis->cbarg = APK_BLOB_NULL;
|
gis->cbarg = APK_BLOB_NULL;
|
||||||
}
|
}
|
||||||
if (gis->zs.avail_in == 0) {
|
if (gis->zs.avail_in == 0) {
|
||||||
|
@ -86,14 +89,8 @@ static ssize_t gzi_read(void *stream, void *ptr, size_t size)
|
||||||
goto ret;
|
goto ret;
|
||||||
} else if (gis->zs.avail_in == 0) {
|
} else if (gis->zs.avail_in == 0) {
|
||||||
gis->err = 1;
|
gis->err = 1;
|
||||||
if (gis->cb != NULL) {
|
gis->cbarg = APK_BLOB_NULL;
|
||||||
r = gis->cb(gis->cbctx, APK_MPART_END,
|
gzi_boundary_change(gis);
|
||||||
APK_BLOB_NULL);
|
|
||||||
if (r > 0)
|
|
||||||
r = -ECANCELED;
|
|
||||||
if (r != 0)
|
|
||||||
gis->err = r;
|
|
||||||
}
|
|
||||||
goto ret;
|
goto ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,11 +112,7 @@ static ssize_t gzi_read(void *stream, void *ptr, size_t size)
|
||||||
* For boundaries it should be postponed to not
|
* For boundaries it should be postponed to not
|
||||||
* be called until next gzip read is started. */
|
* be called until next gzip read is started. */
|
||||||
if (gis->err) {
|
if (gis->err) {
|
||||||
r = gis->cb(gis->cbctx,
|
gzi_boundary_change(gis);
|
||||||
gis->err ? APK_MPART_END : APK_MPART_BOUNDARY,
|
|
||||||
gis->cbarg);
|
|
||||||
if (r > 0)
|
|
||||||
r = -ECANCELED;
|
|
||||||
goto ret;
|
goto ret;
|
||||||
}
|
}
|
||||||
inflateEnd(&gis->zs);
|
inflateEnd(&gis->zs);
|
||||||
|
|
|
@ -476,13 +476,7 @@ void apk_sign_ctx_init(struct apk_sign_ctx *ctx, int action,
|
||||||
ctx->md = EVP_md_null();
|
ctx->md = EVP_md_null();
|
||||||
break;
|
break;
|
||||||
case APK_SIGN_VERIFY_IDENTITY:
|
case APK_SIGN_VERIFY_IDENTITY:
|
||||||
if (identity->type == APK_CHECKSUM_MD5) {
|
|
||||||
ctx->md = EVP_md5();
|
|
||||||
ctx->control_started = 1;
|
|
||||||
ctx->data_started = 1;
|
|
||||||
} else {
|
|
||||||
ctx->md = EVP_sha1();
|
ctx->md = EVP_sha1();
|
||||||
}
|
|
||||||
memcpy(&ctx->identity, identity, sizeof(ctx->identity));
|
memcpy(&ctx->identity, identity, sizeof(ctx->identity));
|
||||||
break;
|
break;
|
||||||
case APK_SIGN_GENERATE:
|
case APK_SIGN_GENERATE:
|
||||||
|
@ -552,6 +546,9 @@ int apk_sign_ctx_process_file(struct apk_sign_ctx *ctx,
|
||||||
* style .PKGINFO */
|
* style .PKGINFO */
|
||||||
if (ctx->has_data_checksum)
|
if (ctx->has_data_checksum)
|
||||||
return -ENOMSG;
|
return -ENOMSG;
|
||||||
|
/* Error out early if identity part is missing */
|
||||||
|
if (ctx->action == APK_SIGN_VERIFY_IDENTITY)
|
||||||
|
return -EKEYREJECTED;
|
||||||
ctx->data_started = 1;
|
ctx->data_started = 1;
|
||||||
ctx->control_started = 1;
|
ctx->control_started = 1;
|
||||||
r = check_signing_key_trust(ctx);
|
r = check_signing_key_trust(ctx);
|
||||||
|
|
Loading…
Reference in New Issue