From 6c9b82e72ac067207b1d66a3112485ad8d690f32 Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Sat, 11 Jun 2011 12:50:15 -0400 Subject: dload: handle irregular URLs URLs might end with a slash and follow redirects, or could be a generated by a script such as /getpkg.php?id=12345. In both cases, we may have a better filename that we can write to, taken from either content-disposition header, or the effective URL. Specific to the first case, we write to a temporary file of the format 'alpmtmp.XXXXXX', where XXXXXX is randomized by mkstemp(3). Since this is a randomly generated file, we cannot support resuming and the file is unlinked in the event of an interrupt. We also run into the possibility of changing out the filename from under alpm on a -U operation, so callers of _alpm_download can optionally pass a pointer to a *char to be filled in by curl_download_internal with the actual filename we wrote to. Any sync operation will pass a NULL pointer here, as we rely on specific names for packages from a mirror. Fixes FS#22645. Signed-off-by: Dave Reisner --- lib/libalpm/be_sync.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/libalpm/be_sync.c') diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c index e3871001..a784536b 100644 --- a/lib/libalpm/be_sync.c +++ b/lib/libalpm/be_sync.c @@ -181,7 +181,7 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) CALLOC(fileurl, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); snprintf(fileurl, len, "%s/%s.db", server, db->treename); - ret = _alpm_download(handle, fileurl, syncpath, force, 0, 0); + ret = _alpm_download(handle, fileurl, syncpath, NULL, force, 0, 0); if(ret == 0 && (level & ALPM_SIG_DATABASE)) { /* an existing sig file is no good at this point */ @@ -197,7 +197,7 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) /* if we downloaded a DB, we want the .sig from the same server */ snprintf(fileurl, len, "%s/%s.db.sig", server, db->treename); - sig_ret = _alpm_download(handle, fileurl, syncpath, 1, 0, errors_ok); + sig_ret = _alpm_download(handle, fileurl, syncpath, NULL, 1, 0, errors_ok); /* errors_ok suppresses error messages, but not the return code */ sig_ret = errors_ok ? 0 : sig_ret; } -- cgit v1.2.3-24-g4f1b From 6dc71926f9b16ebcf11b924941092d6eab204224 Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Fri, 24 Jun 2011 00:18:01 -0400 Subject: lib/dload: prevent large file attacks This means creating a new struct which can pass more descriptive data from the back end sync functions to the downloader. In particular, we're interested in the download size read from the sync DB. When the remote server reports a size larger than this (via a content-length header), abort the transfer. In cases where the size is unknown, we set a hard upper limit of: * 25MiB for a sync DB * 16KiB for a signature For reference, 25MiB is more than twice the size of all of the current binary repos (with files) combined, and 16KiB is a truly gargantuan signature. Signed-off-by: Dave Reisner --- lib/libalpm/be_sync.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'lib/libalpm/be_sync.c') diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c index a784536b..f681fc8e 100644 --- a/lib/libalpm/be_sync.c +++ b/lib/libalpm/be_sync.c @@ -172,16 +172,21 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) for(i = db->servers; i; i = i->next) { const char *server = i->data; - char *fileurl; + struct dload_payload *payload; size_t len; int sig_ret = 0; + CALLOC(payload, 1, sizeof(*payload), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); + + /* set hard upper limit of 25MiB */ + payload->max_size = 25 * 1024 * 1024; + /* print server + filename into a buffer (leave space for .sig) */ len = strlen(server) + strlen(db->treename) + 9; - CALLOC(fileurl, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); - snprintf(fileurl, len, "%s/%s.db", server, db->treename); + CALLOC(payload->fileurl, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); + snprintf(payload->fileurl, len, "%s/%s.db", server, db->treename); - ret = _alpm_download(handle, fileurl, syncpath, NULL, force, 0, 0); + ret = _alpm_download(handle, payload, syncpath, NULL, force, 0, 0); if(ret == 0 && (level & ALPM_SIG_DATABASE)) { /* an existing sig file is no good at this point */ @@ -195,14 +200,17 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) int errors_ok = (level & ALPM_SIG_DATABASE_OPTIONAL); /* if we downloaded a DB, we want the .sig from the same server */ - snprintf(fileurl, len, "%s/%s.db.sig", server, db->treename); + snprintf(payload->fileurl, len, "%s/%s.db.sig", server, db->treename); + + /* set hard upper limit of 16KiB */ + payload->max_size = 16 * 1024; - sig_ret = _alpm_download(handle, fileurl, syncpath, NULL, 1, 0, errors_ok); + sig_ret = _alpm_download(handle, payload, syncpath, NULL, 1, 0, errors_ok); /* errors_ok suppresses error messages, but not the return code */ sig_ret = errors_ok ? 0 : sig_ret; } - FREE(fileurl); + _alpm_dload_payload_free(payload); if(ret != -1 && sig_ret != -1) { break; } -- cgit v1.2.3-24-g4f1b From 3eec745910bb908717a8b4ed7f5b630a92a5c9eb Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Thu, 30 Jun 2011 21:19:25 -0400 Subject: absorb some _alpm_download params into payload struct Restore some sanity to the number of arguments passed to _alpm_download and curl_download_internal. Signed-off-by: Dave Reisner --- lib/libalpm/be_sync.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'lib/libalpm/be_sync.c') diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c index f681fc8e..d7e14ba3 100644 --- a/lib/libalpm/be_sync.c +++ b/lib/libalpm/be_sync.c @@ -185,8 +185,10 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) len = strlen(server) + strlen(db->treename) + 9; CALLOC(payload->fileurl, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); snprintf(payload->fileurl, len, "%s/%s.db", server, db->treename); + payload->handle = handle; + payload->force = force; - ret = _alpm_download(handle, payload, syncpath, NULL, force, 0, 0); + ret = _alpm_download(payload, syncpath, NULL); if(ret == 0 && (level & ALPM_SIG_DATABASE)) { /* an existing sig file is no good at this point */ @@ -198,16 +200,18 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) unlink(sigpath); free(sigpath); - int errors_ok = (level & ALPM_SIG_DATABASE_OPTIONAL); /* if we downloaded a DB, we want the .sig from the same server */ snprintf(payload->fileurl, len, "%s/%s.db.sig", server, db->treename); + payload->handle = handle; + payload->force = 1; + payload->errors_ok = (level & ALPM_SIG_DATABASE_OPTIONAL); /* set hard upper limit of 16KiB */ payload->max_size = 16 * 1024; - sig_ret = _alpm_download(handle, payload, syncpath, NULL, 1, 0, errors_ok); + sig_ret = _alpm_download(payload, syncpath, NULL); /* errors_ok suppresses error messages, but not the return code */ - sig_ret = errors_ok ? 0 : sig_ret; + sig_ret = payload->errors_ok ? 0 : sig_ret; } _alpm_dload_payload_free(payload); -- cgit v1.2.3-24-g4f1b