From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail.openvz.org (unknown [69.168.225.77]) by lore.virtuozzo.com (Postfix) with ESMTPS id CC96B80726 for ; Wed, 14 Oct 2026 17:13:58 +0000 (UTC) Received: from mail.openvz.org (localhost [127.0.0.1]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 69EHCin0001360; Wed, 14 Oct 2026 20:12:45 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 69EHCin0001360 Authentication-Results: mail.openvz.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=virtuozzo.com header.i=@virtuozzo.com header.b="JIp2oBfE" Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 69EHCU3W001313 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=FAIL) for ; Wed, 14 Oct 2026 20:12:31 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 69EHCU3W001313 Received: by mail-wr1-f71.google.com with SMTP id ffacd0b85a97d-48c427421f6so547817f8f.2 for ; Wed, 14 Oct 2026 10:12:31 -0700 (PDT) X-Gm-Message-State: AFq9FYIaxn28XYqGoTGtCWdYXiOKQHFPpVNxB4A1fojqA3flyy22w3/+ hhXa4xGOSbiCWZ/ZWDFn3B2M/Qu16auXiDczEagFznIsaVxfBRepTdU8sCOra1IXuzyorppzN4Y sYUoinfuaCEo4dtgqwPWSuZNJdmJWvjJsQnbUu8Cf3XEftaNoPNBsXw== X-Gm-Gg: AYBFou1bQDie57btXFUaEGWZkf4aPOF8uVG5sHX/pa800YTeVB0HAkFbVV8T/9qqlGx JJLZlVJTzpdQ922tLXKxx7PdkrcmjG7WBeInhfi3eYM8Tfpq1umrw+9ZBEjO76gpneJu5CGoJFC Im0SKaiDb8M+lrVDKDYy2FaMfyyt+8KLvqMRRQNYLihveY+v+Z0vw9t81PyQKJd7LeTmtsaGz1L pvsIC/y36Bj72kbCzo2VVk2Ne6GdaI6RFAKwCjqBAy4BXVOOmwebKcttLQgrrruTxYB+aodA8NG 40AmRGMSH3ademaRJEiyBYz24Zq31wqbKV4sogtSK8kV5/gIyXFZ0yWQ2glU4DQxse2pH+/fb+N PNT5uY2EmxdbRfrhq X-Received: by 2002:a05:6000:41cd:b0:48d:f14a:917e with SMTP id ffacd0b85a97d-48df14a9316mr2112081f8f.11.1791997950573; Wed, 14 Oct 2026 10:12:30 -0700 (PDT) X-Received: by 2002:a05:6000:41cd:b0:48d:f14a:917e with SMTP id ffacd0b85a97d-48df14a9316mr2112010f8f.11.1791997949857; Wed, 14 Oct 2026 10:12:29 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1791997949; cv=none; d=google.com; s=arc-20260327; b=jFZ3JdpThTz4ESUPE9E57IFIGypctv3WPOx0WfApFle3euHdZNU5hxwQSWksgSyi5R vrniGiwNyitY8cH/EIzBoHLNC/mjsjDbGaKUpqrc9MA1paE3Z0eBtja/J9eNtyB9B60v VOloiuVsFBVFSkovXdT4DKhh3mO/ZDE7FA6vJ13ns0G/D8xfU+N0XxypUTtCWKlM/ZWO K2IAG97AYLSza8W+NswQbEHPfN+S5gs5lQyGTkck4MLAYfFUVr8x925ziXE6BphQVO5A wDaZbc6kNwTIYt8t8qM+lv8MTA0rNT+HnB90wldEfKAPNo6tdyIj3/PcgoebI1QAj3gJ CocA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:dkim-signature; bh=S4VtDYERvGm5Thf53ExbV4hUaC2e9lHgcP7s71RDNtI=; fh=xUcS46XhSaUOWFT7CPWNuABJ4EJ7/+S5u4N+e+rlWN4=; b=Q431s6NTIyGVMfHRqsSQJi0aKp41t+Q351f4xAF0LWXpAND/ASqlhesFuMK5l7EDEl wSnNZVoqyBOnJX15e1wbllQ4+ertYnWVNt+ZfJ5Uew8S4CKMCvUJcPMjW9xexnlQMvE5 43AJAAzPFPsDBaPV/yUcEDDBR9PcQqwU4IWHqqegU7OXfcXcUvND43krIsactohNiPnx dyc8Aq97eqovR4yz/UZRAcarjGT1kmKhU5YBkc4CwiMM/I2X9JT0L0iJ3MZfHg8DYDee VC36Ol++SY0dV0Jz2A690yyhhpwxC+yDu+y9SOtV0BSXe2xAsK0FmyWpTFyQJ6vJMXMU MDRQ==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b=JIp2oBfE; spf=pass (google.com: domain of khorenko@virtuozzo.com designates 130.117.225.111 as permitted sender) smtp.mailfrom=khorenko@virtuozzo.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=virtuozzo.com Received: from relay.virtuozzo.com (relay.virtuozzo.com. [130.117.225.111]) by mx.google.com with ESMTPS id ffacd0b85a97d-48deec4e7d6si3155295f8f.30.2026.10.14.10.12.29 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 14 Oct 2026 10:12:29 -0700 (PDT) Received-SPF: pass (google.com: domain of khorenko@virtuozzo.com designates 130.117.225.111 as permitted sender) client-ip=130.117.225.111; Authentication-Results: mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b=JIp2oBfE; spf=pass (google.com: domain of khorenko@virtuozzo.com designates 130.117.225.111 as permitted sender) smtp.mailfrom=khorenko@virtuozzo.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=virtuozzo.com DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=virtuozzo.com; s=relay; h=Message-Id:Content-Type:MIME-Version:Subject:Date :From; bh=S4VtDYERvGm5Thf53ExbV4hUaC2e9lHgcP7s71RDNtI=; b=JIp2oBfElrZJSOoB119 OOLYtXOmPyzF4CW/icvGkj8BoILPPgl6r+A+8ornWobNOzYKwLW51we+QYX5VevVXGzloIx0BW7Lv ZiEadkK4rt0K8wnrrW3Qd7Y83lVqMaoSKaKPIXYl6AAhx2pjB+O4mTI4HveUdDuD8jT5W9RouExbI DT+5x1B5cFkGTSf86rIUdLRN9VNFun80hSB8zK25LtaMKrN4oficQOSW1n54S3pZexVHw9LP4icB0 QVImJ4nlFT4lbv83+c0hvtS2Veuj0JGK+1yFNs8itX5oIwhzMAwkMfiaLoSD5SFdSrwTgOiMilmxg Xd1DTuVfSxUJ96A==; Received: from ch-demo-asa.virtuozzo.com ([130.117.225.8] helo=f0.sw.ru) by relay.virtuozzo.com with esmtp (Exim 4.96) (envelope-from ) id 1xH2TI-0082VK-1F; Wed, 14 Oct 2026 19:12:28 +0200 From: Konstantin Khorenko Date: Wed, 14 Oct 2026 19:12:23 +0200 MIME-Version: 1.0 Message-Id: <20261014-b4-prep-khorenko-vstor-149847-3-doexec-oracle-fixes-v1-4-e34cbe0d1440@virtuozzo.com> References: <20261014-b4-prep-khorenko-vstor-149847-3-doexec-oracle-fixes-v1-0-e34cbe0d1440@virtuozzo.com> In-Reply-To: <20261014-b4-prep-khorenko-vstor-149847-3-doexec-oracle-fixes-v1-0-e34cbe0d1440@virtuozzo.com> To: Pavel Tikhomirov , Andrey Drobyshev , Vasileios Almpanis X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=7453; i=khorenko@virtuozzo.com; h=from:subject:message-id; bh=1Bdy8XnKT65qOkB468k/I3ejKlsQWepOoPb/2pK048o=; b=owEBbQKS/ZANAwAKAVGWCkf5YVwqAcsmYgBqz7f6SLZqBCUZZ4dHJuUSZshKVOgmCKe2oHUMe dL0vCkqB0uJAjMEAAEKAB0WIQRWD23IPcXT0GO9CCxRlgpH+WFcKgUCas+3+gAKCRBRlgpH+WFc KqTnD/9dI/h0Ih5daT+5AqQq0pptbK5VAJwszyXf63VRgAhBupc7jKiFFXalDrJnTi8rOifUeoI X5OpWKVK5bdbPu9PEmXVjUS/GA51GxcA4sHaHj3rvsDECxsn1hW8SlmYwaUGcTnPNaD1TYQkt6u XghEasOYSyX4Za+wFoBzHNNNBfUMwH7aC8UT5Jy+OkBZBeh36D8ueR1tx/WMdvmyKrofFq3wmWZ 87v1aCZOgl2p6IbZPhJHTXM66LcLrsER9fXRA6AeW8jhKc/fBHuUqMEvbcCryfhoYA41EWJtOBR 8zP/CAIiK1GnHm4WNkCKKp/VdUKFbk/UjNmkBjL7FSeiAPWynLJsIJb+9zT2dkuqQoezM1SgzD2 tqE9rgEBDtkCeAhtgcfhg7Mx896FuzDy9GZs3kR5vp/dO+SfrxeMH0U09I2yebaEbNsS9SCcp0D 6vNG6mZSn/33ztSe5rpek4Rl5Q5+zvdEQ+S1OaUyZWuAzgYDiuBt3ra6pdM18MFD2mzUpxnC7WP MsiBUBLxqIKrOq9xQ35hIm1z7Hexd4TBWKgTob+a3pRflkyWf2ivedO+jn3FFMmK1GW4B9QBdbS SrkcOXMpnpS3R49ALFJyT6/a9DDahBY7oPq1+LVLv11i+2CgZJlEMkCE+6vSaMiR6hT5Iy+IuhD T5shlgqTcDrosrA== X-Developer-Key: i=khorenko@virtuozzo.com; a=openpgp; fpr=560F6DC83DC5D3D063BD082C51960A47F9615C2A X-OZ-Fwd: true Cc: devel@openvz.org Subject: [Devel] [PATCH hci-8.1 4/7] oracle/exec, elf: look for the opt-in note in every PT_NOTE segment X-BeenThere: devel@openvz.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: OpenVZ development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: devel-bounces@openvz.org Errors-To: devel-bounces@openvz.org load_elf_binary() keeps only the last PT_NOTE segment it sees and looks for the preserved-mem-ok note there. Linkers group notes into segments by alignment: .note.gnu.property, aligned to 8, gets a PT_NOTE of its own, and the 4-aligned notes share another. ld.bfd happens to put the 4-aligned one last, but another linker or a linker script can put the segment with the opt-in elsewhere. The binary then silently gets no preserved memory, and a live update loses the guest RAM it meant to keep. Check the notes of every PT_NOTE segment. The last segment, the only one read before, keeps its check: its first note of the opt-in type fails the exec with ENOEXEC unless it is the opt-in, that is when its name size is over 17, its name is another or it is cut off by the end of the segment. In the other segments only the opt-in counts and anything else is skipped, so the notes refuse nothing the old check accepted. The opt-in is recorded in bprm only after all segments passed, so that an ENOEXEC does not leave it behind for the next binfmt handler. The walk keeps the 4-byte padding it always used, so in an 8-aligned segment it stays in step only with notes whose name size rounds up to an odd multiple of 4 and whose descriptor size rounds up to a multiple of 8, as the GNU property notes have. It stops at a note whose sizes run past the segment, which on a 32-bit kernel could wrap the offset and loop forever. The notes are read for every ELF binary. A segment too short for a note, larger than MAX_FILE_NOTE_SIZE or past the end of the file holds nothing a linker emits and is skipped; the exec of a binary whose last PT_NOTE was like that used to fail with ENOEXEC, EIO or EINVAL. An error reading a segment, or allocating the buffer for it, fails the exec, since skipping it could drop the opt-in and the memory with it. Fixes: d07a690048ce ("oracle/exec, elf: require opt-in for accepting preserved mem") https://virtuozzo.atlassian.net/browse/VSTOR-150232 Feature: oracle/mm: MADV_DOEXEC madvise() flag Assisted-by: LLM Signed-off-by: Konstantin Khorenko --- fs/binfmt_elf.c | 87 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 35 deletions(-) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index a5689a2844d43..9cc84cdbb60fb 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -837,16 +837,19 @@ static int parse_elf_properties(struct file *f, const struct elf_phdr *phdr, static int get_elf_notes(struct linux_binprm *bprm, struct elf_phdr *phdr, char **notes, size_t *notes_sz) { + u64 isize = i_size_read(file_inode(bprm->file)); char *data; size_t datasz; int ret; - if (!phdr) - return 0; - + /* + * Skip a segment too short for a note, too large to read or past the + * end of the file; an error reading it is fatal. + */ datasz = phdr->p_filesz; - if ((datasz > MAX_FILE_NOTE_SIZE) || (datasz < sizeof(struct elf_note))) - return -ENOEXEC; + if (datasz > MAX_FILE_NOTE_SIZE || datasz < sizeof(struct elf_note) || + phdr->p_offset > isize || datasz > isize - phdr->p_offset) + return 0; data = kvmalloc(datasz, GFP_KERNEL); if (!data) @@ -866,10 +869,17 @@ static int get_elf_notes(struct linux_binprm *bprm, struct elf_phdr *phdr, char #define PRESERVED_MEM_OK_STRING "preserved-mem-ok" #define SZ_PRESERVED_MEM_OK_STRING sizeof(PRESERVED_MEM_OK_STRING) -static int check_preserved_mem_ok(struct linux_binprm *bprm, const char *data, const size_t datasz) +/* + * 1 if the notes hold the opt-in. In the last PT_NOTE segment the first note + * of the opt-in type fails the exec with -ENOEXEC unless it is the opt-in; in + * the other segments only the opt-in counts. + */ +static int check_preserved_mem_ok(const char *data, const size_t datasz, + bool last) { size_t off = 0; size_t remain; + u64 next; if (!data) return 0; @@ -887,21 +897,21 @@ static int check_preserved_mem_ok(struct linux_binprm *bprm, const char *data, c off += sizeof(*nhdr); remain -= sizeof(*nhdr); - if (nhdr->n_type != 0x07c1feed) { - off += roundup(nhdr->n_namesz, 4) + roundup(nhdr->n_descsz, 4); - continue; + if (nhdr->n_type == 0x07c1feed) { + name = data + off; + if (nhdr->n_namesz <= SZ_PRESERVED_MEM_OK_STRING && + remain >= SZ_PRESERVED_MEM_OK_STRING && + !strncmp(name, PRESERVED_MEM_OK_STRING, + SZ_PRESERVED_MEM_OK_STRING)) + return 1; + if (last) + return -ENOEXEC; } - - if (nhdr->n_namesz > SZ_PRESERVED_MEM_OK_STRING) - return -ENOEXEC; - - name = data + off; - if (remain < SZ_PRESERVED_MEM_OK_STRING || - strncmp(name, PRESERVED_MEM_OK_STRING, SZ_PRESERVED_MEM_OK_STRING)) - return -ENOEXEC; - - bprm->accepts_preserved_mem = 1; - break; + next = round_up((u64)nhdr->n_namesz, 4) + + round_up((u64)nhdr->n_descsz, 4); + if (next > remain) + break; + off += next; } return 0; @@ -915,9 +925,7 @@ static int load_elf_binary(struct linux_binprm *bprm) unsigned long error; struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL; struct elf_phdr *elf_property_phdata = NULL; - struct elf_phdr *elf_notes_phdata = NULL; - char *elf_notes = NULL; - size_t elf_notes_sz = 0; + int accepts_preserved_mem = 0, last_note = -1; unsigned long elf_brk; bool brk_moved = false; int retval, i; @@ -1028,10 +1036,6 @@ static int load_elf_binary(struct linux_binprm *bprm) executable_stack = EXSTACK_DISABLE_X; break; - case PT_NOTE: - elf_notes_phdata = elf_ppnt; - break; - case PT_LOPROC ... PT_HIPROC: retval = arch_elf_pt_proc(elf_ex, elf_ppnt, bprm->file, false, @@ -1097,13 +1101,28 @@ static int load_elf_binary(struct linux_binprm *bprm) if (retval) goto out_free_dentry; - retval = get_elf_notes(bprm, elf_notes_phdata, &elf_notes, &elf_notes_sz); - if (retval) - goto out_free_dentry; + /* The linker spreads notes over several segments by their alignment. */ + for (i = 0, elf_ppnt = elf_phdata; i < elf_ex->e_phnum; i++, elf_ppnt++) + if (elf_ppnt->p_type == PT_NOTE) + last_note = i; + for (i = 0, elf_ppnt = elf_phdata; i < elf_ex->e_phnum; i++, elf_ppnt++) { + size_t elf_notes_sz = 0; + char *elf_notes = NULL; - retval = check_preserved_mem_ok(bprm, elf_notes, elf_notes_sz); - if (retval) - goto out_free_dentry; + if (elf_ppnt->p_type != PT_NOTE) + continue; + retval = get_elf_notes(bprm, elf_ppnt, &elf_notes, &elf_notes_sz); + if (retval) + goto out_free_dentry; + retval = check_preserved_mem_ok(elf_notes, elf_notes_sz, + i == last_note); + kvfree(elf_notes); + if (retval < 0) + goto out_free_dentry; + accepts_preserved_mem |= retval; + } + /* Only now: an ENOEXEC above lets another binfmt handler try the file. */ + bprm->accepts_preserved_mem = accepts_preserved_mem; /* Flush all traces of the currently running executable */ retval = begin_new_exec(bprm); @@ -1381,7 +1400,6 @@ static int load_elf_binary(struct linux_binprm *bprm) } } - kvfree(elf_notes); kfree(elf_phdata); set_binfmt(&elf_format); @@ -1486,7 +1504,6 @@ static int load_elf_binary(struct linux_binprm *bprm) if (interpreter) fput(interpreter); out_free_ph: - kvfree(elf_notes); kfree(elf_phdata); goto out; } -- 2.43.0 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel