Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

infinite loop in nvlist_print_json() #12175

Closed
cfcs opened this issue Jun 1, 2021 · 0 comments · Fixed by #12176
Closed

infinite loop in nvlist_print_json() #12175

cfcs opened this issue Jun 1, 2021 · 0 comments · Fixed by #12176
Labels
Status: Triage Needed New issue which needs to be triaged Type: Defect Incorrect behavior (e.g. crash, hang)

Comments

@cfcs
Copy link

cfcs commented Jun 1, 2021

System information

Type Version/Name
Distribution Name debian
Distribution Version testing
Linux Kernel 5.4.88-1
Architecture amd64
ZFS Version 2.0.3-8
SPL Version n/a

Describe the problem you're observing

When printing a string that ends in an invalid UTF-8 sequence, nvlist_print_json_string goes into an infinite loop because mbrtowc will return a negative result when passed a &mbr that has detected an error, without looking at input or the other parameters.

It's quite possible that mbrtowc behaves differently in other implementations, I'm using glibc.

The conditional below is true when when the result is negative because size_t is unsigned (maybe it should be ssize_t?), meaning it stays in the loop whenever sz != 0:

size_t sz;
while ((sz = mbrtowc(&c, input, MB_CUR_MAX, &mbr)) > 0) {

I'm not sure how this should be fixed: either changing the type of sz or ensuring that input does stay smaller than the end of input seem like decent candidates for a solution.

I would have expected that the function should either fail, or print a truncated version of the string.

Describe how to reproduce the problem

hang.hex:

000100000000000001000000200000000300000001000000090000006162
000000000000418000000900000000000000

This is the nvlist encoding of

{
   "ab": "A\x80"
}

trigger.c:

#define _POSIX_SOURCE 1
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
typedef unsigned int uint_t;
typedef int boolean_t;
typedef unsigned char uchar_t;
typedef int hrtime_t; /* TODO wrong */

#include <libzfs/sys/nvpair.h>
#include <libzfs/libnvpair.h>

int
main(int argc, char **argv)
{
  size_t nv_sz = 0;
  FILE *fd = NULL;
  struct stat statbuf;
  if (argc != 2) return (10);

  fd = fopen(argv[1], "r");
  if (!fd) return (1);

  if(fstat(fileno(fd), &statbuf)) return (2);
  nv_sz = statbuf.st_size;

  char *outbuf = malloc(nv_sz);
  if (fread(outbuf, nv_sz, 1, fd) != 1) return (3);

  nvlist_t *check = fnvlist_unpack(outbuf, nv_sz);

  // nvlist_print(stdout, check);

  nvlist_print_json(stdout, check);

  fflush(stdout);
  return 0;
}
xxd -ps -r hang.hex > hang.bin

gcc -std=c18 -Wall -pie  -I/usr/include/libzfs/ trigger.c -lnvpair -luutil -o trigger.exe

./trigger.exe hang.bin

This (on linux with glibc) outputs

{"ab":"AAAAAAA .... infinite A's

Here is ldd ./trigger.exe:

	linux-vdso.so.1 (0x00007ffdfb444000)
	libnvpair.so.3 => /lib/x86_64-linux-gnu/libnvpair.so.3 (0x000079b9258c9000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x000079b925704000)
	/lib64/ld-linux-x86-64.so.2 (0x000079b925904000)

Background

I ran into this when using afl-fuzz to look for cases where my own implementation of libnvlist disagrees with the upstream implementation, using the JSON output to compare outputs from decoding.
The function is not part of the standard Solaris interface, but I was unable to find much documentation on the expected semantics in the serialization format, so I thought this would be an easy way to find inconsistencies.
I don't rely on nvlist_print_json() for anything important, and don't know if anybody else does, but I guess it would be neat if this behaviour could be changed.

@cfcs cfcs added Status: Triage Needed New issue which needs to be triaged Type: Defect Incorrect behavior (e.g. crash, hang) labels Jun 1, 2021
ghost pushed a commit to truenas/zfs that referenced this issue Jun 1, 2021
Move check for errors from mbrtowc() into the loop.  The error values
are not actually negative, so we don't break out of the loop when they
are encountered.

Fixes: openzfs#12175
Signed-off-by: Ryan Moeller <ryan@iXsystems.com>
@ghost ghost linked a pull request Jun 1, 2021 that will close this issue
13 tasks
tonynguien pushed a commit that referenced this issue Jun 4, 2021
Move check for errors from mbrtowc() into the loop.  The error values
are not actually negative, so we don't break out of the loop when they
are encountered.

Reviewed-by: Tony Nguyen <tony.nguyen@delphix.com>
Reviewed-by: John Kennedy <john.kennedy@delphix.com>
Signed-off-by: Ryan Moeller <ryan@iXsystems.com>
Closes #12175
Closes #12176
behlendorf pushed a commit to behlendorf/zfs that referenced this issue Jun 8, 2021
Move check for errors from mbrtowc() into the loop.  The error values
are not actually negative, so we don't break out of the loop when they
are encountered.

Reviewed-by: Tony Nguyen <tony.nguyen@delphix.com>
Reviewed-by: John Kennedy <john.kennedy@delphix.com>
Signed-off-by: Ryan Moeller <ryan@iXsystems.com>
Closes openzfs#12175
Closes openzfs#12176
behlendorf pushed a commit to behlendorf/zfs that referenced this issue Jun 8, 2021
Move check for errors from mbrtowc() into the loop.  The error values
are not actually negative, so we don't break out of the loop when they
are encountered.

Reviewed-by: Tony Nguyen <tony.nguyen@delphix.com>
Reviewed-by: John Kennedy <john.kennedy@delphix.com>
Signed-off-by: Ryan Moeller <ryan@iXsystems.com>
Closes openzfs#12175
Closes openzfs#12176
behlendorf pushed a commit to behlendorf/zfs that referenced this issue Jun 9, 2021
Move check for errors from mbrtowc() into the loop.  The error values
are not actually negative, so we don't break out of the loop when they
are encountered.

Reviewed-by: Tony Nguyen <tony.nguyen@delphix.com>
Reviewed-by: John Kennedy <john.kennedy@delphix.com>
Signed-off-by: Ryan Moeller <ryan@iXsystems.com>
Closes openzfs#12175
Closes openzfs#12176
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Triage Needed New issue which needs to be triaged Type: Defect Incorrect behavior (e.g. crash, hang)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant