diff --git a/.gitignore b/.gitignore index 61f6ee3a7..74004908b 100644 --- a/.gitignore +++ b/.gitignore @@ -444,6 +444,7 @@ Makefile.in /tests/parallel/test-parallel /tests/regressions/rhbz501893 /tests/regressions/rhbz790721 +/tests/regressions/rhbz914931 /tests/rsync/rsyncd.pid /test-tool/libguestfs-test-tool /test-tool/libguestfs-test-tool.1 diff --git a/daemon/debug.c b/daemon/debug.c index 19349514e..0bb4626bf 100644 --- a/daemon/debug.c +++ b/daemon/debug.c @@ -73,6 +73,7 @@ static char *debug_qtrace (const char *subcmd, size_t argc, char *const *const a static char *debug_segv (const char *subcmd, size_t argc, char *const *const argv); static char *debug_setenv (const char *subcmd, size_t argc, char *const *const argv); static char *debug_sh (const char *subcmd, size_t argc, char *const *const argv); +static void deliberately_cause_a_segfault (void); static struct cmd cmds[] = { { "help", debug_help }, @@ -210,14 +211,7 @@ debug_fds (const char *subcmd, size_t argc, char *const *const argv) static char * debug_segv (const char *subcmd, size_t argc, char *const *const argv) { - /* http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html - * "Dereferencing a NULL Pointer: contrary to popular belief, - * dereferencing a null pointer in C is undefined. It is not defined - * to trap [...]" - */ - volatile int *ptr = NULL; - /* coverity[var_deref_op] */ - *ptr = 1; + deliberately_cause_a_segfault (); return NULL; } @@ -689,3 +683,64 @@ do_debug_upload (const char *filename, int mode) return 0; } + +/* Internal function used only when testing + * https://bugzilla.redhat.com/show_bug.cgi?id=914931 + */ + +static int +crash_cb (void *countv, const void *buf, size_t len) +{ + int *countp = countv; + + (*countp)--; + sleep (1); + + if (*countp == 0) + deliberately_cause_a_segfault (); + + return 0; +} + +/* Has one FileIn parameter. */ +int +do_internal_rhbz914931 (int count) +{ + int r; + + if (count <= 0 || count > 1000) { + reply_with_error ("count out of range"); + return -1; + } + + r = receive_file (crash_cb, &count); + if (r == -1) { /* write error */ + int err = errno; + cancel_receive (); + errno = err; + reply_with_error ("write error"); + return -1; + } + if (r == -2) { /* cancellation from library */ + /* This error is ignored by the library since it initiated the + * cancel. Nevertheless we must send an error reply here. + */ + reply_with_error ("file upload cancelled"); + return -1; + } + + return 0; +} + +static void +deliberately_cause_a_segfault (void) +{ + /* http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html + * "Dereferencing a NULL Pointer: contrary to popular belief, + * dereferencing a null pointer in C is undefined. It is not defined + * to trap [...]" + */ + volatile int *ptr = NULL; + /* coverity[var_deref_op] */ + *ptr = 1; +} diff --git a/generator/actions.ml b/generator/actions.ml index 4f18f418c..8a8e3ffc0 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -10735,6 +10735,17 @@ device. That is, not a partition or a logical device." }; longdesc = "\ Parse a mountable string." }; + { defaults with + name = "internal_rhbz914931"; + style = RErr, [FileIn "filename"; Int "count"], []; + proc_nr = Some 397; + visibility = VInternal; + cancellable = true; + shortdesc = "used only to test rhbz914931 (internal use only)"; + longdesc = "\ +This is only used to debug RHBZ#914931. Note that this +deliberately crashes guestfsd." }; + ] (* Non-API meta-commands available only in guestfish. diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index 4391a3343..8b84f5708 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -396 +397 diff --git a/tests/regressions/Makefile.am b/tests/regressions/Makefile.am index ce02a7144..e0077d71d 100644 --- a/tests/regressions/Makefile.am +++ b/tests/regressions/Makefile.am @@ -30,6 +30,7 @@ TESTS = \ rhbz790721 \ rhbz811649.sh \ rhbz895904.sh \ + rhbz914931 \ test-noexec-stack.pl tests_not_run = \ @@ -42,7 +43,8 @@ TESTS_ENVIRONMENT = \ check_PROGRAMS = \ rhbz501893 \ - rhbz790721 + rhbz790721 \ + rhbz914931 rhbz501893_SOURCES = rhbz501893.c rhbz501893_CPPFLAGS = \ @@ -63,6 +65,17 @@ rhbz790721_CFLAGS = \ rhbz790721_LDADD = \ $(top_builddir)/src/libguestfs.la +rhbz914931_SOURCES = rhbz914931.c +rhbz914931_CPPFLAGS = \ + -I$(top_srcdir)/src -I$(top_builddir)/src \ + -DGUESTFS_PRIVATE=1 +rhbz914931_CFLAGS = \ + -pthread \ + $(WARN_CFLAGS) $(WERROR_CFLAGS) \ + $(GPROF_CFLAGS) $(GCOV_CFLAGS) +rhbz914931_LDADD = \ + $(top_builddir)/src/libguestfs.la + EXTRA_DIST = \ $(TESTS) \ $(tests_not_run) \ diff --git a/tests/regressions/rhbz914931.c b/tests/regressions/rhbz914931.c new file mode 100644 index 000000000..c33ab3c56 --- /dev/null +++ b/tests/regressions/rhbz914931.c @@ -0,0 +1,70 @@ +/* libguestfs + * Copyright (C) 2013 Red Hat 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 of the License, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* Regression test for RHBZ#914931. Simulate an appliance crash + * during a FileIn operation. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "guestfs.h" +#include "guestfs-internal-frontend.h" + +int +main (int argc, char *argv[]) +{ + guestfs_h *g; + int r; + + g = guestfs_create (); + if (!g) { + perror ("guestfs_create"); + exit (EXIT_FAILURE); + } + + if (guestfs_add_drive_opts (g, "/dev/null", + GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", + GUESTFS_ADD_DRIVE_OPTS_READONLY, 1, + -1) == -1) + exit (EXIT_FAILURE); + + if (guestfs_launch (g) == -1) + exit (EXIT_FAILURE); + + /* Perform the upload-with-crash. Prior to RHBZ#914931 being fixed, + * this would also cause libguestfs (ie. us) to segfault. + */ + r = guestfs_internal_rhbz914931 (g, "/dev/zero", + 5 /* seconds before appliance crash */); + + /* We expect that call to fail, not segfault. */ + assert (r == -1); + + /* Close the handle. */ + guestfs_close (g); + + /* It's success if we get this far without the program segfaulting. */ + exit (EXIT_SUCCESS); +}