[3/3] alfred: properly initialize stack buffer before sending over unix socket
Commit Message
Without explicitely initializing the buffer with null bytes, the stack
variables may contain process information which may be leaked when
transmitted via unix socket.
Also, the size of the variables sitting on the stack can be reduced.
Signed-off-by: Marek Lindner <mareklindner@neomailbox.ch>
---
client.c | 4 ++++
1 file changed, 4 insertions(+)
Comments
On Wednesday, 12 January 2022 22:05:06 CET Marek Lindner wrote:
[...]
> diff --git a/client.c b/client.c
> index b5d8943..cf15ff4 100644
> --- a/client.c
> +++ b/client.c
> @@ -35,6 +35,7 @@ int alfred_client_request_data(struct globals *globals)
> return -1;
>
> len = sizeof(request);
> + memset(&request, 0, len);
>
> request.header.type = ALFRED_REQUEST;
> request.header.version = ALFRED_VERSION;
All bytes (also all bits) are overwritten in the lines below the memset. So I
don't see why memset would be required here.
> @@ -184,6 +185,7 @@ int alfred_client_modeswitch(struct globals *globals)
> return -1;
>
> len = sizeof(modeswitch);
> + memset(&modeswitch, 0, len);
>
> modeswitch.header.type = ALFRED_MODESWITCH;
> modeswitch.header.version = ALFRED_VERSION;
Same here - with a minor exception. When mode is not written then the data is
not written to the socket.
> @@ -260,6 +262,7 @@ int alfred_client_change_interface(struct globals *globals)
> }
>
> len = sizeof(change_interface);
> + memset(&change_interface, 0, len);
>
> change_interface.header.type = ALFRED_CHANGE_INTERFACE;
> change_interface.header.version = ALFRED_VERSION;\
Same here.
> @@ -308,6 +311,7 @@ int alfred_client_change_bat_iface(struct globals *globals)
> }
>
> len = sizeof(change_bat_iface);
> + memset(&change_bat_iface, 0, len);
>
> change_bat_iface.header.type = ALFRED_CHANGE_BAT_IFACE;
> change_bat_iface.header.version = ALFRED_VERSION;
>
Same here.
Kind regards,
Sven
On Friday, 21 January 2022 16:34:50 CET Sven Eckelmann wrote:
> > @@ -260,6 +262,7 @@ int alfred_client_change_interface(struct globals
> > *globals) }
> >
> > len = sizeof(change_interface);
> > + memset(&change_interface, 0, len);
> >
> > change_interface.header.type = ALFRED_CHANGE_INTERFACE;
> > change_interface.header.version = ALFRED_VERSION;\
>
> Same here.
>
> > @@ -308,6 +311,7 @@ int alfred_client_change_bat_iface(struct globals
> > *globals) }
> >
> > len = sizeof(change_bat_iface);
> > + memset(&change_bat_iface, 0, len);
> >
> > change_bat_iface.header.type = ALFRED_CHANGE_BAT_IFACE;
> > change_bat_iface.header.version = ALFRED_VERSION;
>
> Same here.
The struct alfred_change_interface_v0 -> ifaces[IFNAMSIZ * 16] may be written
to but not fully initialized. The interface name may be much shorter than the
buffer holding it. Same applies struct alfred_change_bat_iface_v0 ->
bat_iface[IFNAMSIZ] but to a lesser extent because the buffer is smaller.
This patch is based on your earlier observation that stack data may be leaked
due to the lack of (complete) initialization.
You are correct that the structs struct alfred_request_v0 &
alfred_modeswitch_v0 technically don't require initialization because all
fields are set manually. I added those for completeness sake for the next
person coming along copy & pasting the code (as I had done).
Kind regards,
Marek Lindner
On Saturday, 22 January 2022 01:41:36 CET Marek Lindner wrote:
[...]
> The struct alfred_change_interface_v0 -> ifaces[IFNAMSIZ * 16] may be written
> to but not fully initialized. The interface name may be much shorter than the
> buffer holding it. Same applies struct alfred_change_bat_iface_v0 ->
> bat_iface[IFNAMSIZ] but to a lesser extent because the buffer is smaller.
But strncpy writes n bytes (second parameter of n). So the name + n-
strlen(name) 0-bytes. I thought I've corrected my earlier statement about
strncpy but maybe I forgot it. So strlcpy will take care of always writing a
single 0-byte at the end of a non-0-length buffer - but is not writing more than
1x 0-byte (so half of the buffer might be uninitialised). strncpy will fill
the remaining bytes with 0 but might end up writing NO 0-bytes when the buffer
was already full.
But in your status patch, not all 16 name entries were written. So it leaks
things from the stack and the receiver might parse things which are not
actually written by the sender. And your code was not explicitly making sure
that the buffer ends with a 0-byte.
Kind regards,
Sven
On Saturday, 22 January 2022 09:03:12 CET Sven Eckelmann wrote:
> > The struct alfred_change_interface_v0 -> ifaces[IFNAMSIZ * 16] may be
> > written to but not fully initialized. The interface name may be much
> > shorter than the buffer holding it. Same applies struct
> > alfred_change_bat_iface_v0 -> bat_iface[IFNAMSIZ] but to a lesser extent
> > because the buffer is smaller.
>
> But strncpy writes n bytes (second parameter of n). So the name + n-
> strlen(name) 0-bytes. I thought I've corrected my earlier statement about
> strncpy but maybe I forgot it. So strlcpy will take care of always writing a
> single 0-byte at the end of a non-0-length buffer - but is not writing more
> than 1x 0-byte (so half of the buffer might be uninitialised). strncpy will
> fill the remaining bytes with 0 but might end up writing NO 0-bytes when
> the buffer was already full.
Thanks for highlighting this difference between strncpy() and strlcpy(). I see
your point.
> But in your status patch, not all 16 name entries were written. So it leaks
> things from the stack and the receiver might parse things which are not
> actually written by the sender. And your code was not explicitly making sure
> that the buffer ends with a 0-byte.
The server status patch iterates over the list of interfaces and performs
individual strncpy() calls, so that strncpy() can't initialize the entire
buffer unless there are 16 interfaces to begin with. Ok!
Then drop this patch.
Kind regards,
Marek Lindner
@@ -35,6 +35,7 @@ int alfred_client_request_data(struct globals *globals)
return -1;
len = sizeof(request);
+ memset(&request, 0, len);
request.header.type = ALFRED_REQUEST;
request.header.version = ALFRED_VERSION;
@@ -184,6 +185,7 @@ int alfred_client_modeswitch(struct globals *globals)
return -1;
len = sizeof(modeswitch);
+ memset(&modeswitch, 0, len);
modeswitch.header.type = ALFRED_MODESWITCH;
modeswitch.header.version = ALFRED_VERSION;
@@ -260,6 +262,7 @@ int alfred_client_change_interface(struct globals *globals)
}
len = sizeof(change_interface);
+ memset(&change_interface, 0, len);
change_interface.header.type = ALFRED_CHANGE_INTERFACE;
change_interface.header.version = ALFRED_VERSION;
@@ -308,6 +311,7 @@ int alfred_client_change_bat_iface(struct globals *globals)
}
len = sizeof(change_bat_iface);
+ memset(&change_bat_iface, 0, len);
change_bat_iface.header.type = ALFRED_CHANGE_BAT_IFACE;
change_bat_iface.header.version = ALFRED_VERSION;