lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <a2dec2d0-84be-4a4f-bfd4-b5f56219ac82@redhat.com>
Date: Tue, 26 Aug 2025 18:17:09 +0200
From: Paolo Abeni <pabeni@...hat.com>
To: John Ousterhout <ouster@...stanford.edu>, netdev@...r.kernel.org
Cc: edumazet@...gle.com, horms@...nel.org, kuba@...nel.org
Subject: Re: [PATCH net-next v15 14/15] net: homa: create homa_plumbing.c

On 8/18/25 10:55 PM, John Ousterhout wrote:
> +/* This variable contains the address of the statically-allocated struct homa
> + * used throughout Homa. This variable should almost never be used directly:
> + * it should be passed as a parameter to functions that need it. This
> + * variable is used only by a few functions called from Linux where there
> + * is no struct homa* available.
> + */
> +static struct homa *global_homa = &homa_data;

No need for this, use hame_data directly everywhere.

> +static struct proto homav6_prot = {
> +	.name		   = "HOMAv6",
> +	.owner		   = THIS_MODULE,
> +	.close		   = homa_close,
> +	.connect	   = ip6_datagram_connect,
> +	.ioctl		   = homa_ioctl,
> +	.init		   = homa_socket,
> +	.destroy	   = homa_sock_destroy,
> +	.setsockopt	   = homa_setsockopt,
> +	.getsockopt	   = homa_getsockopt,
> +	.sendmsg	   = homa_sendmsg,
> +	.recvmsg	   = homa_recvmsg,
> +	.hash		   = homa_hash,
> +	.unhash		   = homa_unhash,
> +	.obj_size	   = sizeof(struct homa_v6_sock),
> +	.ipv6_pinfo_offset = offsetof(struct homa_v6_sock, inet6),
> +
> +	.no_autobind       = 1,

Minor nit: no empty line above

> +};
> +
> +/* Top-level structure describing the Homa protocol. */
> +static struct inet_protosw homa_protosw = {
> +	.type              = SOCK_DGRAM,
> +	.protocol          = IPPROTO_HOMA,
> +	.prot              = &homa_prot,
> +	.ops               = &homa_proto_ops,
> +	.flags             = INET_PROTOSW_REUSE,
> +};
> +
> +static struct inet_protosw homav6_protosw = {
> +	.type              = SOCK_DGRAM,
> +	.protocol          = IPPROTO_HOMA,
> +	.prot              = &homav6_prot,
> +	.ops               = &homav6_proto_ops,
> +	.flags             = INET_PROTOSW_REUSE,
> +};
> +
> +/* This structure is used by IP to deliver incoming Homa packets to us. */
> +static struct net_protocol homa_protocol = {
> +	.handler =	homa_softirq,
> +	.err_handler =	homa_err_handler_v4,
> +	.no_policy =     1,
> +};
> +
> +static struct inet6_protocol homav6_protocol = {
> +	.handler =	homa_softirq,
> +	.err_handler =	homa_err_handler_v6,
> +	.flags =        INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
> +};
> +
> +/* Sizes of the headers for each Homa packet type, in bytes. */
> +static u16 header_lengths[] = {
> +	sizeof(struct homa_data_hdr),
> +	0,
> +	sizeof(struct homa_resend_hdr),
> +	sizeof(struct homa_rpc_unknown_hdr),
> +	sizeof(struct homa_busy_hdr),
> +	0,
> +	0,
> +	sizeof(struct homa_need_ack_hdr),
> +	sizeof(struct homa_ack_hdr)
> +};
> +
> +/* Thread that runs timer code to detect lost packets and crashed peers. */
> +static struct task_struct *timer_kthread;
> +static DECLARE_COMPLETION(timer_thread_done);
> +
> +/* Used to wakeup timer_kthread at regular intervals. */
> +static struct hrtimer hrtimer;
> +
> +/* Nonzero is an indication to the timer thread that it should exit. */
> +static int timer_thread_exit;
> +
> +/**
> + * homa_load() - invoked when this module is loaded into the Linux kernel
> + * Return: 0 on success, otherwise a negative errno.
> + */
> +int __init homa_load(void)
> +{
> +	struct homa *homa = global_homa;
> +	bool init_protocol6 = false;
> +	bool init_protosw6 = false;
> +	bool init_protocol = false;
> +	bool init_protosw = false;
> +	bool init_net_ops = false;
> +	bool init_proto6 = false;
> +	bool init_proto = false;
> +	bool init_homa = false;
> +	int status;
> +
> +	/* Compile-time validations that no packet header is longer
> +	 * than HOMA_MAX_HEADER.
> +	 */
> +	BUILD_BUG_ON(sizeof(struct homa_data_hdr) > HOMA_MAX_HEADER);
> +	BUILD_BUG_ON(sizeof(struct homa_resend_hdr) > HOMA_MAX_HEADER);
> +	BUILD_BUG_ON(sizeof(struct homa_rpc_unknown_hdr) > HOMA_MAX_HEADER);
> +	BUILD_BUG_ON(sizeof(struct homa_busy_hdr) > HOMA_MAX_HEADER);
> +	BUILD_BUG_ON(sizeof(struct homa_need_ack_hdr) > HOMA_MAX_HEADER);
> +	BUILD_BUG_ON(sizeof(struct homa_ack_hdr) > HOMA_MAX_HEADER);
> +
> +	/* Extra constraints on data packets:
> +	 * - Ensure minimum header length so Homa doesn't have to worry about
> +	 *   padding data packets.
> +	 * - Make sure data packet headers are a multiple of 4 bytes (needed
> +	 *   for TCP/TSO compatibility).
> +	 */
> +	BUILD_BUG_ON(sizeof(struct homa_data_hdr) < HOMA_MIN_PKT_LENGTH);
> +	BUILD_BUG_ON((sizeof(struct homa_data_hdr) -
> +		      sizeof(struct homa_seg_hdr)) & 0x3);
> +
> +	/* Detect size changes in uAPI structs. */
> +	BUILD_BUG_ON(sizeof(struct homa_sendmsg_args) != 24);
> +	BUILD_BUG_ON(sizeof(struct homa_recvmsg_args) != 88);
> +
> +	pr_err("Homa module loading\n");

Please use pr_notice() instead.

> +	status = proto_register(&homa_prot, 1);
> +	if (status != 0) {
> +		pr_err("proto_register failed for homa_prot: %d\n", status);
> +		goto error;
> +	}
> +	init_proto = true;

The standard way of handling the error paths it to avoid local flags and
use different goto labels.

> +
> +	status = proto_register(&homav6_prot, 1);
> +	if (status != 0) {
> +		pr_err("proto_register failed for homav6_prot: %d\n", status);
> +		goto error;
> +	}
> +	init_proto6 = true;
> +
> +	inet_register_protosw(&homa_protosw);
> +	init_protosw = true;
> +
> +	status = inet6_register_protosw(&homav6_protosw);
> +	if (status != 0) {
> +		pr_err("inet6_register_protosw failed in %s: %d\n", __func__,
> +		       status);
> +		goto error;
> +	}
> +	init_protosw6 = true;
> +
> +	status = inet_add_protocol(&homa_protocol, IPPROTO_HOMA);
> +	if (status != 0) {
> +		pr_err("inet_add_protocol failed in %s: %d\n", __func__,
> +		       status);
> +		goto error;
> +	}
> +	init_protocol = true;
> +
> +	status = inet6_add_protocol(&homav6_protocol, IPPROTO_HOMA);
> +	if (status != 0) {
> +		pr_err("inet6_add_protocol failed in %s: %d\n",  __func__,
> +		       status);
> +		goto error;
> +	}
> +	init_protocol6 = true;
> +
> +	status = homa_init(homa);
> +	if (status)
> +		goto error;
> +	init_homa = true;

home_init() should be likely the first call in this function

> +
> +	status = register_pernet_subsys(&homa_net_ops);
> +	if (status != 0) {
> +		pr_err("Homa got error from register_pernet_subsys: %d\n",
> +		       status);
> +		goto error;
> +	}
> +	init_net_ops = true;
> +
> +	timer_kthread = kthread_run(homa_timer_main, homa, "homa_timer");
> +	if (IS_ERR(timer_kthread)) {
> +		status = PTR_ERR(timer_kthread);
> +		pr_err("couldn't create Homa timer thread: error %d\n",
> +		       status);
> +		timer_kthread = NULL;
> +		goto error;
> +	}
> +
> +	return 0;
> +
> +error:
> +	if (timer_kthread) {
> +		timer_thread_exit = 1;
> +		wake_up_process(timer_kthread);
> +		wait_for_completion(&timer_thread_done);
> +	}
> +	if (init_net_ops)
> +		unregister_pernet_subsys(&homa_net_ops);
> +	if (init_homa)
> +		homa_destroy(homa);
> +	if (init_protocol)
> +		inet_del_protocol(&homa_protocol, IPPROTO_HOMA);
> +	if (init_protocol6)
> +		inet6_del_protocol(&homav6_protocol, IPPROTO_HOMA);
> +	if (init_protosw)
> +		inet_unregister_protosw(&homa_protosw);
> +	if (init_protosw6)
> +		inet6_unregister_protosw(&homav6_protosw);
> +	if (init_proto)
> +		proto_unregister(&homa_prot);
> +	if (init_proto6)
> +		proto_unregister(&homav6_prot);
> +	return status;
> +}
> +
> +/**
> + * homa_unload() - invoked when this module is unloaded from the Linux kernel.
> + */
> +void __exit homa_unload(void)
> +{
> +	struct homa *homa = global_homa;
> +
> +	pr_notice("Homa module unloading\n");
> +
> +	unregister_pernet_subsys(&homa_net_ops);
> +	homa_destroy(homa);

home_destroy() should likely be the last call of this function.

> +/**
> + * homa_softirq() - This function is invoked at SoftIRQ level to handle
> + * incoming packets.
> + * @skb:   The incoming packet.
> + * Return: Always 0
> + */
> +int homa_softirq(struct sk_buff *skb)
> +{
> +	struct sk_buff *packets, *other_pkts, *next;
> +	struct sk_buff **prev_link, **other_link;
> +	struct homa_common_hdr *h;
> +	int header_offset;
> +
> +	/* skb may actually contain many distinct packets, linked through
> +	 * skb_shinfo(skb)->frag_list by the Homa GRO mechanism. Make a
> +	 * pass through the list to process all of the short packets,
> +	 * leaving the longer packets in the list. Also, perform various
> +	 * prep/cleanup/error checking functions.

It's hard to tell without the GRO/GSO code handy, but I guess the
implementation here could be simplified invoking __skb_gso_segment()...

> +	 */
> +	skb->next = skb_shinfo(skb)->frag_list;
> +	skb_shinfo(skb)->frag_list = NULL;
> +	packets = skb;
> +	prev_link = &packets;
> +	for (skb = packets; skb; skb = next) {
> +		next = skb->next;
> +
> +		/* Make the header available at skb->data, even if the packet
> +		 * is fragmented. One complication: it's possible that the IP
> +		 * header hasn't yet been removed (this happens for GRO packets
> +		 * on the frag_list, since they aren't handled explicitly by IP.

... at very least it will avoif this complication and will simplify the
list handling.

> +		 */
> +		if (!homa_make_header_avl(skb))
> +			goto discard;

It looks like the above is too aggressive, i.e. pskb_may_pull() may fail
for a correctly formatted homa_ack_hdr - or any other packet with hdr
size < HOMA_MAX_HEADER

> +		header_offset = skb_transport_header(skb) - skb->data;
> +		if (header_offset)
> +			__skb_pull(skb, header_offset);
> +
> +		/* Reject packets that are too short or have bogus types. */
> +		h = (struct homa_common_hdr *)skb->data;
> +		if (unlikely(skb->len < sizeof(struct homa_common_hdr) ||
> +			     h->type < DATA || h->type > MAX_OP ||
> +			     skb->len < header_lengths[h->type - DATA]))
> +			goto discard;
> +
> +		/* Process the packet now if it is a control packet or
> +		 * if it contains an entire short message.
> +		 */
> +		if (h->type != DATA || ntohl(((struct homa_data_hdr *)h)
> +				->message_length) < 1400) {

I could not fined where `message_length` is validated. AFAICS
data_hdr->message_length could be > skb->len.

Also I don't see how the condition checked above ensures that the pkt
contains the whole message.

/P


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ