diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/explicit_bzero.c | 74 | ||||
-rw-r--r-- | lib/file-has-acl.c | 120 | ||||
-rw-r--r-- | lib/gnulib.mk.in | 28 | ||||
-rw-r--r-- | lib/memset_explicit.c | 55 | ||||
-rw-r--r-- | lib/string.in.h | 17 | ||||
-rw-r--r-- | lib/time.in.h | 1 | ||||
-rw-r--r-- | lib/verify.h | 2 |
7 files changed, 209 insertions, 88 deletions
diff --git a/lib/explicit_bzero.c b/lib/explicit_bzero.c deleted file mode 100644 index ad0bfd170ca..00000000000 --- a/lib/explicit_bzero.c +++ /dev/null @@ -1,74 +0,0 @@ -/* Erasure of sensitive data, generic implementation. - Copyright (C) 2016-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/>. */ - -/* An assembler implementation of explicit_bzero can be created as an - assembler alias of an optimized bzero implementation. - Architecture-specific implementations also need to define - __explicit_bzero_chk. */ - -#if !_LIBC -# include <config.h> -#endif - -/* memset_s need this define */ -#if HAVE_MEMSET_S -# define __STDC_WANT_LIB_EXT1__ 1 -#endif - -#include <string.h> - -#if defined _WIN32 && !defined __CYGWIN__ -# define WIN32_LEAN_AND_MEAN -# include <windows.h> -#endif - -#if _LIBC -/* glibc-internal users use __explicit_bzero_chk, and explicit_bzero - redirects to that. */ -# undef explicit_bzero -#endif - -/* Set LEN bytes of S to 0. The compiler will not delete a call to - this function, even if S is dead after the call. */ -void -explicit_bzero (void *s, size_t len) -{ -#if defined _WIN32 && !defined __CYGWIN__ - (void) SecureZeroMemory (s, len); -#elif HAVE_EXPLICIT_MEMSET - explicit_memset (s, '\0', len); -#elif HAVE_MEMSET_S - (void) memset_s (s, len, '\0', len); -#elif defined __GNUC__ && !defined __clang__ - memset (s, '\0', len); - /* Compiler barrier. */ - asm volatile ("" ::: "memory"); -#elif defined __clang__ - memset (s, '\0', len); - /* Compiler barrier. */ - /* With asm ("" ::: "memory") LLVM analyzes uses of 's' and finds that the - whole thing is dead and eliminates it. Use 'g' to work around this - problem. See <https://bugs.llvm.org/show_bug.cgi?id=15495#c11>. */ - __asm__ volatile ("" : : "g"(s) : "memory"); -#else - /* Invoke memset through a volatile function pointer. This defeats compiler - optimizations. */ - void * (* const volatile volatile_memset) (void *, int, size_t) = memset; - (void) volatile_memset (s, '\0', len); -#endif -} diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c index e02f0626ad3..676523ba821 100644 --- a/lib/file-has-acl.c +++ b/lib/file-has-acl.c @@ -29,9 +29,97 @@ #include "acl-internal.h" -#if GETXATTR_WITH_POSIX_ACLS +#if USE_ACL && GETXATTR_WITH_POSIX_ACLS +# include <string.h> +# include <arpa/inet.h> # include <sys/xattr.h> # include <linux/xattr.h> +# ifndef XATTR_NAME_NFSV4_ACL +# define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" +# endif + +enum { + /* ACE4_ACCESS_ALLOWED_ACE_TYPE = 0x00000000, */ + ACE4_ACCESS_DENIED_ACE_TYPE = 0x00000001, + ACE4_IDENTIFIER_GROUP = 0x00000040 +}; + +/* Return 1 if given ACL in XDR format is non-trivial, 0 if it is trivial. + -1 upon failure to determine it. Possibly change errno. Assume that + the ACL is valid, except avoid undefined behavior even if invalid. + + See <https://linux.die.net/man/5/nfs4_acl>. The NFSv4 acls are + defined in Internet RFC 7530 and as such, every NFSv4 server + supporting ACLs should support NFSv4 ACLs (they differ from from + POSIX draft ACLs). The ACLs can be obtained via the + nfsv4-acl-tools, e.g., the nfs4_getfacl command. Gnulib provides + only basic support of NFSv4 ACLs, i.e., recognize trivial vs + nontrivial ACLs. */ + +static int +acl_nfs4_nontrivial (uint32_t *xattr, ssize_t nbytes) +{ + enum { BYTES_PER_NETWORK_UINT = 4}; + + /* Grab the number of aces in the acl. */ + nbytes -= BYTES_PER_NETWORK_UINT; + if (nbytes < 0) + return -1; + uint32_t num_aces = ntohl (*xattr++); + if (6 < num_aces) + return 1; + int ace_found = 0; + + for (int ace_n = 0; ace_n < num_aces; ace_n++) + { + /* Get the acl type and flag. Skip the mask; it's too risky to + test it and it does not seem to be needed. Get the wholen. */ + nbytes -= 4 * BYTES_PER_NETWORK_UINT; + if (nbytes < 0) + return -1; + uint32_t type = ntohl (xattr[0]); + uint32_t flag = ntohl (xattr[1]); + uint32_t wholen = ntohl (xattr[3]); + xattr += 4; + int64_t wholen4 = wholen; + wholen4 = ((wholen4 + (BYTES_PER_NETWORK_UINT)) + & ~ (BYTES_PER_NETWORK_UINT - 1)); + + /* Trivial ACLs have only ACE4_ACCESS_ALLOWED_ACE_TYPE or + ACE4_ACCESS_DENIED_ACE_TYPE. */ + if (ACE4_ACCESS_DENIED_ACE_TYPE < type) + return 1; + + /* RFC 7530 says FLAG should be 0, but be generous to NetApp and + also accept the group flag. */ + if (flag & ~ACE4_IDENTIFIER_GROUP) + return 1; + + /* Get the who string. Check NBYTES - WHOLEN4 before storing + into NBYTES, to avoid truncation on conversion. */ + if (nbytes - wholen4 < 0) + return -1; + nbytes -= wholen4; + + /* For a trivial ACL, max 6 (typically 3) ACEs, 3 allow, 3 deny. + Check that there is at most one ACE of each TYPE and WHO. */ + int who2 + = (wholen == 6 && memcmp (xattr, "OWNER@", 6) == 0 ? 0 + : wholen == 6 && memcmp (xattr, "GROUP@", 6) == 0 ? 2 + : wholen == 9 && memcmp (xattr, "EVERYONE@", 9) == 0 ? 4 + : -1); + if (who2 < 0) + return 1; + int ace_found_bit = 1 << (who2 | type); + if (ace_found & ace_found_bit) + return 1; + ace_found |= ace_found_bit; + + xattr = (uint32_t *) ((char *) xattr + wholen4); + } + + return 0; +} #endif /* Return 1 if NAME has a nontrivial access control list, @@ -51,6 +139,7 @@ file_has_acl (char const *name, struct stat const *sb) # if GETXATTR_WITH_POSIX_ACLS ssize_t ret; + int initial_errno = errno; ret = getxattr (name, XATTR_NAME_POSIX_ACL_ACCESS, NULL, 0); if (ret < 0 && errno == ENODATA) @@ -68,6 +157,35 @@ file_has_acl (char const *name, struct stat const *sb) } if (ret < 0) + { + /* Check for NFSv4 ACLs. The max length of a trivial + ACL is 6 words for owner, 6 for group, 7 for everyone, + all times 2 because there are both allow and deny ACEs. + There are 6 words for owner because of type, flag, mask, + wholen, "OWNER@"+pad and similarly for group; everyone is + another word to hold "EVERYONE@". */ + uint32_t xattr[2 * (6 + 6 + 7)]; + + ret = getxattr (name, XATTR_NAME_NFSV4_ACL, xattr, sizeof xattr); + if (ret < 0) + switch (errno) + { + case ENODATA: return 0; + case ERANGE : return 1; /* ACL must be nontrivial. */ + } + else + { + /* It looks like a trivial ACL, but investigate further. */ + ret = acl_nfs4_nontrivial (xattr, ret); + if (ret < 0) + { + errno = EINVAL; + return ret; + } + errno = initial_errno; + } + } + if (ret < 0) return - acl_errno_valid (errno); return ret; diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index 9af8fd0c579..fcbf5bde2db 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in @@ -93,7 +93,6 @@ # dup2 \ # environ \ # execinfo \ -# explicit_bzero \ # faccessat \ # fchmodat \ # fcntl \ @@ -126,6 +125,7 @@ # memmem-simple \ # mempcpy \ # memrchr \ +# memset_explicit \ # minmax \ # mkostemp \ # mktime \ @@ -264,7 +264,6 @@ GL_COND_OBJ_DIRFD_CONDITION = @GL_COND_OBJ_DIRFD_CONDITION@ GL_COND_OBJ_DUP2_CONDITION = @GL_COND_OBJ_DUP2_CONDITION@ GL_COND_OBJ_EUIDACCESS_CONDITION = @GL_COND_OBJ_EUIDACCESS_CONDITION@ GL_COND_OBJ_EXECINFO_CONDITION = @GL_COND_OBJ_EXECINFO_CONDITION@ -GL_COND_OBJ_EXPLICIT_BZERO_CONDITION = @GL_COND_OBJ_EXPLICIT_BZERO_CONDITION@ GL_COND_OBJ_FACCESSAT_CONDITION = @GL_COND_OBJ_FACCESSAT_CONDITION@ GL_COND_OBJ_FCHMODAT_CONDITION = @GL_COND_OBJ_FCHMODAT_CONDITION@ GL_COND_OBJ_FCNTL_CONDITION = @GL_COND_OBJ_FCNTL_CONDITION@ @@ -286,6 +285,7 @@ GL_COND_OBJ_LCHMOD_CONDITION = @GL_COND_OBJ_LCHMOD_CONDITION@ GL_COND_OBJ_LSTAT_CONDITION = @GL_COND_OBJ_LSTAT_CONDITION@ GL_COND_OBJ_MEMPCPY_CONDITION = @GL_COND_OBJ_MEMPCPY_CONDITION@ GL_COND_OBJ_MEMRCHR_CONDITION = @GL_COND_OBJ_MEMRCHR_CONDITION@ +GL_COND_OBJ_MEMSET_EXPLICIT_CONDITION = @GL_COND_OBJ_MEMSET_EXPLICIT_CONDITION@ GL_COND_OBJ_MINI_GMP_GNULIB_CONDITION = @GL_COND_OBJ_MINI_GMP_GNULIB_CONDITION@ GL_COND_OBJ_MKOSTEMP_CONDITION = @GL_COND_OBJ_MKOSTEMP_CONDITION@ GL_COND_OBJ_NANOSLEEP_CONDITION = @GL_COND_OBJ_NANOSLEEP_CONDITION@ @@ -485,6 +485,7 @@ GL_GNULIB_MEMCHR = @GL_GNULIB_MEMCHR@ GL_GNULIB_MEMMEM = @GL_GNULIB_MEMMEM@ GL_GNULIB_MEMPCPY = @GL_GNULIB_MEMPCPY@ GL_GNULIB_MEMRCHR = @GL_GNULIB_MEMRCHR@ +GL_GNULIB_MEMSET_EXPLICIT = @GL_GNULIB_MEMSET_EXPLICIT@ GL_GNULIB_MKDIR = @GL_GNULIB_MKDIR@ GL_GNULIB_MKDIRAT = @GL_GNULIB_MKDIRAT@ GL_GNULIB_MKDTEMP = @GL_GNULIB_MKDTEMP@ @@ -749,6 +750,7 @@ HAVE_MAX_ALIGN_T = @HAVE_MAX_ALIGN_T@ HAVE_MBSLEN = @HAVE_MBSLEN@ HAVE_MBTOWC = @HAVE_MBTOWC@ HAVE_MEMPCPY = @HAVE_MEMPCPY@ +HAVE_MEMSET_EXPLICIT = @HAVE_MEMSET_EXPLICIT@ HAVE_MKDIRAT = @HAVE_MKDIRAT@ HAVE_MKDTEMP = @HAVE_MKDTEMP@ HAVE_MKFIFO = @HAVE_MKFIFO@ @@ -1857,16 +1859,6 @@ EXTRA_DIST += execinfo.in.h endif ## end gnulib module execinfo -## begin gnulib module explicit_bzero -ifeq (,$(OMIT_GNULIB_MODULE_explicit_bzero)) - -ifneq (,$(GL_COND_OBJ_EXPLICIT_BZERO_CONDITION)) -libgnu_a_SOURCES += explicit_bzero.c -endif - -endif -## end gnulib module explicit_bzero - ## begin gnulib module faccessat ifeq (,$(OMIT_GNULIB_MODULE_faccessat)) @@ -2536,6 +2528,16 @@ endif endif ## end gnulib module memrchr +## begin gnulib module memset_explicit +ifeq (,$(OMIT_GNULIB_MODULE_memset_explicit)) + +ifneq (,$(GL_COND_OBJ_MEMSET_EXPLICIT_CONDITION)) +libgnu_a_SOURCES += memset_explicit.c +endif + +endif +## end gnulib module memset_explicit + ## begin gnulib module minmax ifeq (,$(OMIT_GNULIB_MODULE_minmax)) @@ -3362,6 +3364,7 @@ string.h: string.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H -e 's/@''GNULIB_MEMMEM''@/$(GL_GNULIB_MEMMEM)/g' \ -e 's/@''GNULIB_MEMPCPY''@/$(GL_GNULIB_MEMPCPY)/g' \ -e 's/@''GNULIB_MEMRCHR''@/$(GL_GNULIB_MEMRCHR)/g' \ + -e 's/@''GNULIB_MEMSET_EXPLICIT''@/$(GL_GNULIB_MEMSET_EXPLICIT)/g' \ -e 's/@''GNULIB_RAWMEMCHR''@/$(GL_GNULIB_RAWMEMCHR)/g' \ -e 's/@''GNULIB_STPCPY''@/$(GL_GNULIB_STPCPY)/g' \ -e 's/@''GNULIB_STPNCPY''@/$(GL_GNULIB_STPNCPY)/g' \ @@ -3393,6 +3396,7 @@ string.h: string.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H -e 's|@''HAVE_DECL_MEMMEM''@|$(HAVE_DECL_MEMMEM)|g' \ -e 's|@''HAVE_MEMPCPY''@|$(HAVE_MEMPCPY)|g' \ -e 's|@''HAVE_DECL_MEMRCHR''@|$(HAVE_DECL_MEMRCHR)|g' \ + -e 's|@''HAVE_MEMSET_EXPLICIT''@|$(HAVE_MEMSET_EXPLICIT)|g' \ -e 's|@''HAVE_RAWMEMCHR''@|$(HAVE_RAWMEMCHR)|g' \ -e 's|@''HAVE_STPCPY''@|$(HAVE_STPCPY)|g' \ -e 's|@''HAVE_STPNCPY''@|$(HAVE_STPNCPY)|g' \ diff --git a/lib/memset_explicit.c b/lib/memset_explicit.c new file mode 100644 index 00000000000..eabeb3ec2b8 --- /dev/null +++ b/lib/memset_explicit.c @@ -0,0 +1,55 @@ +/* Erase sensitive data from memory. + Copyright 2022 Free Software Foundation, Inc. + + This file 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. + + This file 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 this program. If not, see <https://www.gnu.org/licenses/>. */ + +#include <config.h> + +/* memset_s need this define */ +#if HAVE_MEMSET_S +# define __STDC_WANT_LIB_EXT1__ 1 +#endif + +#include <string.h> + +/* Set S's bytes to C, where S has LEN bytes. The compiler will not + optimize effects away, even if S is dead after the call. */ +void * +memset_explicit (void *s, int c, size_t len) +{ +#if HAVE_EXPLICIT_MEMSET + return explicit_memset (s, c, len); +#elif HAVE_MEMSET_S + (void) memset_s (s, len, c, len); + return s; +#elif defined __GNUC__ && !defined __clang__ + memset (s, c, len); + /* Compiler barrier. */ + __asm__ volatile ("" ::: "memory"); + return s; +#elif defined __clang__ + memset (s, c, len); + /* Compiler barrier. */ + /* With asm ("" ::: "memory") LLVM analyzes uses of 's' and finds that the + whole thing is dead and eliminates it. Use 'g' to work around this + problem. See <https://bugs.llvm.org/show_bug.cgi?id=15495#c11>. */ + __asm__ volatile ("" : : "g"(s) : "memory"); + return s; +#else + /* Invoke memset through a volatile function pointer. This defeats compiler + optimizations. */ + void * (* const volatile volatile_memset) (void *, int, size_t) = memset; + return volatile_memset (s, c, len); +#endif +} diff --git a/lib/string.in.h b/lib/string.in.h index e56f6db0c9c..21356914e21 100644 --- a/lib/string.in.h +++ b/lib/string.in.h @@ -347,6 +347,23 @@ _GL_WARN_ON_USE (memrchr, "memrchr is unportable - " # endif #endif +/* Overwrite a block of memory. The compiler will not optimize + effects away, even if the block is dead after the call. */ +#if @GNULIB_MEMSET_EXPLICIT@ +# if ! @HAVE_MEMSET_EXPLICIT@ +_GL_FUNCDECL_SYS (memset_explicit, void *, + (void *__dest, int __c, size_t __n) _GL_ARG_NONNULL ((1))); +# endif +_GL_CXXALIAS_SYS (memset_explicit, void *, (void *__dest, int __c, size_t __n)); +_GL_CXXALIASWARN (memset_explicit); +#elif defined GNULIB_POSIXCHECK +# undef memset_explicit +# if HAVE_RAW_DECL_MEMSET_EXPLICIT +_GL_WARN_ON_USE (memset_explicit, "memset_explicit is unportable - " + "use gnulib module memset_explicit for portability"); +# endif +#endif + /* Find the first occurrence of C in S. More efficient than memchr(S,C,N), at the expense of undefined behavior if C does not occur within N bytes. */ diff --git a/lib/time.in.h b/lib/time.in.h index 6aa67498f57..aba2eda8759 100644 --- a/lib/time.in.h +++ b/lib/time.in.h @@ -315,6 +315,7 @@ _GL_CXXALIASWARN (strptime); # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # define ctime rpl_ctime # endif +_GL_ATTRIBUTE_DEPRECATED _GL_FUNCDECL_RPL (ctime, char *, (time_t const *__tp) _GL_ARG_NONNULL ((1))); _GL_CXXALIAS_RPL (ctime, char *, (time_t const *__tp)); diff --git a/lib/verify.h b/lib/verify.h index 99af802993e..5225a8e616d 100644 --- a/lib/verify.h +++ b/lib/verify.h @@ -37,7 +37,7 @@ && (4 < __GNUC__ + (6 <= __GNUC_MINOR__) || 5 <= __clang_major__))) # define _GL_HAVE__STATIC_ASSERT 1 # endif -# if (202000 <= __STDC_VERSION__ \ +# if (202311 <= __STDC_VERSION__ \ || (!defined __STRICT_ANSI__ && 9 <= __GNUC__)) # define _GL_HAVE__STATIC_ASSERT1 1 # endif |