From nobody Sun Apr 07 23:57:06 2024 X-Original-To: dev-commits-src-main@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 4VCTfV4Nj0z5FbM6; Sun, 7 Apr 2024 23:57:06 +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 4VCTfV2ZkGz4CM7; Sun, 7 Apr 2024 23:57:06 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1712534226; 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=u+s0fNuABbD7jsqA8rTNN4BBT6v/HyJwgfOvSSRBQmw=; b=ks8wrZXX4EC4EKOLgG16GLKV4/4v5abjLapa1ugffrZvRCm7qKtA566I0SYm0887NRIATU VSfbb0QWSr2oisdwkOns+KTp6E+iJrvfjSCUkeE+uB35pAe9JSZkGx0dAu5CaclwXJ8Kr5 zCVe9iHAlNlWuEhO9RvTvpwWb4P5uhOFl0LmRVu1xu4NCGB8bmfLTehcebPbKo9ZEzIO4J UpxxahOvtzHw8WkhfVoyoC1Z7zd9QwQh/5GARLuk3FAg5T1hOSze2kqKpKEbyCtPLnP6LB Bh9GHyHdU72gcIfJa/CLnhWbmJHrTZTd9wc6y0ZOL491/vN4HXbNY0S6ZpG4cw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1712534226; a=rsa-sha256; cv=none; b=UMVgdG0yRwuTyXIu8hWbLsP0mWC0W05Vm9ejw4cHvW+apA2k/LUwXr4TbCvRlVq2e6/irG ilaii81pERjDqL/9CjeaPKcdv9SQMIe9bumj037OjalTAtYR5g8pjO98QctF84KzeAXzY/ qAOWHFqWQ+InPjCrMRoeM+WRlU+Y8IHypIWaaxBnhl8ANr9PrOcs8Q3aokRUxtC0NAkkc9 Nrrz+nHZhYj9KwDSYRcP9QXtCpZcWubCi9h2AvUvZoDLZFXvPxKsYxmKdsEZkQsA5GSuBk nsr/Fj+wpQkRqw2MHet0Fntc9dHrLsN/x7S+6t8wDQ0bjnf6JSZSHaUkmdxy9Q== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1712534226; 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=u+s0fNuABbD7jsqA8rTNN4BBT6v/HyJwgfOvSSRBQmw=; b=XWylAF7/pfovzg9rMYRpOT/7LdKeC7ybwKhIQ1aFTW5hhl3cLlg6uRk2UtsrDP9DBwoi9z bRB27KAsQom/1bAeHvWYrXh2O8oyRpddgKmAKkcQgqHVJ++WWF0gK0t9E0w8e12wH37TeK jeOUI6UsEG0Wax4SGoReIMXWwx3bYES70Fsb+sM5J+Z+8IGsXRTcf44MaJ1z5zo0sl7U/E mZokOwQgtX5Qvjz9WFCVS+4QU39gbiRF4074BZf9x0mn+NcGqTJQqqu31oVj0NNjjp4lCI 6/nYyHyHqrcyJi2U8tHD7BtirSmO8slQMEP4+TRaemPHrfapz/jWn3Sg1BOUIQ== 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 4VCTfV2BPMzp2h; Sun, 7 Apr 2024 23:57:06 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 437Nv6Qo037335; Sun, 7 Apr 2024 23:57:06 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 437Nv6p2037332; Sun, 7 Apr 2024 23:57:06 GMT (envelope-from git) Date: Sun, 7 Apr 2024 23:57:06 GMT Message-Id: <202404072357.437Nv6p2037332@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Jake Freeland Subject: git: 9bec84131215 - main - ktrace: Record detailed ECAPMODE violations List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-main@freebsd.org X-BeenThere: dev-commits-src-main@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: jfree X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 9bec84131215ed554f435e208399f36e982246f1 Auto-Submitted: auto-generated The branch main has been updated by jfree: URL: https://cgit.FreeBSD.org/src/commit/?id=9bec84131215ed554f435e208399f36e982246f1 commit 9bec84131215ed554f435e208399f36e982246f1 Author: Jake Freeland AuthorDate: 2024-04-06 18:29:45 +0000 Commit: Jake Freeland CommitDate: 2024-04-07 23:52:51 +0000 ktrace: Record detailed ECAPMODE violations When a Capsicum violation occurs in the kernel, ktrace will now record detailed information pertaining to the violation. For example: - When a namei lookup violation occurs, ktrace will record the path. - When a signal violation occurs, ktrace will record the signal number. - When a sendto(2) violation occurs, ktrace will record the recipient sockaddr. For all violations, the syscall and ABI is recorded. kdump is also modified to display this new information to the user. Reviewed by: oshogbo, markj Approved by: markj (mentor) MFC after: 1 month Differential Revision: https://reviews.freebsd.org/D40676 --- sys/kern/kern_ktrace.c | 43 +++++++++++++++++++++++-------- sys/kern/sys_capability.c | 16 +++++------- sys/sys/capsicum.h | 7 +++++ sys/sys/ktrace.h | 32 +++++++++++++++++------ usr.bin/kdump/kdump.c | 65 +++++++++++++++++++++++++++++++++++++---------- 5 files changed, 122 insertions(+), 41 deletions(-) diff --git a/sys/kern/kern_ktrace.c b/sys/kern/kern_ktrace.c index 6ace3ea52c64..142aa790a908 100644 --- a/sys/kern/kern_ktrace.c +++ b/sys/kern/kern_ktrace.c @@ -923,14 +923,17 @@ ktrstructarray(const char *name, enum uio_seg seg, const void *data, } void -ktrcapfail(enum ktr_cap_fail_type type, const cap_rights_t *needed, - const cap_rights_t *held) +ktrcapfail(enum ktr_cap_violation type, const void *data) { struct thread *td = curthread; struct ktr_request *req; struct ktr_cap_fail *kcf; + union ktr_cap_data *kcd; - if (__predict_false(curthread->td_pflags & TDP_INKTRACE)) + if (__predict_false(td->td_pflags & TDP_INKTRACE)) + return; + if (type != CAPFAIL_SYSCALL && + (td->td_sa.callp->sy_flags & SYF_CAPENABLED) == 0) return; req = ktr_getrequest(KTR_CAPFAIL); @@ -938,14 +941,32 @@ ktrcapfail(enum ktr_cap_fail_type type, const cap_rights_t *needed, return; kcf = &req->ktr_data.ktr_cap_fail; kcf->cap_type = type; - if (needed != NULL) - kcf->cap_needed = *needed; - else - cap_rights_init(&kcf->cap_needed); - if (held != NULL) - kcf->cap_held = *held; - else - cap_rights_init(&kcf->cap_held); + kcf->cap_code = td->td_sa.code; + kcf->cap_svflags = td->td_proc->p_sysent->sv_flags; + if (data != NULL) { + kcd = &kcf->cap_data; + switch (type) { + case CAPFAIL_NOTCAPABLE: + case CAPFAIL_INCREASE: + kcd->cap_needed = *(const cap_rights_t *)data; + kcd->cap_held = *((const cap_rights_t *)data + 1); + break; + case CAPFAIL_SYSCALL: + case CAPFAIL_SIGNAL: + case CAPFAIL_PROTO: + kcd->cap_int = *(const int *)data; + break; + case CAPFAIL_SOCKADDR: + kcd->cap_sockaddr = *(const struct sockaddr *)data; + break; + case CAPFAIL_NAMEI: + strlcpy(kcd->cap_path, data, MAXPATHLEN); + break; + case CAPFAIL_CPUSET: + default: + break; + } + } ktr_enqueuerequest(td, req); ktrace_exit(td); } diff --git a/sys/kern/sys_capability.c b/sys/kern/sys_capability.c index fac264a78531..d59ad37f35ec 100644 --- a/sys/kern/sys_capability.c +++ b/sys/kern/sys_capability.c @@ -154,14 +154,13 @@ MALLOC_DECLARE(M_FILECAPS); static inline int _cap_check(const cap_rights_t *havep, const cap_rights_t *needp, - enum ktr_cap_fail_type type) + enum ktr_cap_violation type) { + const cap_rights_t rights[] = { *needp, *havep }; if (!cap_rights_contains(havep, needp)) { -#ifdef KTRACE - if (KTRPOINT(curthread, KTR_CAPFAIL)) - ktrcapfail(type, needp, havep); -#endif + if (CAP_TRACING(curthread)) + ktrcapfail(type, rights); return (ENOTCAPABLE); } return (0); @@ -180,11 +179,10 @@ cap_check(const cap_rights_t *havep, const cap_rights_t *needp) int cap_check_failed_notcapable(const cap_rights_t *havep, const cap_rights_t *needp) { + const cap_rights_t rights[] = { *needp, *havep }; -#ifdef KTRACE - if (KTRPOINT(curthread, KTR_CAPFAIL)) - ktrcapfail(CAPFAIL_NOTCAPABLE, needp, havep); -#endif + if (CAP_TRACING(curthread)) + ktrcapfail(CAPFAIL_NOTCAPABLE, rights); return (ENOTCAPABLE); } diff --git a/sys/sys/capsicum.h b/sys/sys/capsicum.h index 3979fd718909..e1113f590b85 100644 --- a/sys/sys/capsicum.h +++ b/sys/sys/capsicum.h @@ -44,6 +44,7 @@ #include #include #include +#include #ifndef _KERNEL #include @@ -419,6 +420,12 @@ __END_DECLS #include +#ifdef KTRACE +#define CAP_TRACING(td) KTRPOINT((td), KTR_CAPFAIL) +#else +#define CAP_TRACING(td) 0 +#endif + #define IN_CAPABILITY_MODE(td) (((td)->td_ucred->cr_flags & CRED_FLAG_CAPMODE) != 0) struct filedesc; diff --git a/sys/sys/ktrace.h b/sys/sys/ktrace.h index 710c78c2604d..263f25945bff 100644 --- a/sys/sys/ktrace.h +++ b/sys/sys/ktrace.h @@ -32,8 +32,10 @@ #ifndef _SYS_KTRACE_H_ #define _SYS_KTRACE_H_ +#include #include #include +#include #include /* @@ -205,16 +207,31 @@ struct ktr_proc_ctor { * KTR_CAPFAIL - trace capability check failures */ #define KTR_CAPFAIL 12 -enum ktr_cap_fail_type { +enum ktr_cap_violation { CAPFAIL_NOTCAPABLE, /* insufficient capabilities in cap_check() */ - CAPFAIL_INCREASE, /* attempt to increase capabilities */ + CAPFAIL_INCREASE, /* attempt to increase rights on a capability */ CAPFAIL_SYSCALL, /* disallowed system call */ - CAPFAIL_LOOKUP, /* disallowed VFS lookup */ + CAPFAIL_SIGNAL, /* sent signal to process other than self */ + CAPFAIL_PROTO, /* disallowed protocol */ + CAPFAIL_SOCKADDR, /* restricted address lookup */ + CAPFAIL_NAMEI, /* restricted namei lookup */ + CAPFAIL_CPUSET, /* restricted CPU set modification */ }; + +union ktr_cap_data { + cap_rights_t cap_rights[2]; +#define cap_needed cap_rights[0] +#define cap_held cap_rights[1] + int cap_int; + struct sockaddr cap_sockaddr; + char cap_path[MAXPATHLEN]; +}; + struct ktr_cap_fail { - enum ktr_cap_fail_type cap_type; - cap_rights_t cap_needed; - cap_rights_t cap_held; + enum ktr_cap_violation cap_type; + short cap_code; + u_int cap_svflags; + union ktr_cap_data cap_data; }; /* @@ -317,8 +334,7 @@ void ktruserret(struct thread *); void ktrstruct(const char *, const void *, size_t); void ktrstruct_error(const char *, const void *, size_t, int); void ktrstructarray(const char *, enum uio_seg, const void *, int, size_t); -void ktrcapfail(enum ktr_cap_fail_type, const cap_rights_t *, - const cap_rights_t *); +void ktrcapfail(enum ktr_cap_violation, const void *); #define ktrcaprights(s) \ ktrstruct("caprights", (s), sizeof(cap_rights_t)) #define ktritimerval(s) \ diff --git a/usr.bin/kdump/kdump.c b/usr.bin/kdump/kdump.c index f5bb4dcfea42..f7ac82c757fa 100644 --- a/usr.bin/kdump/kdump.c +++ b/usr.bin/kdump/kdump.c @@ -2125,35 +2125,74 @@ invalid: void ktrcapfail(struct ktr_cap_fail *ktr) { + union ktr_cap_data *kcd = &ktr->cap_data; + switch (ktr->cap_type) { case CAPFAIL_NOTCAPABLE: /* operation on fd with insufficient capabilities */ printf("operation requires "); - sysdecode_cap_rights(stdout, &ktr->cap_needed); + sysdecode_cap_rights(stdout, &kcd->cap_needed); printf(", descriptor holds "); - sysdecode_cap_rights(stdout, &ktr->cap_held); + sysdecode_cap_rights(stdout, &kcd->cap_held); break; case CAPFAIL_INCREASE: /* requested more capabilities than fd already has */ printf("attempt to increase capabilities from "); - sysdecode_cap_rights(stdout, &ktr->cap_held); + sysdecode_cap_rights(stdout, &kcd->cap_held); printf(" to "); - sysdecode_cap_rights(stdout, &ktr->cap_needed); + sysdecode_cap_rights(stdout, &kcd->cap_needed); break; case CAPFAIL_SYSCALL: /* called restricted syscall */ - printf("disallowed system call"); + printf("system call not allowed: "); + syscallname(ktr->cap_code, ktr->cap_svflags); + if (syscallabi(ktr->cap_svflags) == SYSDECODE_ABI_FREEBSD) { + switch (ktr->cap_code) { + case SYS_sysarch: + printf(", op: "); + print_integer_arg(sysdecode_sysarch_number, + kcd->cap_int); + break; + case SYS_fcntl: + printf(", cmd: "); + print_integer_arg(sysdecode_fcntl_cmd, + kcd->cap_int); + break; + } + } break; - case CAPFAIL_LOOKUP: - /* absolute or AT_FDCWD path, ".." path, etc. */ - printf("restricted VFS lookup"); + case CAPFAIL_SIGNAL: + /* sent signal to proc other than self */ + syscallname(ktr->cap_code, ktr->cap_svflags); + printf(": signal delivery not allowed: "); + print_integer_arg(sysdecode_signal, kcd->cap_int); break; - default: - printf("unknown capability failure: "); - sysdecode_cap_rights(stdout, &ktr->cap_needed); - printf(" "); - sysdecode_cap_rights(stdout, &ktr->cap_held); + case CAPFAIL_PROTO: + /* created socket with restricted protocol */ + syscallname(ktr->cap_code, ktr->cap_svflags); + printf(": protocol not allowed: "); + print_integer_arg(sysdecode_ipproto, kcd->cap_int); break; + case CAPFAIL_SOCKADDR: + /* unable to look up address */ + syscallname(ktr->cap_code, ktr->cap_svflags); + printf(": restricted address lookup: "); + ktrsockaddr(&kcd->cap_sockaddr); + return; + case CAPFAIL_NAMEI: + /* absolute or AT_FDCWD path, ".." path, etc. */ + syscallname(ktr->cap_code, ktr->cap_svflags); + printf(": restricted VFS lookup: %s\n", kcd->cap_path); + return; + case CAPFAIL_CPUSET: + /* modification of an external cpuset */ + syscallname(ktr->cap_code, ktr->cap_svflags); + printf(": restricted cpuset operation\n"); + return; + default: + syscallname(ktr->cap_code, ktr->cap_svflags); + printf(": unknown capability failure\n"); + return; } printf("\n"); }