diff -urN cvs-nserver-1.11.1.52.org/acinclude.m4 cvs-nserver-1.11.1.52/acinclude.m4 --- cvs-nserver-1.11.1.52.org/acinclude.m4 2004-06-11 15:13:22.806441712 +0200 +++ cvs-nserver-1.11.1.52/acinclude.m4 2004-06-11 15:14:12.949818760 +0200 @@ -229,3 +229,85 @@ AC_SEARCH_LIBS([gss_import_name], [gssapi_krb5 gssapi]) fi ])dnl + + + +# size_max.m4 serial 2 +dnl Copyright (C) 2003 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl From Bruno Haible. + +AC_DEFUN([gl_SIZE_MAX], +[ + AC_CHECK_HEADERS(stdint.h) + dnl First test whether the system already has SIZE_MAX. + AC_MSG_CHECKING([for SIZE_MAX]) + result= + AC_EGREP_CPP([Found it], [ +#include +#if HAVE_STDINT_H +#include +#endif +#ifdef SIZE_MAX +Found it +#endif +], result=yes) + if test -z "$result"; then + dnl Define it ourselves. Here we assume that the type 'size_t' is not wider + dnl than the type 'unsigned long'. + dnl The _AC_COMPUTE_INT macro works up to LONG_MAX, since it uses 'expr', + dnl which is guaranteed to work from LONG_MIN to LONG_MAX. + _AC_COMPUTE_INT([~(size_t)0 / 10], res_hi, + [#include ], result=?) + _AC_COMPUTE_INT([~(size_t)0 % 10], res_lo, + [#include ], result=?) + _AC_COMPUTE_INT([sizeof (size_t) <= sizeof (unsigned int)], fits_in_uint, + [#include ], result=?) + if test "$fits_in_uint" = 1; then + dnl Even though SIZE_MAX fits in an unsigned int, it must be of type + dnl 'unsigned long' if the type 'size_t' is the same as 'unsigned long'. + AC_TRY_COMPILE([#include + extern size_t foo; + extern unsigned long foo; + ], [], fits_in_uint=0) + fi + if test -z "$result"; then + if test "$fits_in_uint" = 1; then + result="$res_hi$res_lo"U + else + result="$res_hi$res_lo"UL + fi + else + dnl Shouldn't happen, but who knows... + result='~(size_t)0' + fi + fi + AC_MSG_RESULT([$result]) + if test "$result" != yes; then + AC_DEFINE_UNQUOTED([SIZE_MAX], [$result], + [Define as the maximum value of type 'size_t', if the system doesn't define it.]) + fi +]) + + + +# xsize.m4 serial 3 +dnl Copyright (C) 2003-2004 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +AC_DEFUN([gl_XSIZE], +[ + dnl Prerequisites of lib/xsize.h. + AC_REQUIRE([gl_SIZE_MAX]) + AC_REQUIRE([AC_C_INLINE]) + AC_CHECK_HEADERS(stdint.h) +]) diff -urN cvs-nserver-1.11.1.52.org/config.h.in cvs-nserver-1.11.1.52/config.h.in --- cvs-nserver-1.11.1.52.org/config.h.in 2004-06-11 15:13:22.807441560 +0200 +++ cvs-nserver-1.11.1.52/config.h.in 2004-06-11 15:15:19.522698144 +0200 @@ -9,6 +9,10 @@ clients. */ #undef SERVER_SUPPORT +/* Define as the maximum value of type 'size_t', if the system doesn't define ++ it. */ +#undef SIZE_MAX + /* Define if you want to use the password authenticated server. */ #undef AUTH_SERVER_SUPPORT @@ -377,6 +381,12 @@ /* Define to `int' if doesn't define. */ #undef gid_t +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + /* Define to `int' if does not define. */ #undef mode_t diff -urN cvs-nserver-1.11.1.52.org/configure.in cvs-nserver-1.11.1.52/configure.in --- cvs-nserver-1.11.1.52.org/configure.in 2004-06-11 15:13:22.811440952 +0200 +++ cvs-nserver-1.11.1.52/configure.in 2004-06-11 15:16:03.298043280 +0200 @@ -121,6 +121,8 @@ AC_TYPE_SIZE_T AC_TYPE_SIGNAL +gl_XSIZE + AC_STRUCT_ST_BLKSIZE AC_STRUCT_ST_RDEV AC_REPLACE_FUNCS(mkdir rename strstr dup2 strerror valloc waitpid memmove strtoul) diff -urN cvs-nserver-1.11.1.52.org/lib/Makefile.am cvs-nserver-1.11.1.52/lib/Makefile.am --- cvs-nserver-1.11.1.52.org/lib/Makefile.am 2004-06-11 15:13:22.873431528 +0200 +++ cvs-nserver-1.11.1.52/lib/Makefile.am 2004-06-11 15:16:50.173917064 +0200 @@ -83,6 +83,9 @@ build_lib.com \ xgssapi.h +# For the xsize module from GNULIB. +libcvs_a_SOURCES += xsize.h + # for backwards compatibility with the old makefiles realclean: maintainer-clean .PHONY: realclean diff -urN cvs-nserver-1.11.1.52.org/lib/Makefile.in cvs-nserver-1.11.1.52/lib/Makefile.in --- cvs-nserver-1.11.1.52.org/lib/Makefile.in 2004-06-11 15:13:22.874431376 +0200 +++ cvs-nserver-1.11.1.52/lib/Makefile.in 2004-06-11 15:14:13.013809032 +0200 @@ -128,6 +128,8 @@ # Also should look into unifying regular expression matching in CVS # with the diff library (perhaps to have the caller, CVS, do the # matching?) + +# For the xsize module from GNULIB. libcvs_a_SOURCES = \ argmatch.c \ ftruncate.c \ @@ -151,8 +153,8 @@ system.h \ wait.h \ xselect.h \ - xtime.h - + xtime.h\ +xsize.h libcvs_a_LIBADD = @LIBOBJS@ EXTRA_DIST = \ diff -urN cvs-nserver-1.11.1.52.org/lib/xsize.h cvs-nserver-1.11.1.52/lib/xsize.h --- cvs-nserver-1.11.1.52.org/lib/xsize.h 1970-01-01 01:00:00.000000000 +0100 +++ cvs-nserver-1.11.1.52/lib/xsize.h 2004-06-11 15:14:13.015808728 +0200 @@ -0,0 +1,108 @@ +/* xsize.h -- Checked size_t computations. + + Copyright (C) 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _XSIZE_H +#define _XSIZE_H + +/* Get size_t. */ +#include + +/* Get SIZE_MAX. */ +#include +#if HAVE_STDINT_H +# include +#endif + +/* The size of memory objects is often computed through expressions of + type size_t. Example: + void* p = malloc (header_size + n * element_size). + These computations can lead to overflow. When this happens, malloc() + returns a piece of memory that is way too small, and the program then + crashes while attempting to fill the memory. + To avoid this, the functions and macros in this file check for overflow. + The convention is that SIZE_MAX represents overflow. + malloc (SIZE_MAX) is not guaranteed to fail -- think of a malloc + implementation that uses mmap --, it's recommended to use size_overflow_p() + or size_in_bounds_p() before invoking malloc(). + The example thus becomes: + size_t size = xsum (header_size, xtimes (n, element_size)); + void *p = (size_in_bounds_p (size) ? malloc (size) : NULL); +*/ + +/* Convert an arbitrary value >= 0 to type size_t. */ +#define xcast_size_t(N) \ + ((N) <= SIZE_MAX ? (size_t) (N) : SIZE_MAX) + +/* Sum of two sizes, with overflow check. */ +static inline size_t +#if __GNUC__ >= 3 +__attribute__ ((__pure__)) +#endif +xsum (size_t size1, size_t size2) +{ + size_t sum = size1 + size2; + return (sum >= size1 ? sum : SIZE_MAX); +} + +/* Sum of three sizes, with overflow check. */ +static inline size_t +#if __GNUC__ >= 3 +__attribute__ ((__pure__)) +#endif +xsum3 (size_t size1, size_t size2, size_t size3) +{ + return xsum (xsum (size1, size2), size3); +} + +/* Sum of four sizes, with overflow check. */ +static inline size_t +#if __GNUC__ >= 3 +__attribute__ ((__pure__)) +#endif +xsum4 (size_t size1, size_t size2, size_t size3, size_t size4) +{ + return xsum (xsum (xsum (size1, size2), size3), size4); +} + +/* Maximum of two sizes, with overflow check. */ +static inline size_t +#if __GNUC__ >= 3 +__attribute__ ((__pure__)) +#endif +xmax (size_t size1, size_t size2) +{ + /* No explicit check is needed here, because for any n: + max (SIZE_MAX, n) == SIZE_MAX and max (n, SIZE_MAX) == SIZE_MAX. */ + return (size1 >= size2 ? size1 : size2); +} + +/* Multiplication of a count with an element size, with overflow check. + The count must be >= 0 and the element size must be > 0. + This is a macro, not an inline function, so that it works correctly even + when N is of a wider tupe and N > SIZE_MAX. */ +#define xtimes(N, ELSIZE) \ + ((N) <= SIZE_MAX / (ELSIZE) ? (size_t) (N) * (ELSIZE) : SIZE_MAX) + +/* Check for overflow. */ +#define size_overflow_p(SIZE) \ + ((SIZE) == SIZE_MAX) +/* Check against overflow. */ +#define size_in_bounds_p(SIZE) \ + ((SIZE) != SIZE_MAX) + +#endif /* _XSIZE_H */ diff -urN cvs-nserver-1.11.1.52.org/src/commit.c cvs-nserver-1.11.1.52/src/commit.c --- cvs-nserver-1.11.1.52.org/src/commit.c 2004-06-11 15:13:22.631468312 +0200 +++ cvs-nserver-1.11.1.52/src/commit.c 2004-06-11 15:14:13.030806448 +0200 @@ -476,7 +476,12 @@ operate on, and only work with those files in the future. This saves time--we don't want to search the file system of the working directory twice. */ - find_args.argv = (char **) xmalloc (find_args.argc * sizeof (char **)); + if (size_overflow_p (xtimes (find_args.argc, sizeof (char **)))) + { + find_args.argc = 0; + return 0; + } + find_args.argv = xmalloc (xtimes (find_args.argc, sizeof (char **))); find_args.argc = 0; walklist (find_args.ulist, copy_ulist, &find_args); diff -urN cvs-nserver-1.11.1.52.org/src/cvs.h cvs-nserver-1.11.1.52/src/cvs.h --- cvs-nserver-1.11.1.52.org/src/cvs.h 2004-06-11 15:13:22.711456152 +0200 +++ cvs-nserver-1.11.1.52/src/cvs.h 2004-06-11 15:14:13.039805080 +0200 @@ -37,6 +37,10 @@ #include "popen.h" #endif +/* Begin GNULIB headers. */ +#include "xsize.h" +/* End GNULIB headers. */ + #ifdef STDC_HEADERS #include #else diff -urN cvs-nserver-1.11.1.52.org/src/filesubr.c cvs-nserver-1.11.1.52/src/filesubr.c --- cvs-nserver-1.11.1.52.org/src/filesubr.c 2004-06-11 15:13:22.638467248 +0200 +++ cvs-nserver-1.11.1.52/src/filesubr.c 2004-06-11 15:14:13.042804624 +0200 @@ -925,8 +925,14 @@ char ***pargv; { int i; + if (size_overflow_p (xtimes (argc, sizeof (char *)))) { + *pargc = 0; + *pargv = NULL; + error (0, 0, "expand_wild: too many arguments"); + return; + } *pargc = argc; - *pargv = (char **) xmalloc (argc * sizeof (char *)); + *pargv = xmalloc (xtimes (argc, sizeof (char *))); for (i = 0; i < argc; ++i) (*pargv)[i] = xstrdup (argv[i]); } diff -urN cvs-nserver-1.11.1.52.org/src/history.c cvs-nserver-1.11.1.52/src/history.c --- cvs-nserver-1.11.1.52.org/src/history.c 2004-06-11 15:13:22.642466640 +0200 +++ cvs-nserver-1.11.1.52/src/history.c 2004-06-11 15:14:13.046804016 +0200 @@ -417,8 +417,11 @@ working = 1; break; case 'X': /* Undocumented debugging flag */ +#ifdef DEBUG histfile = optarg; +#endif break; + case 'D': /* Since specified date */ if (*since_rev || *since_tag || *backto) { @@ -900,9 +903,13 @@ { if (user_count == user_max) { - user_max += USER_INCREMENT; - user_list = (char **) xrealloc ((char *) user_list, - (int) user_max * sizeof (char *)); + user_max = xsum (user_max, USER_INCREMENT); + if (size_overflow_p (xtimes (user_max, sizeof (char *)))) + { + error (0, 0, "save_user: too many users"); + return; + } + user_list = xrealloc (user_list, xtimes (user_max, sizeof (char *))); } user_list[user_count++] = xstrdup (name); } @@ -930,9 +937,13 @@ if (file_count == file_max) { - file_max += FILE_INCREMENT; - file_list = (struct file_list_str *) xrealloc ((char *) file_list, - file_max * sizeof (*fl)); + file_max = xsum (file_max, FILE_INCREMENT); + if (size_overflow_p (xtimes (file_max, sizeof (*fl)))) + { + error (0, 0, "save_file: too many files"); + return; + } + file_list = xrealloc (file_list, xtimes (file_max, sizeof (*fl))); } fl = &file_list[file_count++]; fl->l_file = cp = xmalloc (strlen (dir) + strlen (name) + 2); @@ -971,9 +982,13 @@ { if (mod_count == mod_max) { - mod_max += MODULE_INCREMENT; - mod_list = (char **) xrealloc ((char *) mod_list, - mod_max * sizeof (char *)); + mod_max = xsum (mod_max, MODULE_INCREMENT); + if (size_overflow_p (xtimes (mod_max, sizeof (char *)))) + { + error (0, 0, "save_module: too many modules"); + return; + } + mod_list = xrealloc (mod_list, xtimes (mod_max, sizeof (char *))); } mod_list[mod_count++] = xstrdup (module); } diff -urN cvs-nserver-1.11.1.52.org/src/server.c cvs-nserver-1.11.1.52/src/server.c --- cvs-nserver-1.11.1.52.org/src/server.c 2004-06-11 15:13:22.702457520 +0200 +++ cvs-nserver-1.11.1.52/src/server.c 2004-06-11 15:20:44.835243120 +0200 @@ -914,7 +914,7 @@ int i; char *p; - if (lim < 0) + if (lim < 0 || lim > 10000) return; p = malloc (strlen (server_temp_dir) + 2 * lim + 10); if (p == NULL) @@ -1977,6 +1977,9 @@ { char *cp; + if (!data[0]) + goto error; + if (strchr (data, '+')) goto error; @@ -2108,6 +2111,14 @@ char *p; if (error_pending()) return; + + if (argument_count >= 10000) + { + if (alloc_pending (80)) + sprintf (pending_error_text, + "E Protocol error: too many arguments"); + return; + } if (argument_vector_size <= argument_count + 1) { @@ -2139,6 +2150,14 @@ char *p; if (error_pending()) return; + + if (argument_count <= 1) + { + if (alloc_pending (80)) + sprintf (pending_error_text, + "E Protocol error: called argumentx without prior call to argument"); + return; + } p = argument_vector[argument_count - 1]; p = realloc (p, strlen (p) + 1 + strlen (arg) + 1); @@ -2496,7 +2515,7 @@ save some code here... -kff */ /* Chop newline by hand, for strcmp()'s sake. */ - if (linebuf[num_red - 1] == '\n') + if (num_red > 0 && linebuf[num_red - 1] == '\n') linebuf[num_red - 1] = '\0'; if (strcmp (linebuf, CVS_Username) == 0) diff -urN cvs-nserver-1.11.1.52.org/src/wrapper.c cvs-nserver-1.11.1.52/src/wrapper.c --- cvs-nserver-1.11.1.52.org/src/wrapper.c 2004-06-11 15:13:22.708456608 +0200 +++ cvs-nserver-1.11.1.52/src/wrapper.c 2004-06-11 15:14:13.083798392 +0200 @@ -252,6 +252,30 @@ #endif /* SERVER_SUPPORT || CLIENT_SUPPORT */ /* + * Remove fmt str specifier other than %% or %s. And allow + * only max_s %s specifiers + */ +wrap_clean_fmt_str(char *fmt, int max_s) +{ + while (*fmt) { + if (fmt[0] == '%' && fmt[1]) + { + if (fmt[1] == '%') + fmt++; + else + if (fmt[1] == 's' && max_s > 0) + { + max_s--; + fmt++; + } else + *fmt = ' '; + } + fmt++; + } + return; +} + +/* * Open a file and read lines, feeding each line to a line parser. Arrange * for keeping a temporary list of wrappers at the end, if the "temp" * argument is set. @@ -575,9 +599,8 @@ args = xmalloc (strlen (e->tocvsFilter) + strlen (fileName) + strlen (buf)); - /* FIXME: sprintf will blow up if the format string contains items other - than %s, or contains too many %s's. We should instead be parsing - e->tocvsFilter ourselves and giving a real error. */ + + wrap_clean_fmt_str(e->tocvsFilter, 2); sprintf (args, e->tocvsFilter, fileName, buf); run_setup (args); run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY ); @@ -609,9 +632,8 @@ args = xmalloc (strlen (e->fromcvsFilter) + strlen (fileName)); - /* FIXME: sprintf will blow up if the format string contains items other - than %s, or contains too many %s's. We should instead be parsing - e->fromcvsFilter ourselves and giving a real error. */ + + wrap_clean_fmt_str(e->fromcvsFilter, 1); sprintf (args, e->fromcvsFilter, fileName); run_setup (args); run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL );