| From e368b12f6c16b6888dda99ba641e999b9c9643c8 Mon Sep 17 00:00:00 2001 |
| From: Florian Weimer <fweimer@redhat.com> |
| Date: Mon, 17 Jan 2022 10:21:34 +0100 |
| Subject: [PATCH] socket: Add the __sockaddr_un_set function |
| |
| Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;h=e368b12f6c16b6888dda99ba641e999b9c9643c8] |
| CVE: CVE-2022-23219 |
| |
| Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org> |
| Signed-off-by: Pgowda <pgowda.cve@gmail.com> |
| --- |
| include/sys/un.h | 12 +++++++ |
| socket/Makefile | 6 +++- |
| socket/sockaddr_un_set.c | 41 ++++++++++++++++++++++++ |
| socket/tst-sockaddr_un_set.c | 62 ++++++++++++++++++++++++++++++++++++ |
| 4 files changed, 120 insertions(+), 1 deletion(-) |
| create mode 100644 socket/sockaddr_un_set.c |
| create mode 100644 socket/tst-sockaddr_un_set.c |
| |
| diff --git a/include/sys/un.h b/include/sys/un.h |
| index bdbee99980..152afd9fc7 100644 |
| --- a/include/sys/un.h |
| +++ b/include/sys/un.h |
| @@ -1 +1,13 @@ |
| #include <socket/sys/un.h> |
| + |
| +#ifndef _ISOMAC |
| + |
| +/* Set ADDR->sun_family to AF_UNIX and ADDR->sun_path to PATHNAME. |
| + Return 0 on success or -1 on failure (due to overlong PATHNAME). |
| + The caller should always use sizeof (struct sockaddr_un) as the |
| + socket address length, disregaring the length of PATHNAME. |
| + Only concrete (non-abstract) pathnames are supported. */ |
| +int __sockaddr_un_set (struct sockaddr_un *addr, const char *pathname) |
| + attribute_hidden; |
| + |
| +#endif /* _ISOMAC */ |
| diff --git a/socket/Makefile b/socket/Makefile |
| index 39333e10ca..156eec6c85 100644 |
| --- a/socket/Makefile |
| +++ b/socket/Makefile |
| @@ -29,13 +29,17 @@ headers := sys/socket.h sys/un.h bits/sockaddr.h bits/socket.h \ |
| routines := accept bind connect getpeername getsockname getsockopt \ |
| listen recv recvfrom recvmsg send sendmsg sendto \ |
| setsockopt shutdown socket socketpair isfdtype opensock \ |
| - sockatmark accept4 recvmmsg sendmmsg |
| + sockatmark accept4 recvmmsg sendmmsg sockaddr_un_set |
| |
| tests := \ |
| tst-accept4 \ |
| tst-sockopt \ |
| # tests |
| |
| +tests-internal := \ |
| + tst-sockaddr_un_set \ |
| + # tests-internal |
| + |
| tests-time64 := \ |
| tst-sockopt-time64 \ |
| # tests |
| diff --git a/socket/sockaddr_un_set.c b/socket/sockaddr_un_set.c |
| new file mode 100644 |
| index 0000000000..0bd40dc34e |
| --- /dev/null |
| +++ b/socket/sockaddr_un_set.c |
| @@ -0,0 +1,41 @@ |
| +/* Set the sun_path member of struct sockaddr_un. |
| + Copyright (C) 2022 Free Software Foundation, Inc. |
| + This file is part of the GNU C Library. |
| + |
| + The GNU C Library is free software; you can redistribute it and/or |
| + modify it under the terms of the GNU Lesser General Public |
| + License as published by the Free Software Foundation; either |
| + version 2.1 of the License, or (at your option) any later version. |
| + |
| + The GNU C Library is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + Lesser General Public License for more details. |
| + |
| + You should have received a copy of the GNU Lesser General Public |
| + License along with the GNU C Library; if not, see |
| + <https://www.gnu.org/licenses/>. */ |
| + |
| +#include <errno.h> |
| +#include <string.h> |
| +#include <sys/socket.h> |
| +#include <sys/un.h> |
| + |
| +int |
| +__sockaddr_un_set (struct sockaddr_un *addr, const char *pathname) |
| +{ |
| + size_t name_length = strlen (pathname); |
| + |
| + /* The kernel supports names of exactly sizeof (addr->sun_path) |
| + bytes, without a null terminator, but userspace does not; see the |
| + SUN_LEN macro. */ |
| + if (name_length >= sizeof (addr->sun_path)) |
| + { |
| + __set_errno (EINVAL); /* Error code used by the kernel. */ |
| + return -1; |
| + } |
| + |
| + addr->sun_family = AF_UNIX; |
| + memcpy (addr->sun_path, pathname, name_length + 1); |
| + return 0; |
| +} |
| diff --git a/socket/tst-sockaddr_un_set.c b/socket/tst-sockaddr_un_set.c |
| new file mode 100644 |
| index 0000000000..29c2a81afd |
| --- /dev/null |
| +++ b/socket/tst-sockaddr_un_set.c |
| @@ -0,0 +1,62 @@ |
| +/* Test the __sockaddr_un_set function. |
| + Copyright (C) 2022 Free Software Foundation, Inc. |
| + This file is part of the GNU C Library. |
| + |
| + The GNU C Library is free software; you can redistribute it and/or |
| + modify it under the terms of the GNU Lesser General Public |
| + License as published by the Free Software Foundation; either |
| + version 2.1 of the License, or (at your option) any later version. |
| + |
| + The GNU C Library is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + Lesser General Public License for more details. |
| + |
| + You should have received a copy of the GNU Lesser General Public |
| + License along with the GNU C Library; if not, see |
| + <https://www.gnu.org/licenses/>. */ |
| + |
| +/* Re-compile the function because the version in libc is not |
| + exported. */ |
| +#include "sockaddr_un_set.c" |
| + |
| +#include <support/check.h> |
| + |
| +static int |
| +do_test (void) |
| +{ |
| + struct sockaddr_un sun; |
| + |
| + memset (&sun, 0xcc, sizeof (sun)); |
| + __sockaddr_un_set (&sun, ""); |
| + TEST_COMPARE (sun.sun_family, AF_UNIX); |
| + TEST_COMPARE (__sockaddr_un_set (&sun, ""), 0); |
| + |
| + memset (&sun, 0xcc, sizeof (sun)); |
| + TEST_COMPARE (__sockaddr_un_set (&sun, "/example"), 0); |
| + TEST_COMPARE_STRING (sun.sun_path, "/example"); |
| + |
| + { |
| + char pathname[108]; /* Length of sun_path (ABI constant). */ |
| + memset (pathname, 'x', sizeof (pathname)); |
| + pathname[sizeof (pathname) - 1] = '\0'; |
| + memset (&sun, 0xcc, sizeof (sun)); |
| + TEST_COMPARE (__sockaddr_un_set (&sun, pathname), 0); |
| + TEST_COMPARE (sun.sun_family, AF_UNIX); |
| + TEST_COMPARE_STRING (sun.sun_path, pathname); |
| + } |
| + |
| + { |
| + char pathname[109]; |
| + memset (pathname, 'x', sizeof (pathname)); |
| + pathname[sizeof (pathname) - 1] = '\0'; |
| + memset (&sun, 0xcc, sizeof (sun)); |
| + errno = 0; |
| + TEST_COMPARE (__sockaddr_un_set (&sun, pathname), -1); |
| + TEST_COMPARE (errno, EINVAL); |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +#include <support/test-driver.c> |
| -- |
| 2.27.0 |
| |