commit badf4c4724dcd838d27b40f92eb7d0039a968793 Author: Florian Weimer Date: Thu Sep 1 15:49:45 2016 +0200 WIP fcntl hardening diff --git a/include/bits/fcntl3.h b/include/bits/fcntl3.h new file mode 100644 index 0000000000..d31154f635 --- /dev/null +++ b/include/bits/fcntl3.h @@ -0,0 +1 @@ +#include "../../io/bits/fcntl3.h" diff --git a/io/Makefile b/io/Makefile index deb6100156..98603e012c 100644 --- a/io/Makefile +++ b/io/Makefile @@ -25,7 +25,7 @@ include ../Makeconfig headers := sys/stat.h bits/stat.h sys/statfs.h bits/statfs.h sys/vfs.h \ sys/statvfs.h bits/statvfs.h fcntl.h sys/fcntl.h bits/fcntl.h \ poll.h sys/poll.h bits/poll.h bits/fcntl2.h bits/poll2.h \ - utime.h ftw.h fts.h sys/sendfile.h + utime.h ftw.h fts.h sys/sendfile.h bits/fcntl3.h routines := \ utime \ diff --git a/io/bits/fcntl3.h b/io/bits/fcntl3.h new file mode 100644 index 0000000000..f9778ecec3 --- /dev/null +++ b/io/bits/fcntl3.h @@ -0,0 +1,180 @@ +/* Checking macros for fcntl functions. + Copyright (C) 2016 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 + . */ + +#ifndef _FCNTL_H +# error "Never include directly; use instead." +#endif + +/* The type-safe aliases call the __fcntl_chk function. Only calls + which are not known to be type-safe use fcntl. */ +int __fcntl_chk (int, int, ...); + +__errordecl (__fcntl_too_many_args, + "fcntl can only be called with 2 or 3 arguments"); + +/* Void arguments are ignored if present, and the return value must be + used. */ +__fortify_function __wur int +__fcntl_void (int __fd, int __cmd, ...) +{ + if (__va_arg_pack_len () > 1) + __fcntl_too_many_args (); + return __fcntl_chk (__fd, __cmd, __va_arg_pack ()); +} + +#ifdef F_GET_SEALS +# define __fcntl_is_F_GET_SEALS(cmd) ((cmd) == F_GET_SEALS) +#else +# define __fcntl_is_F_GET_SEALS(cmd) 0 +#endif +#define __fcntl_is_void(cmd) \ + ((cmd) == F_GET_FD \ + || (cmd) == F_GETFL \ + || (cmd) == F_GETOWN \ + || (cmd) == F_GETSIG \ + || (cmd) == __fcntl_is_F_GET_SEALS(cmd)) + +int __REDIRECT (__fcntl_int, (int, int, int __arg), __fcntl_chk); +#ifdef F_ADD_SEALS +# define __fcntl_is_F_ADD_SEALS(cmd) (cmd) == F_ADD_SEALS +#else +# define __fcntl_is_F_ADD_SEALS(cmd) 0 +#endif +#define __fcntl_is_int(cmd) \ + ((cmd) == F_DUPFD \ + || (cmd) == F_DUPFD_CLOEXEC \ + || (cmd) == F_SETFD \ + || (cmd) == F_SETFL \ + || (cmd) == F_SETOWN \ + || (cmd) == F_SETSIG \ + || (cmd) == F_SETLEASE \ + || (cmd) == F_NOTIFY \ + || (cmd) == F_SETPIPE_SZ \ + || __fcntl_is_F_ADD_SEALS (cmd)) + +int __REDIRECT (__fcntl_f_owner_ex, (int, int, struct f_owner_ex *), + __fcntl_chk); +int __REDIRECT (__fcntl_f_owner_ex_const, + (int, int, const struct f_owner_ex *), + __fcntl_chk); + +/* struct flock *, struct flock64 * arguments. */ +#define __fcntl_is_flock_const(cmd) ((cmd) == F_SETLK || (cmd) == F_SETLKW) +#define __fcntl_is_flock(cmd) ((cmd) == F_GETLK) + +#ifdef F_SETLK64 +# define __fcntl_is_flock64_const(cmd) \ + ((cmd) == F_SETLK64 || (cmd) == F_SETLKW64) +# define __fcntl_is_flock64(cmd) ((cmd) == F_GETLK64) +#else +# define __fcntl_is_flock64_const(cmd) 0 +# define __fcntl_is_flock64(cmd) 0 +#endif +#ifdef F_SETLK32 +# define __fcntl_is_flock32_const(cmd) \ + ((cmd) == F_SETLK32 || (cmd) == F_SETLKW32) +# define __fcntl_is_flock32(cmd) ((cmd) == F_GETLK32) +#else +# define __fcntl_is_flock32_const(cmd) 0 +# define __fcntl_is_flock32(cmd) 0 +#endif + +#if defined (__USE_LARGEFILE64) && defined (__OFF_T_MATCHES_OFF64_T) +typedef union __attribute__ ((__transparent_union__)) +{ + struct flock *__flock; + struct flock64 *__flock64; +} __flock_pointer; +typedef union __attribute__ ((__transparent_union__)) +{ + const struct flock *__flock; + const struct flock64 *__flock64; +} __flock_const_pointer; +#else /* flock and flock64 are distinct */ +typedef struct flock *__flock_pointer; +typedef const struct flock *__flock_const_pointer; +#endif + +int __REDIRECT (__fcntl_flock, (int, int, __flock_pointer), __fcntl_chk) __wur; +int __REDIRECT (__fcntl_flock_const, (int, int, __flock_const_pointer), + __fcntl_chk) __wur; +int __REDIRECT (__fcntl_flock32, (int, int, struct flock *), + __fcntl_chk) __wur; +int __REDIRECT (__fcntl_flock32_const, (int, int, const struct flock *), + __fcntl_chk) __wur; +#ifdef __USE_LARGEFILE64 +int __REDIRECT (__fcntl_flock64, (int, int, struct flock64 *), + __fcntl_chk) __wur; +int __REDIRECT (__fcntl_flock64_const, (int, int, const struct flock64 *), + __fcntl_chk) __wur; +#endif + +#ifdef F_OFD_SETLK +# define __fcntl_is_ofd_flock_const(cmd) \ + ((cmd) == F_OFD_SETLK || (cmd) == F_OFD_SETLKW) +# define __fcntl_is_ofd_flock(cmd) ((cmd) == F_OFD_GETLK) + +/* OFD locks are only available with 64-bit struct flock. */ +# if defined (__OFF_T_MATCHES_OFF64_T) +int __REDIRECT (__fcntl_ofd_flock, (int, int, __flock_pointer), + __fcntl_chk) __wur; +int __REDIRECT (__fcntl_ofd_flock_const, (int, int, __flock_const_pointer), + __fcntl_chk) __wur; +# else +int __REDIRECT (__fcntl_ofd_flock, (int, int, struct flock64 *), + __fcntl_chk) __wur; +int __REDIRECT (__fcntl_ofd_flock_const, (int, const struct flock64 *), + __fcntl_chk) __wur; +# endif + +#else /* !defined (F_OFD_SETLK) */ +# define __fcntl_is_ofd_flock_const (cmd) 0 +# define __fcntl_is_ofd_flock (cmd) 0 +#endif + +extern int __REDIRECT (__fcntl_warn, (int, int, ...), fcntl) + __warnattr ("fcntl called with an unknown command argument"); + +__fortify_function int +__fcntl_unchecked (int __fd, int __cmd, ...) +{ + if (__va_arg_pack_len () > 1) + __fcntl_too_many_args (); + return __fcntl_warn (__fd, __cmd, __va_arg_pack ()); +} + +#define fcntl(fd, cmd, ...) \ + (__builtin_constant_p (cmd) \ + ? __builtin_choose_expression \ + (__fcntl_is_void (cmd), __fcntl_void (fd, cmd, __VA_ARGS__), \ + __builtin_choose_expression \ + (__fcntl_is_int (cmd), __fcntl_int (fd, cmd, __VA_ARGS__), \ + __builtin_choose_expression \ + (__fcntl_is_flock_const (cmd), __fcntl_flock_const (fd, cmd, __VA_ARGS__), \ + __builtin_choose_expression \ + (__fcntl_is_flock (cmd), __fcntl_flock (fd, cmd, __VA_ARGS__), \ + __builtin_chose_expression \ + (__fcntl_is_flock64_const (cmd), __fcntl_flock64_const (fd, cmd, __VA_ARGS__), \ + __builtin_choose_expression \ + (__fcntl_is_flock64 (cmd), __fcntl_flock64 (fd, cmd, __VA_ARGS__), \ + __builtin_choose_expression \ + (__fcntl_is_flock32_const (cmd), __fcntl_flock32_const (fd, cmd, __VA_ARGS__), \ + __builtin_choose_expression \ + (__fcntl_is_flock32 (cmd), __fcntl_flock32 (fd, cmd, __VA_ARGS__), \ + __fcntl_unchecked (fd, cmd, __VA_ARGS__))))))))) \ + : __fcntl_unchecked (fd, cmd, __VA_ARGS__)) diff --git a/io/fcntl.h b/io/fcntl.h index cb706b4f0f..79887db6f8 100644 --- a/io/fcntl.h +++ b/io/fcntl.h @@ -314,6 +314,11 @@ extern int posix_fallocate64 (int __fd, off64_t __offset, off64_t __len); # include #endif +# if !defined (__cplusplus) && __USE_FORTIFY_LEVEL > 0 \ + && defined __fortify_function && defined __va_arg_pack_len +# include +#endif + __END_DECLS #endif /* fcntl.h */