From: Paolo Abeni <pabeni@redhat.com>
To: Chuck Lever <cel@kernel.org>, kuba@kernel.org, edumazet@google.com
Cc: netdev@vger.kernel.org, kernel-tls-handshake@lists.linux.dev,
john.haxby@oracle.com
Subject: Re: [PATCH v7 1/2] net/handshake: Create a NETLINK service for handling handshake requests
Date: Tue, 21 Mar 2023 12:27:54 +0100 [thread overview]
Message-ID: <3dc6b9290984bc07ae5ac9c5a9fba01742b64f84.camel@redhat.com> (raw)
In-Reply-To: <167915629953.91792.17220269709156129944.stgit@manet.1015granger.net>
On Sat, 2023-03-18 at 12:18 -0400, Chuck Lever wrote:
> +/**
> + * handshake_req_alloc - consumer API to allocate a request
> + * @sock: open socket on which to perform a handshake
> + * @proto: security protocol
> + * @flags: memory allocation flags
> + *
> + * Returns an initialized handshake_req or NULL.
> + */
> +struct handshake_req *handshake_req_alloc(struct socket *sock,
> + const struct handshake_proto *proto,
> + gfp_t flags)
> +{
> + struct sock *sk = sock->sk;
> + struct net *net = sock_net(sk);
> + struct handshake_net *hn = handshake_pernet(net);
> + struct handshake_req *req;
> +
> + if (!hn)
> + return NULL;
> +
> + req = kzalloc(struct_size(req, hr_priv, proto->hp_privsize), flags);
> + if (!req)
> + return NULL;
> +
> + sock_hold(sk);
The hr_sk reference counting is unclear to me. It looks like
handshake_req retain a reference to such socket, but
handshake_req_destroy()/handshake_sk_destruct() do not release it.
Perhaps is better moving such sock_hold() into handshake_req_submit(),
once that the request is successful?
> +
> + INIT_LIST_HEAD(&req->hr_list);
> + req->hr_sk = sk;
> + req->hr_proto = proto;
> + return req;
> +}
> +EXPORT_SYMBOL(handshake_req_alloc);
> +
> +/**
> + * handshake_req_private - consumer API to return per-handshake private data
> + * @req: handshake arguments
> + *
> + */
> +void *handshake_req_private(struct handshake_req *req)
> +{
> + return (void *)&req->hr_priv;
> +}
> +EXPORT_SYMBOL(handshake_req_private);
> +
> +static bool __add_pending_locked(struct handshake_net *hn,
> + struct handshake_req *req)
> +{
> + if (!list_empty(&req->hr_list))
> + return false;
> + hn->hn_pending++;
> + list_add_tail(&req->hr_list, &hn->hn_requests);
> + return true;
> +}
> +
> +void __remove_pending_locked(struct handshake_net *hn,
> + struct handshake_req *req)
> +{
> + hn->hn_pending--;
> + list_del_init(&req->hr_list);
> +}
> +
> +/*
> + * Returns %true if the request was found on @net's pending list,
> + * otherwise %false.
> + *
> + * If @req was on a pending list, it has not yet been accepted.
> + */
> +static bool remove_pending(struct handshake_net *hn, struct handshake_req *req)
> +{
> + bool ret;
> +
> + ret = false;
Nit: merge the initialization and the declaration
> +
> + spin_lock(&hn->hn_lock);
> + if (!list_empty(&req->hr_list)) {
> + __remove_pending_locked(hn, req);
> + ret = true;
> + }
> + spin_unlock(&hn->hn_lock);
> +
> + return ret;
> +}
> +
> +/**
> + * handshake_req_submit - consumer API to submit a handshake request
> + * @req: handshake arguments
> + * @flags: memory allocation flags
> + *
> + * Return values:
> + * %0: Request queued
> + * %-EBUSY: A handshake is already under way for this socket
> + * %-ESRCH: No handshake agent is available
> + * %-EAGAIN: Too many pending handshake requests
> + * %-ENOMEM: Failed to allocate memory
> + * %-EMSGSIZE: Failed to construct notification message
> + * %-EOPNOTSUPP: Handshake module not initialized
> + *
> + * A zero return value from handshake_request() means that
> + * exactly one subsequent completion callback is guaranteed.
> + *
> + * A negative return value from handshake_request() means that
> + * no completion callback will be done and that @req has been
> + * destroyed.
> + */
> +int handshake_req_submit(struct handshake_req *req, gfp_t flags)
> +{
> + struct sock *sk = req->hr_sk;
> + struct net *net = sock_net(sk);
> + struct handshake_net *hn = handshake_pernet(net);
> + int ret;
Nit: reverse xmas tree. In this case you have to split declaration and
initialization ;)
> +
> + if (!hn)
> + return -EOPNOTSUPP;
> +
> + ret = -EAGAIN;
> + if (READ_ONCE(hn->hn_pending) >= hn->hn_pending_max)
> + goto out_err;
> +
> + req->hr_odestruct = sk->sk_destruct;
> + sk->sk_destruct = handshake_sk_destruct;
> + spin_lock(&hn->hn_lock);
> + ret = -EOPNOTSUPP;
> + if (test_bit(HANDSHAKE_F_NET_DRAINING, &hn->hn_flags))
> + goto out_unlock;
> + ret = -EBUSY;
> + if (!handshake_req_hash_add(req))
> + goto out_unlock;
> + if (!__add_pending_locked(hn, req))
> + goto out_unlock;
> + spin_unlock(&hn->hn_lock);
> +
> + ret = handshake_genl_notify(net, req->hr_proto->hp_handler_class,
> + flags);
> + if (ret) {
> + trace_handshake_notify_err(net, req, sk, ret);
> + if (remove_pending(hn, req))
> + goto out_err;
> + }
> +
> + trace_handshake_submit(net, req, sk);
> + return 0;
> +
> +out_unlock:
> + spin_unlock(&hn->hn_lock);
> +out_err:
> + trace_handshake_submit_err(net, req, sk, ret);
> + handshake_req_destroy(req);
> + return ret;
> +}
> +EXPORT_SYMBOL(handshake_req_submit);
> +
> +void handshake_complete(struct handshake_req *req, unsigned int status,
> + struct genl_info *info)
> +{
> + struct sock *sk = req->hr_sk;
> + struct net *net = sock_net(sk);
> +
> + if (!test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED, &req->hr_flags)) {
> + trace_handshake_complete(net, req, sk, status);
> + req->hr_proto->hp_done(req, status, info);
> + __sock_put(sk);
Is unclear to me who acquired the reference released above?!? If that
is the reference acquire by handshake_req_alloc(), I think it's cleaner
moving the sock_put() in handshake_req_destroy() or
handshake_req_destroy()
> + }
> +}
> +
> +/**
> + * handshake_req_cancel - consumer API to cancel an in-progress handshake
> + * @sock: socket on which there is an ongoing handshake
> + *
> + * XXX: Perhaps killing the user space agent might also be necessary?
> + *
> + * Request cancellation races with request completion. To determine
> + * who won, callers examine the return value from this function.
> + *
> + * Return values:
> + * %true - Uncompleted handshake request was canceled or not found
> + * %false - Handshake request already completed
> + */
> +bool handshake_req_cancel(struct socket *sock)
> +{
> + struct handshake_req *req;
> + struct handshake_net *hn;
> + struct sock *sk;
> + struct net *net;
> +
> + sk = sock->sk;
> + net = sock_net(sk);
> + req = handshake_req_hash_lookup(sk);
> + if (!req) {
> + trace_handshake_cancel_none(net, req, sk);
> + return true;
> + }
> +
> + hn = handshake_pernet(net);
> + if (hn && remove_pending(hn, req)) {
> + /* Request hadn't been accepted */
> + trace_handshake_cancel(net, req, sk);
> + return true;
> + }
> + if (test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED, &req->hr_flags)) {
> + /* Request already completed */
> + trace_handshake_cancel_busy(net, req, sk);
> + return false;
> + }
> +
> + __sock_put(sk);
Same here.
Side note, I think at this point some tests could surface here? If
user-space-based self-tests are too cumbersome and/or do not offer
adequate coverage perhaps you could consider using kunit?
Cheers,
Paolo
next prev parent reply other threads:[~2023-03-21 11:28 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-03-18 16:18 [PATCH v7 0/2] Another crack at a handshake upcall mechanism Chuck Lever
2023-03-18 16:18 ` [PATCH v7 1/2] net/handshake: Create a NETLINK service for handling handshake requests Chuck Lever
2023-03-20 6:49 ` Hannes Reinecke
2023-03-21 11:27 ` Paolo Abeni [this message]
2023-03-21 13:58 ` Chuck Lever III
2023-03-22 9:03 ` Paolo Abeni
2023-03-22 13:35 ` Chuck Lever III
2023-03-22 16:32 ` Chuck Lever III
2023-03-21 19:55 ` Fwd: " Chuck Lever III
2023-03-22 9:06 ` Paolo Abeni
2023-03-28 18:14 ` Jeff Layton
2023-03-28 18:19 ` Chuck Lever III
2023-03-28 18:32 ` Jeff Layton
2023-03-18 16:18 ` [PATCH v7 2/2] net/tls: Add kernel APIs for requesting a TLSv1.3 handshake Chuck Lever
2023-03-20 6:53 ` Hannes Reinecke
2023-03-18 16:26 ` [PATCH v7 0/2] Another crack at a handshake upcall mechanism Chuck Lever III
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3dc6b9290984bc07ae5ac9c5a9fba01742b64f84.camel@redhat.com \
--to=pabeni@redhat.com \
--cc=cel@kernel.org \
--cc=edumazet@google.com \
--cc=john.haxby@oracle.com \
--cc=kernel-tls-handshake@lists.linux.dev \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.