From 19419f1a88285a0dee53bdf49201c4d3d4cbf19f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 8 Oct 2010 15:36:54 +0300 Subject: [PATCH 1/2] io, db: id cache should be specific to database root, not system root Otherwise we end up using wrong uid/gid mappings when doing install to alternate system root. Fixes #434. --- src/apk.c | 2 - src/apk_archive.h | 2 +- src/apk_database.h | 2 + src/apk_io.h | 18 ++++++++--- src/apk_package.h | 5 ++- src/archive.c | 6 ++-- src/database.c | 22 ++++++++----- src/io.c | 88 ++++++++++++++++++++++++++++++--------------------- src/package.c | 9 +++-- src/verify.c | 2 +- 10 files changed, 93 insertions(+), 63 deletions(-) diff --git a/src/apk.c b/src/apk.c index 4196f74..55628c1 100644 --- a/src/apk.c +++ b/src/apk.c @@ -248,7 +248,6 @@ int main(int argc, char **argv) memset(&dbopts, 0, sizeof(dbopts)); list_init(&dbopts.repository_list); umask(0); - apk_id_cache_init(); applet = deduce_applet(argc, argv); num_options = ARRAY_SIZE(generic_options) + 1; @@ -370,7 +369,6 @@ int main(int argc, char **argv) r = applet->main(ctx, &db, argc, argv); apk_db_close(&db); - apk_id_cache_free(); if (r == -EINVAL) return usage(applet); diff --git a/src/apk_archive.h b/src/apk_archive.h index f1b5aaf..ff4fb48 100644 --- a/src/apk_archive.h +++ b/src/apk_archive.h @@ -22,7 +22,7 @@ typedef int (*apk_archive_entry_parser)(void *ctx, int apk_tar_parse(struct apk_istream *, apk_archive_entry_parser parser, void *ctx, - int soft_checksums); + int soft_checksums, struct apk_id_cache *); int apk_tar_write_entry(struct apk_ostream *, const struct apk_file_info *ae, const char *data); int apk_tar_write_padding(struct apk_ostream *, const struct apk_file_info *ae); diff --git a/src/apk_database.h b/src/apk_database.h index da33289..249ddae 100644 --- a/src/apk_database.h +++ b/src/apk_database.h @@ -16,6 +16,7 @@ #include "apk_hash.h" #include "apk_archive.h" #include "apk_package.h" +#include "apk_io.h" #define APK_MAX_REPOS 32 #define APK_CACHE_CSUM_BYTES 4 @@ -109,6 +110,7 @@ struct apk_database { struct apk_dependency_array *world; struct apk_string_array *protected_paths; struct apk_repository repos[APK_MAX_REPOS]; + struct apk_id_cache id_cache; struct { struct apk_hash names; diff --git a/src/apk_io.h b/src/apk_io.h index 3a3abff..20051a6 100644 --- a/src/apk_io.h +++ b/src/apk_io.h @@ -15,6 +15,14 @@ #include "apk_defines.h" #include "apk_blob.h" +#include "apk_hash.h" + +struct apk_id_cache { + int root_fd; + unsigned int genid; + struct apk_hash uid_cache; + struct apk_hash gid_cache; +}; struct apk_file_info { char *name; @@ -95,10 +103,10 @@ int apk_file_get_info(int atfd, const char *filename, unsigned int flags, int apk_url_download(const char *url, int atfd, const char *file); const char *apk_url_local_file(const char *url); -void apk_id_cache_init(void); -void apk_id_cache_free(void); -void apk_id_cache_reset(void); -uid_t apk_resolve_uid(const char *username, uid_t default_uid); -uid_t apk_resolve_gid(const char *groupname, uid_t default_gid); +void apk_id_cache_init(struct apk_id_cache *idc, int root_fd); +void apk_id_cache_free(struct apk_id_cache *idc); +void apk_id_cache_reset(struct apk_id_cache *idc); +uid_t apk_resolve_uid(struct apk_id_cache *idc, const char *username, uid_t default_uid); +uid_t apk_resolve_gid(struct apk_id_cache *idc, const char *groupname, uid_t default_gid); #endif diff --git a/src/apk_package.h b/src/apk_package.h index 7901ddb..55f6845 100644 --- a/src/apk_package.h +++ b/src/apk_package.h @@ -143,8 +143,9 @@ void apk_pkg_uninstall(struct apk_database *db, struct apk_package *pkg); int apk_ipkg_add_script(struct apk_installed_package *ipkg, struct apk_istream *is, unsigned int type, unsigned int size); -int apk_ipkg_run_script(struct apk_installed_package *ipkg, int root_fd, - unsigned int type, char **argv); +int apk_ipkg_run_script(struct apk_installed_package *ipkg, + struct apk_database *db, + unsigned int type, char **argv); struct apk_package *apk_pkg_parse_index_entry(struct apk_database *db, apk_blob_t entry); int apk_pkg_write_index_entry(struct apk_package *pkg, struct apk_ostream *os); diff --git a/src/archive.c b/src/archive.c index b60b3b2..6e555b4 100644 --- a/src/archive.c +++ b/src/archive.c @@ -117,7 +117,7 @@ static void tar_entry_close(void *stream) } int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser, - void *ctx, int soft_checksums) + void *ctx, int soft_checksums, struct apk_id_cache *idc) { struct apk_file_info entry; struct apk_tar_entry_istream teis = { @@ -146,8 +146,8 @@ int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser, entry = (struct apk_file_info){ .size = GET_OCTAL(buf.size), - .uid = apk_resolve_uid(buf.uname, GET_OCTAL(buf.uid)), - .gid = apk_resolve_gid(buf.gname, GET_OCTAL(buf.gid)), + .uid = apk_resolve_uid(idc, buf.uname, GET_OCTAL(buf.uid)), + .gid = apk_resolve_gid(idc, buf.gname, GET_OCTAL(buf.gid)), .mode = GET_OCTAL(buf.mode) & 07777, .mtime = GET_OCTAL(buf.mtime), .name = entry.name, diff --git a/src/database.c b/src/database.c index 0054837..f0b8cb6 100644 --- a/src/database.c +++ b/src/database.c @@ -472,7 +472,7 @@ int apk_cache_download(struct apk_database *db, const char *url, apk_bstream_from_file(db->cachetmp_fd, cacheitem), apk_sign_ctx_mpart_cb, &sctx); - r = apk_tar_parse(is, apk_sign_ctx_verify_tar, &sctx, FALSE); + r = apk_tar_parse(is, apk_sign_ctx_verify_tar, &sctx, FALSE, &db->id_cache); is->close(is); apk_sign_ctx_free(&sctx); if (r != 0) { @@ -916,7 +916,7 @@ static int apk_db_read_state(struct apk_database *db, int flags) is = apk_istream_from_file(db->root_fd, "var/lib/apk/scripts.tar"); if (is != NULL) { apk_tar_parse(is, apk_read_script_archive_entry, db, - FALSE); + FALSE, &db->id_cache); } else { is = apk_istream_from_file(db->root_fd, "var/lib/apk/scripts"); if (is != NULL) @@ -1177,6 +1177,8 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts) goto ret_r; } + apk_id_cache_init(&db->id_cache, db->root_fd); + return rr; ret_errno: @@ -1266,6 +1268,8 @@ void apk_db_close(struct apk_database *db) struct hlist_node *dc, *dn; int i; + apk_id_cache_free(&db->id_cache); + list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) { hlist_for_each_entry_safe(diri, dc, dn, &ipkg->owned_dirs, pkg_dirs_list) { apk_db_diri_free(db, diri, APK_DISALLOW_RMDIR); @@ -1343,7 +1347,7 @@ int apk_db_run_triggers(struct apk_database *db) continue; *apk_string_array_add(&ipkg->pending_triggers) = NULL; - apk_ipkg_run_script(ipkg, db->root_fd, APK_SCRIPT_TRIGGER, + apk_ipkg_run_script(ipkg, db, APK_SCRIPT_TRIGGER, ipkg->pending_triggers->item); apk_string_array_free(&ipkg->pending_triggers); } @@ -1520,7 +1524,7 @@ static int load_index(struct apk_database *db, struct apk_bstream *bs, ctx.found = 0; apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY, NULL, db->keys_fd); is = apk_bstream_gunzip_mpart(bs, apk_sign_ctx_mpart_cb, &ctx.sctx); - r = apk_tar_parse(is, load_apkindex, &ctx, FALSE); + r = apk_tar_parse(is, load_apkindex, &ctx, FALSE, &db->id_cache); is->close(is); apk_sign_ctx_free(&ctx.sctx); if (ctx.found == 0) @@ -1624,7 +1628,7 @@ static int apk_db_run_pending_script(struct install_ctx *ctx) return 0; ctx->script_pending = FALSE; - r = apk_ipkg_run_script(ctx->ipkg, ctx->db->root_fd, ctx->script, + r = apk_ipkg_run_script(ctx->ipkg, ctx->db, ctx->script, ctx->script_args); if (r != 0) apk_error("%s-%s: Failed to execute " @@ -2043,7 +2047,7 @@ static int apk_db_unpack_pkg(struct apk_database *db, apk_name_array_init(&ctx.replaces); apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY_IDENTITY, &pkg->csum, db->keys_fd); tar = apk_bstream_gunzip_mpart(bs, apk_sign_ctx_mpart_cb, &ctx.sctx); - r = apk_tar_parse(tar, apk_db_install_archive_entry, &ctx, TRUE); + r = apk_tar_parse(tar, apk_db_install_archive_entry, &ctx, TRUE, &db->id_cache); apk_sign_ctx_free(&ctx.sctx); apk_name_array_free(&ctx.replaces); tar->close(tar); @@ -2098,13 +2102,13 @@ int apk_db_install_pkg(struct apk_database *db, if (ipkg == NULL) return 0; - r = apk_ipkg_run_script(ipkg, db->root_fd, + r = apk_ipkg_run_script(ipkg, db, APK_SCRIPT_PRE_DEINSTALL, script_args); if (r != 0) return r; apk_db_purge_pkg(db, ipkg, NULL); - r = apk_ipkg_run_script(ipkg, db->root_fd, + r = apk_ipkg_run_script(ipkg, db, APK_SCRIPT_POST_DEINSTALL, script_args); apk_pkg_uninstall(db, oldpkg); @@ -2135,7 +2139,7 @@ int apk_db_install_pkg(struct apk_database *db, apk_pkg_uninstall(db, oldpkg); } - r = apk_ipkg_run_script(ipkg, db->root_fd, + r = apk_ipkg_run_script(ipkg, db, (oldpkg == NULL) ? APK_SCRIPT_POST_INSTALL : APK_SCRIPT_POST_UPGRADE, script_args); diff --git a/src/io.c b/src/io.c index 5100d41..38bc4e6 100644 --- a/src/io.c +++ b/src/io.c @@ -766,48 +766,55 @@ static struct cache_item *resolve_cache_item(struct apk_hash *hash, apk_blob_t n return ci; } -static unsigned int id_genid = 0; -static struct apk_hash uid_cache, gid_cache; - -void apk_id_cache_init(void) +void apk_id_cache_init(struct apk_id_cache *idc, int root_fd) { - apk_hash_init(&uid_cache, &id_hash_ops, 256); - apk_hash_init(&gid_cache, &id_hash_ops, 256); - id_genid = 1; + idc->root_fd = root_fd; + idc->genid = 1; + apk_hash_init(&idc->uid_cache, &id_hash_ops, 256); + apk_hash_init(&idc->gid_cache, &id_hash_ops, 256); } -void apk_id_cache_free(void) +void apk_id_cache_free(struct apk_id_cache *idc) { - apk_hash_free(&uid_cache); - apk_hash_free(&gid_cache); + apk_hash_free(&idc->uid_cache); + apk_hash_free(&idc->gid_cache); } -void apk_id_cache_reset(void) +void apk_id_cache_reset(struct apk_id_cache *idc) { - id_genid++; - if (id_genid == 0) - id_genid = 1; + idc->genid++; + if (idc->genid == 0) + idc->genid = 1; } -uid_t apk_resolve_uid(const char *username, uid_t default_uid) +uid_t apk_resolve_uid(struct apk_id_cache *idc, const char *username, uid_t default_uid) { struct cache_item *ci; struct passwd pwent, *pwd; char buf[1024]; - int r; + FILE *in; - ci = resolve_cache_item(&uid_cache, APK_BLOB_STR(username)); + ci = resolve_cache_item(&idc->uid_cache, APK_BLOB_STR(username)); if (ci == NULL) return default_uid; - if (ci->genid != id_genid) { - r = getpwnam_r(username, &pwent, buf, sizeof(buf), &pwd); - if (pwd != NULL) - ci->uid = pwd->pw_uid; - else - ci->uid = -1; - if (r == 0) - ci->genid = id_genid; + if (ci->genid != idc->genid) { + ci->genid = idc->genid; + ci->uid = -1; + + in = fdopen(openat(idc->root_fd, "etc/passwd", O_RDONLY|O_CLOEXEC), "r"); + if (in != NULL) { + do { + fgetpwent_r(in, &pwent, buf, sizeof(buf), &pwd); + if (pwd == NULL) + break; + if (strcmp(pwd->pw_name, username) == 0) { + ci->uid = pwd->pw_uid; + break; + } + } while (1); + fclose(in); + } } if (ci->uid != -1) @@ -816,25 +823,34 @@ uid_t apk_resolve_uid(const char *username, uid_t default_uid) return default_uid; } -uid_t apk_resolve_gid(const char *groupname, uid_t default_gid) +uid_t apk_resolve_gid(struct apk_id_cache *idc, const char *groupname, uid_t default_gid) { struct cache_item *ci; struct group grent, *grp; char buf[1024]; - int r; + FILE *in; - ci = resolve_cache_item(&gid_cache, APK_BLOB_STR(groupname)); + ci = resolve_cache_item(&idc->gid_cache, APK_BLOB_STR(groupname)); if (ci == NULL) return default_gid; - if (ci->genid != id_genid) { - r = getgrnam_r(groupname, &grent, buf, sizeof(buf), &grp); - if (grp != NULL) - ci->gid = grp->gr_gid; - else - ci->gid = -1; - if (r == 0) - ci->genid = id_genid; + if (ci->genid != idc->genid) { + ci->genid = idc->genid; + ci->gid = -1; + + in = fdopen(openat(idc->root_fd, "etc/passwd", O_RDONLY|O_CLOEXEC), "r"); + if (in != NULL) { + do { + fgetgrent_r(in, &grent, buf, sizeof(buf), &grp); + if (grp == NULL) + break; + if (strcmp(grp->gr_name, groupname) == 0) { + ci->gid = grp->gr_gid; + break; + } + } while (1); + fclose(in); + } } if (ci->gid != -1) diff --git a/src/package.c b/src/package.c index 8f15e7a..df53d93 100644 --- a/src/package.c +++ b/src/package.c @@ -793,7 +793,7 @@ int apk_pkg_read(struct apk_database *db, const char *file, ctx.pkg->size = fi.size; tar = apk_bstream_gunzip_mpart(bs, apk_sign_ctx_mpart_cb, sctx); - r = apk_tar_parse(tar, read_info_entry, &ctx, FALSE); + r = apk_tar_parse(tar, read_info_entry, &ctx, FALSE, &db->id_cache); tar->close(tar); if (r < 0 && r != -ECANCELED) goto err; @@ -856,7 +856,8 @@ int apk_ipkg_add_script(struct apk_installed_package *ipkg, return 0; } -int apk_ipkg_run_script(struct apk_installed_package *ipkg, int root_fd, +int apk_ipkg_run_script(struct apk_installed_package *ipkg, + struct apk_database *db, unsigned int type, char **argv) { static char * const environment[] = { @@ -865,7 +866,7 @@ int apk_ipkg_run_script(struct apk_installed_package *ipkg, int root_fd, }; struct apk_package *pkg = ipkg->pkg; char fn[PATH_MAX]; - int fd, status; + int fd, status, root_fd = db->root_fd; pid_t pid; if (type >= APK_SCRIPT_MAX) @@ -911,7 +912,7 @@ int apk_ipkg_run_script(struct apk_installed_package *ipkg, int root_fd, } waitpid(pid, &status, 0); unlinkat(root_fd, fn, 0); - apk_id_cache_reset(); + apk_id_cache_reset(&db->id_cache); if (WIFEXITED(status)) return WEXITSTATUS(status); diff --git a/src/verify.c b/src/verify.c index 006b548..b6a5cbc 100644 --- a/src/verify.c +++ b/src/verify.c @@ -33,7 +33,7 @@ static int verify_main(void *ctx, struct apk_database *db, int argc, char **argv rc++; continue; } - r = apk_tar_parse(is, apk_sign_ctx_verify_tar, &sctx, FALSE); + r = apk_tar_parse(is, apk_sign_ctx_verify_tar, &sctx, FALSE, &db->id_cache); is->close(is); ok = sctx.control_verified && sctx.data_verified; if (apk_verbosity >= 1) -- 1.7.3.1