From nobody Tue Mar 14 15:04:35 2023 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4PbcJ41mh3z3yMrC; Tue, 14 Mar 2023 15:04:36 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4PbcJ415NNz48Sv; Tue, 14 Mar 2023 15:04:36 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1678806276; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=hJvTHCMH215yIZLXXFY7DkZ3NGisrHDgH6TJ1vvlBN4=; b=jTCBmF+sjBR2+1DFCc57jRKFtOdp36C7Zd7I4P5NXouW3WE8Um6XB4L2DmLXo0H1T9seU1 a1e2uSkZ76n2RXAa1H5zWFzW+zUr/UPG+W4l+t0s92EASwMJTWh0eSWg+EY7iJgxBXVLHV IYE+LWgiJrXy9oeTBJif3cLAKr6hbnvJvZp17gfCScScs68S6vGv+yEamTAaLunyyw589k 2qv2GfJR0EkLO5PUAop9JY/a9DTRrZLbA+odQuQWmSyRvZtOQAJCuULugApqnLUs+rrXlM 8Dj2Hv4sEsUUxv73nKERu245uxPIN4kINCLFURXlVGL1HykcrwqkQc+LQfIt/w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1678806276; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=hJvTHCMH215yIZLXXFY7DkZ3NGisrHDgH6TJ1vvlBN4=; b=oOS90whaNEGoenO3ug7Yf4Tx4NxoP13I0B0ZStxFxquduzE0Q+m3Wlvln9gbHq/YcyFdUL 8cIDk/48hsHRWfvhDPb0DwujdSJHLaBxSTDFjepFgiKbSLrDzfYYynODvo39qmb/a4LWeN avOk7OQx15DWM4iCy75bQL5tav1D6rdI9sjs7Dw6agYv9Ih3Pji/+bzW8O53H/6oADhvVq i8YchomljWUc/vvzUMH18s+6WlhoD8NDrazSC5UgH5eaaFNg2OQo2L6YdzBOOKpNT8taU+ KPxrrLlVQctJTqic6scUJahhw4LZN1WaELNaB6ur/iztxua6o/ndZczIUNi8/w== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1678806276; a=rsa-sha256; cv=none; b=Y+xwMbF0wjO/qe8TkCbtYsFAPP83h1DDmHn0Y4jtO607Bgw+XuHfjluJVCYUhHXYqLKK49 NjTIc8tV9mPpPuvNuA5TcOlJL7UsX/z4S90rwNT9L1YDNbhKjrFyns9zR5RmsxMdc3nuf/ TCNiM0BkJNeHwOEzet9Dszj1R+5B0rPmLo4t+hWRZXnI0vR0YwMaej5uQWPY4JA7WMv23z iWz/5AfsPqruRN2QrYAhJZldltk3Mu8aqDc4aeX+jaY/tNOVuD5Gj902stT02z6Xnuzavq pPqk/HZz1T3aI8B2gJMyqYGryqtTT9cSeWHcBnUC960KvYVMG0kUzmjKyp2WSQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4PbcJ36y09zgFr; Tue, 14 Mar 2023 15:04:35 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 32EF4Z3M026039; Tue, 14 Mar 2023 15:04:35 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 32EF4Ztx026038; Tue, 14 Mar 2023 15:04:35 GMT (envelope-from git) Date: Tue, 14 Mar 2023 15:04:35 GMT Message-Id: <202303141504.32EF4Ztx026038@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Warner Losh Subject: git: 2ef8baba4c0c - main - Increase protection provided by veriexec with new unlink/rename hooks. List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: imp X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 2ef8baba4c0c75f39e6e67b264ae71507bbb4782 Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by imp: URL: https://cgit.FreeBSD.org/src/commit/?id=2ef8baba4c0c75f39e6e67b264ae71507bbb4782 commit 2ef8baba4c0c75f39e6e67b264ae71507bbb4782 Author: dl AuthorDate: 2023-03-14 04:26:41 +0000 Commit: Warner Losh CommitDate: 2023-03-14 15:04:31 +0000 Increase protection provided by veriexec with new unlink/rename hooks. Functions implemented : - mac_veriexec_vnode_check_unlink: Unlink on a file has been requested and requires validation. This function prohibits the deleting a protected file (or deleting one of these hard links, if any). - mac_veriexec_vnode_check_rename_from: Rename the file has been requested and must be validated. This function controls the renaming of protected file - mac_veriexec_vnode_check_rename_to: File overwrite rename has been requested and must be validated. This function prevent overwriting of a file protected (overwriting by mv command). The 3 fonctions together aim to control the 'removal' (via unlink) and the 'mv' on files protected by veriexec. The intention is to reach the functional level of NetBSD veriexec. Add sysctl node security.mac.veriexec.unlink to toggle control on syscall unlink. Add tunable kernel variable security.mac.veriexec.block_unlink to toggle unlink protection. Add the corresponding read-only sysctl. [ tidied up commit message, trailing whitespace, long lines, { placement ] Reviewed by: sjg, imp Pull Request: https://github.com/freebsd/freebsd-src/pull/613 --- sys/security/mac_veriexec/mac_veriexec.c | 163 +++++++++++++++++++++++++++++-- 1 file changed, 155 insertions(+), 8 deletions(-) diff --git a/sys/security/mac_veriexec/mac_veriexec.c b/sys/security/mac_veriexec/mac_veriexec.c index 99a76abd4afb..6f06a8577212 100644 --- a/sys/security/mac_veriexec/mac_veriexec.c +++ b/sys/security/mac_veriexec/mac_veriexec.c @@ -73,6 +73,7 @@ static int sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS); static int sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS); +static struct mac_policy_ops mac_veriexec_ops; SYSCTL_DECL(_security_mac); @@ -94,8 +95,11 @@ SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, db, 0, 0, sysctl_mac_veriexec_db, "A", "Verified execution fingerprint database"); + static int mac_veriexec_slot; +static int mac_veriexec_block_unlink; + MALLOC_DEFINE(M_VERIEXEC, "veriexec", "Verified execution data"); /** @@ -235,8 +239,8 @@ mac_veriexec_vfs_unmounted(void *arg __unused, struct mount *mp, * * @param label the label that is being initialized */ -static void -mac_veriexec_mount_init_label(struct label *label) +static void +mac_veriexec_mount_init_label(struct label *label) { SLOT_SET(label, 0); @@ -252,8 +256,8 @@ mac_veriexec_mount_init_label(struct label *label) * * @param label the label that is being destroyed */ -static void -mac_veriexec_mount_destroy_label(struct label *label) +static void +mac_veriexec_mount_destroy_label(struct label *label) { SLOT_SET(label, 0); @@ -296,7 +300,7 @@ mac_veriexec_vnode_destroy_label(struct label *label) * @brief Copy the value in the MAC per-policy slot assigned to veriexec from * the @p src label to the @p dest label */ -static void +static void mac_veriexec_copy_label(struct label *src, struct label *dest) { @@ -505,7 +509,7 @@ mac_veriexec_check_vp(struct ucred *cred, struct vnode *vp, accmode_t accmode) /* * If file has a fingerprint then deny the write request, * otherwise invalidate the status so we don't keep checking - * for the file having a fingerprint. + * for the file having a fingerprint. */ switch (status) { case FINGERPRINT_FILE: @@ -531,7 +535,7 @@ mac_veriexec_check_vp(struct ucred *cred, struct vnode *vp, accmode_t accmode) default: /* * Caller wants open to fail unless there is a valid - * fingerprint registered. + * fingerprint registered. */ MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev " "%ju, file %ju.%ju\n", status, @@ -571,6 +575,136 @@ mac_veriexec_vnode_check_open(struct ucred *cred, struct vnode *vp, return (error); } +/** + * @brief Unlink on a file has been requested and may need to be validated. + * + * @param cred credentials to use + * @param dvp parent directory for file vnode vp + * @param dlabel vnode label assigned to the directory vnode + * @param vp vnode of the file to unlink + * @param label vnode label assigned to the vnode + * @param cnp component name for vp + * + * + * @return 0 if opening the file should be allowed, otherwise an error code. + */ +static int +mac_veriexec_vnode_check_unlink(struct ucred *cred, struct vnode *dvp __unused, + struct label *dvplabel __unused, struct vnode *vp, + struct label *label __unused, struct componentname *cnp __unused) +{ + int error; + + /* + * Look for the file on the fingerprint lists iff it has not been seen + * before. + */ + if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) + return (0); + + /* + * Check if it's a verified file + */ + error = mac_veriexec_check_vp(cred, vp, VVERIFY); + if (error == 0) { /* file is verified */ + MAC_VERIEXEC_DBG(2, + "(UNLINK) attempted to unlink a protected file (euid: %u)", cred->cr_uid); + + return (EAUTH); + } + return (0); +} + +/** + * @brief Rename the file has been requested and may need to be validated. + * + * @param cred credentials to use + * @param dvp parent directory for file vnode vp + * @param dlabel vnode label assigned to the directory vnode + * @param vp vnode of the file to rename + * @param label vnode label assigned to the vnode + * @param cnp component name for vp + * + * + * @return 0 if opening the file should be allowed, otherwise an error code. + */ +static int +mac_veriexec_vnode_check_rename_from(struct ucred *cred, + struct vnode *dvp __unused, struct label *dvplabel __unused, + struct vnode *vp, struct label *label __unused, + struct componentname *cnp __unused) +{ + int error; + + /* + * Look for the file on the fingerprint lists iff it has not been seen + * before. + */ + if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) + return (0); + + /* + * Check if it's a verified file + */ + error = mac_veriexec_check_vp(cred, vp, VVERIFY); + if (error == 0) { /* file is verified */ + MAC_VERIEXEC_DBG(2, + "(RENAME_FROM) attempted to rename a protected file (euid: %u)", cred->cr_uid); + return (EAUTH); + } + return (0); +} + + +/** + * @brief Rename to file into the directory (overwrite the file name) has been + * requested and may need to be validated. + * + * @param cred credentials to use + * @param dvp parent directory for file vnode vp + * @param dlabel vnode label assigned to the directory vnode + * @param vp vnode of the overwritten file + * @param label vnode label assigned to the vnode + * @param samedir 1 if the source and destination directories are the same + * @param cnp component name for vp + * + * + * @return 0 if opening the file should be allowed, otherwise an error code. + */ + static int +mac_veriexec_vnode_check_rename_to(struct ucred *cred, struct vnode *dvp __unused, + struct label *dvplabel __unused, struct vnode *vp, + struct label *label __unused, int samedir __unused, + struct componentname *cnp __unused) +{ + int error; + /* + * If there is no existing file to overwrite, vp and label will be + * NULL. + */ + if (vp == NULL) + return (0); + + /* + * Look for the file on the fingerprint lists iff it has not been seen + * before. + */ + if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) + return (0); + + /* + * Check if it's a verified file + */ + error = mac_veriexec_check_vp(cred, vp, VVERIFY); + if (error == 0) { /* file is verified */ + MAC_VERIEXEC_DBG(2, + "(RENAME_TO) attempted to overwrite a protected file (euid: %u)", cred->cr_uid); + return (EAUTH); + } + return (0); +} + + /** * @brief Check mode changes on file to ensure they should be allowed. * @@ -626,6 +760,16 @@ mac_veriexec_init(struct mac_policy_conf *mpc __unused) EVENTHANDLER_PRI_FIRST); EVENTHANDLER_REGISTER(vfs_unmounted, mac_veriexec_vfs_unmounted, NULL, EVENTHANDLER_PRI_LAST); + + /* Fetch tunable value in kernel env and define a corresponding read-only sysctl */ + mac_veriexec_block_unlink = 0; + TUNABLE_INT_FETCH("security.mac.veriexec.block_unlink", &mac_veriexec_block_unlink); + SYSCTL_INT(_security_mac_veriexec, OID_AUTO, block_unlink, + CTLFLAG_RDTUN, &mac_veriexec_block_unlink, 0, "Veriexec unlink protection"); + + /* Check if unlink control is activated via tunable value */ + if (!mac_veriexec_block_unlink) + mac_veriexec_ops.mpo_vnode_check_unlink = NULL; } /** @@ -685,7 +829,7 @@ mac_veriexec_syscall(struct thread *td, int call, void *arg) error = VOP_GETATTR(fp->f_vnode, &va, td->td_ucred); if (error) goto check_done; - + MAC_VERIEXEC_DBG(2, "mac_veriexec_fingerprint_check_image: " "va_mode=%o, check_files=%d\n", va.va_mode, ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0)); @@ -729,6 +873,9 @@ static struct mac_policy_ops mac_veriexec_ops = .mpo_system_check_sysctl = mac_veriexec_sysctl_check, .mpo_vnode_check_exec = mac_veriexec_vnode_check_exec, .mpo_vnode_check_open = mac_veriexec_vnode_check_open, + .mpo_vnode_check_unlink = mac_veriexec_vnode_check_unlink, + .mpo_vnode_check_rename_to = mac_veriexec_vnode_check_rename_to, + .mpo_vnode_check_rename_from = mac_veriexec_vnode_check_rename_from, .mpo_vnode_check_setmode = mac_veriexec_vnode_check_setmode, .mpo_vnode_copy_label = mac_veriexec_copy_label, .mpo_vnode_destroy_label = mac_veriexec_vnode_destroy_label,