From nobody Sat Feb 7 17:41:16 2026 Received: from mail-qv1-f52.google.com (mail-qv1-f52.google.com [209.85.219.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 42A1A2F85B for ; Sun, 28 Dec 2025 03:19:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766891978; cv=none; b=L1lPExN9lxXWaUGN1wqxFsNiff6Ac9Kc4nDemOVTrRfc7cLz0PaHhAWqn1lhvNPlBu0NCgVPAw9ekuaytbO5QdXkF88Jkrg9CS28UoS8rvSuvCvTY2+oMQTZwd0811ESWKwnHOpKsIfABRxzuWw8kFF2fqD1lLlMt4r+g5a4q8U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766891978; c=relaxed/simple; bh=eG8oUFAI4PetIG9wFbyzjuQjQ953cNpI3qyl1mZiJgw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=FDvxN011CSG3Pa/puQyu7+eFvjGRWmilRsvIYMNMREDrQBfwZW1hJEmz6Bu0MJf1d5ZNrbuAFTpGCIpGYwjxveo4ADiJ8yrX996Vn2XrYowAq1H3bQvHUzSVfX8GsIMfm6Qq9jN1VCQWNHjbGF/09A4UbzRK1e4O/oqAMyOAfok= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cloudflare.com; spf=pass smtp.mailfrom=cloudflare.com; dkim=pass (2048-bit key) header.d=cloudflare.com header.i=@cloudflare.com header.b=QNesZ4SG; arc=none smtp.client-ip=209.85.219.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cloudflare.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=cloudflare.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=cloudflare.com header.i=@cloudflare.com header.b="QNesZ4SG" Received: by mail-qv1-f52.google.com with SMTP id 6a1803df08f44-88a2e3bd3cdso105984396d6.0 for ; Sat, 27 Dec 2025 19:19:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cloudflare.com; s=google09082023; t=1766891975; x=1767496775; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Wz8HMmajZ9W4jVJulNGBtrLS2GpN8d2v1Td+fLbOd2A=; b=QNesZ4SGqjLCescb4LGbuerABczHli+mj0TYW0rFGCy5EUwCOuO1NAWflLXbyyJKBl 08vY13bnfi7rzEFhBGas9FADAHHDxy7JzG4bfq8gtymZHGy067rEga8GVBGy+LM0WLBW 0H0bAyF6VOEG0qcIftE0y9i1Qqzm1BD9FuisF663E09n0NnOvqn9EOSObhNOG1J+Fjn/ vVSzUInvSYH6Zg8Irx0i3Q3UYnC+yPbYt3EjoO9lV0hXdjh3ShPvG3YRxn6ltUMFfdiT pbsSv7abwI22k1tWmsDWRuxcIYekcUm0b62C6kwU/c8Nb8bampyRJb2VMzcsXE1Duiz+ fMGA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1766891975; x=1767496775; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=Wz8HMmajZ9W4jVJulNGBtrLS2GpN8d2v1Td+fLbOd2A=; b=ryA0QJJSoL70kd7sTJ3s/zklMEi3UWlVVnbNL6Mmacwr+E8Onw3fOfqQRzbj0SEq3j bXUGDyAfs8Uh/S8D4tkF3ZIDytg9+4K8m7QVizBasAx6HK3OYGrsIwKP5Se/CM0BN+F1 yuoRVm3Rc2PFds+WbrZe6Tj5YCl2QdUX+h3Qwsz8GbV8pamojZWCpFtoHPM+DZ09PeyR WcZswub0wTwpMht8D/gzW9gRhy3SVNtCv1x3dGQ0P640byJRcS926hObYKGEnoYpkOBY bxeo8OgABlm7jDhLxvNGYtexFVEHIrp9lt6Q4m6LQB+/fAGFR4tIDg/bG0YxSvFk555U txbg== X-Forwarded-Encrypted: i=1; AJvYcCWQpXJ8p5kpObIzMA8sfNZunkNQKZqdT+FfIyYWkwI2U27aI/87gYgBAEnjWWeDT5+NSk66CKmuerYoQWI=@vger.kernel.org X-Gm-Message-State: AOJu0YwQKRiU0LTFF76TUAO379YObduXHp7x/iRbBwm0s1y8FRbADATw ivExGBG94jSJfHgWp4zAQr9RcbvjvuqoGwaZh/3a3rzI50ck4tCVnjw5Q1eo/7J5l6w= X-Gm-Gg: AY/fxX6JprW2xHMZh11qCNUxw5f3S3Zzi53Gh6J5TdaLPT5k8q1au8FsUFK7Cr7e3c6 eupbGNjPLzDurRcnpmKrdqV6QU/MJ9Z+giOLASb8u1tGu9TdLh52n9yUpNam2oakigvFge56JzR DqMPqTu3VYe7VlPJuAT/EF+7i9kknkTD7qJ9RQRykdxUXbAFJGcmzcEqC+nVnLSliLNRZuQLRNp seynUCRUU5m+MMYKMQMOGZrZvu2XSrLY/RXBfS2qwBaJoiIObNNSlnXSt05EBgi2q+Aj0/KO4F6 KCK6H1HO/VTwqfnkUZtEpHnaPItcSu0hCIbaYeoVIIWth+m7BCuRtIt4qBPgKSefYnH0hGcwHGD wO7fIFlSF2MiyawfaQ2szA7gjjqOQZ1Qk/DfQv5laPYkyOMWOGFva2WQRdaUZ0pnsZZwKq7bcD+ izcgxy+EXbUQ== X-Google-Smtp-Source: AGHT+IFUZcvu/IX20E9sdhoqfHxwFxSu+aK649g3tolccQ2x7sR+ykIEOMiRboAEbGc3M6AHIHL+Og== X-Received: by 2002:a05:6214:23c5:b0:88a:4c50:3be0 with SMTP id 6a1803df08f44-88c5001fe40mr466683966d6.6.1766891974886; Sat, 27 Dec 2025 19:19:34 -0800 (PST) Received: from 861G6M3.attlocal.net ([2a09:bac1:76a0:780::5e:1f]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-88d997aef2esm200481436d6.32.2025.12.27.19.19.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 27 Dec 2025 19:19:34 -0800 (PST) From: Chris J Arges To: zohar@linux.ibm.com, roberto.sassu@huawei.com Cc: kernel-team@cloudflare.com, Chris J Arges , Dmitry Kasatkin , Eric Snowberg , Paul Moore , James Morris , "Serge E. Hallyn" , =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= , Kees Cook , linux-integrity@vger.kernel.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v3] ima: Fix stack-out-of-bounds in is_bprm_creds_for_exec() Date: Sat, 27 Dec 2025 21:18:54 -0600 Message-ID: <20251228031914.47618-1-carges@cloudflare.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <3aeed1ff9388f09555bf5c6ade03cbe9ce93ff14.camel@linux.ibm.com> References: <3aeed1ff9388f09555bf5c6ade03cbe9ce93ff14.camel@linux.ibm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" KASAN reported a stack-out-of-bounds access in ima_appraise_measurement from is_bprm_creds_for_exec: BUG: KASAN: stack-out-of-bounds in ima_appraise_measurement+0x12dc/0x16a0 Read of size 1 at addr ffffc9000160f940 by task sudo/550 The buggy address belongs to stack of task sudo/550 and is located at offset 24 in frame: ima_appraise_measurement+0x0/0x16a0 This frame has 2 objects: [48, 56) 'file' [80, 148) 'hash' This is caused by using container_of on the *file pointer. This offset calculation is what triggers the stack-out-of-bounds error. In order to fix this, pass in a bprm_is_check boolean which can be set depending on how process_measurement is called. If the caller has a linux_binprm pointer and the function is BPRM_CHECK we can determine is_check and set it then. Otherwise set it to false. Fixes: 95b3cdafd7cb7 ("ima: instantiate the bprm_creds_for_exec() hook") Signed-off-by: Chris J Arges --- security/integrity/ima/ima.h | 6 ++++-- security/integrity/ima/ima_appraise.c | 16 +++------------- security/integrity/ima/ima_main.c | 22 +++++++++++++--------- 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index e3d71d8d56e3..89ebe98ffc5e 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -441,7 +441,8 @@ int ima_check_blacklist(struct ima_iint_cache *iint, int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *i= int, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, - int xattr_len, const struct modsig *modsig); + int xattr_len, const struct modsig *modsig, + bool bprm_is_check); int ima_must_appraise(struct mnt_idmap *idmap, struct inode *inode, int mask, enum ima_hooks func); void ima_update_xattr(struct ima_iint_cache *iint, struct file *file); @@ -466,7 +467,8 @@ static inline int ima_appraise_measurement(enum ima_hoo= ks func, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, int xattr_len, - const struct modsig *modsig) + const struct modsig *modsig, + bool bprm_is_check) { return INTEGRITY_UNKNOWN; } diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima= /ima_appraise.c index 5149ff4fd50d..16c20c578ea8 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -470,17 +470,6 @@ int ima_check_blacklist(struct ima_iint_cache *iint, return rc; } =20 -static bool is_bprm_creds_for_exec(enum ima_hooks func, struct file *file) -{ - struct linux_binprm *bprm; - - if (func =3D=3D BPRM_CHECK) { - bprm =3D container_of(&file, struct linux_binprm, file); - return bprm->is_check; - } - return false; -} - /* * ima_appraise_measurement - appraise file measurement * @@ -492,7 +481,8 @@ static bool is_bprm_creds_for_exec(enum ima_hooks func,= struct file *file) int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *i= int, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, - int xattr_len, const struct modsig *modsig) + int xattr_len, const struct modsig *modsig, + bool bprm_is_check) { static const char op[] =3D "appraise_data"; int audit_msgno =3D AUDIT_INTEGRITY_DATA; @@ -514,7 +504,7 @@ int ima_appraise_measurement(enum ima_hooks func, struc= t ima_iint_cache *iint, * of the script interpreter(userspace). Differentiate kernel and * userspace enforced integrity audit messages. */ - if (is_bprm_creds_for_exec(func, file)) + if (bprm_is_check) audit_msgno =3D AUDIT_INTEGRITY_USERSPACE; =20 /* If reading the xattr failed and there's no modsig, error out. */ diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima= _main.c index 5770cf691912..1d6229b156fb 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -236,7 +236,8 @@ static void ima_file_free(struct file *file) static int process_measurement(struct file *file, const struct cred *cred, struct lsm_prop *prop, char *buf, loff_t size, int mask, enum ima_hooks func, - enum kernel_read_file_id read_id) + enum kernel_read_file_id read_id, + bool bprm_is_check) { struct inode *real_inode, *inode =3D file_inode(file); struct ima_iint_cache *iint =3D NULL; @@ -426,7 +427,8 @@ static int process_measurement(struct file *file, const= struct cred *cred, inode_lock(inode); rc =3D ima_appraise_measurement(func, iint, file, pathname, xattr_value, - xattr_len, modsig); + xattr_len, modsig, + bprm_is_check); inode_unlock(inode); } if (!rc) @@ -493,14 +495,15 @@ static int ima_file_mmap(struct file *file, unsigned = long reqprot, =20 if (reqprot & PROT_EXEC) { ret =3D process_measurement(file, current_cred(), &prop, NULL, - 0, MAY_EXEC, MMAP_CHECK_REQPROT, 0); + 0, MAY_EXEC, MMAP_CHECK_REQPROT, 0, + false); if (ret) return ret; } =20 if (prot & PROT_EXEC) return process_measurement(file, current_cred(), &prop, NULL, - 0, MAY_EXEC, MMAP_CHECK, 0); + 0, MAY_EXEC, MMAP_CHECK, 0, false); =20 return 0; } @@ -584,7 +587,8 @@ static int ima_bprm_check(struct linux_binprm *bprm) =20 security_current_getlsmprop_subj(&prop); return process_measurement(bprm->file, current_cred(), - &prop, NULL, 0, MAY_EXEC, BPRM_CHECK, 0); + &prop, NULL, 0, MAY_EXEC, BPRM_CHECK, 0, + bprm->is_check); } =20 /** @@ -614,7 +618,7 @@ static int ima_creds_check(struct linux_binprm *bprm, c= onst struct file *file) =20 security_current_getlsmprop_subj(&prop); return process_measurement((struct file *)file, bprm->cred, &prop, NULL, - 0, MAY_EXEC, CREDS_CHECK, 0); + 0, MAY_EXEC, CREDS_CHECK, 0, false); } =20 /** @@ -662,7 +666,7 @@ static int ima_file_check(struct file *file, int mask) security_current_getlsmprop_subj(&prop); return process_measurement(file, current_cred(), &prop, NULL, 0, mask & (MAY_READ | MAY_WRITE | MAY_EXEC | - MAY_APPEND), FILE_CHECK, 0); + MAY_APPEND), FILE_CHECK, 0, false); } =20 static int __ima_inode_hash(struct inode *inode, struct file *file, char *= buf, @@ -881,7 +885,7 @@ static int ima_read_file(struct file *file, enum kernel= _read_file_id read_id, func =3D read_idmap[read_id] ?: FILE_CHECK; security_current_getlsmprop_subj(&prop); return process_measurement(file, current_cred(), &prop, NULL, 0, - MAY_READ, func, 0); + MAY_READ, func, 0, false); } =20 const int read_idmap[READING_MAX_ID] =3D { @@ -925,7 +929,7 @@ static int ima_post_read_file(struct file *file, char *= buf, loff_t size, func =3D read_idmap[read_id] ?: FILE_CHECK; security_current_getlsmprop_subj(&prop); return process_measurement(file, current_cred(), &prop, buf, size, - MAY_READ, func, read_id); + MAY_READ, func, read_id, false); } =20 /** --=20 2.43.0