Commit 8e23a2ba authored by Timo Teräs's avatar Timo Teräs

db: checksum installed files, protect config files

Checksum of installed is computed on the fly when extracting them
and it'll be saved to fdb. When installing config files those are
diverted with suffix .apk-new if earlier version of same file with
local changes exist.
parent 86676ac8
...@@ -8,9 +8,6 @@ ...@@ -8,9 +8,6 @@
- cache .apks on USB stick when using network repo for reboot - cache .apks on USB stick when using network repo for reboot
- Installation of .APK files not in any repository - Installation of .APK files not in any repository
- Configfiles list in .PKGINFO
- Implement lbu stuff
- Error handling and rollback - Error handling and rollback
- Dependency manipulation API: deletion, overwrite, check compatibility - Dependency manipulation API: deletion, overwrite, check compatibility
......
...@@ -16,29 +16,17 @@ ...@@ -16,29 +16,17 @@
#include "apk_blob.h" #include "apk_blob.h"
#include "apk_io.h" #include "apk_io.h"
struct apk_archive_entry {
char *name;
char *link_target;
char *uname;
char *gname;
off_t size;
uid_t uid;
gid_t gid;
mode_t mode;
time_t mtime;
dev_t device;
};
typedef int (*apk_archive_entry_parser)(void *ctx, typedef int (*apk_archive_entry_parser)(void *ctx,
const struct apk_archive_entry *ae, const struct apk_file_info *ae,
struct apk_istream *istream); struct apk_istream *istream);
int apk_file_get_info(const char *filename, struct apk_file_info *fi);
struct apk_istream *apk_gunzip_bstream(struct apk_bstream *); struct apk_istream *apk_gunzip_bstream(struct apk_bstream *);
int apk_parse_tar(struct apk_istream *, apk_archive_entry_parser parser, void *ctx); int apk_parse_tar(struct apk_istream *, apk_archive_entry_parser parser, void *ctx);
int apk_parse_tar_gz(struct apk_bstream *, apk_archive_entry_parser parser, void *ctx); int apk_parse_tar_gz(struct apk_bstream *, apk_archive_entry_parser parser, void *ctx);
int apk_archive_entry_extract(const struct apk_archive_entry *ae, int apk_archive_entry_extract(const struct apk_file_info *ae,
struct apk_istream *is, struct apk_istream *is,
const char *to); const char *to);
......
...@@ -25,9 +25,12 @@ struct apk_db_file { ...@@ -25,9 +25,12 @@ struct apk_db_file {
struct apk_db_dir *dir; struct apk_db_dir *dir;
struct apk_package *owner; struct apk_package *owner;
csum_t csum;
char filename[]; char filename[];
}; };
#define APK_DBDIRF_PROTECTED 0x0001
struct apk_db_dir { struct apk_db_dir {
apk_hash_node hash_node; apk_hash_node hash_node;
...@@ -38,6 +41,7 @@ struct apk_db_dir { ...@@ -38,6 +41,7 @@ struct apk_db_dir {
mode_t mode; mode_t mode;
uid_t uid; uid_t uid;
gid_t gid; gid_t gid;
unsigned flags;
char dirname[]; char dirname[];
}; };
...@@ -58,6 +62,7 @@ struct apk_database { ...@@ -58,6 +62,7 @@ struct apk_database {
unsigned pkg_id, num_repos; unsigned pkg_id, num_repos;
struct apk_dependency_array *world; struct apk_dependency_array *world;
struct apk_string_array *protected_paths;
struct apk_repository repos[APK_MAX_REPOS]; struct apk_repository repos[APK_MAX_REPOS];
struct { struct {
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#ifndef APK_DEFINES_H #ifndef APK_DEFINES_H
#define APK_DEFINES_H #define APK_DEFINES_H
#include <malloc.h>
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define BIT(x) (1 << (x)) #define BIT(x) (1 << (x))
...@@ -36,12 +38,15 @@ ...@@ -36,12 +38,15 @@
#if 1 #if 1
#include "md5.h" #include "md5.h"
typedef unsigned char *csum_p;
typedef md5sum_t csum_t; typedef md5sum_t csum_t;
typedef struct md5_ctx csum_ctx_t; typedef struct md5_ctx csum_ctx_t;
extern csum_t bad_checksum;
#define csum_init(ctx) md5_init(ctx) #define csum_init(ctx) md5_init(ctx)
#define csum_process(ctx, buf, len) md5_process(ctx, buf, len) #define csum_process(ctx, buf, len) md5_process(ctx, buf, len)
#define csum_finish(ctx, buf) md5_finish(ctx, buf) #define csum_finish(ctx, buf) md5_finish(ctx, buf)
#define csum_valid(buf) memcmp(buf, bad_checksum, sizeof(csum_t))
#endif #endif
extern int apk_cwd_fd, apk_quiet; extern int apk_cwd_fd, apk_quiet;
...@@ -76,6 +81,8 @@ void apk_log(const char *prefix, const char *format, ...); ...@@ -76,6 +81,8 @@ void apk_log(const char *prefix, const char *format, ...);
return &(*a)->item[size-1]; \ return &(*a)->item[size-1]; \
} }
APK_ARRAY(apk_string_array, char *);
#define LIST_END (void *) 0xe01 #define LIST_END (void *) 0xe01
#define LIST_POISON1 (void *) 0xdeadbeef #define LIST_POISON1 (void *) 0xdeadbeef
#define LIST_POISON2 (void *) 0xabbaabba #define LIST_POISON2 (void *) 0xabbaabba
......
...@@ -14,15 +14,28 @@ ...@@ -14,15 +14,28 @@
#include "apk_defines.h" #include "apk_defines.h"
#include "apk_blob.h" #include "apk_blob.h"
struct apk_file_info {
char *name;
char *link_target;
char *uname;
char *gname;
off_t size;
uid_t uid;
gid_t gid;
mode_t mode;
time_t mtime;
dev_t device;
csum_t csum;
};
struct apk_istream { struct apk_istream {
size_t (*read)(void *stream, void *ptr, size_t size); size_t (*read)(void *stream, void *ptr, size_t size);
size_t (*splice)(void *stream, int fd, size_t size);
void (*close)(void *stream); void (*close)(void *stream);
}; };
struct apk_bstream { struct apk_bstream {
size_t (*read)(void *stream, void **ptr); size_t (*read)(void *stream, void **ptr);
void (*close)(void *stream, csum_t csum); void (*close)(void *stream, csum_p csum);
}; };
struct apk_istream *apk_istream_from_fd(int fd); struct apk_istream *apk_istream_from_fd(int fd);
......
...@@ -53,6 +53,8 @@ struct apk_tar_entry_istream { ...@@ -53,6 +53,8 @@ struct apk_tar_entry_istream {
struct apk_istream is; struct apk_istream is;
struct apk_istream *tar_is; struct apk_istream *tar_is;
size_t bytes_left; size_t bytes_left;
csum_ctx_t csum_ctx;
csum_p csum;
}; };
static size_t tar_entry_read(void *stream, void *ptr, size_t size) static size_t tar_entry_read(void *stream, void *ptr, size_t size)
...@@ -63,33 +65,24 @@ static size_t tar_entry_read(void *stream, void *ptr, size_t size) ...@@ -63,33 +65,24 @@ static size_t tar_entry_read(void *stream, void *ptr, size_t size)
if (size > teis->bytes_left) if (size > teis->bytes_left)
size = teis->bytes_left; size = teis->bytes_left;
size = teis->tar_is->read(teis->tar_is, ptr, size); size = teis->tar_is->read(teis->tar_is, ptr, size);
if (size >= 0) if (size > 0) {
teis->bytes_left -= size;
return size;
}
static size_t tar_entry_splice(void *stream, int fd, size_t size)
{
struct apk_tar_entry_istream *teis =
container_of(stream, struct apk_tar_entry_istream, is);
if (size > teis->bytes_left)
size = teis->bytes_left;
size = teis->tar_is->splice(teis->tar_is, fd, size);
if (size >= 0)
teis->bytes_left -= size; teis->bytes_left -= size;
csum_process(&teis->csum_ctx, ptr, size);
if (teis->bytes_left == 0)
csum_finish(&teis->csum_ctx, teis->csum);
}
return size; return size;
} }
int apk_parse_tar(struct apk_istream *is, apk_archive_entry_parser parser, int apk_parse_tar(struct apk_istream *is, apk_archive_entry_parser parser,
void *ctx) void *ctx)
{ {
struct apk_file_info entry;
struct apk_tar_entry_istream teis = { struct apk_tar_entry_istream teis = {
.is.read = tar_entry_read, .is.read = tar_entry_read,
.is.splice = tar_entry_splice,
.tar_is = is, .tar_is = is,
.csum = entry.csum,
}; };
struct apk_archive_entry entry;
struct tar_header buf; struct tar_header buf;
unsigned long offset = 0; unsigned long offset = 0;
int end = 0, r; int end = 0, r;
...@@ -107,7 +100,7 @@ int apk_parse_tar(struct apk_istream *is, apk_archive_entry_parser parser, ...@@ -107,7 +100,7 @@ int apk_parse_tar(struct apk_istream *is, apk_archive_entry_parser parser,
continue; continue;
} }
entry = (struct apk_archive_entry){ entry = (struct apk_file_info){
.size = GET_OCTAL(buf.size), .size = GET_OCTAL(buf.size),
.uid = GET_OCTAL(buf.uid), .uid = GET_OCTAL(buf.uid),
.gid = GET_OCTAL(buf.gid), .gid = GET_OCTAL(buf.gid),
...@@ -160,6 +153,7 @@ int apk_parse_tar(struct apk_istream *is, apk_archive_entry_parser parser, ...@@ -160,6 +153,7 @@ int apk_parse_tar(struct apk_istream *is, apk_archive_entry_parser parser,
entry.name = strdup(buf.name); entry.name = strdup(buf.name);
/* callback parser function */ /* callback parser function */
csum_init(&teis.csum_ctx);
r = parser(ctx, &entry, &teis.is); r = parser(ctx, &entry, &teis.is);
if (r != 0) if (r != 0)
return r; return r;
...@@ -191,7 +185,7 @@ int apk_parse_tar_gz(struct apk_bstream *bs, apk_archive_entry_parser parser, ...@@ -191,7 +185,7 @@ int apk_parse_tar_gz(struct apk_bstream *bs, apk_archive_entry_parser parser,
return apk_parse_tar(apk_gunzip_bstream(bs), parser, ctx); return apk_parse_tar(apk_gunzip_bstream(bs), parser, ctx);
} }
int apk_archive_entry_extract(const struct apk_archive_entry *ae, int apk_archive_entry_extract(const struct apk_file_info *ae,
struct apk_istream *is, struct apk_istream *is,
const char *fn) const char *fn)
{ {
...@@ -216,7 +210,7 @@ int apk_archive_entry_extract(const struct apk_archive_entry *ae, ...@@ -216,7 +210,7 @@ int apk_archive_entry_extract(const struct apk_archive_entry *ae,
r = -1; r = -1;
break; break;
} }
if (is->splice(is, fd, ae->size) == ae->size) if (apk_istream_splice(is, fd, ae->size) == ae->size)
r = 0; r = 0;
close(fd); close(fd);
} else { } else {
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h>
#include <unistd.h> #include <unistd.h>
#include <malloc.h> #include <malloc.h>
#include <string.h> #include <string.h>
...@@ -137,6 +138,7 @@ static struct apk_db_dir *apk_db_dir_get(struct apk_database *db, ...@@ -137,6 +138,7 @@ static struct apk_db_dir *apk_db_dir_get(struct apk_database *db,
struct apk_db_dir *dir; struct apk_db_dir *dir;
apk_blob_t bparent; apk_blob_t bparent;
char *cstr; char *cstr;
int i;
if (name.len && name.ptr[name.len-1] == '/') if (name.len && name.ptr[name.len-1] == '/')
name.len--; name.len--;
...@@ -154,11 +156,22 @@ static struct apk_db_dir *apk_db_dir_get(struct apk_database *db, ...@@ -154,11 +156,22 @@ static struct apk_db_dir *apk_db_dir_get(struct apk_database *db,
if (name.len == 0) if (name.len == 0)
dir->parent = NULL; dir->parent = NULL;
else if (apk_blob_rsplit(name, '/', &bparent, NULL)) else if (apk_blob_rsplit(name, '/', &bparent, NULL))
dir->parent = apk_db_dir_get(db, bparent); dir->parent = apk_db_dir_get(db, bparent);
else else
dir->parent = apk_db_dir_get(db, APK_BLOB_NULL); dir->parent = apk_db_dir_get(db, APK_BLOB_NULL);
if (dir->parent != NULL)
dir->flags = dir->parent->flags;
for (i = 0; i < db->protected_paths->num; i++) {
if (db->protected_paths->item[i][0] == '-' &&
strcmp(&db->protected_paths->item[i][1], dir->dirname) == 0)
dir->flags &= ~APK_DBDIRF_PROTECTED;
else if (strcmp(db->protected_paths->item[i], dir->dirname) == 0)
dir->flags |= APK_DBDIRF_PROTECTED;
}
return dir; return dir;
} }
...@@ -295,6 +308,16 @@ static int apk_db_read_fdb(struct apk_database *db, int fd) ...@@ -295,6 +308,16 @@ static int apk_db_read_fdb(struct apk_database *db, int fd)
file_dir_node = &file->dir_files_list.next; file_dir_node = &file->dir_files_list.next;
file_pkg_node = &file->pkg_files_list.next; file_pkg_node = &file->pkg_files_list.next;
break; break;
case 'C':
if (file == NULL) {
apk_error("FDB checksum entry before file entry");
return -1;
}
if (apk_hexdump_parse(APK_BLOB_BUF(file->csum), l)) {
apk_error("Not a valid checksum");
return -1;
}
break;
default: default:
apk_error("FDB entry '%c' unsupported", n); apk_error("FDB entry '%c' unsupported", n);
return -1; return -1;
...@@ -342,6 +365,12 @@ static int apk_db_write_fdb(struct apk_database *db, int fd) ...@@ -342,6 +365,12 @@ static int apk_db_write_fdb(struct apk_database *db, int fd)
n += snprintf(&buf[n], sizeof(buf)-n, n += snprintf(&buf[n], sizeof(buf)-n,
"F%s\n", "F%s\n",
file->filename); file->filename);
if (csum_valid(file->csum)) {
n += snprintf(&buf[n], sizeof(buf)-n, "C");
n += apk_hexdump_format(sizeof(buf)-n, &buf[n],
APK_BLOB_BUF(file->csum));
n += snprintf(&buf[n], sizeof(buf)-n, "\n");
}
if (write(fd, buf, n) != n) if (write(fd, buf, n) != n)
return -1; return -1;
...@@ -418,7 +447,7 @@ int apk_db_create(const char *root) ...@@ -418,7 +447,7 @@ int apk_db_create(const char *root)
return 0; return 0;
} }
static int apk_db_read_config(struct apk_database *db) static int apk_db_read_state(struct apk_database *db)
{ {
struct apk_istream *is; struct apk_istream *is;
struct stat st; struct stat st;
...@@ -466,8 +495,18 @@ static int apk_db_read_config(struct apk_database *db) ...@@ -466,8 +495,18 @@ static int apk_db_read_config(struct apk_database *db)
return 0; return 0;
} }
static int add_protected_path(void *ctx, apk_blob_t blob)
{
struct apk_database *db = (struct apk_database *) ctx;
*apk_string_array_add(&db->protected_paths) = apk_blob_cstr(blob);
return 0;
}
int apk_db_open(struct apk_database *db, const char *root) int apk_db_open(struct apk_database *db, const char *root)
{ {
apk_blob_t dirs;
memset(db, 0, sizeof(*db)); memset(db, 0, sizeof(*db));
apk_hash_init(&db->available.names, &pkg_name_hash_ops, 1000); apk_hash_init(&db->available.names, &pkg_name_hash_ops, 1000);
apk_hash_init(&db->available.packages, &pkg_info_hash_ops, 4000); apk_hash_init(&db->available.packages, &pkg_info_hash_ops, 4000);
...@@ -485,7 +524,10 @@ int apk_db_open(struct apk_database *db, const char *root) ...@@ -485,7 +524,10 @@ int apk_db_open(struct apk_database *db, const char *root)
if (apk_repository != NULL) if (apk_repository != NULL)
apk_db_add_repository(db, apk_repository); apk_db_add_repository(db, apk_repository);
return apk_db_read_config(db); dirs = APK_BLOB_STR("etc:-etc/init.d");
apk_blob_for_each_segment(dirs, ":", add_protected_path, db);
return apk_db_read_state(db);
} }
struct write_ctx { struct write_ctx {
...@@ -668,7 +710,7 @@ int apk_db_recalculate_and_commit(struct apk_database *db) ...@@ -668,7 +710,7 @@ int apk_db_recalculate_and_commit(struct apk_database *db)
} }
static int apk_db_install_archive_entry(void *_ctx, static int apk_db_install_archive_entry(void *_ctx,
const struct apk_archive_entry *ae, const struct apk_file_info *ae,
struct apk_istream *is) struct apk_istream *is)
{ {
struct install_ctx *ctx = (struct install_ctx *) _ctx; struct install_ctx *ctx = (struct install_ctx *) _ctx;
...@@ -677,6 +719,8 @@ static int apk_db_install_archive_entry(void *_ctx, ...@@ -677,6 +719,8 @@ static int apk_db_install_archive_entry(void *_ctx,
apk_blob_t name = APK_BLOB_STR(ae->name); apk_blob_t name = APK_BLOB_STR(ae->name);
struct apk_db_dir *dir; struct apk_db_dir *dir;
struct apk_db_file *file; struct apk_db_file *file;
struct apk_file_info fi;
char alt_name[PATH_MAX];
const char *p; const char *p;
int r = 0, type = APK_SCRIPT_INVALID; int r = 0, type = APK_SCRIPT_INVALID;
...@@ -740,7 +784,20 @@ static int apk_db_install_archive_entry(void *_ctx, ...@@ -740,7 +784,20 @@ static int apk_db_install_archive_entry(void *_ctx,
if (strncmp(file->filename, ".keep_", 6) == 0) if (strncmp(file->filename, ".keep_", 6) == 0)
return 0; return 0;
r = apk_archive_entry_extract(ae, is, NULL); if ((file->dir->flags & APK_DBDIRF_PROTECTED) &&
csum_valid(file->csum) &&
apk_file_get_info(ae->name, &fi) == 0 &&
memcmp(file->csum, fi.csum, sizeof(csum_t)) != 0) {
/* Protected file, which is modified locally.
* Extract to separate place */
snprintf(alt_name, sizeof(alt_name),
"%s/%s.apk-new",
dir->dirname, file->filename);
r = apk_archive_entry_extract(ae, is, alt_name);
} else {
r = apk_archive_entry_extract(ae, is, NULL);
}
memcpy(file->csum, ae->csum, sizeof(csum_t));
} else { } else {
if (name.ptr[name.len-1] == '/') if (name.ptr[name.len-1] == '/')
name.len--; name.len--;
......
...@@ -77,7 +77,6 @@ struct apk_istream *apk_gunzip_bstream(struct apk_bstream *bs) ...@@ -77,7 +77,6 @@ struct apk_istream *apk_gunzip_bstream(struct apk_bstream *bs)
*gis = (struct apk_gzip_istream) { *gis = (struct apk_gzip_istream) {
.is.read = gz_read, .is.read = gz_read,
.is.splice = apk_istream_splice,
.is.close = gz_close, .is.close = gz_close,
.bs = bs, .bs = bs,
.z_err = 0, .z_err = 0,
......
...@@ -47,22 +47,6 @@ static size_t fd_read(void *stream, void *ptr, size_t size) ...@@ -47,22 +47,6 @@ static size_t fd_read(void *stream, void *ptr, size_t size)
return i; return i;
} }
static size_t fd_splice(void *stream, int fd, size_t size)
{
struct apk_fd_istream *fis =
container_of(stream, struct apk_fd_istream, is);
size_t i = 0, r;
while (i != size) {
r = splice(fis->fd, NULL, fd, NULL, size - i, SPLICE_F_MOVE);
if (r == -1)
return i;
i += r;
}
return i;
}
static void fd_close(void *stream) static void fd_close(void *stream)
{ {
struct apk_fd_istream *fis = struct apk_fd_istream *fis =
...@@ -82,7 +66,6 @@ struct apk_istream *apk_istream_from_fd(int fd) ...@@ -82,7 +66,6 @@ struct apk_istream *apk_istream_from_fd(int fd)
*fis = (struct apk_fd_istream) { *fis = (struct apk_fd_istream) {
.is.read = fd_read, .is.read = fd_read,
.is.splice = fd_splice,
.is.close = fd_close, .is.close = fd_close,
.fd = fd, .fd = fd,
}; };
...@@ -322,3 +305,31 @@ apk_blob_t apk_blob_from_istream(struct apk_istream *is, size_t size) ...@@ -322,3 +305,31 @@ apk_blob_t apk_blob_from_istream(struct apk_istream *is, size_t size)
return APK_BLOB_PTR_LEN(ptr, rsize); return APK_BLOB_PTR_LEN(ptr, rsize);
} }
int apk_file_get_info(const char *filename, struct apk_file_info *fi)
{
struct stat st;
struct apk_bstream *bs;
int fd;
if (stat(filename, &st) != 0)
return -1;
*fi = (struct apk_file_info) {
.size = st.st_size,
.uid = st.st_uid,
.gid = st.st_gid,
.mode = st.st_mode,
.mtime = st.st_mtime,
.device = st.st_dev,
};
fd = open(filename, O_RDONLY);
if (fd < 0)
return 0;
bs = apk_bstream_from_fd(fd);
if (bs != NULL)
bs->close(bs, fi->csum);
return 0;
}
...@@ -58,6 +58,8 @@ ...@@ -58,6 +58,8 @@
#include "md5.h" #include "md5.h"
md5sum_t bad_checksum = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
/* Handle endian-ness */ /* Handle endian-ness */
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
#define SWAP(n) (n) #define SWAP(n) (n)
......
...@@ -255,7 +255,7 @@ static int read_info_line(void *ctx, apk_blob_t line) ...@@ -255,7 +255,7 @@ static int read_info_line(void *ctx, apk_blob_t line)
return 0; return 0;
} }
static int read_info_entry(void *ctx, const struct apk_archive_entry *ae, static int read_info_entry(void *ctx, const struct apk_file_info *ae,
struct apk_istream *is) struct apk_istream *is)
{ {
static struct { static struct {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment