From 6d85d9ae08520d446805f973797188533aead6fa Mon Sep 17 00:00:00 2001 From: Allan McRae Date: Sun, 5 May 2024 11:12:33 +1000 Subject: [PATCH 01/17] Document makepkg.conf.d/ drop-in configuration Signed-off-by: Allan McRae --- doc/makepkg.conf.5.asciidoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/makepkg.conf.5.asciidoc b/doc/makepkg.conf.5.asciidoc index 57fbc966..36dcb77e 100644 --- a/doc/makepkg.conf.5.asciidoc +++ b/doc/makepkg.conf.5.asciidoc @@ -23,6 +23,9 @@ NOTE: This does not guarantee that all package Makefiles will use your exported variables. Some of them are non-standard. The system-wide configuration file is found in {sysconfdir}/makepkg.conf. +Specific additions (e.g. build flags for additional languages) can be placed +in {sysconfdir}/makepkg.conf.d/*.conf. + Individual options can be overridden (or added to) on a per-user basis in $XDG_CONFIG_HOME/pacman/makepkg.conf or ~/.makepkg.conf, with the former taking priority. From e1df19ee6f5a872791142a8dee34b4299d5b3dfe Mon Sep 17 00:00:00 2001 From: Allan McRae Date: Sun, 5 May 2024 14:27:20 +1000 Subject: [PATCH 02/17] makepkg: drop sudo permissions after use Add the -k parameter to the sudo call to prevent caching of credientials. This would (potentailly) stop a rogue sudo use within a PKGBUILD. Signed-off-by: Allan McRae --- scripts/makepkg.sh.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in index e74e987e..bad9f15c 100644 --- a/scripts/makepkg.sh.in +++ b/scripts/makepkg.sh.in @@ -241,7 +241,7 @@ run_pacman() { cmd=("${PACMAN_AUTH[@]}" "${cmd[@]}") fi elif type -p sudo >/dev/null; then - cmd=(sudo "${cmd[@]}") + cmd=(sudo -k "${cmd[@]}") else cmd=(su root -c "$cmdescape") fi From 0f2417f919dd60572467dbeffd03640115d67a46 Mon Sep 17 00:00:00 2001 From: Allan McRae Date: Sun, 5 May 2024 15:04:20 +1000 Subject: [PATCH 03/17] doc/makepkg.8: Improve --cleanbuild documentation Fixes #45. Signed-off-by: Allan McRae --- doc/makepkg.8.asciidoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/makepkg.8.asciidoc b/doc/makepkg.8.asciidoc index 5ba13ace..b7b6d044 100644 --- a/doc/makepkg.8.asciidoc +++ b/doc/makepkg.8.asciidoc @@ -144,7 +144,8 @@ Options Display version information. *-C, \--cleanbuild*:: - Remove the $srcdir before building the package. + Clean build artifacts from previous runs of makepkg in the current + directory by removing $srcdir before building the package. *-D* , *\--dir* :: Change to directory before reading the PKGBUILD or doing anything else. From 76e1cb1bf1ee78d81062a57e4ffd0c08514d07e8 Mon Sep 17 00:00:00 2001 From: Allan McRae Date: Mon, 20 May 2024 10:15:33 +1000 Subject: [PATCH 04/17] Revert "Prepare git src with `git worktree`" This causes issues when repeatedly building a package using the same git checkout. There is also ambiguity of the default checkout when trying to build from HEAD. See #142 and #143. This reverts commit 85c421f1cb7beb7631a7d972edd8df940c23d1cd. --- scripts/libmakepkg/source/git.sh.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/libmakepkg/source/git.sh.in b/scripts/libmakepkg/source/git.sh.in index e8051760..dbe844a0 100644 --- a/scripts/libmakepkg/source/git.sh.in +++ b/scripts/libmakepkg/source/git.sh.in @@ -100,7 +100,7 @@ extract_git() { exit 1 fi cd_safe "$srcdir" - elif ! git -C "$dir" worktree add --force "${srcdir}/${dir##*/}"; then + elif ! git clone --origin=origin -s "$dir" "${dir##*/}"; then error "$(gettext "Failure while creating working copy of %s %s repo")" "${repo}" "git" plainerr "$(gettext "Aborting...")" exit 1 From d74d7ec32cbeb687dea57e0f4078176914a22578 Mon Sep 17 00:00:00 2001 From: Allan McRae Date: Sun, 5 May 2024 15:12:18 +1000 Subject: [PATCH 05/17] makepkg: remove GITFLAGS support Supporting git source fragments (branch, commit, tag) is difficult in conjunction with GITFLAGS usage - particularly with the most common use cases that reduce the amount of data cloned from the upstream repo. Leaving GITFLAGS in place an documenting that various git source features are not supported when GITFLAGS are in used is not an ideal 'solution'. Instead, remove GITFLAGS support. Signed-off-by: Allan McRae --- doc/makepkg.8.asciidoc | 3 --- scripts/libmakepkg/source/git.sh.in | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/doc/makepkg.8.asciidoc b/doc/makepkg.8.asciidoc index b7b6d044..a2ad5279 100644 --- a/doc/makepkg.8.asciidoc +++ b/doc/makepkg.8.asciidoc @@ -297,9 +297,6 @@ Environment Variables **BUILDTOOLVER=**"":: The version of the '$BUILDTOOL' used. -**GITFLAGS**:: - The options to pass when checking out git sources, replacing the default - "--mirror". Configuration ------------- diff --git a/scripts/libmakepkg/source/git.sh.in b/scripts/libmakepkg/source/git.sh.in index dbe844a0..5f700a09 100644 --- a/scripts/libmakepkg/source/git.sh.in +++ b/scripts/libmakepkg/source/git.sh.in @@ -49,7 +49,7 @@ download_git() { if [[ ! -d "$dir" ]] || dir_is_empty "$dir" ; then msg2 "$(gettext "Cloning %s %s repo...")" "${repo}" "git" - if ! git clone --origin=origin ${GITFLAGS:---mirror} "$url" "$dir"; then + if ! git clone --origin=origin ---mirror "$url" "$dir"; then error "$(gettext "Failure while downloading %s %s repo")" "${repo}" "git" plainerr "$(gettext "Aborting...")" exit 1 From 7bbfc17f3c016da0e6758a6e73b7e8eabcdaac2c Mon Sep 17 00:00:00 2001 From: Diego Viola Date: Mon, 20 May 2024 02:15:37 -0300 Subject: [PATCH 06/17] Fix typos Signed-off-by: Diego Viola --- NEWS | 2 +- scripts/libmakepkg/autodep/library_depends.sh.in | 2 +- scripts/makepkg.sh.in | 2 +- test/pacman/ChangeLog | 2 +- test/pacman/tests/symlink020.py | 2 +- test/pacman/tests/symlink021.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index 5d7c07cd..89936409 100644 --- a/NEWS +++ b/NEWS @@ -182,7 +182,7 @@ VERSION DESCRIPTION - fix segfault when Usage is specified without a value - include timezones in pacman.log - bash-completion: use POSIX character classes for portability - - correctly report a download failiure for 404s + - correctly report a download failure for 404s - fix handling of signals during SIGSEGV - fix buffer overread in pacman/callback - fix crash when downloading files with a Content-Disposition diff --git a/scripts/libmakepkg/autodep/library_depends.sh.in b/scripts/libmakepkg/autodep/library_depends.sh.in index c088baff..6f58781b 100644 --- a/scripts/libmakepkg/autodep/library_depends.sh.in +++ b/scripts/libmakepkg/autodep/library_depends.sh.in @@ -60,7 +60,7 @@ library_depends() { continue fi - # only add library dependency if it exists - this helps bootstraping dependencies + # only add library dependency if it exists - this helps bootstrapping dependencies if [[ $(run_pacman -T "$prefix:$sofile") ]]; then continue fi diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in index bad9f15c..d5976434 100644 --- a/scripts/makepkg.sh.in +++ b/scripts/makepkg.sh.in @@ -713,7 +713,7 @@ create_srcpackage() { done pkgname=(${pkgname_backup[@]}) - # add a copy of source PGP signing public keys if availabe in keys/pgp/.asc + # add a copy of source PGP signing public keys if available in keys/pgp/.asc local key for key in ${validpgpkeys[@]}; do if [[ -f keys/pgp/$key.asc ]]; then diff --git a/test/pacman/ChangeLog b/test/pacman/ChangeLog index eb097084..1e92c3e0 100644 --- a/test/pacman/ChangeLog +++ b/test/pacman/ChangeLog @@ -16,7 +16,7 @@ Release 0.2 (06/02/13) ----------- - added support for directories, symlinks and altered files - removed hardcoded references to package names in testcase scripts -- splited pactest.py in several modules +- split pactest.py in several modules - lots of code optimizations - created a home page to host the project - added README, TODO and ChangeLog files diff --git a/test/pacman/tests/symlink020.py b/test/pacman/tests/symlink020.py index 343add2d..c8c0cae8 100644 --- a/test/pacman/tests/symlink020.py +++ b/test/pacman/tests/symlink020.py @@ -1,4 +1,4 @@ -self.description = "symlink -> dir replacment" +self.description = "symlink -> dir replacement" lp1 = pmpkg("pkg1") lp1.files = ["usr/lib/foo", diff --git a/test/pacman/tests/symlink021.py b/test/pacman/tests/symlink021.py index 1ba7c025..0baca727 100644 --- a/test/pacman/tests/symlink021.py +++ b/test/pacman/tests/symlink021.py @@ -1,4 +1,4 @@ -self.description = "symlink -> dir replacment with file move" +self.description = "symlink -> dir replacement with file move" lp1 = pmpkg("pkg1") lp1.files = ["usr/include/foo/", From 24455cc5b206cc1dd783a6e219d506019ffee877 Mon Sep 17 00:00:00 2001 From: Diego Viola Date: Mon, 27 May 2024 02:30:38 -0300 Subject: [PATCH 07/17] editorconfig: update url Use https and lowercase characters. Signed-off-by: Diego Viola --- .editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 220ffbc8..d7ee9c26 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,5 +1,5 @@ # EditorConfig configuration for pacman -# http://EditorConfig.org +# https://editorconfig.org # Top-most EditorConfig file root = true From 44b9a53b2d3d62f095438d84565bd8f8a4d8d435 Mon Sep 17 00:00:00 2001 From: Diego Viola Date: Fri, 31 May 2024 16:11:07 +0000 Subject: [PATCH 08/17] Fix spelling of environment --- NEWS | 10 +++++----- doc/repo-add.8.asciidoc | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index 89936409..b67fe49b 100644 --- a/NEWS +++ b/NEWS @@ -15,7 +15,7 @@ VERSION DESCRIPTION - makepkg: - Replace libdepends and libprovides with autodeps - Support configuration via makepkg.conf.d drop-ins - - Add GITFLAGS environmental variable to customize checkouts + - Add GITFLAGS environment variable to customize checkouts - Add -D option to change directory before building - Implement verify() function for custom source verificaton - Add checksum support for git/mercurial/bzr sources @@ -585,8 +585,8 @@ VERSION DESCRIPTION - remove --asroot and enforce fakeroot usage - all PKGBUILDs require a package() function - PKGBUILDs can no longer be read from stdin - - enable make style environmental overrides - - Read CARCH environmental variable (FS#35030) + - enable make-style environment variable overrides + - Read CARCH environment variable (FS#35030) - makedepends and checkdepends are installed together (FS#31557) - added support for sha224 checksums (FS#36776) - remove warning when license is not specified in PKGBUILD @@ -683,7 +683,7 @@ VERSION DESCRIPTION - pkgrel must be in decimal format - PKGBUILDs without package() functions are deprecated - support specifying CPPFLAGS in makepkg.conf - - support PACKAGER environmental variable + - support PACKAGER environment variable - allow source renaming to work on signature files - configurable compression options (FS#27430) - allow multiple packages to be build when using @@ -697,7 +697,7 @@ VERSION DESCRIPTION - add LOGDEST configuration option - install makedepends with --repackage - repo-add: - - honor TMPDIR environmental variable + - honor TMPDIR environment variable - add makedepends/checkdepends information to database - pacman-key: - fix importing keys with quotes in file name (FS#28445) diff --git a/doc/repo-add.8.asciidoc b/doc/repo-add.8.asciidoc index 0b8eab49..a6f77cd4 100644 --- a/doc/repo-add.8.asciidoc +++ b/doc/repo-add.8.asciidoc @@ -48,7 +48,7 @@ Common Options *-k, \--key* :: Specify a key to use when signing packages. Can also be specified using - the GPGKEY environmental variable. If not specified in either location, the + the GPGKEY environment variable. If not specified in either location, the default key from the keyring will be used. *-v, \--verify*:: From b013ca4221852edf920d1c7b0a910de303ce9826 Mon Sep 17 00:00:00 2001 From: Allan McRae Date: Mon, 20 May 2024 20:50:43 +1000 Subject: [PATCH 09/17] makepkg: provide environment variable to disable PKGBUILD linting On Windows based systems (e.g. msys), running PKGBUILD linting is very slow due to time taken spawning bash subshells. Additionally, some packages have extreme amounts of (usually procedurally generated) splitting, which also causes linting to be extremely slow. Provide an environment variable to disable PKGBUILD linting. Signed-off-by: Allan McRae --- doc/makepkg.8.asciidoc | 5 +++++ scripts/makepkg.sh.in | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/makepkg.8.asciidoc b/doc/makepkg.8.asciidoc index a2ad5279..bb5e2f4a 100644 --- a/doc/makepkg.8.asciidoc +++ b/doc/makepkg.8.asciidoc @@ -297,6 +297,11 @@ Environment Variables **BUILDTOOLVER=**"":: The version of the '$BUILDTOOL' used. +**MAKEPKG_LINT_PKGBUILD=**0 + Setting to 0 disables PKGBUILD linting within makepkg. Useful on systems + with slow bash subshell operations, or on PKGBUILDs with extreme amounts of + package splitting. + Configuration ------------- diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in index d5976434..75df3650 100644 --- a/scripts/makepkg.sh.in +++ b/scripts/makepkg.sh.in @@ -87,6 +87,8 @@ else fi export SOURCE_DATE_EPOCH +MAKEPKG_LINT_PKGBUILD=${MAKEPKG_LINT_PKGBUILD:-1} + PACMAN_OPTS=() shopt -s extglob @@ -1151,7 +1153,9 @@ fi pkgbase=${pkgbase:-${pkgname[0]}} # check the PKGBUILD for some basic requirements -lint_pkgbuild || exit $E_PKGBUILD_ERROR +if (( MAKEPKG_LINT_PKGBUILD != 0 )); then + lint_pkgbuild || exit $E_PKGBUILD_ERROR +fi if (( !SOURCEONLY && !PRINTSRCINFO )); then merge_arch_attrs From f0a7f85dbb4e8da43325ad4eb45b09e0636ee6de Mon Sep 17 00:00:00 2001 From: Allan McRae Date: Mon, 20 May 2024 21:08:53 +1000 Subject: [PATCH 10/17] libmakepkg: make configured BUILDENV readonly PKGBUILDs should not be directly adjusting this variable Signed-off-by: Allan McRae --- scripts/libmakepkg/util/config.sh.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/libmakepkg/util/config.sh.in b/scripts/libmakepkg/util/config.sh.in index e9bb7044..63f16d66 100644 --- a/scripts/libmakepkg/util/config.sh.in +++ b/scripts/libmakepkg/util/config.sh.in @@ -77,5 +77,8 @@ load_makepkg_config() { source_makepkg_config "$MAKEPKG_CONF" + # prevent PKGBUILDs altering this directly + readonly -a BUILDENV + eval "$restore_envvars" } From 24304c6df04c9e8e9479a965b8f767b609742116 Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Wed, 29 May 2024 17:33:32 +0200 Subject: [PATCH 11/17] Fix up-to-date repo databases being redownloaded when sandboxed Signed-off-by: Remi Gacogne Signed-off-by: Allan McRae --- lib/libalpm/dload.c | 22 +++++++++++++++------- lib/libalpm/dload.h | 2 ++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c index 8dc5b640..b086fac1 100644 --- a/lib/libalpm/dload.c +++ b/lib/libalpm/dload.c @@ -413,14 +413,13 @@ static void curl_set_handle_opts(CURL *curl, struct dload_payload *payload) curl_easy_setopt(curl, CURLOPT_USERAGENT, useragent); } - if(!payload->force && payload->destfile_name && - stat(payload->destfile_name, &st) == 0) { + if(!payload->force && payload->mtime_existing_file) { /* start from scratch, but only download if our local is out of date. */ curl_easy_setopt(curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE); - curl_easy_setopt(curl, CURLOPT_TIMEVALUE, (long)st.st_mtime); + curl_easy_setopt(curl, CURLOPT_TIMEVALUE, payload->mtime_existing_file); _alpm_log(handle, ALPM_LOG_DEBUG, "%s: using time condition %ld\n", - payload->remote_name, (long)st.st_mtime); + payload->remote_name, (long)payload->mtime_existing_file); } else if(stat(payload->tempfile_name, &st) == 0 && payload->allow_resume) { /* a previous partial download exists, resume from end of file. */ payload->tempfile_openmode = "ab"; @@ -1138,11 +1137,20 @@ static void prepare_resumable_downloads(alpm_list_t *payloads, const char *local alpm_list_t *p; for(p = payloads; p; p = p->next) { struct dload_payload *payload = p->data; + if(payload->destfile_name) { + const char *destfilename = mbasename(payload->destfile_name); + char *dest = _alpm_get_fullpath(localpath, destfilename, ""); + struct stat deststat; + if(stat(dest, &deststat) == 0 && deststat.st_size != 0) { + payload->mtime_existing_file = deststat.st_mtime; + } + FREE(dest); + } if(!payload->tempfile_name) { continue; - } + } const char *filename = mbasename(payload->tempfile_name); - char *src = _alpm_get_fullpath(localpath, filename, "");; + char *src = _alpm_get_fullpath(localpath, filename, ""); struct stat st; if(stat(src, &st) != 0 || st.st_size == 0) { FREE(src); @@ -1249,7 +1257,7 @@ download_signature: ret = updated ? 0 : 1; } - if (finalize_download_locations(payloads, localpath) != 0) { + if (finalize_download_locations(payloads, localpath) != 0 && ret == 0) { return -1; } return ret; diff --git a/lib/libalpm/dload.h b/lib/libalpm/dload.h index 88684676..a4a7d27c 100644 --- a/lib/libalpm/dload.h +++ b/lib/libalpm/dload.h @@ -42,6 +42,8 @@ struct dload_payload { alpm_list_t *cache_servers; alpm_list_t *servers; long respcode; + /* the mtime of the existing version of this file, if there is one */ + long mtime_existing_file; off_t initial_size; off_t max_size; off_t prevprogress; From eacadbcc41eb0dd9ebbafbab8e1ae0fc84b61fdb Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Wed, 3 Apr 2024 16:18:17 +0200 Subject: [PATCH 12/17] Restrict filesystem access to the download process whenever possible Signed-off-by: Remi Gacogne --- lib/libalpm/alpm.h | 4 +- lib/libalpm/dload.c | 2 +- lib/libalpm/meson.build | 1 + lib/libalpm/sandbox.c | 8 +- lib/libalpm/sandbox_fs.c | 173 +++++++++++++++++++++++++++++++++++++++ lib/libalpm/sandbox_fs.h | 27 ++++++ meson.build | 1 + src/pacman/conf.c | 10 +-- 8 files changed, 217 insertions(+), 9 deletions(-) create mode 100644 lib/libalpm/sandbox_fs.c create mode 100644 lib/libalpm/sandbox_fs.h diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 268f7213..43d45198 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -2954,10 +2954,12 @@ const char *alpm_version(void); int alpm_capabilities(void); /** Drop privileges by switching to a different user. + * @param handle the context handle * @param sandboxuser the user to switch to + * @param sandbox_path if non-NULL, restrict writes to this filesystem path * @return 0 on success, -1 on failure */ -int alpm_sandbox_setup_child(const char *sandboxuser); +int alpm_sandbox_setup_child(alpm_handle_t *handle, const char *sandboxuser, const char *sandbox_path); /* End of libalpm_misc */ /** @} */ diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c index b086fac1..9815d474 100644 --- a/lib/libalpm/dload.c +++ b/lib/libalpm/dload.c @@ -959,7 +959,7 @@ static int curl_download_internal_sandboxed(alpm_handle_t *handle, _alpm_log(handle, ALPM_LOG_ERROR, _("could not chdir to download directory %s\n"), localpath); ret = -1; } else { - ret = alpm_sandbox_setup_child(handle->sandboxuser); + ret = alpm_sandbox_setup_child(handle, handle->sandboxuser, localpath); if (ret != 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("switching to sandbox user '%s' failed!\n"), handle->sandboxuser); _Exit(2); diff --git a/lib/libalpm/meson.build b/lib/libalpm/meson.build index 224fbf5f..1a6672da 100644 --- a/lib/libalpm/meson.build +++ b/lib/libalpm/meson.build @@ -25,6 +25,7 @@ libalpm_sources = files(''' rawstr.c remove.h remove.c sandbox.h sandbox.c + sandbox_fs.h sandbox_fs.c signing.c signing.h sync.h sync.c trans.h trans.c diff --git a/lib/libalpm/sandbox.c b/lib/libalpm/sandbox.c index 0f3d7084..fd3b8c45 100644 --- a/lib/libalpm/sandbox.c +++ b/lib/libalpm/sandbox.c @@ -1,7 +1,7 @@ /* * sandbox.c * - * Copyright (c) 2021-2022 Pacman Development Team + * Copyright (c) 2021-2024 Pacman Development Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,15 +26,19 @@ #include "alpm.h" #include "log.h" #include "sandbox.h" +#include "sandbox_fs.h" #include "util.h" -int SYMEXPORT alpm_sandbox_setup_child(const char* sandboxuser) +int SYMEXPORT alpm_sandbox_setup_child(alpm_handle_t *handle, const char* sandboxuser, const char* sandbox_path) { struct passwd const *pw = NULL; ASSERT(sandboxuser != NULL, return -1); ASSERT(getuid() == 0, return -1); ASSERT((pw = getpwnam(sandboxuser)), return -1); + if(sandbox_path != NULL) { + _alpm_sandbox_fs_restrict_writes_to(handle, sandbox_path); + } ASSERT(setgid(pw->pw_gid) == 0, return -1); ASSERT(setgroups(0, NULL) == 0, return -1); ASSERT(setuid(pw->pw_uid) == 0, return -1); diff --git a/lib/libalpm/sandbox_fs.c b/lib/libalpm/sandbox_fs.c new file mode 100644 index 00000000..3d7de013 --- /dev/null +++ b/lib/libalpm/sandbox_fs.c @@ -0,0 +1,173 @@ +/* + * sandbox_fs.c + * + * Copyright (c) 2021-2024 Pacman Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include +#include + +#include "config.h" +#include "log.h" +#include "sandbox_fs.h" +#include "util.h" + +#ifdef HAVE_LINUX_LANDLOCK_H +# include +# include +# include +#endif /* HAVE_LINUX_LANDLOCK_H */ + +#ifdef HAVE_LINUX_LANDLOCK_H +#ifndef landlock_create_ruleset +static inline int landlock_create_ruleset(const struct landlock_ruleset_attr *const attr, + const size_t size, const __u32 flags) +{ + return syscall(__NR_landlock_create_ruleset, attr, size, flags); +} +#endif /* landlock_create_ruleset */ + +#ifndef landlock_add_rule +static inline int landlock_add_rule(const int ruleset_fd, + const enum landlock_rule_type rule_type, + const void *const rule_attr, const __u32 flags) +{ + return syscall(__NR_landlock_add_rule, ruleset_fd, rule_type, rule_attr, flags); +} +#endif /* landlock_add_rule */ + +#ifndef landlock_restrict_self +static inline int landlock_restrict_self(const int ruleset_fd, const __u32 flags) +{ + return syscall(__NR_landlock_restrict_self, ruleset_fd, flags); +} +#endif /* landlock_restrict_self */ + +#define _LANDLOCK_ACCESS_FS_WRITE ( \ + LANDLOCK_ACCESS_FS_WRITE_FILE | \ + LANDLOCK_ACCESS_FS_REMOVE_DIR | \ + LANDLOCK_ACCESS_FS_REMOVE_FILE | \ + LANDLOCK_ACCESS_FS_MAKE_CHAR | \ + LANDLOCK_ACCESS_FS_MAKE_DIR | \ + LANDLOCK_ACCESS_FS_MAKE_REG | \ + LANDLOCK_ACCESS_FS_MAKE_SOCK | \ + LANDLOCK_ACCESS_FS_MAKE_FIFO | \ + LANDLOCK_ACCESS_FS_MAKE_BLOCK | \ + LANDLOCK_ACCESS_FS_MAKE_SYM) + +#define _LANDLOCK_ACCESS_FS_READ ( \ + LANDLOCK_ACCESS_FS_READ_FILE | \ + LANDLOCK_ACCESS_FS_READ_DIR) + +#ifdef LANDLOCK_ACCESS_FS_REFER +#define _LANDLOCK_ACCESS_FS_REFER LANDLOCK_ACCESS_FS_REFER +#else +#define _LANDLOCK_ACCESS_FS_REFER 0 +#endif /* LANDLOCK_ACCESS_FS_REFER */ + +#ifdef LANDLOCK_ACCESS_FS_TRUNCATE +#define _LANDLOCK_ACCESS_FS_TRUNCATE LANDLOCK_ACCESS_FS_TRUNCATE +#else +#define _LANDLOCK_ACCESS_FS_TRUNCATE 0 +#endif /* LANDLOCK_ACCESS_FS_TRUNCATE */ + +#endif /* HAVE_LINUX_LANDLOCK_H */ + +bool _alpm_sandbox_fs_restrict_writes_to(alpm_handle_t *handle, const char *path) +{ + ASSERT(handle != NULL, return false); + ASSERT(path != NULL, return false); + +#ifdef HAVE_LINUX_LANDLOCK_H + struct landlock_ruleset_attr ruleset_attr = { + .handled_access_fs = \ + _LANDLOCK_ACCESS_FS_READ | \ + _LANDLOCK_ACCESS_FS_WRITE | \ + _LANDLOCK_ACCESS_FS_REFER | \ + _LANDLOCK_ACCESS_FS_TRUNCATE | \ + LANDLOCK_ACCESS_FS_EXECUTE, + }; + struct landlock_path_beneath_attr path_beneath = { + .allowed_access = _LANDLOCK_ACCESS_FS_READ, + }; + int abi = 0; + int result = 0; + int ruleset_fd; + + abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION); + if(abi < 0) { + /* landlock is not supported/enabled in the kernel */ + _alpm_log(handle, ALPM_LOG_ERROR, _("restricting filesystem access failed because landlock is not supported by the kernel!\n")); + return true; + } +#ifdef LANDLOCK_ACCESS_FS_REFER + if(abi < 2) { + _alpm_log(handle, ALPM_LOG_DEBUG, _("landlock ABI < 2, LANDLOCK_ACCESS_FS_REFER is not supported\n")); + ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER; + } +#endif /* LANDLOCK_ACCESS_FS_REFER */ +#ifdef LANDLOCK_ACCESS_FS_TRUNCATE + if(abi < 3) { + _alpm_log(handle, ALPM_LOG_DEBUG, _("landlock ABI < 3, LANDLOCK_ACCESS_FS_TRUNCATE is not supported\n")); + ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE; + } +#endif /* LANDLOCK_ACCESS_FS_TRUNCATE */ + + ruleset_fd = landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); + if(ruleset_fd < 0) { + _alpm_log(handle, ALPM_LOG_ERROR, _("restricting filesystem access failed because the landlock ruleset could not be created!\n")); + return false; + } + + /* allow / as read-only */ + path_beneath.parent_fd = open("/", O_PATH | O_CLOEXEC | O_DIRECTORY); + path_beneath.allowed_access = _LANDLOCK_ACCESS_FS_READ; + + if(landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, &path_beneath, 0) != 0) { + _alpm_log(handle, ALPM_LOG_ERROR, _("restricting filesystem access failed because the landlock rule for / could not be added!\n")); + close(path_beneath.parent_fd); + close(ruleset_fd); + return false; + } + + close(path_beneath.parent_fd); + + /* allow read-write access to the directory passed as parameter */ + path_beneath.parent_fd = open(path, O_PATH | O_CLOEXEC | O_DIRECTORY); + path_beneath.allowed_access = _LANDLOCK_ACCESS_FS_READ | _LANDLOCK_ACCESS_FS_WRITE | _LANDLOCK_ACCESS_FS_TRUNCATE; + + if(!landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, &path_beneath, 0) != 0) { + if(landlock_restrict_self(ruleset_fd, 0)) { + _alpm_log(handle, ALPM_LOG_ERROR, _("restricting filesystem access failed because the landlock ruleset could not be applied!\n")); + result = errno; + } + } else { + result = errno; + _alpm_log(handle, ALPM_LOG_ERROR, _("restricting filesystem access failed because the landlock rule for the temporary download directory could not be added!\n")); + } + + close(path_beneath.parent_fd); + close(ruleset_fd); + if(result == 0) { + _alpm_log(handle, ALPM_LOG_DEBUG, _("filesystem access has been restricted to %s, landlock ABI is %d\n"), path, abi); + return true; + } + return false; +#else /* HAVE_LINUX_LANDLOCK_H */ + return true; +#endif /* HAVE_LINUX_LANDLOCK_H */ +} diff --git a/lib/libalpm/sandbox_fs.h b/lib/libalpm/sandbox_fs.h new file mode 100644 index 00000000..70bfa157 --- /dev/null +++ b/lib/libalpm/sandbox_fs.h @@ -0,0 +1,27 @@ +/* + * sandbox_fs.h + * + * Copyright (c) 2021-2024 Pacman Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef ALPM_SANDBOX_FS_H +#define ALPM_SANDBOX_FS_H + +#include +#include "alpm.h" + +bool _alpm_sandbox_fs_restrict_writes_to(alpm_handle_t *handle, const char *path); + +#endif /* ALPM_SANDBOX_FS_H */ diff --git a/meson.build b/meson.build index bc2ef468..21b8cede 100644 --- a/meson.build +++ b/meson.build @@ -123,6 +123,7 @@ else endif foreach header : [ + 'linux/landlock.h', 'mntent.h', 'sys/mnttab.h', 'sys/mount.h', diff --git a/src/pacman/conf.c b/src/pacman/conf.c index 2cf56bf1..9529aefc 100644 --- a/src/pacman/conf.c +++ b/src/pacman/conf.c @@ -218,7 +218,7 @@ static char *get_tempfile(const char *path, const char *filename) * - not thread-safe * - errno may be set by fork(), pipe(), or execvp() */ -static int systemvp(const char *file, char *const argv[], const char *sandboxuser) +static int systemvp(const char *file, char *const argv[]) { int pid, err = 0, ret = -1, err_fd[2]; sigset_t oldblock; @@ -245,10 +245,10 @@ static int systemvp(const char *file, char *const argv[], const char *sandboxuse sigaction(SIGQUIT, &oldquit, NULL); sigprocmask(SIG_SETMASK, &oldblock, NULL); - if (sandboxuser) { - ret = alpm_sandbox_setup_child(sandboxuser); + if (config->sandboxuser) { + ret = alpm_sandbox_setup_child(config->handle, config->sandboxuser, NULL); if (ret != 0) { - pm_printf(ALPM_LOG_ERROR, _("switching to sandbox user '%s' failed!\n"), sandboxuser); + pm_printf(ALPM_LOG_ERROR, _("switching to sandbox user '%s' failed!\n"), config->sandboxuser); _Exit(ret); } } @@ -363,7 +363,7 @@ static int download_with_xfercommand(void *ctx, const char *url, free(cmd); } } - retval = systemvp(argv[0], (char**)argv, config->sandboxuser); + retval = systemvp(argv[0], (char**)argv); if(retval == -1) { pm_printf(ALPM_LOG_WARNING, _("running XferCommand: fork failed!\n")); From 9f8f94c05630f0afb13baaffe84c4d01e4a6860e Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Wed, 15 May 2024 15:36:28 +0200 Subject: [PATCH 13/17] Add --disable-sandbox and DisableSandbox Signed-off-by: Remi Gacogne --- doc/pacman.8.asciidoc | 4 ++++ doc/pacman.conf.5.asciidoc | 4 ++++ lib/libalpm/alpm.h | 14 ++++++++++++++ lib/libalpm/handle.c | 8 ++++++++ lib/libalpm/handle.h | 1 + lib/libalpm/sandbox.c | 2 +- src/pacman/conf.c | 3 +++ src/pacman/conf.h | 4 +++- src/pacman/pacman-conf.c | 3 +++ src/pacman/pacman.c | 6 ++++++ 10 files changed, 47 insertions(+), 2 deletions(-) diff --git a/doc/pacman.8.asciidoc b/doc/pacman.8.asciidoc index 345405d4..3ea1fef1 100644 --- a/doc/pacman.8.asciidoc +++ b/doc/pacman.8.asciidoc @@ -200,6 +200,10 @@ Options beginning with `file://`. Any paths or URLs passed as targets will not be modified. This allows mounted guest systems to be properly operated on. +*\--disable-sandbox*:: + Disable the default sandbox applied to the process downloading files on Linux + systems. Useful if experiencing landlock related failues while downloading + files when running a Linux kernel that does not support this feature. Transaction Options (apply to '-S', '-R' and '-U') -------------------------------------------------- diff --git a/doc/pacman.conf.5.asciidoc b/doc/pacman.conf.5.asciidoc index 9c46ce6e..b462169b 100644 --- a/doc/pacman.conf.5.asciidoc +++ b/doc/pacman.conf.5.asciidoc @@ -211,6 +211,10 @@ Options Specifies the user to switch to for downloading files. If this config option is not set then the downloads are done as the user running pacman. +*DisableSandbox*:: + Disable the default sandbox applied to the process downloading files on Linux + systems. Useful if experiencing landlock related failues while downloading + files when running a Linux kernel that does not support this feature. Repository Sections ------------------- diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 43d45198..1759a9a2 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -2300,6 +2300,20 @@ int alpm_option_set_parallel_downloads(alpm_handle_t *handle, unsigned int num_s /* End of parallel_downloads accessors */ /** @} */ +/** @name Accessors for sandbox + * + * By default, libalpm will sandbox the downloader process. + * @{ + */ + +/** Enables/disables the sandbox. + * @param handle the context handle + * @param disable_sandbox 0 for enabled, 1 for disabled + * @return 0 on success, -1 on error (pm_errno is set accordingly) + */ +int alpm_option_set_disable_sandbox(alpm_handle_t *handle, unsigned short disable_sandbox); +/* End of disable_sandbox accessors */ +/** @} */ /* End of libalpm_options */ /** @} */ diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c index 2d360f46..e2f919f6 100644 --- a/lib/libalpm/handle.c +++ b/lib/libalpm/handle.c @@ -951,3 +951,11 @@ int SYMEXPORT alpm_option_set_parallel_downloads(alpm_handle_t *handle, handle->parallel_downloads = num_streams; return 0; } + +int SYMEXPORT alpm_option_set_disable_sandbox(alpm_handle_t *handle, + unsigned short disable_sandbox) +{ + CHECK_HANDLE(handle, return -1); + handle->disable_sandbox = disable_sandbox; + return 0; +} diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h index 63efc3d0..37724344 100644 --- a/lib/libalpm/handle.h +++ b/lib/libalpm/handle.h @@ -65,6 +65,7 @@ struct _alpm_handle_t { #endif unsigned short disable_dl_timeout; + unsigned short disable_sandbox; unsigned int parallel_downloads; /* number of download streams */ #ifdef HAVE_LIBGPGME diff --git a/lib/libalpm/sandbox.c b/lib/libalpm/sandbox.c index fd3b8c45..d8e01e44 100644 --- a/lib/libalpm/sandbox.c +++ b/lib/libalpm/sandbox.c @@ -36,7 +36,7 @@ int SYMEXPORT alpm_sandbox_setup_child(alpm_handle_t *handle, const char* sandbo ASSERT(sandboxuser != NULL, return -1); ASSERT(getuid() == 0, return -1); ASSERT((pw = getpwnam(sandboxuser)), return -1); - if(sandbox_path != NULL) { + if(sandbox_path != NULL && !handle->disable_sandbox) { _alpm_sandbox_fs_restrict_writes_to(handle, sandbox_path); } ASSERT(setgid(pw->pw_gid) == 0, return -1); diff --git a/src/pacman/conf.c b/src/pacman/conf.c index 9529aefc..d0966eea 100644 --- a/src/pacman/conf.c +++ b/src/pacman/conf.c @@ -629,6 +629,8 @@ static int _parse_options(const char *key, char *value, config->noprogressbar = 1; } else if(strcmp(key, "DisableDownloadTimeout") == 0) { config->disable_dl_timeout = 1; + } else if(strcmp(key, "DisableSandbox") == 0) { + config->disable_sandbox = 1; } else { pm_printf(ALPM_LOG_WARNING, _("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"), @@ -937,6 +939,7 @@ static int setup_libalpm(void) alpm_option_set_checkspace(handle, config->checkspace); alpm_option_set_usesyslog(handle, config->usesyslog); alpm_option_set_sandboxuser(handle, config->sandboxuser); + alpm_option_set_disable_sandbox(handle, config->disable_sandbox); alpm_option_set_ignorepkgs(handle, config->ignorepkg); alpm_option_set_ignoregroups(handle, config->ignoregrp); diff --git a/src/pacman/conf.h b/src/pacman/conf.h index e9f17123..5bffd187 100644 --- a/src/pacman/conf.h +++ b/src/pacman/conf.h @@ -58,6 +58,7 @@ typedef struct __config_t { unsigned short usesyslog; unsigned short color; unsigned short disable_dl_timeout; + unsigned short disable_sandbox; char *print_format; /* unfortunately, we have to keep track of paths both here and in the library * because they can come from both the command line or config file, and we @@ -212,7 +213,8 @@ enum { OP_DOWNLOADONLY, OP_REFRESH, OP_ASSUMEINSTALLED, - OP_DISABLEDLTIMEOUT + OP_DISABLEDLTIMEOUT, + OP_DISABLESANDBOX }; /* clean method */ diff --git a/src/pacman/pacman-conf.c b/src/pacman/pacman-conf.c index d73d6c4c..92e68003 100644 --- a/src/pacman/pacman-conf.c +++ b/src/pacman/pacman-conf.c @@ -280,6 +280,7 @@ static void dump_config(void) show_bool("DisableDownloadTimeout", config->disable_dl_timeout); show_bool("ILoveCandy", config->chomp); show_bool("NoProgressBar", config->noprogressbar); + show_bool("DisableSandbox", config->disable_sandbox); show_int("ParallelDownloads", config->parallel_downloads); @@ -397,6 +398,8 @@ static int list_directives(void) show_bool("ILoveCandy", config->chomp); } else if(strcasecmp(i->data, "NoProgressBar") == 0) { show_bool("NoProgressBar", config->noprogressbar); + } else if(strcasecmp(i->data, "DisableSandbox") == 0) { + show_bool("DisableSandbox", config->disable_sandbox); } else if(strcasecmp(i->data, "ParallelDownloads") == 0) { show_int("ParallelDownloads", config->parallel_downloads); diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 6b64ffc7..90d37b16 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -226,6 +226,8 @@ static void usage(int op, const char * const myname) addlist(_(" --confirm always ask for confirmation\n")); addlist(_(" --disable-download-timeout\n" " use relaxed timeouts for download\n")); + addlist(_(" --disable-sandbox\n" + " disable the sandbox used for the downloader process\n")); } list = alpm_list_msort(list, alpm_list_count(list), options_cmp); for(i = list; i; i = alpm_list_next(i)) { @@ -490,6 +492,9 @@ static int parsearg_global(int opt) case OP_DISABLEDLTIMEOUT: config->disable_dl_timeout = 1; break; + case OP_DISABLESANDBOX: + config->disable_sandbox = 1; + break; case OP_VERBOSE: case 'v': (config->verbose)++; @@ -976,6 +981,7 @@ static int parseargs(int argc, char *argv[]) {"dbonly", no_argument, 0, OP_DBONLY}, {"color", required_argument, 0, OP_COLOR}, {"disable-download-timeout", no_argument, 0, OP_DISABLEDLTIMEOUT}, + {"disable-sandbox", no_argument, 0, OP_DISABLESANDBOX}, {0, 0, 0, 0} }; From 479f4d574a25fee0d24ffbb6d8b476210c653ea9 Mon Sep 17 00:00:00 2001 From: Allan McRae Date: Tue, 18 Jun 2024 09:24:03 +1000 Subject: [PATCH 14/17] Prevent buffer overflow when using a scriptlet shell with a long path Observed in Nixpkgs. Fixes #157. Signed-off-by: Allan McRae --- lib/libalpm/trans.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c index 4892820b..ef77e792 100644 --- a/lib/libalpm/trans.c +++ b/lib/libalpm/trans.c @@ -337,7 +337,7 @@ static int grep(const char *fn, const char *needle) int _alpm_runscriptlet(alpm_handle_t *handle, const char *filepath, const char *script, const char *ver, const char *oldver, int is_archive) { - char arg0[64], arg1[3], cmdline[PATH_MAX]; + char arg0[PATH_MAX], arg1[3], cmdline[PATH_MAX]; char *argv[] = { arg0, arg1, cmdline, NULL }; char *tmpdir, *scriptfn = NULL, *scriptpath; int retval = 0; From b60b779fc83396c9f4c6816389646e697f7ee2a9 Mon Sep 17 00:00:00 2001 From: Allan McRae Date: Wed, 19 Jun 2024 14:09:48 +1000 Subject: [PATCH 15/17] Fix calculation of space needed for download package The calculation used the size of the package rather than the amount remaining to download for partially downloaded packages. Signed-off-by: Allan McRae --- lib/libalpm/sync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index e73b8ffc..821e75a3 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -805,7 +805,7 @@ static int download_files(alpm_handle_t *handle) for(i = files, idx = 0; i; i = i->next, idx++) { const alpm_pkg_t *pkg = i->data; - file_sizes[idx] = pkg->size; + file_sizes[idx] = pkg->download_size; } ret = _alpm_check_downloadspace(handle, temporary_cachedir, num_files, file_sizes); From c9acfc2b50b79390c58d8aa52a134030e7cec58a Mon Sep 17 00:00:00 2001 From: Allan McRae Date: Wed, 19 Jun 2024 17:31:54 +1000 Subject: [PATCH 16/17] Fix error when downloading signature file for an existing package file If a package was already downloaded but its signature file was not, pacman would download the signature then error out despite all files being present. Also fixes a similar error when some, but not all, package databases were updated with -Sy. Fixes #156 Signed-off-by: Allan McRae --- lib/libalpm/dload.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c index 9815d474..da2ca24c 100644 --- a/lib/libalpm/dload.c +++ b/lib/libalpm/dload.c @@ -1108,7 +1108,10 @@ static int finalize_download_locations(alpm_list_t *payloads, const char *localp int ret = move_file(payload->destfile_name, localpath); if(ret == -1) { - returnvalue = -1; + /* ignore error if the file already existed - only signature file was downloaded */ + if(payload->mtime_existing_file == 0) { + returnvalue = -1; + } } if (payload->download_signature) { From 3f1943c84d94ab5135f89d01227f2f29f06fa410 Mon Sep 17 00:00:00 2001 From: Allan McRae Date: Wed, 19 Jun 2024 11:38:24 +1000 Subject: [PATCH 17/17] Only copy source files onces when creating debug packages The Arch sharutils package was spewing messages about "Permission denied" when copying source files into the debug package. This is due to the source files having 444 permissions and being used in multiple binaries. Only copy each source file into the debug package onces to avoid this error. Signed-off-by: Allan McRae --- scripts/libmakepkg/tidy/strip.sh.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/libmakepkg/tidy/strip.sh.in b/scripts/libmakepkg/tidy/strip.sh.in index db359167..0b44004c 100644 --- a/scripts/libmakepkg/tidy/strip.sh.in +++ b/scripts/libmakepkg/tidy/strip.sh.in @@ -60,7 +60,7 @@ package_source_files() { file="${srcdir}/${t}" dest="${dbgsrc}/${t}" mkdir -p "${dest%/*}" - if [[ -f "$file" ]]; then + if [[ -f "$file" && ! -f "$dest" ]]; then cp -- "$file" "$dest" fi done < <(source_files "$binary")