[PATCH v3 1/9] net: Add struct sockaddr_unspec for sockaddr of unknown length

Kees Cook posted 9 patches 3 months, 2 weeks ago
[PATCH v3 1/9] net: Add struct sockaddr_unspec for sockaddr of unknown length
Posted by Kees Cook 3 months, 2 weeks ago
Add flexible sockaddr structure to support addresses longer than the
traditional 14-byte struct sockaddr::sa_data limitation without
requiring the full 128-byte sa_data of struct sockaddr_storage. This
allows the network APIs to pass around a pointer to an object that
isn't lying to the compiler about how big it is, but must be accompanied
by its actual size as an additional parameter.

It's possible we may way to migrate to including the size with the
struct in the future, e.g.:

struct sockaddr_unspec {
	u16 sa_data_len;
	u16 sa_family;
	u8  sa_data[] __counted_by(sa_data_len);
};

Signed-off-by: Kees Cook <kees@kernel.org>
---
 include/linux/socket.h | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/include/linux/socket.h b/include/linux/socket.h
index 3b262487ec06..27f57c7ee02a 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -40,6 +40,23 @@ struct sockaddr {
 	};
 };
 
+/**
+ * struct sockaddr_unspec - Unspecified size sockaddr for callbacks
+ * @sa_family: Address family (AF_UNIX, AF_INET, AF_INET6, etc.)
+ * @sa_data: Flexible array for address data
+ *
+ * This structure is designed for callback interfaces where the
+ * total size is known via the sockaddr_len parameter. Unlike struct
+ * sockaddr which has a fixed 14-byte sa_data limit or struct
+ * sockaddr_storage which has a fixed 128-byte sa_data limit, this
+ * structure can accommodate addresses of any size, but must be used
+ * carefully.
+ */
+struct sockaddr_unspec {
+	__kernel_sa_family_t	sa_family;	/* address family, AF_xxx */
+	char			sa_data[];	/* flexible address data */
+};
+
 struct linger {
 	int		l_onoff;	/* Linger active		*/
 	int		l_linger;	/* How long to linger for	*/
-- 
2.34.1
Re: [PATCH v3 1/9] net: Add struct sockaddr_unspec for sockaddr of unknown length
Posted by Paolo Abeni 3 months, 2 weeks ago
On 10/20/25 11:26 PM, Kees Cook wrote:
> Add flexible sockaddr structure to support addresses longer than the
> traditional 14-byte struct sockaddr::sa_data limitation without
> requiring the full 128-byte sa_data of struct sockaddr_storage. This
> allows the network APIs to pass around a pointer to an object that
> isn't lying to the compiler about how big it is, but must be accompanied
> by its actual size as an additional parameter.
> 
> It's possible we may way to migrate to including the size with the
> struct in the future, e.g.:
> 
> struct sockaddr_unspec {
> 	u16 sa_data_len;
> 	u16 sa_family;
> 	u8  sa_data[] __counted_by(sa_data_len);
> };
> 
> Signed-off-by: Kees Cook <kees@kernel.org>

Another side note: please include the 'net-next' subj prefix in next
submissions, otherwise patchwork could be fouled, and the patches will
not be picked by our CI - I guess we need all the possible testing done
here ;)

/P
Re: [PATCH v3 1/9] net: Add struct sockaddr_unspec for sockaddr of unknown length
Posted by Kees Cook 3 months, 2 weeks ago
On Thu, Oct 23, 2025 at 12:59:59PM +0200, Paolo Abeni wrote:
> On 10/20/25 11:26 PM, Kees Cook wrote:
> > Add flexible sockaddr structure to support addresses longer than the
> > traditional 14-byte struct sockaddr::sa_data limitation without
> > requiring the full 128-byte sa_data of struct sockaddr_storage. This
> > allows the network APIs to pass around a pointer to an object that
> > isn't lying to the compiler about how big it is, but must be accompanied
> > by its actual size as an additional parameter.
> > 
> > It's possible we may way to migrate to including the size with the
> > struct in the future, e.g.:
> > 
> > struct sockaddr_unspec {
> > 	u16 sa_data_len;
> > 	u16 sa_family;
> > 	u8  sa_data[] __counted_by(sa_data_len);
> > };
> > 
> > Signed-off-by: Kees Cook <kees@kernel.org>
> 
> Another side note: please include the 'net-next' subj prefix in next
> submissions, otherwise patchwork could be fouled, and the patches will
> not be picked by our CI - I guess we need all the possible testing done
> here ;)

Okay, I've tweaked my workflow automation to attempt this now. I had a
bit of a catch-22 in that I generated the CC list after "git
format-patch" (and format-patch is what has the --prefix option, so I
couldn't see if netdev@ was in the CC list yet...) Anyway, it should be
part of my automation now...

-- 
Kees Cook
Re: [PATCH v3 1/9] net: Add struct sockaddr_unspec for sockaddr of unknown length
Posted by Paolo Abeni 3 months, 2 weeks ago
On 10/20/25 11:26 PM, Kees Cook wrote:
> Add flexible sockaddr structure to support addresses longer than the
> traditional 14-byte struct sockaddr::sa_data limitation without
> requiring the full 128-byte sa_data of struct sockaddr_storage. This
> allows the network APIs to pass around a pointer to an object that
> isn't lying to the compiler about how big it is, but must be accompanied
> by its actual size as an additional parameter.
> 
> It's possible we may way to migrate to including the size with the
> struct in the future, e.g.:
> 
> struct sockaddr_unspec {
> 	u16 sa_data_len;
> 	u16 sa_family;
> 	u8  sa_data[] __counted_by(sa_data_len);
> };

Side note: sockaddr_unspec is possibly not the optimal name, as
AF_UNSPEC has a specific meaning/semantic.

Name-wise, I think 'sockaddr_sized' would be better, but I agree with
David the struct may cause unaligned access problems.

/P
Re: [PATCH v3 1/9] net: Add struct sockaddr_unspec for sockaddr of unknown length
Posted by Kees Cook 3 months, 2 weeks ago
On Thu, Oct 23, 2025 at 12:43:06PM +0200, Paolo Abeni wrote:
> On 10/20/25 11:26 PM, Kees Cook wrote:
> > Add flexible sockaddr structure to support addresses longer than the
> > traditional 14-byte struct sockaddr::sa_data limitation without
> > requiring the full 128-byte sa_data of struct sockaddr_storage. This
> > allows the network APIs to pass around a pointer to an object that
> > isn't lying to the compiler about how big it is, but must be accompanied
> > by its actual size as an additional parameter.
> > 
> > It's possible we may way to migrate to including the size with the
> > struct in the future, e.g.:
> > 
> > struct sockaddr_unspec {
> > 	u16 sa_data_len;
> > 	u16 sa_family;
> > 	u8  sa_data[] __counted_by(sa_data_len);
> > };
> 
> Side note: sockaddr_unspec is possibly not the optimal name, as
> AF_UNSPEC has a specific meaning/semantic.
> 
> Name-wise, I think 'sockaddr_sized' would be better, but I agree with
> David the struct may cause unaligned access problems.

I'll go with sockaddr_unsized -- doing the sockaddr_sized variant is a
much more involved change. I just want to get us to where we are today
but with no lying to the compiler about sizes. :)

-- 
Kees Cook
Re: [PATCH v3 1/9] net: Add struct sockaddr_unspec for sockaddr of unknown length
Posted by David Laight 3 months, 2 weeks ago
On Thu, 23 Oct 2025 12:43:06 +0200
Paolo Abeni <pabeni@redhat.com> wrote:

> On 10/20/25 11:26 PM, Kees Cook wrote:
> > Add flexible sockaddr structure to support addresses longer than the
> > traditional 14-byte struct sockaddr::sa_data limitation without
> > requiring the full 128-byte sa_data of struct sockaddr_storage. This
> > allows the network APIs to pass around a pointer to an object that
> > isn't lying to the compiler about how big it is, but must be accompanied
> > by its actual size as an additional parameter.
> > 
> > It's possible we may way to migrate to including the size with the
> > struct in the future, e.g.:
> > 
> > struct sockaddr_unspec {
> > 	u16 sa_data_len;
> > 	u16 sa_family;
> > 	u8  sa_data[] __counted_by(sa_data_len);
> > };  
> 
> Side note: sockaddr_unspec is possibly not the optimal name, as
> AF_UNSPEC has a specific meaning/semantic.
> 
> Name-wise, I think 'sockaddr_sized' would be better,

Or even sockaddr_unsized ?

> but I agree with David the struct may cause unaligned access problems.

It probably also wants the 'sized_by' attribute rather than 'counted_by'.
So wherever the length is saved it is the length the user supplied
for the structure (or the sizeof the protocol-specific one).

	David


> 
> /P
> 
>
Re: [PATCH v3 1/9] net: Add struct sockaddr_unspec for sockaddr of unknown length
Posted by David Laight 3 months, 2 weeks ago
On Mon, 20 Oct 2025 14:26:30 -0700
Kees Cook <kees@kernel.org> wrote:

> Add flexible sockaddr structure to support addresses longer than the
> traditional 14-byte struct sockaddr::sa_data limitation without
> requiring the full 128-byte sa_data of struct sockaddr_storage. This
> allows the network APIs to pass around a pointer to an object that
> isn't lying to the compiler about how big it is, but must be accompanied
> by its actual size as an additional parameter.
> 
> It's possible we may way to migrate to including the size with the
> struct in the future, e.g.:
> 
> struct sockaddr_unspec {
> 	u16 sa_data_len;
> 	u16 sa_family;
> 	u8  sa_data[] __counted_by(sa_data_len);
> };

One on the historic Unix implementations split the 'sa_family'
field into two single byte fields - the second one containing the length.
That might work - although care would be needed not to pass a length
back to userspace.

NetBSD certainly forbid declaring variables of type 'sockaddr storage',
the kernel could only use pointers to it.
These days that might be enforcable by the compiler.

	David
Re: [PATCH v3 1/9] net: Add struct sockaddr_unspec for sockaddr of unknown length
Posted by Kees Cook 3 months, 2 weeks ago
On Tue, Oct 21, 2025 at 10:26:00AM +0100, David Laight wrote:
> On Mon, 20 Oct 2025 14:26:30 -0700
> Kees Cook <kees@kernel.org> wrote:
> 
> > Add flexible sockaddr structure to support addresses longer than the
> > traditional 14-byte struct sockaddr::sa_data limitation without
> > requiring the full 128-byte sa_data of struct sockaddr_storage. This
> > allows the network APIs to pass around a pointer to an object that
> > isn't lying to the compiler about how big it is, but must be accompanied
> > by its actual size as an additional parameter.
> > 
> > It's possible we may way to migrate to including the size with the
> > struct in the future, e.g.:
> > 
> > struct sockaddr_unspec {
> > 	u16 sa_data_len;
> > 	u16 sa_family;
> > 	u8  sa_data[] __counted_by(sa_data_len);
> > };
> 
> One on the historic Unix implementations split the 'sa_family'
> field into two single byte fields - the second one containing the length.
> That might work - although care would be needed not to pass a length
> back to userspace.

I think this is just asking for trouble -- leaving that inline could
be hard to track down places that needed filtering out.

It might be easier to move to a separate struct like I suggest above,
though maybe as:

struct sockaddr_sized {
    u16 sa_data_len;
    struct {
        u16 sa_family;
        u8  sa_data[] __counted_by(sa_data_len);
    } sa_unspec;
};

(So it's easier to cast between implementation-specific sockaddr and the
"sa_unspec" member.)

And then pass that around. But I think that'll require a LOT of
refactoring. But that could happen separately from this change, which is
to just get us back to the existing state of passing around an unknown
sized object but now we're not lying to the compiler about its size.

-- 
Kees Cook
Re: [PATCH v3 1/9] net: Add struct sockaddr_unspec for sockaddr of unknown length
Posted by David Laight 3 months, 2 weeks ago
On Tue, 21 Oct 2025 12:42:10 -0700
Kees Cook <kees@kernel.org> wrote:

> On Tue, Oct 21, 2025 at 10:26:00AM +0100, David Laight wrote:
> > On Mon, 20 Oct 2025 14:26:30 -0700
> > Kees Cook <kees@kernel.org> wrote:
> >   
> > > Add flexible sockaddr structure to support addresses longer than the
> > > traditional 14-byte struct sockaddr::sa_data limitation without
> > > requiring the full 128-byte sa_data of struct sockaddr_storage. This
> > > allows the network APIs to pass around a pointer to an object that
> > > isn't lying to the compiler about how big it is, but must be accompanied
> > > by its actual size as an additional parameter.
> > > 
> > > It's possible we may way to migrate to including the size with the
> > > struct in the future, e.g.:
> > > 
> > > struct sockaddr_unspec {
> > > 	u16 sa_data_len;
> > > 	u16 sa_family;
> > > 	u8  sa_data[] __counted_by(sa_data_len);
> > > };  
> > 
> > One on the historic Unix implementations split the 'sa_family'
> > field into two single byte fields - the second one containing the length.
> > That might work - although care would be needed not to pass a length
> > back to userspace.  
> 
> I think this is just asking for trouble -- leaving that inline could
> be hard to track down places that needed filtering out.
> 
> It might be easier to move to a separate struct like I suggest above,
> though maybe as:
> 
> struct sockaddr_sized {
>     u16 sa_data_len;
>     struct {
>         u16 sa_family;
>         u8  sa_data[] __counted_by(sa_data_len);
>     } sa_unspec;
> };
> 
> (So it's easier to cast between implementation-specific sockaddr and the
> "sa_unspec" member.)
> 
> And then pass that around. But I think that'll require a LOT of
> refactoring. But that could happen separately from this change, which is
> to just get us back to the existing state of passing around an unknown
> sized object but now we're not lying to the compiler about its size.

The problem with that is it misaligns things later on.
And you really want to be using the length from the user,
which includes sa_family.

I'm not sure it even works if the extra sa_data_len is u32 (or even u64).

I did wonder if 'union casts' would help.
They would require a union of pointers to all possible sockaddr formats.
Annoyingly I don't think you can avoid the need for the cast on the
call sites for a lot of the functions - unless they are renamed to have
unique names (so a #define can add the cast).

If you do add a #define, it can generate the size from that of the
supplied address structure (and error things that are stupidly short).

	David
Re: [PATCH v3 1/9] net: Add struct sockaddr_unspec for sockaddr of unknown length
Posted by Kees Cook 3 months, 2 weeks ago
On Wed, Oct 22, 2025 at 10:26:24AM +0100, David Laight wrote:
> If you do add a #define, it can generate the size from that of the
> supplied address structure (and error things that are stupidly short).

I have more patches coming that consolidate all the open-coded casting
and size checking into a macro. So far, only a couple places weren't
doing the full checking.

-- 
Kees Cook