diff options
| author | Tobias Hagelborn <tobias.hagelborn@axis.com> | 2024-02-05 15:03:34 +0100 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2024-02-18 07:34:42 +0000 |
| commit | f909d235c95d89bd44a7d3fc719adfc82cdc1d98 (patch) | |
| tree | ab24c1d29bcae1bb5c98ff565077131061b22dcc | |
| parent | a277d1f7a0dc716b497fd855f20cbd6a7d488f8b (diff) | |
| download | poky-f909d235c95d89bd44a7d3fc719adfc82cdc1d98.tar.gz | |
sstate.bbclass: Only sign packages at the time of their creation
The purpose of the change is to never sign a package not created by
the build itself.
sstate_create_package is refactored into Python and re-designed
to handle signing inside the function. Thus, the signing should never apply
to existing sstate packages. The function is therefore renamed into
sstate_create_and_sign_package.
The creation of the archive remains in a separate shellscript function.
Co-authored-by: Peter Kjellerstedt <peter.kjellerstedt@axis.com>
(From OE-Core rev: ba223f8fff19ea59440d56cf3fe46200f3f71e22)
Signed-off-by: Tobias Hagelborn <tobias.hagelborn@axis.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
| -rw-r--r-- | meta/classes-global/sstate.bbclass | 140 |
1 files changed, 94 insertions, 46 deletions
diff --git a/meta/classes-global/sstate.bbclass b/meta/classes-global/sstate.bbclass index efe7f69775..96655ff24f 100644 --- a/meta/classes-global/sstate.bbclass +++ b/meta/classes-global/sstate.bbclass | |||
| @@ -703,9 +703,7 @@ def sstate_package(ss, d): | |||
| 703 | if d.getVar('SSTATE_SKIP_CREATION') == '1': | 703 | if d.getVar('SSTATE_SKIP_CREATION') == '1': |
| 704 | return | 704 | return |
| 705 | 705 | ||
| 706 | sstate_create_package = ['sstate_report_unihash', 'sstate_create_pkgdirs', 'sstate_create_package'] | 706 | sstate_create_package = ['sstate_report_unihash', 'sstate_create_and_sign_package'] |
| 707 | if d.getVar('SSTATE_SIG_KEY'): | ||
| 708 | sstate_create_package.append('sstate_sign_package') | ||
| 709 | 707 | ||
| 710 | for f in (d.getVar('SSTATECREATEFUNCS') or '').split() + \ | 708 | for f in (d.getVar('SSTATECREATEFUNCS') or '').split() + \ |
| 711 | sstate_create_package + \ | 709 | sstate_create_package + \ |
| @@ -810,26 +808,100 @@ python sstate_task_postfunc () { | |||
| 810 | } | 808 | } |
| 811 | sstate_task_postfunc[dirs] = "${WORKDIR}" | 809 | sstate_task_postfunc[dirs] = "${WORKDIR}" |
| 812 | 810 | ||
| 813 | python sstate_create_pkgdirs () { | 811 | # Create a sstate package |
| 814 | # report_unihash can change SSTATE_PKG and mkdir -p in shell doesn't own intermediate directories | 812 | # If enabled, sign the package. |
| 815 | # correctly so do this in an intermediate python task | 813 | # Package and signature are created in a sub-directory |
| 816 | with bb.utils.umask(0o002): | 814 | # and renamed in place once created. |
| 817 | bb.utils.mkdirhier(os.path.dirname(d.getVar('SSTATE_PKG'))) | 815 | python sstate_create_and_sign_package () { |
| 816 | from pathlib import Path | ||
| 817 | |||
| 818 | # Best effort touch | ||
| 819 | def touch(file): | ||
| 820 | try: | ||
| 821 | file.touch() | ||
| 822 | except: | ||
| 823 | pass | ||
| 824 | |||
| 825 | def update_file(src, dst, force=False): | ||
| 826 | if dst.is_symlink() and not dst.exists(): | ||
| 827 | force=True | ||
| 828 | try: | ||
| 829 | # This relies on that src is a temporary file that can be renamed | ||
| 830 | # or left as is. | ||
| 831 | if force: | ||
| 832 | src.rename(dst) | ||
| 833 | else: | ||
| 834 | os.link(src, dst) | ||
| 835 | return True | ||
| 836 | except: | ||
| 837 | pass | ||
| 838 | |||
| 839 | if dst.exists(): | ||
| 840 | touch(dst) | ||
| 841 | |||
| 842 | return False | ||
| 843 | |||
| 844 | sign_pkg = ( | ||
| 845 | bb.utils.to_boolean(d.getVar("SSTATE_VERIFY_SIG")) and | ||
| 846 | bool(d.getVar("SSTATE_SIG_KEY")) | ||
| 847 | ) | ||
| 848 | |||
| 849 | sstate_pkg = Path(d.getVar("SSTATE_PKG")) | ||
| 850 | sstate_pkg_sig = Path(str(sstate_pkg) + ".sig") | ||
| 851 | if sign_pkg: | ||
| 852 | if sstate_pkg.exists() and sstate_pkg_sig.exists(): | ||
| 853 | touch(sstate_pkg) | ||
| 854 | touch(sstate_pkg_sig) | ||
| 855 | return | ||
| 856 | else: | ||
| 857 | if sstate_pkg.exists(): | ||
| 858 | touch(sstate_pkg) | ||
| 859 | return | ||
| 860 | |||
| 861 | # Create the required sstate directory if it is not present. | ||
| 862 | if not sstate_pkg.parent.is_dir(): | ||
| 863 | with bb.utils.umask(0o002): | ||
| 864 | bb.utils.mkdirhier(str(sstate_pkg.parent)) | ||
| 865 | |||
| 866 | if sign_pkg: | ||
| 867 | from tempfile import TemporaryDirectory | ||
| 868 | with TemporaryDirectory(dir=sstate_pkg.parent) as tmp_dir: | ||
| 869 | tmp_pkg = Path(tmp_dir) / sstate_pkg.name | ||
| 870 | d.setVar("TMP_SSTATE_PKG", str(tmp_pkg)) | ||
| 871 | bb.build.exec_func('sstate_archive_package', d) | ||
| 872 | |||
| 873 | from oe.gpg_sign import get_signer | ||
| 874 | signer = get_signer(d, 'local') | ||
| 875 | signer.detach_sign(str(tmp_pkg), d.getVar('SSTATE_SIG_KEY'), None, | ||
| 876 | d.getVar('SSTATE_SIG_PASSPHRASE'), armor=False) | ||
| 877 | |||
| 878 | tmp_pkg_sig = Path(tmp_dir) / sstate_pkg_sig.name | ||
| 879 | if not update_file(tmp_pkg_sig, sstate_pkg_sig): | ||
| 880 | # If the created signature file could not be copied into place, | ||
| 881 | # then we should not use the sstate package either. | ||
| 882 | return | ||
| 883 | |||
| 884 | # If the .sig file was updated, then the sstate package must also | ||
| 885 | # be updated. | ||
| 886 | update_file(tmp_pkg, sstate_pkg, force=True) | ||
| 887 | else: | ||
| 888 | from tempfile import NamedTemporaryFile | ||
| 889 | with NamedTemporaryFile(prefix=sstate_pkg.name, dir=sstate_pkg.parent) as tmp_pkg_fd: | ||
| 890 | tmp_pkg = tmp_pkg_fd.name | ||
| 891 | d.setVar("TMP_SSTATE_PKG", str(tmp_pkg)) | ||
| 892 | bb.build.exec_func('sstate_archive_package',d) | ||
| 893 | update_file(tmp_pkg, sstate_pkg) | ||
| 894 | # update_file() may have renamed tmp_pkg, which must exist when the | ||
| 895 | # NamedTemporaryFile() context handler ends. | ||
| 896 | touch(Path(tmp_pkg)) | ||
| 897 | |||
| 818 | } | 898 | } |
| 819 | 899 | ||
| 820 | # | ||
| 821 | # Shell function to generate a sstate package from a directory | 900 | # Shell function to generate a sstate package from a directory |
| 822 | # set as SSTATE_BUILDDIR. Will be run from within SSTATE_BUILDDIR. | 901 | # set as SSTATE_BUILDDIR. Will be run from within SSTATE_BUILDDIR. |
| 823 | # | 902 | # The calling function handles moving the sstate package into the final |
| 824 | sstate_create_package () { | 903 | # destination. |
| 825 | # Exit early if it already exists | 904 | sstate_archive_package () { |
| 826 | if [ -e ${SSTATE_PKG} ]; then | ||
| 827 | touch ${SSTATE_PKG} 2>/dev/null || true | ||
| 828 | return | ||
| 829 | fi | ||
| 830 | |||
| 831 | TFILE=`mktemp ${SSTATE_PKG}.XXXXXXXX` | ||
| 832 | |||
| 833 | OPT="-cS" | 905 | OPT="-cS" |
| 834 | ZSTD="zstd -${SSTATE_ZSTD_CLEVEL} -T${ZSTD_THREADS}" | 906 | ZSTD="zstd -${SSTATE_ZSTD_CLEVEL} -T${ZSTD_THREADS}" |
| 835 | # Use pzstd if available | 907 | # Use pzstd if available |
| @@ -840,42 +912,18 @@ sstate_create_package () { | |||
| 840 | # Need to handle empty directories | 912 | # Need to handle empty directories |
| 841 | if [ "$(ls -A)" ]; then | 913 | if [ "$(ls -A)" ]; then |
| 842 | set +e | 914 | set +e |
| 843 | tar -I "$ZSTD" $OPT -f $TFILE * | 915 | tar -I "$ZSTD" $OPT -f ${TMP_SSTATE_PKG} * |
| 844 | ret=$? | 916 | ret=$? |
| 845 | if [ $ret -ne 0 ] && [ $ret -ne 1 ]; then | 917 | if [ $ret -ne 0 ] && [ $ret -ne 1 ]; then |
| 846 | exit 1 | 918 | exit 1 |
| 847 | fi | 919 | fi |
| 848 | set -e | 920 | set -e |
| 849 | else | 921 | else |
| 850 | tar -I "$ZSTD" $OPT --file=$TFILE --files-from=/dev/null | 922 | tar -I "$ZSTD" $OPT --file=${TMP_SSTATE_PKG} --files-from=/dev/null |
| 851 | fi | ||
| 852 | chmod 0664 $TFILE | ||
| 853 | # Skip if it was already created by some other process | ||
| 854 | if [ -h ${SSTATE_PKG} ] && [ ! -e ${SSTATE_PKG} ]; then | ||
| 855 | # There is a symbolic link, but it links to nothing. | ||
| 856 | # Forcefully replace it with the new file. | ||
| 857 | ln -f $TFILE ${SSTATE_PKG} || true | ||
| 858 | elif [ ! -e ${SSTATE_PKG} ]; then | ||
| 859 | # Move into place using ln to attempt an atomic op. | ||
| 860 | # Abort if it already exists | ||
| 861 | ln $TFILE ${SSTATE_PKG} || true | ||
| 862 | else | ||
| 863 | touch ${SSTATE_PKG} 2>/dev/null || true | ||
| 864 | fi | 923 | fi |
| 865 | rm $TFILE | 924 | chmod 0664 ${TMP_SSTATE_PKG} |
| 866 | } | 925 | } |
| 867 | 926 | ||
| 868 | python sstate_sign_package () { | ||
| 869 | from oe.gpg_sign import get_signer | ||
| 870 | |||
| 871 | |||
| 872 | signer = get_signer(d, 'local') | ||
| 873 | sstate_pkg = d.getVar('SSTATE_PKG') | ||
| 874 | if os.path.exists(sstate_pkg + '.sig'): | ||
| 875 | os.unlink(sstate_pkg + '.sig') | ||
| 876 | signer.detach_sign(sstate_pkg, d.getVar('SSTATE_SIG_KEY', False), None, | ||
| 877 | d.getVar('SSTATE_SIG_PASSPHRASE'), armor=False) | ||
| 878 | } | ||
| 879 | 927 | ||
| 880 | python sstate_report_unihash() { | 928 | python sstate_report_unihash() { |
| 881 | report_unihash = getattr(bb.parse.siggen, 'report_unihash', None) | 929 | report_unihash = getattr(bb.parse.siggen, 'report_unihash', None) |
