Page MenuHomeFreeBSD

D50653.id156670.diff
No OneTemporary

D50653.id156670.diff

diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c
--- a/sys/kern/kern_prot.c
+++ b/sys/kern/kern_prot.c
@@ -2150,6 +2150,44 @@
CTLFLAG_MPSAFE, 0, 0, sysctl_unprivileged_proc_debug, "I",
"Unprivileged processes may use process debugging facilities");
+/*
+ * Return true if the object owner/group ids are subset of the active
+ * credentials.
+ */
+bool
+cr_xids_subset(struct ucred *active_cred, struct ucred *obj_cred)
+{
+ int i;
+ bool grpsubset, uidsubset;
+
+ /*
+ * Is p's group set a subset of td's effective group set? This
+ * includes p's egid, group access list, rgid, and svgid.
+ */
+ grpsubset = true;
+ for (i = 0; i < obj_cred->cr_ngroups; i++) {
+ if (!groupmember(obj_cred->cr_groups[i], active_cred)) {
+ grpsubset = false;
+ break;
+ }
+ }
+ grpsubset = grpsubset &&
+ groupmember(obj_cred->cr_rgid, active_cred) &&
+ groupmember(obj_cred->cr_svgid, active_cred);
+
+ /*
+ * Are the uids present in obj_cred's credential equal to
+ * active_cred's effective uid? This includes obj_cred's
+ * euid, svuid, and ruid.
+ */
+ uidsubset = (active_cred->cr_uid == obj_cred->cr_uid &&
+ active_cred->cr_uid == obj_cred->cr_svuid &&
+ active_cred->cr_uid == obj_cred->cr_ruid);
+
+ return (uidsubset && grpsubset);
+
+}
+
/*-
* Determine whether td may debug p.
* Returns: 0 for permitted, an errno value otherwise
@@ -2161,7 +2199,7 @@
int
p_candebug(struct thread *td, struct proc *p)
{
- int error, grpsubset, i, uidsubset;
+ int error;
KASSERT(td == curthread, ("%s: td not curthread", __func__));
PROC_LOCK_ASSERT(p, MA_OWNED);
@@ -2178,35 +2216,12 @@
if ((error = cr_bsd_visible(td->td_ucred, p->p_ucred)))
return (error);
- /*
- * Is p's group set a subset of td's effective group set? This
- * includes p's egid, group access list, rgid, and svgid.
- */
- grpsubset = 1;
- for (i = 0; i < p->p_ucred->cr_ngroups; i++) {
- if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) {
- grpsubset = 0;
- break;
- }
- }
- grpsubset = grpsubset &&
- groupmember(p->p_ucred->cr_rgid, td->td_ucred) &&
- groupmember(p->p_ucred->cr_svgid, td->td_ucred);
-
- /*
- * Are the uids present in p's credential equal to td's
- * effective uid? This includes p's euid, svuid, and ruid.
- */
- uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid &&
- td->td_ucred->cr_uid == p->p_ucred->cr_svuid &&
- td->td_ucred->cr_uid == p->p_ucred->cr_ruid);
-
/*
* If p's gids aren't a subset, or the uids aren't a subset,
* or the credential has changed, require appropriate privilege
* for td to debug p.
*/
- if (!grpsubset || !uidsubset) {
+ if (!cr_xids_subset(td->td_ucred, p->p_ucred)) {
error = priv_check(td, PRIV_DEBUG_DIFFCRED);
if (error)
return (error);
diff --git a/sys/kern/uipc_ktls.c b/sys/kern/uipc_ktls.c
--- a/sys/kern/uipc_ktls.c
+++ b/sys/kern/uipc_ktls.c
@@ -595,6 +595,8 @@
return (error);
}
+uint64_t ktls_glob_gen = 1;
+
static int
ktls_create_session(struct socket *so, struct tls_enable *en,
struct ktls_session **tlsp, int direction)
@@ -819,6 +821,8 @@
arc4rand(tls->params.iv + 8, sizeof(uint64_t), 0);
}
+ atomic_thread_fence_rel();
+ tls->gen = atomic_fetchadd_64(&ktls_glob_gen, 1);
*tlsp = tls;
return (0);
}
@@ -861,6 +865,8 @@
memcpy(tls_new->params.cipher_key, tls->params.cipher_key,
tls->params.cipher_key_len);
+ atomic_thread_fence_rel();
+ tls_new->gen = atomic_fetchadd_64(&ktls_glob_gen, 1);
return (tls_new);
}
@@ -1940,6 +1946,8 @@
MPASS(tls->refcount == 0);
+ atomic_add_acq_64(&ktls_glob_gen, 1);
+
inp = tls->inp;
if (tls->tx) {
wlocked = INP_WLOCKED(inp);
@@ -3439,3 +3447,51 @@
TASK_INIT(&tls->disable_ifnet_task, 0, ktls_disable_ifnet_help, tls);
(void)taskqueue_enqueue(taskqueue_thread, &tls->disable_ifnet_task);
}
+
+void
+ktls_session_to_xktls_onedir(const struct ktls_session *ktls,
+ struct xktls_session_onedir *xk)
+{
+ if_t ifp;
+ struct m_snd_tag *st;
+
+ memcpy(&xk->iv, &ktls->params.iv, TLS_CBC_IMPLICIT_IV_LEN);
+ xk->gen = ktls->gen;
+#define A(m) xk->m = ktls->params.m
+ A(cipher_algorithm);
+ A(auth_algorithm);
+ A(cipher_key_len);
+ A(iv_len);
+ A(auth_key_len);
+ A(max_frame_len);
+ A(tls_vmajor);
+ A(tls_vminor);
+ A(tls_hlen);
+ A(tls_tlen);
+ A(tls_bs);
+ A(flags);
+#undef A
+ if ((st = ktls->snd_tag) != NULL &&
+ (ifp = ktls->snd_tag->ifp) != NULL)
+ strncpy(xk->ifnet, if_name(ifp), sizeof(xk->ifnet));
+}
+
+void
+ktls_session_copy_keys(const struct ktls_session *ktls,
+ uint8_t *data, size_t *sz)
+{
+ size_t t, ta, tc;
+
+ if (ktls == NULL) {
+ *sz = 0;
+ return;
+ }
+ t = *sz;
+ tc = MIN(t, ktls->params.cipher_key_len);
+ if (data != NULL)
+ memcpy(data, ktls->params.cipher_key, tc);
+ ta = MIN(t - tc, ktls->params.auth_key_len);
+ if (data != NULL)
+ memcpy(data + tc, ktls->params.auth_key, ta);
+ *sz = ta + tc;
+}
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -297,12 +297,14 @@
typedef int (if_snd_tag_query_t)(struct m_snd_tag *, union if_snd_tag_query_params *);
typedef void (if_snd_tag_free_t)(struct m_snd_tag *);
typedef struct m_snd_tag *(if_next_send_tag_t)(struct m_snd_tag *);
+typedef int (if_snd_tag_status_str_t)(struct m_snd_tag *, char *buf, size_t *sz);
struct if_snd_tag_sw {
if_snd_tag_modify_t *snd_tag_modify;
if_snd_tag_query_t *snd_tag_query;
if_snd_tag_free_t *snd_tag_free;
if_next_send_tag_t *next_snd_tag;
+ if_snd_tag_status_str_t *snd_tag_status_str;
u_int type; /* One of IF_SND_TAG_TYPE_*. */
};
diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h
--- a/sys/netinet/in_pcb.h
+++ b/sys/netinet/in_pcb.h
@@ -303,6 +303,30 @@
char sop_optval[];
};
+#ifdef _SYS_KTLS_H_
+struct xktls_session {
+ uint32_t tsz; /* total sz of elm, next elm is at this+tsz */
+ uint32_t fsz; /* size of the struct up to keys */
+ uint64_t inp_gencnt;
+ kvaddr_t so_pcb;
+ struct in_conninfo coninf;
+ u_short rx_vlan_id;
+ struct xktls_session_onedir rcv;
+ struct xktls_session_onedir snd;
+/*
+ * Next are
+ * - keydata for rcv, first cipher of length rcv.cipher_key_len, then
+ * authentication of length rcv.auth_key_len;
+ * - driver data (string) of length rcv.drv_st_len, if the rcv session is
+ * offloaded to ifnet rcv.ifnet;
+ * - keydata for snd, first cipher of length snd.cipher_key_len, then
+ * authentication of length snd.auth_key_len;
+ * - driver data (string) of length snd.drv_st_len, if the snd session is
+ * offloaded to ifnet snd.ifnet;
+ */
+};
+#endif /* _SYS_KTLS_H_ */
+
#ifdef _KERNEL
int sysctl_setsockopt(SYSCTL_HANDLER_ARGS, struct inpcbinfo *pcbinfo,
int (*ctloutput_set)(struct inpcb *, struct sockopt *));
diff --git a/sys/netinet/in_prot.c b/sys/netinet/in_prot.c
--- a/sys/netinet/in_prot.c
+++ b/sys/netinet/in_prot.c
@@ -26,21 +26,17 @@
*/
/*
- * System calls related to processes and protection
+ * Helpers related to visibility and protection of sockets and inpcb.
*/
-#include <sys/cdefs.h>
-#include "opt_inet.h"
-#include "opt_inet6.h"
-
-#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/jail.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mutex.h>
+#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/socket.h>
-#include <sys/jail.h>
#include <netinet/in.h>
#include <netinet/in_pcb.h>
@@ -72,3 +68,16 @@
return (0);
}
+
+bool
+cr_canexport_ktlskeys(struct thread *td, struct inpcb *inp)
+{
+ int error;
+
+ if (cr_canseeinpcb(td->td_ucred, inp) == 0 &&
+ cr_xids_subset(td->td_ucred, inp->inp_cred))
+ return (true);
+ error = priv_check(td, PRIV_NETINET_KTLSKEYS);
+ return (error == 0);
+
+}
diff --git a/sys/netinet/in_systm.h b/sys/netinet/in_systm.h
--- a/sys/netinet/in_systm.h
+++ b/sys/netinet/in_systm.h
@@ -58,8 +58,10 @@
#ifdef _KERNEL
struct inpcb;
struct ucred;
+struct thread;
int cr_canseeinpcb(struct ucred *cred, struct inpcb *inp);
+bool cr_canexport_ktlskeys(struct thread *td, struct inpcb *inp);
uint32_t iptime(void);
#endif
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -2664,6 +2664,219 @@
NULL, 0, tcp_pcblist, "S,xtcpcb",
"List of active TCP connections");
+#define SND_TAG_STATUS_MAXLEN 128
+
+#ifdef KERN_TLS
+static int
+tcp_ktlslist(SYSCTL_HANDLER_ARGS, bool export_keys)
+{
+ struct xinpgen xig;
+ struct inpcb *inp;
+ struct socket *so;
+ struct ktls_session *ksr, *kss;
+ char *buf;
+ struct xktls_session *xktls;
+ uint64_t ipi_gencnt;
+ size_t buflen, len, sz;
+ u_int cnt;
+ int error;
+ bool p;
+
+ if (req->newptr != NULL)
+ return (EPERM);
+
+ len = 0;
+ cnt = 0;
+ ipi_gencnt = V_tcbinfo.ipi_gencnt;
+ bzero(&xig, sizeof(xig));
+ xig.xig_len = sizeof(xig);
+ xig.xig_gen = atomic_load_acq_64(&ktls_glob_gen);
+ xig.xig_sogen = so_gencnt;
+
+ struct inpcb_iterator inpi = INP_ALL_ITERATOR(&V_tcbinfo,
+ INPLOOKUP_RLOCKPCB);
+ while ((inp = inp_next(&inpi)) != NULL) {
+ if (inp->inp_gencnt > ipi_gencnt ||
+ cr_canseeinpcb(req->td->td_ucred, inp) != 0)
+ continue;
+
+ so = inp->inp_socket;
+ if (so != NULL && so->so_gencnt <= xig.xig_sogen) {
+ p = false;
+ ksr = so->so_rcv.sb_tls_info;
+ if (ktls_session_genvis(ksr, xig.xig_gen)) {
+ p = true;
+ if (export_keys && cr_canexport_ktlskeys(
+ req->td, inp)) {
+ sz = SIZE_T_MAX;
+ ktls_session_copy_keys(ksr,
+ NULL, &sz);
+ len += sz;
+ }
+ if (ksr->snd_tag != NULL &&
+ ksr->snd_tag->sw->snd_tag_status_str !=
+ NULL) {
+ sz = SND_TAG_STATUS_MAXLEN;
+ ksr->snd_tag->sw->snd_tag_status_str(
+ ksr->snd_tag, NULL, &sz);
+ len += sz;
+ }
+ }
+ kss = so->so_snd.sb_tls_info;
+ if (ktls_session_genvis(kss, xig.xig_gen)) {
+ p = true;
+ if (export_keys && cr_canexport_ktlskeys(
+ req->td, inp)) {
+ sz = SIZE_T_MAX;
+ ktls_session_copy_keys(kss,
+ NULL, &sz);
+ len += sz;
+ }
+ if (kss->snd_tag != NULL &&
+ kss->snd_tag->sw->snd_tag_status_str !=
+ NULL) {
+ sz = SND_TAG_STATUS_MAXLEN;
+ kss->snd_tag->sw->snd_tag_status_str(
+ kss->snd_tag, NULL, &sz);
+ len += sz;
+ }
+ }
+ if (p) {
+ len += sizeof(*xktls);
+ len = roundup2(len, __alignof(struct
+ xktls_session));
+ }
+ }
+ }
+ if (req->oldptr == NULL) {
+ len += 2 * sizeof(xig);
+ len += 3 * len / 4;
+ req->oldidx = len;
+ return (0);
+ }
+
+ if ((error = sysctl_wire_old_buffer(req, 0)) != 0)
+ return (error);
+
+ error = SYSCTL_OUT(req, &xig, sizeof xig);
+ if (error != 0)
+ return (error);
+
+ buflen = roundup2(sizeof(*xktls) + 2 * TLS_MAX_PARAM_SIZE +
+ 2 * SND_TAG_STATUS_MAXLEN, __alignof(struct xktls_session));
+ buf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO);
+ struct inpcb_iterator inpi1 = INP_ALL_ITERATOR(&V_tcbinfo,
+ INPLOOKUP_RLOCKPCB);
+ while ((inp = inp_next(&inpi1)) != NULL) {
+ if (inp->inp_gencnt > ipi_gencnt ||
+ cr_canseeinpcb(req->td->td_ucred, inp) != 0)
+ continue;
+
+ so = inp->inp_socket;
+ if (so == NULL)
+ continue;
+
+ p = false;
+ ksr = so->so_rcv.sb_tls_info;
+ kss = so->so_snd.sb_tls_info;
+ xktls = (struct xktls_session *)buf;
+ if (ktls_session_genvis(ksr, xig.xig_gen)) {
+ p = true;
+ ktls_session_to_xktls_onedir(ksr, &xktls->rcv);
+ }
+ if (ktls_session_genvis(kss, xig.xig_gen)) {
+ p = true;
+ ktls_session_to_xktls_onedir(kss, &xktls->snd);
+ }
+ if (!p)
+ continue;
+
+ xktls->inp_gencnt = inp->inp_gencnt;
+ xktls->so_pcb = (kvaddr_t)inp;
+ memcpy(&xktls->coninf, &inp->inp_inc, sizeof(xktls->coninf));
+ len = sizeof(*xktls);
+ if (ktls_session_genvis(ksr, xig.xig_gen)) {
+ if (export_keys && cr_canexport_ktlskeys(req->td,
+ inp)) {
+ sz = buflen - len;
+ ktls_session_copy_keys(ksr, buf + len, &sz);
+ len += sz;
+ } else {
+ xktls->rcv.cipher_key_len = 0;
+ xktls->rcv.auth_key_len = 0;
+ }
+ if (ksr->snd_tag != NULL &&
+ ksr->snd_tag->sw->snd_tag_status_str != NULL) {
+ sz = SND_TAG_STATUS_MAXLEN;
+ ksr->snd_tag->sw->snd_tag_status_str(
+ ksr->snd_tag, buf + len, &sz);
+ len += sz;
+ }
+ }
+ if (ktls_session_genvis(kss, xig.xig_gen)) {
+ if (export_keys && cr_canexport_ktlskeys(req->td,
+ inp)) {
+ sz = buflen - len;
+ ktls_session_copy_keys(kss, buf + len, &sz);
+ len += sz;
+ } else {
+ xktls->snd.cipher_key_len = 0;
+ xktls->snd.auth_key_len = 0;
+ }
+ if (kss->snd_tag != NULL &&
+ kss->snd_tag->sw->snd_tag_status_str != NULL) {
+ sz = SND_TAG_STATUS_MAXLEN;
+ kss->snd_tag->sw->snd_tag_status_str(
+ kss->snd_tag, buf + len, &sz);
+ len += sz;
+ }
+ }
+ len = roundup2(len, __alignof(*xktls));
+ xktls->tsz = len;
+ xktls->fsz = sizeof(*xktls);
+
+ error = SYSCTL_OUT(req, xktls, len);
+ if (error != 0) {
+ INP_RUNLOCK(inp);
+ break;
+ }
+ cnt++;
+ }
+
+ if (error == 0) {
+ atomic_thread_fence_rel();
+ xig.xig_gen = atomic_load_64(&ktls_glob_gen);
+ xig.xig_sogen = so_gencnt;
+ xig.xig_count = cnt;
+ error = SYSCTL_OUT(req, &xig, sizeof(xig));
+ }
+
+ free(buf, M_TEMP);
+ return (error);
+}
+
+static int
+tcp_ktlslist_nokeys(SYSCTL_HANDLER_ARGS)
+{
+ return (tcp_ktlslist(oidp, arg1, arg2, req, false));
+}
+
+static int
+tcp_ktlslist_wkeys(SYSCTL_HANDLER_ARGS)
+{
+ return (tcp_ktlslist(oidp, arg1, arg2, req, true));
+}
+
+SYSCTL_PROC(_net_inet_tcp, TCPCTL_KTLSLIST, ktlslist,
+ CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ NULL, 0, tcp_ktlslist_nokeys, "S,xktls_session",
+ "List of active kTLS sessions for TCP connections");
+SYSCTL_PROC(_net_inet_tcp, TCPCTL_KTLSLIST_WKEYS, ktlslist_wkeys,
+ CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ NULL, 0, tcp_ktlslist_wkeys, "S,xktls_session",
+ "List of active kTLS sessions for TCP connections with keys");
+#endif /* KERN_TLS */
+
#ifdef INET
static int
tcp_getcred(SYSCTL_HANDLER_ARGS)
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -1234,6 +1234,8 @@
#define TCPCTL_SACK 14 /* Selective Acknowledgement,rfc 2018 */
#define TCPCTL_DROP 15 /* drop tcp connection */
#define TCPCTL_STATES 16 /* connection counts by TCP state */
+#define TCPCTL_KTLSLIST 17
+#define TCPCTL_KTLSLIST_WKEYS 18
#ifdef _KERNEL
#ifdef SYSCTL_DECL
diff --git a/sys/sys/ktls.h b/sys/sys/ktls.h
--- a/sys/sys/ktls.h
+++ b/sys/sys/ktls.h
@@ -145,6 +145,27 @@
uint16_t tls_length;
};
+struct xktls_session_onedir {
+ uint64_t gen;
+ uint64_t rsrv1[8];
+ uint32_t rsrv2[8];
+ uint8_t iv[TLS_CBC_IMPLICIT_IV_LEN];
+ int cipher_algorithm;
+ int auth_algorithm;
+ uint16_t cipher_key_len;
+ uint16_t iv_len;
+ uint16_t auth_key_len;
+ uint16_t max_frame_len;
+ uint8_t tls_vmajor;
+ uint8_t tls_vminor;
+ uint8_t tls_hlen;
+ uint8_t tls_tlen;
+ uint8_t tls_bs;
+ uint8_t flags;
+ uint16_t drv_st_len;
+ char ifnet[16]; /* IFNAMSIZ */
+};
+
#ifdef _KERNEL
struct tls_session_params {
@@ -206,9 +227,12 @@
/* Used to destroy any kTLS session */
struct task destroy_task;
+
+ uint64_t gen;
} __aligned(CACHE_LINE_SIZE);
extern unsigned int ktls_ifnet_max_rexmit_pct;
+extern uint64_t ktls_glob_gen;
typedef enum {
KTLS_MBUF_CRYPTO_ST_MIXED = 0,
@@ -258,5 +282,16 @@
ktls_destroy(tls);
}
+static inline bool
+ktls_session_genvis(const struct ktls_session *ks, uint64_t gen)
+{
+ return (ks != NULL && ks->gen <= gen);
+}
+
+void ktls_session_to_xktls_onedir(const struct ktls_session *ks,
+ struct xktls_session_onedir *xktls_od);
+void ktls_session_copy_keys(const struct ktls_session *ktls,
+ uint8_t *data, size_t *sz);
+
#endif /* !_KERNEL */
#endif /* !_SYS_KTLS_H_ */
diff --git a/sys/sys/priv.h b/sys/sys/priv.h
--- a/sys/sys/priv.h
+++ b/sys/sys/priv.h
@@ -406,6 +406,7 @@
#define PRIV_NETINET_SETHDROPTS 505 /* Set certain IPv4/6 header options. */
#define PRIV_NETINET_BINDANY 506 /* Allow bind to any address. */
#define PRIV_NETINET_HASHKEY 507 /* Get and set hash keys for IPv4/6. */
+#define PRIV_NETINET_KTLSKEYS 508 /* Read ktls session keys. */
/*
* Placeholders for IPX/SPX privileges, not supported any more.
diff --git a/sys/sys/ucred.h b/sys/sys/ucred.h
--- a/sys/sys/ucred.h
+++ b/sys/sys/ucred.h
@@ -237,6 +237,7 @@
void crsetgroups(struct ucred *cr, int ngrp, const gid_t *groups);
void crsetgroups_fallback(struct ucred *cr, int ngrp, const gid_t *groups,
const gid_t fallback);
+bool cr_xids_subset(struct ucred *active_cred, struct ucred *obj_cred);
/*
* Returns whether gid designates a primary group in cred.

File Metadata

Mime Type
text/plain
Expires
Mon, Feb 9, 3:20 PM (11 m, 54 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28593280
Default Alt Text
D50653.id156670.diff (16 KB)

Event Timeline