@@ -20,7 +20,7 @@
*/

/*
* Copyright (c) 2012, 2017 by Delphix. All rights reserved.
* Copyright (c) 2012, 2018 by Delphix. All rights reserved.
* Copyright (c) 2013 Steven Hartland. All rights reserved.
* Copyright (c) 2017 Datto Inc.
* Copyright 2017 RackTop Systems.
@@ -78,6 +78,9 @@
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#ifdef ZFS_DEBUG
#include <stdio.h>
#endif
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
@@ -91,6 +94,42 @@ static int g_fd = -1;
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
static int g_refcount;

#ifdef ZFS_DEBUG
static zfs_ioc_t fail_ioc_cmd;
static zfs_errno_t fail_ioc_err;

static void
libzfs_core_debug_ioc(void)
{
/*
* To test running newer user space binaries with kernel's
* that don't yet support an ioctl or a new ioctl arg we
* provide an override to intentionally fail an ioctl.
*
* USAGE:
* The override variable, ZFS_IOC_TEST, is of the form "cmd:err"
*
* For example, to fail a ZFS_IOC_POOL_CHECKPOINT with a
* ZFS_ERR_IOC_CMD_UNAVAIL, the string would be "0x5a4d:1029"
*
* $ sudo sh -c "ZFS_IOC_TEST=0x5a4d:1029 zpool checkpoint tank"
* cannot checkpoint 'tank': the loaded zfs module does not support
* this operation. A reboot may be required to enable this operation.
*/
if (fail_ioc_cmd == 0) {
char *ioc_test = getenv("ZFS_IOC_TEST");
unsigned int ioc_num = 0, ioc_err = 0;

if (ioc_test != NULL &&
sscanf(ioc_test, "%i:%i", &ioc_num, &ioc_err) == 2 &&
ioc_num < ZFS_IOC_LAST) {
fail_ioc_cmd = ioc_num;
fail_ioc_err = ioc_err;
}
}
}
#endif

int
libzfs_core_init(void)
{
@@ -103,6 +142,10 @@ libzfs_core_init(void)
}
}
g_refcount++;

#ifdef ZFS_DEBUG
libzfs_core_debug_ioc();
#endif
(void) pthread_mutex_unlock(&g_lock);
return (0);
}
@@ -135,6 +178,11 @@ lzc_ioctl(zfs_ioc_t ioc, const char *name,
ASSERT3S(g_refcount, >, 0);
VERIFY3S(g_fd, !=, -1);

#ifdef ZFS_DEBUG
if (ioc == fail_ioc_cmd)
return (fail_ioc_err);
#endif

if (name != NULL)
(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));

Large diffs are not rendered by default.

@@ -858,5 +858,5 @@ tests = ['zvol_swap_001_pos', 'zvol_swap_002_pos', 'zvol_swap_003_pos',
tags = ['functional', 'zvol', 'zvol_swap']

[tests/functional/libzfs]
tests = ['many_fds']
tests = ['many_fds', 'libzfs_input']
tags = ['functional', 'libzfs']
@@ -9,6 +9,7 @@ SUBDIRS = \
file_trunc \
file_write \
largest_file \
libzfs_input_check \
mkbusy \
mkfile \
mkfiles \
@@ -0,0 +1 @@
/libzfs_input_check
@@ -0,0 +1,14 @@
include $(top_srcdir)/config/Rules.am

pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin

DEFAULT_INCLUDES += \
-I$(top_srcdir)/include \
-I$(top_srcdir)/lib/libspl/include

pkgexec_PROGRAMS = libzfs_input_check

libzfs_input_check_SOURCES = libzfs_input_check.c
libzfs_input_check_LDADD = \
$(top_builddir)/lib/libnvpair/libnvpair.la \
$(top_builddir)/lib/libzfs_core/libzfs_core.la

Large diffs are not rendered by default.

@@ -160,6 +160,7 @@ export ZFSTEST_FILES='chg_usr_exec
file_trunc
file_write
largest_file
libzfs_input_check
mkbusy
mkfile
mkfiles
@@ -6,7 +6,8 @@ pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/libzfs

dist_pkgdata_SCRIPTS = \
cleanup.ksh \
setup.ksh
setup.ksh \
libzfs_input.ksh

DEFAULT_INCLUDES += \
-I$(top_srcdir)/include \
@@ -0,0 +1,30 @@
#!/bin/ksh -p
#
# This file and its contents are supplied under the terms of the
# Common Development and Distribution License ("CDDL"), version 1.0.
# You may only use this file in accordance with the terms of version
# 1.0 of the CDDL.
#
# A full copy of the text of the CDDL should have accompanied this
# source. A copy of the CDDL is also available via the Internet at
# http://www.illumos.org/license/CDDL.
#

#
# Copyright (c) 2018 by Delphix. All rights reserved.
#

. $STF_SUITE/include/libtest.shlib

verify_runnable "global"

#
# DESCRIPTION:
# run C program to test passing different input to libzfs ioctls
#

log_assert "libzfs ioctls handle invalid input arguments"

log_must libzfs_input_check $TESTPOOL

log_pass "libzfs ioctls handle invalid input arguments"