From patchwork Mon Jun 15 09:24:51 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Felix Moessbauer X-Patchwork-Id: 5158 Return-Path: Received: from shymkent.ilbers.de ([unix socket]) by shymkent (Cyrus 2.5.10-Debian-2.5.10-3+deb9u2) with LMTPA; Mon, 15 Jun 2026 11:25:42 +0200 X-Sieve: CMU Sieve 2.4 Received: from mail-dy1-f189.google.com (mail-dy1-f189.google.com [74.125.82.189]) by shymkent.ilbers.de (8.15.2/8.15.2/Debian-8+deb9u1) with ESMTPS id 65F9Pceb009664 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Mon, 15 Jun 2026 11:25:39 +0200 Received: by mail-dy1-f189.google.com with SMTP id 5a478bee46e88-304dd917645sf6686910eec.1 for ; Mon, 15 Jun 2026 02:25:39 -0700 (PDT) ARC-Seal: i=3; a=rsa-sha256; t=1781515533; cv=pass; d=google.com; s=arc-20240605; b=KFzP8QVc3fujYhiMta9ckMlaHBaESVUBVaR7lV6Ux/rDr1WKT3LXNx4hFwlIRy5XkP lGLZDw/MnHSBqV06iz+A+GrzSCvU9drTxilb2uDHiz2B+z85sdg7QtyBouwv2adoTh5t Xwj6Q4gus40aQ5BbQwetyLv0zRFK9b97eHjmWYi9n4SQMxdxVucVozuYHw1srGJWD3UN OFuyjF2vIJa8S+RyNgVYtKiUCuuU5DK1gwpQ4JFhSlZBOpNZmV9G/0Y4EGD0omXXU6Ck sJjEPNvvp+zm5tUhbzBNpSp3uUGsD7eGMOD3mn+xr4YThuEAn+aUvI8C6QhWGlc7Ymnm ed6g== ARC-Message-Signature: i=3; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:reply-to:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:dkim-signature; bh=lzLWqtiB96P4R2rn+ns4O+PcnXIk8aMG5zUFK+nW3Jg=; fh=Pwe73Ly/2jPAp3k/GSbHgCt9F4R/v+J+bn6KlclWTX8=; b=R1IQ8U5hHb07q6znFuA4RbxC5uHSrnDt3yqT8HS6Y8lo98mzwiF++7dgBDhRG3O2y2 +2sLuSiTCaEn67MCTo1ZfuZdYbGEDzcFchWaMsZXIalAUJLWZNGpwd5yze5ZAuV/P6dB 9IjKlcyF/qcaYpIXkMpBtRfNtFxZNkB/ybsZpPDnbP+aCiF0YuMVguWjXwBzTL9ig3fd dHNpVlEZG3yGtOo/ziBBkCnGA846pKxm/U9qmclkaaJGzhOix7ysWcSqVFKVURbtaTOj QpvzC/366Y9MQwO6cR14Wp0bpy/oU48MpMW6ZA8hZON9hVcGQJJqsFgamuaNlDPwhz5e 8ViQ==; darn=isar-build.org ARC-Authentication-Results: i=3; gmr-mx.google.com; dkim=pass header.i=@siemens.com header.s=selector2 header.b=SwOq7Cx9; arc=pass (i=1 spf=pass spfdomain=siemens.com dkim=pass dkdomain=siemens.com dmarc=pass fromdomain=siemens.com); spf=pass (google.com: domain of felix.moessbauer@siemens.com designates 2a01:111:f403:c202::7 as permitted sender) smtp.mailfrom=felix.moessbauer@siemens.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=siemens.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20251104; t=1781515533; x=1782120333; darn=isar-build.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:reply-to :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from:from:to :cc:subject:date:message-id:reply-to; bh=lzLWqtiB96P4R2rn+ns4O+PcnXIk8aMG5zUFK+nW3Jg=; b=M5sbV34iEpL1slFodQlw3TSNSUnqaxkFMrlhHQS3OMssn+N1keCDZMe8vrlFGJ7ofz gdYK0rc7d3TiZ67KynMkFQUr1sbr3IyI9sdXEAWZ4QP/AU1R8sEavNGA40oUj+wnRtEo +5wV9JyVCSA0dljN08Z+qvUiGCmV+TLh50mq9xsjOI/BQgjMU2Q3grH8QA5pHej0fKDb e/LfJOd0GgY+XtIurx2FNZ6scXjH0G6f4kbw0iii3Exgpypf9+46XWywFLsUMqqmlfN6 AjbQUgPnSpWshK8TTlCQqWWN+cDxwfZQKZ8jvhDBmHi8rn11wsCVzC9ceg43kV92tVHu aRnA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781515533; x=1782120333; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence:reply-to :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=lzLWqtiB96P4R2rn+ns4O+PcnXIk8aMG5zUFK+nW3Jg=; b=OAgVISPe8X9KEyYG8mK2vhx/qtSkyeVFCpK0KM9TjT+GSQs+UcKTzaoiJSeNK9gGT2 itCMW9vpz8u8dP+H0ttNsTU68+8CH56UAw2feJQrennngLFShjFAzCkO6YOzbH3MwfTs l0yHLIO39m+5yStPyrYo8tpe93o0IUB6hUBORtnAYdnR7F/TiCvs5IjQsE6+u7ingmOF G82eNy8IQ19jZyNFb2bvkpPcm12cWGpVjZ91V6i8mHK9h4Kk6kP6s2Hu8uaSVAL1vZIj alcaALcwb852nZ+tundYbQkzsHhlf4kG8hHUzMfrapIejewQBgPCpJqFIikqAFIzuuOf Yj2g== X-Forwarded-Encrypted: i=3; AFNElJ+zAwQS2UH7a8/fH+Q2tGgP+qYLI+epIphSXWB4Y+bY4WMVE0BEPzit3MP9mzwgGKzr5x1mb2Y=@isar-build.org X-Gm-Message-State: AOJu0YxJmil7msnB60rCDH5+gxen5n/4Zb0wlxpL/s/t14RkMrZpB/5N lMGf0rYWF8wrs+AXCS0XVh0NOl2fheivK3sXscvw0tp5zCDPVxsTqn3b X-Received: by 2002:a05:7022:49c:b0:127:3f2a:af21 with SMTP id a92af1059eb24-1384bafeddcmr5618892c88.15.1781515532661; Mon, 15 Jun 2026 02:25:32 -0700 (PDT) X-BeenThere: isar-users@googlegroups.com; h="AX0PUUcJHs8bQIPbcQx2ckZmcPKv03uiZdd9MHAlOqXQNwmKWg==" Received: by 2002:a05:701b:420c:20b0:136:49b7:f20b with SMTP id a92af1059eb24-1384a1eb74cls2083586c88.0.-pod-prod-03-us; Mon, 15 Jun 2026 02:25:31 -0700 (PDT) X-Received: by 2002:a05:7022:128c:b0:138:e4:c44d with SMTP id a92af1059eb24-1384bb7e8e3mr6128559c88.25.1781515530596; Mon, 15 Jun 2026 02:25:30 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1781515530; cv=pass; d=google.com; s=arc-20240605; b=UPUAfGzszFu/+CYiJXOTXvhWwc3ybJDMN9XGxhHzjO/hI7bMztbmJ4LD0o05oJxWh9 xsV9ImqgENxew1BTOkBykFvFp0pKeYOv9FL8ACQoK2/THM7xUsIB/OUBVs7SbSAmRG7h wYEtyu1dzSL/sZ97sz/4hPAPOazG1vIiZpe/t9En1eYoPvjPZTKbXjR8hyUfNsWh2ZBz yFAKcKvny4EFtGTux8ZbsBxGKo6eAugGwGD7CsLag8+Dn9POzUKoq2p+JpVhaZI4mBKS glljI28zAIgu7wfhp1MSzchxmQYJyb383959bbVribVzE31bHqgzY6kyb79nBqEyZ3xD xf+Q== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=mime-version:content-transfer-encoding:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=CAWrgaitu9xpKlZZP2y7qayS56wd3okaIy5mkLQPnFo=; fh=WkhL8kaJc+l2wQon1t06Ej3uvBGj9sVhNcE8PaS/XbI=; b=YRxCGHhvRGYYFsuX8BOlcTD0qBs9Vsm1RB3iuwRN9qS4xzyfZECUfVQJUpY9SB9/7d tKx4cP7kmT3nEpSRihw1/zEpIVMyzJIJ6NCfnFW79r3w+HlW077DFgZq9gen1yz0SAF6 G41pEed6E5w9ADV6CTzTn6cbT/ur+A2nwu1kn6Jg4u607DmVc5bRbpOF+s/KuO8cO+oV UetnRLPG4jSLqxCs1meBeYkTzOlenfyLElKzgdSoIkX1XOaam5OlJlOPycLtsEdlg5/K ij7Vc/6M4VNN6DR1Hgh3DqzeAlf7ZM9L3126lOXFfkMu3lDy+nf5QeOmAWK0uydrIRD3 iiZw==; dara=google.com ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@siemens.com header.s=selector2 header.b=SwOq7Cx9; arc=pass (i=1 spf=pass spfdomain=siemens.com dkim=pass dkdomain=siemens.com dmarc=pass fromdomain=siemens.com); spf=pass (google.com: domain of felix.moessbauer@siemens.com designates 2a01:111:f403:c202::7 as permitted sender) smtp.mailfrom=felix.moessbauer@siemens.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=siemens.com Received: from GVXPR05CU001.outbound.protection.outlook.com (mail-swedencentralazlp170130007.outbound.protection.outlook.com. [2a01:111:f403:c202::7]) by gmr-mx.google.com with ESMTPS id a92af1059eb24-1397261c28asi191681c88.4.2026.06.15.02.25.30 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Jun 2026 02:25:30 -0700 (PDT) Received-SPF: pass (google.com: domain of felix.moessbauer@siemens.com designates 2a01:111:f403:c202::7 as permitted sender) client-ip=2a01:111:f403:c202::7; ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=YVFA9Rhv4dkz8seYPC3ZHefZsIORDmIYu5V9ZCDKVCreUesSOuA6G7dlWx8dX9/mOMr4r1ISE3ldPg5403aeKQORwDH+eYYsmx725WzZCpjcnmqOwKqeD9ncQLRMTuAhTAuc98Jhm5YKLvSAdtwu70Vf3DjRUOWtEFkLKdNojE0xtoUuxK3RXXps81cd4t2Sni/5Ddq9M043sWZqh4SN0CC3DsAHznNUAbwObDY6VFQKN1UiiNyjrjHESlYo0oWmIbK7vJ1IymeS9FuCeMTG7KdMpFdMLe5z9XdUtEVO4/LbU2mJ//QASEm07h8weOlu7yrl6eIUeGYVgTvQ2S6ZaQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=CAWrgaitu9xpKlZZP2y7qayS56wd3okaIy5mkLQPnFo=; b=ZVu/eZ/jVDAy+vShyl3glAq4y9DVezebYODCibu8ckIBQVHkm7r7p1vMkVEIEgdADnMUmzEaO+qyB69ieaq4sUhLqr1cHVKQeQ0pzZaCRFvfOo0XmnMRlstMNUuTdb8gi3iYetEQcbP3pqdPXB2AzUaMYcusKNteh1OVfWvcX2Qyytcuh75IJGFQ1UTevJdPofzR86ZmjtTZK+9h4rgWb3+Zgby2UGPrS4Pyk7GwOJL2k1afmXB33TJC18ZGljWGWRgTdLhE7GbGHMCS3jkELko2/PIfp+HFXvaWxlYs8fdSSYk2fkbgnRm7pII4MKYZM9uumPNJfm/KqlQdnqEGsQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=siemens.com; dmarc=pass action=none header.from=siemens.com; dkim=pass header.d=siemens.com; arc=none Received: from AM7PR10MB3956.EURPRD10.PROD.OUTLOOK.COM (2603:10a6:20b:17e::10) by PAWPR10MB6830.EURPRD10.PROD.OUTLOOK.COM (2603:10a6:102:33a::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.113.18; Mon, 15 Jun 2026 09:25:23 +0000 Received: from AM7PR10MB3956.EURPRD10.PROD.OUTLOOK.COM ([fe80::c54c:ccd8:ebbf:477c]) by AM7PR10MB3956.EURPRD10.PROD.OUTLOOK.COM ([fe80::c54c:ccd8:ebbf:477c%5]) with mapi id 15.21.0113.015; Mon, 15 Jun 2026 09:25:23 +0000 X-Patchwork-Original-From: "'Felix Moessbauer' via isar-users" From: Felix Moessbauer To: isar-users@googlegroups.com Cc: jan.kiszka@siemens.com, quirin.gylstorff@siemens.com, Felix Moessbauer Subject: [PATCH v6 10/17] add support for fully rootless builds Date: Mon, 15 Jun 2026 11:24:51 +0200 Message-ID: <20260615092458.259691-11-felix.moessbauer@siemens.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260615092458.259691-1-felix.moessbauer@siemens.com> References: <20260615092458.259691-1-felix.moessbauer@siemens.com> X-ClientProxiedBy: FR4P281CA0109.DEUP281.PROD.OUTLOOK.COM (2603:10a6:d10:bb::13) To AM7PR10MB3956.EURPRD10.PROD.OUTLOOK.COM (2603:10a6:20b:17e::10) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: AM7PR10MB3956:EE_|PAWPR10MB6830:EE_ X-MS-Office365-Filtering-Correlation-Id: 968d380c-aafa-4567-4d36-08decac00617 X-MS-Exchange-AtpMessageProperties: SA X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|23010399003|376014|10070799003|366016|1800799024|3023799007|18002099003|22082099003|56012099006|11063799006|6133799003|5023799004|55112099003; X-Microsoft-Antispam-Message-Info: CgQ1tFxK5E2+Y0MXR3IF6RwKSJU3v2oU6XV0+TJBgYgDhoY4kU1K8L//b/VjH0nupN4sTFWaxv9J9TX+5LRaLBXxNdF4s9PqJIdEqDxAK7vMidfjTf/GgtPpznZDkKfig9+TO4UE55fAv2tnHuFSupOTbN2dnG4O/P1c+utn/+o1AJsNPki48/L8yLYeqiUkfhJNQiZGmOVsHl0/MqZm6UfJHTNpMN+MPhLETBvRDg1zYbOnVyop5ztnzmWkpe4daSnQWpdXQ4h9xUy3Hx+y7on+TgLhRdTpVXYvlnjPqop5Eu91an9BYbtPRS4Bnw7BdqBqnDwy1x8MkjDssf8cEnY4S/IOU6KY5NvolIEk6xH70kjx85/mn3lebHJzBDyB7mKz9hdhEHYRNxCa+q5o33xD+q0r17WaWseG/FW8+k+haHR90zn2kWrNHWB4sfGpxWUF1RCNlGbXZchu/acLNLGpcFo2m0gH+EPLXiGDpPZrD/m+KrPVMd955hIQY5ikPqgbpTozM6SBydyYdcTEZA6GsVkdzeBBO61e8Qlfafxr8NqkNxNEyv04DbaH7r3obY6P5f6WziAQ/yyqNKbDue7Rb2sO5hBgzhSmR2jUglpmfZ6SQCb4RCn9IlygueODaHAYpw3vy039Bkba4JEQ5GfGUQ0S6Uki5YQskg/jGColk89V1RMyazxljUNl4XLD X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:AM7PR10MB3956.EURPRD10.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(23010399003)(376014)(10070799003)(366016)(1800799024)(3023799007)(18002099003)(22082099003)(56012099006)(11063799006)(6133799003)(5023799004)(55112099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 2 X-MS-Exchange-AntiSpam-MessageData-0: BXpb82KP3u+A1GIM9SZn/Fe7voHQOGXmZVbdiKtgj9FffO9k1uV07PVjzMsdgV0AQqU+A9aKcX9/NyCJ5Uf+tonBaKwUrVMG+1wwRBcnnmnrxVKwZhw3ngxMSntprjnEDaRFOMSehS49NONdY2hyxJSjABmJBAVSze5a0cltEOzeQQjuZRTUtd1l0xGP+ZFsHITTK8sZUJ/XrFxNtG2pioduS4nK0q326+sZoGD84VxdzmUzh5HOWwvtHyznw6mVlOg888t71KunhPPux3CuQfDld0i7jdFX6giNnBLSlksKgcTaK1hXMWeSPPsyjIKI8lNNOuNzKb2gjr5FcR6019omWbEOyEghAb9SPaotTO0ppSQhfW6FmGvGY5wzye32YDd0CY6D9+opIkYwBupGbZ55C5tu/q9Ta3x3CTPIfkDd9JzQz7ZLxe8A311/PCnXrHPNKnqLb8d8zBfYTvngvzh+WrWTnbphMeTk3DJjH431soXvLEZVWjNWei2Yb5iebIcYxiNBLEAVp+Gn7oReAaLGTDlfIRvW6dYQv5oBltTPoFOiAwm0GBYrYwDTZ9DODyfKj9P5HlfW4grus6RdK9IsWlVn4FyPsp8nBLIEkLb7qugwN+XaKh2ekvt5o+ryKb8urExwPXRxyHlTXEAVO70zlfO6uUwoGdbbgm754olb85OeTggbYFeqBsb8IPWjjTtm9LyJbzvG2WP+1uhNlx+ky8Gftc2Vjw75yDEkwEDuret6qz1V1REmheOvYqxEjJ/r6h8Gw9QVvAU4efNgfqyBXqRRphiTeyaAdjV0kF3m6b9g2zcMKleJYBi3TCGzIDfljC4EePvVsHxkDv4k0py+JTdi6G7JfdIHHTDEO+z0W95hr/6KOw5RGQbVhrhxl/SJ/3o1CpQA6u2UabivWg0+GP811/Ew22Sn8FUaw74C58Cx8+L/4EfOd4wwULSBPPd5GIPdoOrknSK+lh/EdziUSShzFmebmFGeoPSXpnXjEAzdFuyCWiQRgTRh/Ycpv9o9psVarFRcsKDze+yFYsWu078qb150d0tawg1O1KoEPY0FS65nTvUTXDse9MkjG3pGus+ChTisbA2oesOCEI4mumVH5sO4FAC/0Kezd2v+rouN63NED/PjV/EEYSFu/q5zfEa6JmnHxwsNaqR2P6WztwKzEY4mdB2Bioja+7xz3sI6TUupDLiK02tPzTattpELR3D3gB1Lxdr5i3WxYf5sIfMYfyRXc/LWKa/0K3rqMlw9O4NQE4Nik3TGZPOFrx71QJopPOSWYL9Oi8jUD2t5/WW3HlV2bfVmA+yIC4eNaHog49KBoo7K8eqn0EwCaUg0kdS0onip781U/2/zyiHNFJb4Kj/PttFbiA2Gk6eyMDoAmvNTlrCBUfOaBp4qIWBFAatA116YGK7uc7AL3630I30faShe8C+jbpPWUZMjDyHG1uwmK3yVYknFT12paEqItBFjX+RBtNVPw3AOSRfm1M4R0qBLqkpNjyWgKnurPCY/+iZ/1ONTePt1S2u6BLONZ+xzrAHS/Ee3saI529k8SYxuo4L//V7nOuyYzdavFpn3PttjR0/oSRHGBQIzZm0R8N9mP4G1Z4W0Wab8b653uU35nknZfR5+XNN47lvW4x0It6G54j5kJfNuJVwfnL1MQDLeXYy9dUZusNqKlbB/Uo4O8D+NoGfLpvwRTyYsiUBBBZBPBlu6yZfpOXvLUQFBJbcQNPsqiy7B4IcdmcXSa/Yj9KxcE5VizphaJUFnzx5OcVRkpeoA4gj221sxJHA0JdME X-MS-Exchange-AntiSpam-MessageData-1: uFvOQbGuutPZopQEvZ+ueTXenurbVPIY9bU= X-OriginatorOrg: siemens.com X-MS-Exchange-CrossTenant-Network-Message-Id: 968d380c-aafa-4567-4d36-08decac00617 X-MS-Exchange-CrossTenant-AuthSource: AM7PR10MB3956.EURPRD10.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 15 Jun 2026 09:25:21.9858 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 38ae3bcd-9579-4fd4-adda-b42e1495d55a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 5cNg9dYWI3xQhCVVJtc9i7P+wxu7FbqFSGyPbMW0yz3dalS30/jwE0FeaWuFwvBJxVmVJq/Q++fZwrbHQTiHsN5IlIXwzT6I1oiqrL3XH78= X-MS-Exchange-Transport-CrossTenantHeadersStamped: PAWPR10MB6830 X-Original-Sender: felix.moessbauer@siemens.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@siemens.com header.s=selector2 header.b=SwOq7Cx9; arc=pass (i=1 spf=pass spfdomain=siemens.com dkim=pass dkdomain=siemens.com dmarc=pass fromdomain=siemens.com); spf=pass (google.com: domain of felix.moessbauer@siemens.com designates 2a01:111:f403:c202::7 as permitted sender) smtp.mailfrom=felix.moessbauer@siemens.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=siemens.com X-Original-From: Felix Moessbauer Reply-To: Felix Moessbauer Precedence: list Mailing-list: list isar-users@googlegroups.com; contact isar-users+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: isar-users@googlegroups.com X-Google-Group-Id: 914930254986 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , X-Spam-Status: No, score=-4.9 required=5.0 tests=DKIMWL_WL_MED,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,MAILING_LIST_MULTI, RCVD_IN_DNSWL_BLOCKED,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, RCVD_IN_RP_CERTIFIED,RCVD_IN_RP_RNBL,RCVD_IN_RP_SAFE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on shymkent.ilbers.de X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= Currently isar requires passwordless sudo and an environment where mounting file systems is possible. This has proven problematic for security reasons, both when running in a privileged container or locally. To solve this, we implement fully rootless builds that rely on the unshare syscall which allows us to avoid sudo and instead operate in temporary kernel namespaces as a user that is just privileged within that namespace. This comes with some challenges regarding the handling of mounts (they are cleared when leaving the namespace), as well as cross namespace deployments (the outer user might not be able to access the inner data). For that, we rework the handling of mounts and artifact passing to make it compatible with both chroot modes (schroot and unshare). We intentionally do not switch the build_system in isar.yaml resp. the KAS_BUILD_SYSTEM in the menu KConfig, as there is no kas release with support for the new modes as of today. We further don't want to break backward compatibility with older kas versions of the isar examples. Signed-off-by: Felix Moessbauer --- RECIPE-API-CHANGELOG.md | 20 +++++ doc/user_manual.md | 2 + meta/classes-global/base.bbclass | 86 ++++++++++++++++++- meta/classes-recipe/deb-dl-dir.bbclass | 9 +- meta/classes-recipe/dpkg-base.bbclass | 22 ++++- meta/classes-recipe/dpkg.bbclass | 17 ++-- .../image-locales-extension.bbclass | 9 +- .../image-tools-extension.bbclass | 84 ++++++++++++++++++ meta/classes-recipe/image.bbclass | 7 +- .../imagetypes_container.bbclass | 4 +- meta/classes-recipe/imagetypes_wic.bbclass | 6 +- meta/classes-recipe/rootfs.bbclass | 54 +++++++++--- meta/classes-recipe/sbuild.bbclass | 24 +++++- meta/classes-recipe/sdk.bbclass | 10 ++- meta/conf/bitbake.conf | 7 +- .../isar-mmdebstrap/isar-mmdebstrap.inc | 18 ++-- .../sbuild-chroot/sbuild-chroot.inc | 24 +++++- 17 files changed, 361 insertions(+), 42 deletions(-) diff --git a/RECIPE-API-CHANGELOG.md b/RECIPE-API-CHANGELOG.md index 552051ad..6d5b6ba3 100644 --- a/RECIPE-API-CHANGELOG.md +++ b/RECIPE-API-CHANGELOG.md @@ -1103,3 +1103,23 @@ specifies the rootfs path. Using these helpers instead of direct `sudo` invocations centralizes platform-specific privileged execution logic in `base.bbclass`. Direct use of `sudo` is discouraged in downstream layers. + +### Rootless isar execution + +Isar is able to run without the need for `sudo` in an environment that +allows unprivileged users to unshare the kernels `user namespace`. Further, +a sufficiently large set of sub ids needs to be configured in `/etc/subuid` / `etc/subgid`. +This range should be `> 65536`, but smaller ranges might work as well, depending on the +ids used in the rootfs. + +A simple check if rootless is supported can be done by running: + +```bash +mmdebstrap --unshare-helper /bin/echo "rootless supported" || echo "rootless not supported" +``` + +To enable rootless builds, set the bitbake variable `ISAR_ROOTLESS = "1"`. +This internally switches the chroot mode from `schroot` to `unshare`. + +When using kas, the `build_system` needs to be set to `isar-rootless`, which currently +requires a development version of kas (for details, check the kas mailing list). diff --git a/doc/user_manual.md b/doc/user_manual.md index 396e1b90..dcc3f560 100644 --- a/doc/user_manual.md +++ b/doc/user_manual.md @@ -75,6 +75,7 @@ Building `debian-trixie` requires host system >= bookworm. Install the following packages: ``` apt install \ + acl \ binfmt-support \ bubblewrap \ bzip2 \ @@ -89,6 +90,7 @@ apt install \ qemu-user-static \ reprepro \ sudo \ + uidmap \ unzip \ xz-utils \ git-buildpackage \ diff --git a/meta/classes-global/base.bbclass b/meta/classes-global/base.bbclass index 90e4525e..7167cbb1 100644 --- a/meta/classes-global/base.bbclass +++ b/meta/classes-global/base.bbclass @@ -141,7 +141,9 @@ root_cleandirs() { die "Could not remove $i, because subdir is mounted" done for i in $ROOT_CLEANDIRS_DIRS; do - run_privileged rm -rf --one-file-system "$TMPDIR$i" + [ -d "$TMPDIR$i" ] || continue + find "$TMPDIR$i" \( ! -user "$(whoami)" -type d -prune \) -exec ${RUN_PRIVILEGED_CMD} rm -rf --one-file-system {} \; + rm -rf --one-file-system "$TMPDIR$i" mkdir -p "$TMPDIR$i" done } @@ -380,7 +382,28 @@ def deb_list_beautify(d, varname): # shall be used outside of this class. def insert_isar_mounts(d, rootfs, mounts): + """ + In unshare mode, all mounts must be created after unsharing the + mount namespace. As needs to happen within the unshared session, + we implement it as a code generator. Note, that the random and urandom + mounts are needed for DDI images. + """ lines = [] + to_touch = ['/dev/null', '/dev/random', '/dev/urandom'] + to_mkdir = ['/dev/pts', '/dev/shm'] + if d.getVar('ISAR_CHROOT_MODE') == 'unshare': + lines.append('touch ' + ' '.join(['{}/{}'.format(rootfs, f) for f in to_touch])) + lines.append('mkdir -p ' + ' '.join(['{}/{}'.format(rootfs, f) for f in to_mkdir])) + lines.append('mount -o bind,private,mode=666 /dev/null {}/dev/null'.format(rootfs)) + lines.append('mount -t devpts -o noexec,nosuid,uid=5,mode=620,ptmxmode=666 none {}/dev/pts'.format(rootfs)) + lines.append('( cd {}/dev; ln -sf pts/ptmx . )'.format(rootfs)) + lines.append('mount -t tmpfs none {}/dev/shm'.format(rootfs)) + lines.append('mount -o bind /dev/random {}/dev/random'.format(rootfs)) + lines.append('mount -o bind /dev/urandom {}/dev/urandom'.format(rootfs)) + lines.append('mount -t proc none {}/proc'.format(rootfs)) + # we do not unshare the network namespace, so we cannot create a sysfs, hence bind-mount + lines.append('mount -o rbind /sys {}/sys'.format(rootfs)) + for m in mounts.split(): host, inner = m.split(':') if ':' in m else (m, m) inner_full = os.path.join(rootfs, inner[1:]) @@ -389,7 +412,18 @@ def insert_isar_mounts(d, rootfs, mounts): return '\n'.join(lines) def insert_isar_umounts(d, rootfs, mounts): + """ + In unshare mount we don't unmount the system mounts but just + remove the mountpoints. + """ lines = [] + to_unlink = ['/dev/null', '/dev/random', '/dev/urandom', '/dev/ptmx'] + to_rmdir = ['/dev/pts', '/dev/shm'] + if d.getVar('ISAR_CHROOT_MODE') == 'unshare': + lines.append('rm -f ' + ' '.join(['{}/{}'.format(rootfs, f) for f in to_unlink])) + for d in ['{}/{}'.format(rootfs, _d) for _d in to_rmdir]: + lines.append('[ -d {} ] && rmdir {}'.format(d, d)) + for m in mounts.split(): host, inner = m.split(':') if ':' in m else (m, m) mp = '{}/{}'.format(rootfs, inner) @@ -397,11 +431,52 @@ def insert_isar_umounts(d, rootfs, mounts): lines.append('[ -d {} ] && rmdir --ignore-fail-on-non-empty {}'.format(mp, mp)) return '\n'.join(lines) +def get_subid_range(idmap, d): + import getpass + with open(idmap, 'r') as f: + entries = f.readlines() + for e in entries: + user, base, cnt = e.split(':') + if user == os.getuid() or user == getpass.getuser(): + return int(base), int(cnt) + bb.error("No sub-id range specified in %s" % idmap) + def run_privileged_cmd(d): - cmd = 'sudo -E' + """ + In unshare mode we need to map the rootfs uid/gid range into the + subuid/subgid range of the parent namespace. As we usually only + get 65534 ids, we cannot map the whole range, as two ids are already + used by the calling environment (root and builder user). Hence, map + as much as we can but also map the highest id (nobody / nogroup) as + these are used within the rootfs. It would be easier to use + mmdebstrap --unshare-helper as command (which is also internally used + by sbuild), but this only maps linear ranges, hence it cannot map the + nobody / nogroup on the default subid range. By that, we have to avoid + the nobody / nogroup when building packages in this case. + """ + if d.getVar('ISAR_CHROOT_MODE') == 'unshare': + nobody_id = 65534 + uid_base, uid_cnt = get_subid_range('/etc/subuid', d) + nobody_subid = uid_base + uid_cnt - 1 + gid_base, gid_cnt = get_subid_range('/etc/subgid', d) + nogroup_subid = gid_base + gid_cnt - 1 + cmd = 'unshare --mount --pid --uts --ipc --user' \ + ' --kill-child' \ + ' --setuid 0 --setgid 0 --fork' \ + f' --map-users 1:{uid_base+1}:{uid_cnt-2}' \ + f' --map-groups 1:{gid_base+1}:{gid_cnt-2}' + if uid_cnt < nobody_id: + cmd += f' --map-users {nobody_id}:{nobody_subid}:1' + if gid_cnt < nobody_id: + cmd += f' --map-groups {nobody_id}:{nogroup_subid}:1' + cmd += " --map-root-user" + else: + cmd = 'sudo -E' bb.debug(1, "privileged cmd: %s" % cmd) return cmd +UNSHARE_SUBUID_BASE := "${@get_subid_range('/etc/subuid', d)[0] if d.getVar('ISAR_CHROOT_MODE') == 'unshare' else '0'}" +# store in variable to only compute once and make available to fetcher RUN_PRIVILEGED_CMD := "${@run_privileged_cmd(d)}" run_privileged() { @@ -415,5 +490,10 @@ run_privileged_heredoc() { run_in_chroot() { rootfs="$1" shift - ${RUN_PRIVILEGED_CMD} chroot "$rootfs" "$@" + + rootfs=$rootfs run_privileged_heredoc <<'EORIC' "$@" + set -e + ${@insert_isar_mounts(d, '$rootfs', '')} + chroot "$rootfs" "$@" +EORIC } diff --git a/meta/classes-recipe/deb-dl-dir.bbclass b/meta/classes-recipe/deb-dl-dir.bbclass index 33630f1e..c69b7df2 100644 --- a/meta/classes-recipe/deb-dl-dir.bbclass +++ b/meta/classes-recipe/deb-dl-dir.bbclass @@ -122,8 +122,13 @@ deb_dl_dir_import() { # let our unprivileged user place downloaded packages in /var/cache/apt/archives/ run_privileged_heredoc << ' EOSUDO' - mkdir -p "${rootfs}"/var/cache/apt/archives/partial/ - chown -R ${uid}:${gid} "${rootfs}"/var/cache/apt/archives/ + if [ "${ISAR_CHROOT_MODE}" = "unshare" ]; then + mkdir -p "${rootfs}"/var/cache/apt/archives + chmod 777 "${rootfs}"/var/cache/apt/archives + else + mkdir -p "${rootfs}"/var/cache/apt/archives/partial/ + chown -R ${uid}:${gid} "${rootfs}"/var/cache/apt/archives/ + fi EOSUDO # nothing to copy if download directory does not exist just yet diff --git a/meta/classes-recipe/dpkg-base.bbclass b/meta/classes-recipe/dpkg-base.bbclass index e8721c79..a0d4fd05 100644 --- a/meta/classes-recipe/dpkg-base.bbclass +++ b/meta/classes-recipe/dpkg-base.bbclass @@ -168,12 +168,30 @@ dpkg_schroot_create_configs() { EOSUDO } +dpkg_chroot_prepare() { + if [ "${ISAR_CHROOT_MODE}" = "schroot" ]; then + dpkg_schroot_create_configs + fi +} + +dpkg_chroot_finalize() { + if [ "${ISAR_CHROOT_MODE}" = "schroot" ]; then + schroot_delete_configs + fi +} + +dpkg_prepare_unshare_ccache() { + mkdir -p "${CCACHE_DIR}" + # sbuild id from https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1110942 + setfacl -m u:${UNSHARE_SUBUID_BASE}:rwX -m u:${@int(d.getVar('UNSHARE_SUBUID_BASE')) + 999}:rwx "${CCACHE_DIR}" +} + python do_dpkg_build() { - bb.build.exec_func('dpkg_schroot_create_configs', d) + bb.build.exec_func('dpkg_chroot_prepare', d) try: bb.build.exec_func("dpkg_runbuild", d) finally: - bb.build.exec_func('schroot_delete_configs', d) + bb.build.exec_func('dpkg_chroot_finalize', d) } do_dpkg_build[network] = "${TASK_USE_NETWORK_AND_SUDO}" diff --git a/meta/classes-recipe/dpkg.bbclass b/meta/classes-recipe/dpkg.bbclass index e693800c..1b2616db 100644 --- a/meta/classes-recipe/dpkg.bbclass +++ b/meta/classes-recipe/dpkg.bbclass @@ -85,7 +85,10 @@ dpkg_runbuild() { ext_deb_dir="${ext_root}${deb_dir}" if [ ${USE_CCACHE} -eq 1 ]; then - schroot_configure_ccache + ${ISAR_CHROOT_MODE}_configure_ccache + fi + if [ "${ISAR_CHROOT_MODE}" = "unshare" ]; then + sbuild_add_unshare_mounts fi profiles="${@ isar_deb_build_profiles(d)}" @@ -109,24 +112,28 @@ dpkg_runbuild() { DSC_FILE=$(find ${WORKDIR} -maxdepth 1 -name "${DEBIAN_SOURCE}_*.dsc" -print) - sbuild -n -c ${SBUILD_CHROOT} --chroot-mode=schroot \ + sbuild -n -c ${SBUILD_CHROOT} \ + --chroot-mode=${ISAR_CHROOT_MODE} \ --host=${PACKAGE_ARCH} --build=${BUILD_ARCH} ${profiles} \ ${@'--no-arch-all' if 'cross' in isar_deb_build_profiles(d).split() else '--arch-all'} \ --no-run-lintian --no-run-piuparts --no-run-autopkgtest --resolve-alternatives \ --bd-uninstallable-explainer=apt \ --no-apt-update --apt-distupgrade \ --chroot-setup-commands="echo \"Package: *\nPin: release n=${DEBDISTRONAME}\nPin-Priority: 1000\" > /etc/apt/preferences.d/isar-apt" \ - --chroot-setup-commands="echo \"APT::Get::allow-downgrades 1;\" > /etc/apt/apt.conf.d/50isar-apt" \ + --chroot-setup-commands="echo \"APT::Get::allow-downgrades 1;${@'\nAPT::Sandbox::User root;' if d.getVar('ISAR_CHROOT_MODE') == 'unshare' else ''}\" > /etc/apt/apt.conf.d/50isar-apt" \ --chroot-setup-commands="rm -f /var/log/dpkg.log" \ --chroot-setup-commands="mkdir -p ${deb_dir}" \ --chroot-setup-commands="find ${ext_deb_dir} -maxdepth 1 -name '*.deb' -exec ln -t ${deb_dir}/ -sf {} +" \ --chroot-setup-commands="apt-get update -o Dir::Etc::SourceList=\"sources.list.d/isar-apt.list\" -o Dir::Etc::SourceParts=\"-\" -o APT::Get::List-Cleanup=\"0\"" \ --finished-build-commands="rm -f ${deb_dir}/sbuild-build-depends-*-dummy_*.deb" \ --finished-build-commands="find ${deb_dir} -maxdepth 1 -type f -name '*.deb' -print -exec cp ${CP_FLAGS} -t ${ext_deb_dir}/ {} +" \ - --finished-build-commands="cp /var/log/dpkg.log ${ext_root}/dpkg_partial.log" \ + ${@ '--finished-build-commands="cp /var/log/dpkg.log $ext_root/dpkg_partial.log"' if d.getVar('ISAR_CHROOT_MODE') == 'schroot' else '' } \ --build-path="" --build-dir=${WORKDIR} --dist="${DEBDISTRONAME}" ${DSC_FILE} - sbuild_dpkg_log_export "${WORKDIR}/rootfs/dpkg_partial.log" + # TODO: port to unshare backend + if [ "${ISAR_CHROOT_MODE}" = "schroot" ]; then + sbuild_dpkg_log_export "${WORKDIR}/rootfs/dpkg_partial.log" + fi deb_dl_dir_export "${WORKDIR}/rootfs" "${distro}" # Cleanup apt artifacts diff --git a/meta/classes-recipe/image-locales-extension.bbclass b/meta/classes-recipe/image-locales-extension.bbclass index 029caec7..9bb43a8d 100644 --- a/meta/classes-recipe/image-locales-extension.bbclass +++ b/meta/classes-recipe/image-locales-extension.bbclass @@ -29,8 +29,12 @@ ROOTFS_INSTALL_COMMAND_BEFORE_EXPORT += "image_install_localepurge_download" image_install_localepurge_download[weight] = "40" image_install_localepurge_download[network] = "${TASK_USE_NETWORK_AND_SUDO}" image_install_localepurge_download() { - run_in_chroot '${ROOTFSDIR}' \ + run_privileged_heredoc <<'EOF' + set -e + ${@insert_isar_mounts(d, d.getVar('ROOTFSDIR'), d.getVar('ROOTFS_MOUNTS') if d.getVar('ISAR_CHROOT_MODE') == 'unshare' else '')} + chroot ${ROOTFSDIR} \ /usr/bin/apt-get ${ROOTFS_APT_ARGS} -oDebug::NoLocking=1 --download-only localepurge +EOF } ROOTFS_INSTALL_COMMAND += "image_install_localepurge_install" @@ -62,6 +66,9 @@ __EOF__ # Install configuration into image: run_privileged_heredoc <<'EOSUDO' set -e + + ${@insert_isar_mounts(d, d.getVar('ROOTFSDIR'), '')} + localepurge_state='i' if chroot '${ROOTFSDIR}' dpkg -s localepurge 2>/dev/null >&2 then diff --git a/meta/classes-recipe/image-tools-extension.bbclass b/meta/classes-recipe/image-tools-extension.bbclass index 766f386d..cc046fdb 100644 --- a/meta/classes-recipe/image-tools-extension.bbclass +++ b/meta/classes-recipe/image-tools-extension.bbclass @@ -16,7 +16,14 @@ do_image_tools[depends] += " \ SCHROOT_MOUNTS = "${WORKDIR}:${PP_WORK} ${IMAGE_ROOTFS}:${PP_ROOTFS} ${DEPLOY_DIR_IMAGE}:${PP_DEPLOY}" SCHROOT_MOUNTS += "${REPO_ISAR_DIR}/${DISTRO}:/isar-apt" +# only used on unshare +ROOTFS_IMAGETOOLS ?= "${WORKDIR}/rootfs-imgtools-${BB_CURRENTTASK}" + imager_run() { + imager_run_${ISAR_CHROOT_MODE} "$@" +} + +imager_run_schroot() { local_install="${@(d.getVar("INSTALL_%s" % d.getVar("BB_CURRENTTASK")) or '').strip()}" local_bom="${@(d.getVar("BOM_%s" % d.getVar("BB_CURRENTTASK")) or '').strip()}" @@ -103,3 +110,80 @@ generate_imager_sbom() { --timestamp $TIMESTAMP ${SBOM_DEBSBOM_EXTRA_ARGS} \ < ${WORKDIR}/imager.manifest } + +imager_run_unshare() { + exec 3<&0 + + # ignore everything before '--'. If the remaining list is empty, + # assume a here document is passed via stdin + while [ "$#" -gt 0 ]; do + case "$1" in + --) shift 1; break ;; + *) shift 1 ;; + esac + done + + if [ "$#" -eq 0 ]; then + set -- "$@" '/bin/bash' '-s' + fi + + local_install="${@(d.getVar("INSTALL_%s" % d.getVar("BB_CURRENTTASK")) or '').strip()}" + + run_privileged_heredoc <<'EOF' + set -e + mkdir -p ${ROOTFS_IMAGETOOLS} + tar -xf "${SBUILD_CHROOT}" -C "${ROOTFS_IMAGETOOLS}" + mkdir -p ${ROOTFS_IMAGETOOLS}/isar-apt + cp -rL /etc/resolv.conf "${ROOTFS_IMAGETOOLS}/etc" +EOF + + # setting up error handler + imager_cleanup() { + run_privileged rm -rf ${ROOTFS_IMAGETOOLS} + } + trap 'exit 1' INT HUP QUIT TERM ALRM USR1 + trap 'imager_cleanup' EXIT + + if [ -n "${local_install}" ]; then + echo "Installing imager deps: ${local_install}" + + distro="${BASE_DISTRO}-${BASE_DISTRO_CODENAME}" + if [ ${ISAR_CROSS_COMPILE} -eq 1 ]; then + distro="${HOST_BASE_DISTRO}-${BASE_DISTRO_CODENAME}" + fi + + E="${@ isar_export_proxies(d)}" + deb_dl_dir_import ${ROOTFS_IMAGETOOLS} ${distro} + ${SCRIPTSDIR}/lockrun.py -r -f "${REPO_ISAR_DIR}/isar.lock" -s <<'EOAPT' + local_install=$local_install ${@run_privileged_cmd(d)} /bin/bash -s <<'EOF' + set -e + ${@insert_isar_mounts(d, d.getVar('ROOTFS_IMAGETOOLS'), d.getVar('SCHROOT_MOUNTS'))} + chroot ${ROOTFS_IMAGETOOLS} apt-get update \ + -o Dir::Etc::SourceList='sources.list.d/isar-apt.list' \ + -o Dir::Etc::SourceParts='-' \ + -o APT::Get::List-Cleanup='0' + chroot ${ROOTFS_IMAGETOOLS} apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends -y \ + --allow-unauthenticated --allow-downgrades --download-only install \ + $local_install +EOF +EOAPT + + deb_dl_dir_export ${ROOTFS_IMAGETOOLS} ${distro} + local_install=$local_install run_privileged_heredoc <<'EOF' + set -e + ${@insert_isar_mounts(d, d.getVar('ROOTFS_IMAGETOOLS'), d.getVar('SCHROOT_MOUNTS'))} + chroot ${ROOTFS_IMAGETOOLS} apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends -y \ + --allow-unauthenticated --allow-downgrades install \ + $local_install +EOF + fi + + run_privileged_heredoc <<'EOF' "$@" + set -e + mkdir -p ${ROOTFS_IMAGETOOLS}/${SCRIPTSDIR} + ${@insert_isar_mounts(d, d.getVar('ROOTFS_IMAGETOOLS'), d.getVar('SCHROOT_MOUNTS'))} + chroot ${ROOTFS_IMAGETOOLS} "$@" <&3 +EOF + + run_privileged rm -rf ${ROOTFS_IMAGETOOLS} +} diff --git a/meta/classes-recipe/image.bbclass b/meta/classes-recipe/image.bbclass index bc3f2181..1590f58a 100644 --- a/meta/classes-recipe/image.bbclass +++ b/meta/classes-recipe/image.bbclass @@ -188,6 +188,7 @@ SUDO_CHROOT = "imager_run -d ${PP_ROOTFS} -u root --" python() { image_types = (d.getVar('IMAGE_FSTYPES') or '').split() conversions = set(d.getVar('IMAGE_CONVERSIONS').split()) + chroot_mode = d.getVar('ISAR_CHROOT_MODE') basetypes = {} typedeps = {} @@ -263,7 +264,8 @@ python() { if image_cmd: localdata.setVar('type', bt) cmds.append(localdata.expand(image_cmd)) - cmds.append(localdata.expand('\tsudo chown $(id -u):$(id -g) ${IMAGE_FILE_HOST}')) + if chroot_mode == 'schroot': + cmds.append(localdata.expand('\tsudo chown $(id -u):$(id -g) ${IMAGE_FILE_HOST}')) else: bb.fatal("No IMAGE_CMD for %s" % bt) vardeps.add('IMAGE_CMD:' + bt_clean) @@ -293,7 +295,8 @@ python() { cmd = '\t' + localdata.getVar('CONVERSION_CMD:' + c) if cmd not in cmds: cmds.append(cmd) - cmds.append(localdata.expand('\tsudo chown $(id -u):$(id -g) ${IMAGE_FILE_HOST}.%s' % c)) + if chroot_mode == 'schroot': + cmds.append(localdata.expand('\tsudo chown $(id -u):$(id -g) ${IMAGE_FILE_HOST}.%s' % c)) vardeps.add('CONVERSION_CMD:' + c) for dep in (localdata.getVar('CONVERSION_DEPS:' + c) or '').split(): conversion_install.add(dep) diff --git a/meta/classes-recipe/imagetypes_container.bbclass b/meta/classes-recipe/imagetypes_container.bbclass index 8d4f8050..84ea63e7 100644 --- a/meta/classes-recipe/imagetypes_container.bbclass +++ b/meta/classes-recipe/imagetypes_container.bbclass @@ -68,7 +68,9 @@ do_containerize() { run_privileged rm -rf "${oci_img_dir}_unpacked" # no root needed anymore - run_privileged chown --recursive $(id -u):$(id -g) "${oci_img_dir}" + if [ "${ISAR_CHROOT_MODE}" = "schroot" ]; then + run_privileged chown --recursive $(id -u):$(id -g) "${oci_img_dir}" + fi } convert_container() { diff --git a/meta/classes-recipe/imagetypes_wic.bbclass b/meta/classes-recipe/imagetypes_wic.bbclass index 8b048dc7..3e261622 100644 --- a/meta/classes-recipe/imagetypes_wic.bbclass +++ b/meta/classes-recipe/imagetypes_wic.bbclass @@ -193,8 +193,10 @@ generate_wic_image() { fi EOIMAGER - run_privileged chown -R $(stat -c "%U" ${LAYERDIR_core}) ${LAYERDIR_core} ${LAYERDIR_isar} ${SCRIPTSDIR} || true - run_privileged chown -R $(id -u):$(id -g) "${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.wic"* + if [ "${ISAR_CHROOT_MODE}" = "schroot" ]; then + run_privileged chown -R $(stat -c "%U" ${LAYERDIR_core}) ${LAYERDIR_core} ${LAYERDIR_isar} ${SCRIPTSDIR} || true + run_privileged chown -R $(id -u):$(id -g) "${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.wic"* + fi rm -rf ${IMAGE_ROOTFS}/../pseudo cat ${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.manifest \ diff --git a/meta/classes-recipe/rootfs.bbclass b/meta/classes-recipe/rootfs.bbclass index 411df93f..e85c4fe4 100644 --- a/meta/classes-recipe/rootfs.bbclass +++ b/meta/classes-recipe/rootfs.bbclass @@ -145,7 +145,12 @@ rootfs_cmd() { } rootfs_do_mounts[weight] = "3" -rootfs_do_mounts() { +python rootfs_do_mounts() { + if d.getVar('ISAR_CHROOT_MODE') == 'schroot': + bb.build.exec_func('rootfs_do_mounts_priv', d) +} + +rootfs_do_mounts_priv() { run_privileged_heredoc <<'EOSUDO' set -e mountpoint -q '${ROOTFSDIR}/dev' || \ @@ -168,7 +173,13 @@ rootfs_do_mounts() { EOSUDO } -rootfs_do_umounts() { +python rootfs_do_umounts() { + # unconditionally run the unmount code as this ignores missing + # mountpoints but also does the cleanup of the directories + bb.build.exec_func('rootfs_do_umounts_priv', d) +} + +rootfs_do_umounts_priv() { run_privileged_heredoc <<'EOSUDO' set -e @@ -215,7 +226,11 @@ ROOTFS_EXTRA_IMPORTED := "${@rootfs_extra_import(d)}" rootfs_prepare[weight] = "25" rootfs_prepare(){ - run_privileged tar -xf "${BOOTSTRAP_SRC}" -C "${ROOTFSDIR}" --exclude="./dev/console" + rm -rf ${ROOTFSDIR} + run_privileged_heredoc << 'EOF' + mkdir -p ${ROOTFSDIR} + tar -xf "${BOOTSTRAP_SRC}" -C "${ROOTFSDIR}" --exclude="./dev/console" +EOF # setup chroot run_privileged "${ROOTFSDIR}/chroot-setup.sh" "setup" "${ROOTFSDIR}" @@ -285,10 +300,14 @@ rootfs_install_pkgs_update[weight] = "5" rootfs_install_pkgs_update[isar-apt-lock] = "acquire-before" rootfs_install_pkgs_update[network] = "${TASK_USE_NETWORK_AND_SUDO}" rootfs_install_pkgs_update() { - run_in_chroot '${ROOTFSDIR}' /usr/bin/apt-get update \ - -o Dir::Etc::SourceList="sources.list.d/isar-apt.list" \ - -o Dir::Etc::SourceParts="-" \ - -o APT::Get::List-Cleanup="0" + run_privileged_heredoc <<'EOF' + set -e + ${@insert_isar_mounts(d, d.getVar('ROOTFSDIR'), d.getVar('ROOTFS_MOUNTS')) if d.getVar('ISAR_CHROOT_MODE') == 'unshare' else ''} + chroot '${ROOTFSDIR}' /usr/bin/apt-get update \ + -o Dir::Etc::SourceList="sources.list.d/isar-apt.list" \ + -o Dir::Etc::SourceParts="-" \ + -o APT::Get::List-Cleanup="0" +EOF } ROOTFS_INSTALL_COMMAND += "rootfs_install_resolvconf" @@ -316,9 +335,12 @@ rootfs_install_pkgs_download[isar-apt-lock] = "release-after" rootfs_install_pkgs_download[network] = "${TASK_USE_NETWORK}" rootfs_install_pkgs_download() { # download packages using apt in a non-privileged namespace - rootfs_cmd --bind "${ROOTFSDIR}/var/cache/apt/archives" /var/cache/apt/archives \ - ${ROOTFSDIR} \ - -- /usr/bin/apt-get ${ROOTFS_APT_ARGS} -oDebug::NoLocking=1 --download-only ${ROOTFS_PACKAGES} + run_privileged_heredoc <<'EOF' + set -e + ${@insert_isar_mounts(d, d.getVar('ROOTFSDIR'), d.getVar('ROOTFS_MOUNTS')) if d.getVar('ISAR_CHROOT_MODE') == 'unshare' else ''} + chroot ${ROOTFSDIR} \ + /usr/bin/apt-get ${ROOTFS_APT_ARGS} -oDebug::NoLocking=1 --download-only ${ROOTFS_PACKAGES} +EOF } ROOTFS_INSTALL_COMMAND_BEFORE_EXPORT ??= "" @@ -346,6 +368,7 @@ rootfs_install_pkgs_isar_download() { rootfs_cmd --bind "${ROOTFSDIR}/var/cache/apt/archives" /var/cache/apt/archives \ --bind "${WORKDIR}/dpkg/lock" /var/lib/dpkg/lock \ --bind "${WORKDIR}/dpkg/lock-frontend" /var/lib/dpkg/lock-frontend \ + ${@'--bind "${REPO_ISAR_DIR}/${DISTRO}" /isar-apt' if d.getVar('ISAR_CHROOT_MODE') == 'unshare' else ''} \ --chdir "/var/cache/apt/archives" \ ${ROOTFSDIR} \ -- /usr/bin/sh -c "apt-get ${ROOTFS_APT_ARGS} --print-uris ${ROOTFS_PACKAGES} | \ @@ -368,8 +391,13 @@ rootfs_install_pkgs_install[weight] = "8000" rootfs_install_pkgs_install[progress] = "custom:rootfs_progress.PkgsInstallProgressHandler" rootfs_install_pkgs_install[network] = "${TASK_USE_SUDO}" rootfs_install_pkgs_install() { - run_in_chroot "${ROOTFSDIR}" \ + run_privileged_heredoc <<'EOF' + set -e + ${@insert_isar_mounts(d, d.getVar('ROOTFSDIR'), d.getVar('ROOTFS_MOUNTS')) if d.getVar('ISAR_CHROOT_MODE') == 'unshare' else ''} + find ${ROOTFSDIR}/isar-apt + chroot "${ROOTFSDIR}" \ /usr/bin/apt-get ${ROOTFS_APT_ARGS} --no-download ${ROOTFS_PACKAGES} +EOF } ROOTFS_INSTALL_COMMAND += "rootfs_restore_initrd_tooling" @@ -678,8 +706,10 @@ rootfs_install_sstate_finalize() { # - after building the rootfs, the tar won't be there, but we also don't need to unpack # - after restoring from cache, there will be a tar which we unpack and then delete if [ -f rootfs.tar ]; then + run_privileged_heredoc <<'EOF' mkdir -p ${ROOTFSDIR} - run_privileged tar -C ${ROOTFSDIR} -xp ${SSTATE_TAR_ATTR_FLAGS} < rootfs.tar + tar -C ${ROOTFSDIR} -xp ${SSTATE_TAR_ATTR_FLAGS} -f rootfs.tar +EOF rm rootfs.tar fi } diff --git a/meta/classes-recipe/sbuild.bbclass b/meta/classes-recipe/sbuild.bbclass index d9ccce7f..8ca66138 100644 --- a/meta/classes-recipe/sbuild.bbclass +++ b/meta/classes-recipe/sbuild.bbclass @@ -7,7 +7,8 @@ SCHROOT_MOUNTS ?= "" inherit crossvars -SBUILD_CHROOT ?= "${DEBDISTRONAME}-${SCHROOT_USER}-${ISAR_BUILD_UUID}-${@os.getpid()}" +SBUILD_CHROOT:unshare ?= "${SCHROOT_DIR}.tar.zst" +SBUILD_CHROOT:schroot ?= "${DEBDISTRONAME}-${SCHROOT_USER}-${ISAR_BUILD_UUID}-${@os.getpid()}" SBUILD_CONF_DIR ?= "${SCHROOT_CONF}/${SBUILD_CHROOT}" SCHROOT_CONF_FILE ?= "${SCHROOT_CONF}/chroot.d/${SBUILD_CHROOT}" @@ -144,6 +145,13 @@ END EOSUDO } +unshare_configure_ccache() { + # ccache must be below /build for file permissions to work properly + cat <<'EOF' >> ${SBUILD_CONFIG} +$path = "/usr/lib/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"; +EOF +} + sbuild_dpkg_log_export() { export dpkg_partial_log="${1}" @@ -152,3 +160,17 @@ sbuild_dpkg_log_export() { cat ${dpkg_partial_log} >> ${SCHROOT_DIR}/tmp/dpkg_common.log ) 9>"${SCHROOT_DIR}/tmp/dpkg_common.log.lock" } + +# additional mounts managed by sbuild +sbuild_add_unshare_mounts() { + dpkg_prepare_unshare_ccache + + cat <<'EOF' >> ${SBUILD_CONFIG} +$unshare_bind_mounts = [ + { directory => '${WORKDIR}/rootfs', mountpoint => '${PP}/rootfs' }, + { directory => '${WORKDIR}/isar-apt/${DISTRO}-${DISTRO_ARCH}/apt/${DISTRO}', mountpoint => '/isar-apt' }, + { directory => '${REPO_BASE_DIR}', mountpoint => '/base-apt' }, + { directory => "${CCACHE_DIR}", mountpoint => "/ccache" } +]; +EOF +} diff --git a/meta/classes-recipe/sdk.bbclass b/meta/classes-recipe/sdk.bbclass index 16165792..7a8d5ff4 100644 --- a/meta/classes-recipe/sdk.bbclass +++ b/meta/classes-recipe/sdk.bbclass @@ -74,13 +74,17 @@ rootfs_configure_isar_apt_dir() { ROOTFS_POSTPROCESS_COMMAND:prepend:class-sdk = "sdkchroot_configscript " sdkchroot_configscript () { - run_in_chroot ${ROOTFSDIR} /configscript.sh ${DISTRO_ARCH} + run_privileged_heredoc <<'EOF' + set -e + ${@insert_isar_mounts(d, d.getVar('ROOTFSDIR'), d.getVar('ROOTFS_MOUNTS')) if d.getVar('ISAR_CHROOT_MODE') == 'unshare' else ''} + cp -rL /etc/resolv.conf '${ROOTFSDIR}/etc' + chroot ${ROOTFSDIR} /configscript.sh ${DISTRO_ARCH} +EOF } ROOTFS_POSTPROCESS_COMMAND:append:class-sdk = " sdkchroot_finalize" sdkchroot_finalize() { - - rootfs_do_umounts + rootfs_do_umounts_priv # Remove setup scripts run_privileged rm -f ${ROOTFSDIR}/chroot-setup.sh ${ROOTFSDIR}/configscript.sh diff --git a/meta/conf/bitbake.conf b/meta/conf/bitbake.conf index 6db10eb3..635b7ea3 100644 --- a/meta/conf/bitbake.conf +++ b/meta/conf/bitbake.conf @@ -69,7 +69,7 @@ KERNEL_FILE ?= "${@ 'vmlinux' if d.getVar('DISTRO_ARCH') in ['mipsel', 'riscv64' MACHINEOVERRIDES ?= "${MACHINE}" DISTROOVERRIDES ?= "${DISTRO}" -OVERRIDES = "${PACKAGE_ARCH}:${MACHINEOVERRIDES}:${DISTROOVERRIDES}:${BASE_DISTRO_CODENAME}:forcevariable" +OVERRIDES = "${PACKAGE_ARCH}:${MACHINEOVERRIDES}:${DISTROOVERRIDES}:${BASE_DISTRO_CODENAME}:${ISAR_CHROOT_MODE}:forcevariable" FILESOVERRIDES = "${PACKAGE_ARCH}:${MACHINE}" # Setting default QEMU_ARCH variables for different DISTRO_ARCH: @@ -148,6 +148,10 @@ ISAR_APT_RETRIES ??= "${@'10' if bb.utils.to_boolean(d.getVar('ISAR_USE_APT_SNAP ISAR_APT_DELAY_MAX ??= "${@'600' if bb.utils.to_boolean(d.getVar('ISAR_USE_APT_SNAPSHOT')) else ''}" ISAR_APT_SNAPSHOT_TIMESTAMP ??= "${SOURCE_DATE_EPOCH}" +# Rootless build execution +ISAR_ROOTLESS ??= "0" +ISAR_CHROOT_MODE ??= "${@'unshare' if bb.utils.to_boolean(d.getVar('ISAR_ROOTLESS')) else 'schroot'}" + # Default parallelism and resource usage for xz XZ_MEMLIMIT ?= "50%" XZ_THREADS ?= "${@oe.utils.cpu_count(at_least=2)}" @@ -203,6 +207,7 @@ CCACHE_DEBUG ?= "0" # Variables for tasks marking # Long term TODO: get rid of sudo marked tasks TASK_USE_NETWORK = "1" +# nested namespacing requires this as well TASK_USE_SUDO = "1" TASK_USE_NETWORK_AND_SUDO = "1" diff --git a/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc b/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc index eba6ea85..7d3e8a2c 100644 --- a/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc +++ b/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc @@ -162,6 +162,8 @@ do_bootstrap() { line="[trusted=yes] ${line}" fi echo "deb-src ${line}" >> "${WORKDIR}/sources.list.d/base-apt.list" + echo > ${WORKDIR}/mmtmpdir + chmod 666 ${WORKDIR}/mmtmpdir # no need to sync /var/cache/apt/archives if base-apt used syncin='echo skip sync-in' @@ -178,12 +180,14 @@ do_bootstrap() { mkdir -p \$1/base-apt && \ mount -o bind,private '${REPO_BASE_DIR}' \$1/base-apt && \ chroot \$1 apt-get update -y \ - -o APT::Update::Error-Mode=any && \ + -o APT::Update::Error-Mode=any \ + ${@'-o APT::Sandbox::User=root' if d.getVar('ISAR_CHROOT_MODE') == 'unshare' else ''} && \ chroot \$1 apt-get install -y dpkg && \ umount \$1/base-apt && \ - umount \$1/$base_apt_tmp && rm ${WORKDIR}/mmtmpdir && \ - umount $base_apt_tmp && rm -rf --one-file-system $base_apt_tmp" + umount \$1/$base_apt_tmp && \ + umount $base_apt_tmp && rmdir \$1/$base_apt_tmp" else + # prepare dl_dir for access from both sides (local and rootfs) deb_dl_dir_import "${WORKDIR}/dl_dir" "${BOOTSTRAP_BASE_DISTRO}-${BASE_DISTRO_CODENAME}" bootstrap_list="${WORKDIR}/sources.list.d/bootstrap.list" @@ -203,6 +207,7 @@ do_bootstrap() { -o Dir::State="$1/var/lib/apt" \ -o Dir::Etc="$1/etc/apt" \ -o Dir::Cache="$1/var/cache/apt" \ + ${@'-o APT::Sandbox::User=root' if d.getVar('ISAR_CHROOT_MODE') == 'unshare' else ''} \ -o Apt::Architecture="${BOOTSTRAP_DISTRO_ARCH}" \ ${@get_apt_opts(d, '-o')}' extra_essential="$extra_essential && $syncout" @@ -226,7 +231,8 @@ do_bootstrap() { mkdir -p ${DEBDIR} touch ${DEB_DL_LOCK} - run_privileged TMPDIR="${BOOTSTRAP_TMPDIR}" mmdebstrap $bootstrap_args \ + ${@'' if d.getVar('ISAR_CHROOT_MODE') == 'unshare' else 'run_privileged'} \ + TMPDIR="${BOOTSTRAP_TMPDIR}" mmdebstrap $bootstrap_args \ $arch_param \ --mode=unshare \ ${MMHOOKS} \ @@ -244,6 +250,7 @@ do_bootstrap() { --customize-hook='sed -i "/en_US.UTF-8 UTF-8/s/^#//g" "$1/etc/locale.gen"' \ --customize-hook='chroot "$1" /usr/sbin/locale-gen' \ --customize-hook='chroot "$1" /usr/bin/apt-get -y clean' \ + ${@'--skip=output/dev' if d.getVar('ISAR_CHROOT_MODE') == 'unshare' else ''} \ --skip=cleanup/apt \ --skip=download/empty \ ${MMOPTS} \ @@ -258,7 +265,8 @@ do_bootstrap() { if [ "${ISAR_USE_CACHED_BASE_REPO}" != "1" ]; then deb_dl_dir_export "${WORKDIR}/dl_dir" "${BOOTSTRAP_BASE_DISTRO}-${BASE_DISTRO_CODENAME}" - run_privileged rm -rf --one-file-system "${WORKDIR}/dl_dir" + run_privileged find ${WORKDIR}/dl_dir -maxdepth 1 -mindepth 1 -exec rm -rf --one-file-system "{}" \; + rmdir ${WORKDIR}/dl_dir fi } addtask bootstrap before do_build after do_generate_keyrings diff --git a/meta/recipes-devtools/sbuild-chroot/sbuild-chroot.inc b/meta/recipes-devtools/sbuild-chroot/sbuild-chroot.inc index aa62b324..054d7fc2 100644 --- a/meta/recipes-devtools/sbuild-chroot/sbuild-chroot.inc +++ b/meta/recipes-devtools/sbuild-chroot/sbuild-chroot.inc @@ -66,8 +66,28 @@ ROOTFS_POSTPROCESS_COMMAND:remove = "rootfs_cleanup_base_apt" DEPLOY_SCHROOT = "${@d.getVar('SCHROOT_' + d.getVar('SBUILD_VARIANT').upper() + '_DIR')}${SBUILD_SCHROOT_SUFFIX}" -do_sbuildchroot_deploy[dirs] = "${DEPLOY_DIR}/schroot-${SBUILD_VARIANT}" -do_sbuildchroot_deploy() { +sbuildchroot_deploy_tree() { ln -Tfsr "${ROOTFSDIR}" "${DEPLOY_SCHROOT}" } +sbuildchroot_deploy_tar() { + lopts="--one-file-system --exclude=var/cache/apt/archives --exclude=isar-apt" + # we cannot use pzstd, as this results in a different magic + # (zstd skippable frame) which is not detected by sbuild + # https://salsa.debian.org/debian/sbuild/-/blob/d975d388a98627a0d7d112791e441c27a6d529df/lib/Sbuild/ChrootUnshare.pm#L608 + ZSTD="zstd -${SSTATE_ZSTD_CLEVEL} -T${ZSTD_THREADS}" + run_privileged \ + tar -C ${ROOTFSDIR} -cpS $lopts ${ROOTFS_TAR_ATTR_FLAGS} . \ + | $ZSTD > ${DEPLOY_SCHROOT}.tar.zst + # cleanup extracted rootfs + run_privileged rm -rf ${ROOTFSDIR} +} + +do_sbuildchroot_deploy[network] = "${TASK_USE_SUDO}" +do_sbuildchroot_deploy[dirs] += "${DEPLOY_DIR}/schroot-${SBUILD_VARIANT}" +python do_sbuildchroot_deploy() { + if d.getVar('ISAR_CHROOT_MODE') == 'unshare': + bb.build.exec_func('sbuildchroot_deploy_tar', d) + else: + bb.build.exec_func('sbuildchroot_deploy_tree', d) +} addtask sbuildchroot_deploy before do_build after do_rootfs