Skip to content

Commit e71941a

Browse files
Taylor R CampbellTaylor R Campbell
authored andcommitted
Verify FILE_CKSUM (sha256) in pkg_summary(5) on download.
This is important for detecting version rollback attacks -- verifying a signature on the package itself doesn't help, because the old one also has a valid signature.
1 parent 2c883d0 commit e71941a

13 files changed

Lines changed: 1300 additions & 17 deletions

File tree

Makefile.am

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@ pkg_install_SOURCES= external/automatic.c external/dewey.c
2424
pkg_install_SOURCES+= external/fexec.c external/iterate.c external/lpkg.c
2525
pkg_install_SOURCES+= external/opattern.c external/pkgdb.c external/plist.c
2626
pkg_install_SOURCES+= external/var.c external/xwrapper.c
27+
pkg_install_SOURCES+= external/sha2.c
2728

2829
pkgin_SOURCES= actions.c autoremove.c depends.c download.c fsops.c impact.c
2930
pkgin_SOURCES+= main.c order.c pkg_check.c pkg_infos.c pkg_install.c
30-
pkgin_SOURCES+= pkg_str.c pkgindb.c pkgindb_queries.c pkglist.c preferred.c
31+
pkgin_SOURCES+= pkg_str.c pkghash.c pkgindb.c pkgindb_queries.c pkglist.c preferred.c
3132
pkgin_SOURCES+= selection.c sqlite_callbacks.c summary.c tools.c
3233
pkgin_SOURCES+= $(openssh_SOURCES) $(pkg_install_SOURCES)
3334

actions.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
#include <sqlite3.h>
3131
#include "pkgin.h"
32+
#include "pkghash.h"
3233
#include <sys/ioctl.h>
3334
#include <time.h>
3435
#include <unistd.h>
@@ -99,6 +100,13 @@ pkg_download(Plisthead *installhead)
99100
continue;
100101
}
101102

103+
if (p->ipkg->rpkg->hash) {
104+
if (!pkghash_verify_file(p->ipkg->rpkg->hash,
105+
pkgurl))
106+
errx(EXIT_FAILURE, "Hash mismatch %s",
107+
p->ipkg->pkgfs);
108+
}
109+
102110
if (symlink(pkgurl, p->ipkg->pkgfs) < 0) {
103111
errx(EXIT_FAILURE,
104112
"Failed to create symlink %s",
@@ -116,7 +124,8 @@ pkg_download(Plisthead *installhead)
116124
err(EXIT_FAILURE, MSG_ERR_OPEN, p->ipkg->pkgfs);
117125

118126
p->ipkg->file_size =
119-
download_pkg(p->ipkg->pkgurl, fp, i++, count);
127+
download_pkg(p->ipkg->pkgurl, fp, i++, count,
128+
p->ipkg->rpkg->hash);
120129

121130
if (p->ipkg->file_size == -1) {
122131
(void) fclose(fp);
@@ -748,12 +757,15 @@ pkgin_install(char **pkgargs, int do_inst, int upgrade)
748757

749758
/*
750759
* If the binary package has not already been downloaded, or
751-
* its size does not match pkg_summary, then mark it to be
760+
* its size/hash do not match pkg_summary, then mark it to be
752761
* downloaded.
753762
*/
754763
if (stat(p->pkgfs, &st) < 0 || st.st_size != p->rpkg->file_size)
755764
p->download = 1;
756-
else {
765+
else if (p->rpkg->hash != NULL &&
766+
pkghash_verify_file(p->rpkg->hash, p->pkgfs)) {
767+
/* exact match, no further check needed */
768+
} else {
757769
/*
758770
* If the cached package has the correct size, we must
759771
* verify that the BUILD_DATE has not changed, in case

download.c

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
*/
2929

3030
#include "pkgin.h"
31+
#include "pkghash.h"
3132
#include "external/progressmeter.h"
3233

3334
extern char fetchflags[3];
@@ -159,7 +160,8 @@ sum_close(struct archive *a, void *data)
159160
* Download a package to the local cache.
160161
*/
161162
off_t
162-
download_pkg(char *pkg_url, FILE *fp, int cur, int total)
163+
download_pkg(char *pkg_url, FILE *fp, int cur, int total,
164+
const struct pkghash *hash)
163165
{
164166
struct url_stat st;
165167
size_t size, wrote;
@@ -168,6 +170,7 @@ download_pkg(char *pkg_url, FILE *fp, int cur, int total)
168170
struct url *url;
169171
fetchIO *f = NULL;
170172
char buf[4096];
173+
struct pkghash_ctx *hash_ctx = NULL;
171174
char *pkg, *ptr, *msg = NULL;
172175

173176
if ((url = fetchParseURL(pkg_url)) == NULL)
@@ -177,7 +180,8 @@ download_pkg(char *pkg_url, FILE *fp, int cur, int total)
177180
fprintf(stderr, "download error: %s %s\n", pkg_url,
178181
fetchLastErrString);
179182
fetchFreeURL(url);
180-
return -1;
183+
written = -1;
184+
goto out;
181185
}
182186
fetchFreeURL(url);
183187

@@ -194,6 +198,9 @@ download_pkg(char *pkg_url, FILE *fp, int cur, int total)
194198
start_progress_meter(msg, st.size, &statsize);
195199
}
196200

201+
if (hash)
202+
hash_ctx = pkghash_verify_init(hash);
203+
197204
while (written < st.size) {
198205
if ((fetched = fetchIO_read(f, buf, sizeof(buf))) == 0)
199206
break;
@@ -202,12 +209,17 @@ download_pkg(char *pkg_url, FILE *fp, int cur, int total)
202209
if (fetched < 0) {
203210
fprintf(stderr, "download error: %s",
204211
fetchLastErrString);
205-
return -1;
212+
written = -1;
213+
goto out;
206214
}
207215

208216
statsize += fetched;
209217
size = (size_t)fetched;
210218

219+
if (hash) {
220+
pkghash_verify_update(hash_ctx, (const void *)buf,
221+
size);
222+
}
211223
for (ptr = buf; size > 0; ptr += wrote, size -= wrote) {
212224
if ((wrote = fwrite(ptr, 1, size, fp)) < size) {
213225
if (ferror(fp) && errno == EINTR)
@@ -230,8 +242,20 @@ download_pkg(char *pkg_url, FILE *fp, int cur, int total)
230242

231243
if (written != st.size) {
232244
fprintf(stderr, "download error: %s truncated\n", pkg_url);
233-
return -1;
245+
written = -1;
246+
goto out;
247+
}
248+
249+
if (hash) {
250+
if (!pkghash_verify_final(hash_ctx)) {
251+
fprintf(stderr, "download error: %s corrupted\n",
252+
pkg_url);
253+
written = -1;
254+
goto out;
255+
}
234256
}
235257

258+
out: if (hash)
259+
free(hash_ctx);
236260
return written;
237261
}

0 commit comments

Comments
 (0)