All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jakub Kicinski <kuba@kernel.org>
To: Kees Cook <keescook@chromium.org>
Cc: Dmitry Vyukov <dvyukov@google.com>,
	syzbot <syzbot+3a080099974c271cd7e9@syzkaller.appspotmail.com>,
	bpf@vger.kernel.org, davem@davemloft.net, edumazet@google.com,
	fw@strlen.de, harshit.m.mogalapalli@oracle.com,
	linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
	pabeni@redhat.com, syzkaller-bugs@googlegroups.com,
	linux-hardening@vger.kernel.org
Subject: Re: [syzbot] upstream boot error: WARNING in netlink_ack
Date: Tue, 4 Oct 2022 17:04:00 -0700	[thread overview]
Message-ID: <20221004170400.52c97523@kernel.org> (raw)
In-Reply-To: <202210041600.7C90DF917@keescook>

On Tue, 4 Oct 2022 16:40:32 -0700 Kees Cook wrote:
> On Tue, Oct 04, 2022 at 10:42:53AM -0700, Jakub Kicinski wrote:
> > This has been weighing on my conscience a little, I don't like how we
> > still depend on putting one length in the skb and then using a
> > different one for the actual memcpy(). How would you feel about this
> > patch on top (untested):  
> 
> tl;dr: yes, I like it. Please add a nlmsg_contents member. :)

Can do, but you'll need to tell me how..

	__DECLARE_FLEX_ARRAY(char, nlmsg_contents)

?

> > +				 u32 size)
> > +{
> > +	if (unlikely(skb_tailroom(skb) < NLMSG_ALIGN(size)))
> > +		return NULL;
> > +
> > +	if (!__builtin_constant_p(size) || NLMSG_ALIGN(size) - size != 0)  
> 
> why does a fixed size mean no memset?

Copy and paste, it seems to originate from:

0c19b0adb8dd ("netlink: avoid memset of 0 bytes sparse warning")

Any idea why sparse would not like empty memsets?

> >  	rep = nlmsg_put(skb, NETLINK_CB(in_skb).portid, nlh->nlmsg_seq,
> > -			NLMSG_ERROR, payload, flags);
> > +			NLMSG_ERROR, sizeof(*errmsg), flags);
> > +	if (!rep)
> > +		goto err_bad_put;
> >  	errmsg = nlmsg_data(rep);
> >  	errmsg->error = err;
> > -	unsafe_memcpy(&errmsg->msg, nlh, payload > sizeof(*errmsg)
> > -					 ? nlh->nlmsg_len : sizeof(*nlh),
> > -		      /* Bounds checked by the skb layer. */);
> > +	memcpy(&errmsg->msg, nlh, sizeof(*nlh));
> > +
> > +	if (!(flags & NLM_F_CAPPED)) {  
> 
> Should it test this flag, or test if the sizes show the need for "extra"
> payload length?
> 
> I always found the progression of sizes here to be confusing. "payload"
> starts as sizeof(*errmsg), and gets nlmsg_len(nlh) added but only when if
> "(err && !(nlk->flags & NETLINK_F_CAP_ACK)" was true.

struct nlmsgerr is one of the least badly documented structs we have in
netlink so let me start with a copy & paste:

struct nlmsgerr {
	int		error;
	struct nlmsghdr msg;
	/*
	 * followed by the message contents unless NETLINK_CAP_ACK was set
	 * or the ACK indicates success (error == 0)
	 * message length is aligned with NLMSG_ALIGN()
	 */
	/*
	 * followed by TLVs defined in enum nlmsgerr_attrs
	 * if NETLINK_EXT_ACK was set
	 */
};

*Why* that's the behavior - 🤷

> Why is nlmsg_len(nlh) _wrong_ if the rest of its contents are
> correct? 

This is an ack message, to be clear, doesn't mean anything was wrong.
It just carries errno.

> If this was "0" in the other state, the logic would just be:
> 
> 	nlh_bytes = nlmsg_len(nlh);
> 	total  = sizeof(*errmsg);
> 	total += nlh_bytes;
> 	total += tlvlen;
> 
> and:
> 
> 	nlmsg_new(total, ...);
> 	... nlmsg_put(..., sizeof(*errmsg), ...);
> 	...
> 	errmsg->error = err;
> 	errmsg->nlh = *nlh;
> 	if (nlh_bytes) {
> 		data = nlmsg_append(..., nlh_bytes), ...);
> 		...
> 		memcpy(data, nlh->nlmsg_contents, nlh_bytes);
> 	}
> 
> > +		size_t data_len = nlh->nlmsg_len - sizeof(*nlh);  
> 
> I think data_len here is also "payload - sizeof(*errmsg)"? So if it's
> >0, we need to append the nlh contents.

I was trying to avoid using payload in case it has overflown :S

> > +		void *data;
> > +
> > +		data = nlmsg_append(skb, rep, data_len);
> > +		if (!data)
> > +			goto err_bad_put;
> > +
> > +		/* the nlh + 1 is probably going to make you
> > unhappy? */  
> 
> Right, the compiler may think it is an object no larger than
> sizeof(*nlh). My earliest attempt at changes here introduced a
> flex-array for the contents, and split the memcpy:
> https://lore.kernel.org/lkml/d7251d92-150b-5346-6237-52afc154bb00@rasmusvillemoes.dk/
> which is basically the solution you have here, except it wasn't having
> the nlmsg_*-helpers do the bounds checking.
> 
> > +		memcpy(data, nlh + 1, data_len);  
> 
> So with the struct nlmsghdr::nlmsg_contents member, this becomes:
> 
> 		memcpy(data, nlh->nlmsg_contents, data_len);
> 

  reply	other threads:[~2022-10-05  0:04 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-04  8:27 [syzbot] upstream boot error: WARNING in netlink_ack syzbot
2022-10-04  8:33 ` Dmitry Vyukov
2022-10-04 14:36   ` Kees Cook
2022-10-04 17:42     ` Jakub Kicinski
2022-10-04 23:40       ` Kees Cook
2022-10-05  0:04         ` Jakub Kicinski [this message]
2022-10-05  0:23           ` Jakub Kicinski
2022-10-05  0:28         ` [RFC] netlink: split up copies in the ack construction Jakub Kicinski
2022-10-05  3:03           ` Kees Cook
     [not found] <PH8PR10MB6290511E9C0A3D20E1C222EEC25A9@PH8PR10MB6290.namprd10.prod.outlook.com>
2022-10-04 12:57 ` [syzbot] upstream boot error: WARNING in netlink_ack syzbot

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=20221004170400.52c97523@kernel.org \
    --to=kuba@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=davem@davemloft.net \
    --cc=dvyukov@google.com \
    --cc=edumazet@google.com \
    --cc=fw@strlen.de \
    --cc=harshit.m.mogalapalli@oracle.com \
    --cc=keescook@chromium.org \
    --cc=linux-hardening@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=syzbot+3a080099974c271cd7e9@syzkaller.appspotmail.com \
    --cc=syzkaller-bugs@googlegroups.com \
    /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.