Skip to content

Commit

Permalink
14223 Add change key zfs channel program
Browse files Browse the repository at this point in the history
Portions contributed by: Alex Wilson <alex@cooperi.net>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Dan McDonald <danmcd@joyent.com>
Reviewed by: Mike Zeller <mike.zeller@joyent.com>
Reviewed by: Toomas Soome <tsoome@me.com>
Approved by: Dan McDonald <danmcd@joyent.com>
  • Loading branch information
jasonbking committed Nov 19, 2021
1 parent 705b668 commit d8f839f
Show file tree
Hide file tree
Showing 13 changed files with 496 additions and 10 deletions.
18 changes: 18 additions & 0 deletions usr/src/lib/libzfs_core/common/libzfs_core.c
Expand Up @@ -25,6 +25,7 @@
* Copyright (c) 2014 Integros [integros.com]
* Copyright 2017 RackTop Systems.
* Copyright (c) 2017 Datto Inc.
* Copyright 2020 Joyent, Inc.
*/

/*
Expand Down Expand Up @@ -1069,13 +1070,30 @@ lzc_channel_program_impl(const char *pool, const char *program, boolean_t sync,
{
int error;
nvlist_t *args;
nvlist_t *hidden_args = NULL;

args = fnvlist_alloc();
fnvlist_add_string(args, ZCP_ARG_PROGRAM, program);
fnvlist_add_nvlist(args, ZCP_ARG_ARGLIST, argnvl);
fnvlist_add_boolean_value(args, ZCP_ARG_SYNC, sync);
fnvlist_add_uint64(args, ZCP_ARG_INSTRLIMIT, instrlimit);
fnvlist_add_uint64(args, ZCP_ARG_MEMLIMIT, memlimit);

/*
* If any hidden arguments are passed, we pull them out of 'args'
* and into a separate nvlist so spa_history_nvl() doesn't log
* their values.
*/
if (nvlist_lookup_nvlist(argnvl, ZPOOL_HIDDEN_ARGS,
&hidden_args) == 0) {
nvlist_t *argcopy = fnvlist_dup(argnvl);

fnvlist_add_nvlist(args, ZPOOL_HIDDEN_ARGS, hidden_args);
fnvlist_remove(argcopy, ZPOOL_HIDDEN_ARGS);
fnvlist_add_nvlist(args, ZCP_ARG_ARGLIST, argcopy);
nvlist_free(argcopy);
}

error = lzc_ioctl(ZFS_IOC_CHANNEL_PROGRAM, pool, args, outnvl);
fnvlist_free(args);

Expand Down
10 changes: 9 additions & 1 deletion usr/src/man/man1m/zfs-program.1m
Expand Up @@ -11,8 +11,9 @@
.\" Copyright (c) 2016, 2017 by Delphix. All rights reserved.
.\" Copyright (c) 2018 Datto Inc.
.\" Copyright 2020 Joyent, Inc.
.\" Copyright 2021 Jason King
.\"
.Dd February 3, 2020
.Dd November 8, 2021
.Dt ZFS-PROGRAM 1M
.Os
.Sh NAME
Expand Down Expand Up @@ -350,6 +351,12 @@ They are executed in "syncing context".
.Pp
The available sync submodule functions are as follows:
.Bl -tag -width "xx"
.It Em zfs.sync.change_key(dataset, key)
Change the dataset encryption key.
.Fa key
must be in the format (raw or hex) specified by the dataset
.Sy keyformat
property.
.It Em zfs.sync.destroy(dataset, [defer=true|false])
Destroy the given dataset.
Returns 0 on successful destroy, or a nonzero error code if the dataset could
Expand Down Expand Up @@ -458,6 +465,7 @@ would successfully destroy the dataset.
.Pp
The available zfs.check functions are:
.Bl -tag -width "xx"
.It Em zfs.check.change_key(dataset, key)
.It Em zfs.check.destroy(dataset, [defer=true|false])
.It Em zfs.check.promote(dataset)
.It Em zfs.check.rollback(filesystem)
Expand Down
7 changes: 7 additions & 0 deletions usr/src/pkg/manifests/system-test-zfstest.p5m
Expand Up @@ -15,6 +15,7 @@
# Copyright 2016, OmniTI Computer Consulting, Inc. All rights reserved.
# Copyright 2020 Joyent, Inc.
# Copyright (c) 2018 Datto Inc.
# Copyright 2021 Jason King
#

set name=pkg.fmri value=pkg:/system/test/zfstest@$(PKGVERS)
Expand Down Expand Up @@ -411,10 +412,16 @@ file \
path=opt/zfs-tests/tests/functional/channel_program/lua_core/tst.timeout.zcp \
mode=0444
dir path=opt/zfs-tests/tests/functional/channel_program/synctask_core
file \
path=opt/zfs-tests/tests/functional/channel_program/synctask_core/change_key.exe \
mode=0555
file path=opt/zfs-tests/tests/functional/channel_program/synctask_core/cleanup \
mode=0555
file path=opt/zfs-tests/tests/functional/channel_program/synctask_core/setup \
mode=0555
file \
path=opt/zfs-tests/tests/functional/channel_program/synctask_core/tst.change_key \
mode=0555
file \
path=opt/zfs-tests/tests/functional/channel_program/synctask_core/tst.destroy_fs \
mode=0555
Expand Down
Expand Up @@ -11,15 +11,27 @@

#
# Copyright (c) 2016 by Delphix. All rights reserved.
# Copyright 2020 Joyent, Inc.
#

include $(SRC)/Makefile.master
include $(SRC)/cmd/Makefile.cmd
include $(SRC)/cmd/Makefile.ctf

ROOTOPTPKG = $(ROOT)/opt/zfs-tests
TESTDIR = $(ROOTOPTPKG)/tests/functional/channel_program/synctask_core

KSHFILES :sh= ls *.ksh
PROGS = $(KSHFILES:.ksh=)
KSHPROGS = $(KSHFILES:.ksh=)

SRCS :sh= ls *.c
CPROGS = $(SRCS:%.c=%.exe)
LDLIBS = $(LDLIBS.cmd)
LDLIBS += -lzfs_core -lnvpair
CSTD = $(CSTD_GNU99)
OBJS = $(SRCS:%.c=%.o)

PROGS = $(KSHPROGS) $(CPROGS)
FILES :sh= ls *.zcp *.out *.err 2>/dev/null; true

INSTPROGS = $(PROGS:%=$(TESTDIR)/%)
Expand All @@ -28,7 +40,9 @@ INSTFILES = $(FILES:%=$(TESTDIR)/%)
$(INSTPROGS) := FILEMODE = 0555
$(INSTFILES) := FILEMODE = 0444

all lint clean clobber:
all: $(CPROGS)

clean clobber:

install: $(INSTPROGS) $(INSTFILES)

Expand All @@ -43,3 +57,16 @@ $(TESTDIR)/%: %.ksh

$(TESTDIR)/%: %
$(INS.file)

%.o: ../%.c
$(COMPILE.c) $<

%.exe: %.o
$(LINK.c) $< -o $@ $(LDLIBS)
$(POST_PROCESS)

clobber: clean
-$(RM) $(PROGS)

clean:
-$(RM) $(OBJS)
@@ -0,0 +1,98 @@
/*
* CDDL HEADER START
*
* 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.
*
* CDDL HEADER END
*/

/*
* Copyright 2020 Joyent, Inc.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/debug.h>
#include <sys/fs/zfs.h>
#include <libzfs_core.h>
#include <libnvpair.h>

const char prog[] =
"arg = ... \n"
"fs = arg[\"dataset\"]\n"
"hexkey = arg[\"" ZPOOL_HIDDEN_ARGS "\"][\"key\"]\n"
"err = zfs.sync.change_key(fs, hexkey, 'hex')\n"
"msg = \"changing key on \" .. fs .. \" err=\" .. err\n"
"return msg";

/*
* Get the pool name from a dataset. This is crude but good enough
* for a test.
*/
static char *
get_pool(const char *dataset)
{
char *res = strdup(dataset);

if (res == NULL)
abort();

char *p = strchr(res, '/');

if (p != NULL)
*p = '\0';

return (res);
}

int
main(int argc, char *argv[])
{
const char *dataset = argv[1];
const char *key = argv[2];
char *pool = NULL;
nvlist_t *args = fnvlist_alloc();
nvlist_t *hidden_args = fnvlist_alloc();
nvlist_t *result = NULL;
int ret = 0;

if (argc != 3) {
(void) fprintf(stderr, "Usage: %s dataset key\n", argv[0]);
exit(2);
}

VERIFY0(libzfs_core_init());

pool = get_pool(dataset);

fnvlist_add_string(args, "dataset", dataset);
fnvlist_add_string(hidden_args, "key", key);
fnvlist_add_nvlist(args, ZPOOL_HIDDEN_ARGS, hidden_args);

ret = lzc_channel_program(pool, prog, ZCP_DEFAULT_INSTRLIMIT,
ZCP_DEFAULT_MEMLIMIT, args, &result);

(void) printf("lzc_channel_program returned %d", ret);
if (ret != 0)
(void) printf(" (%s)", strerror(ret));
(void) fputc('\n', stdout);

dump_nvlist(result, 5);

nvlist_free(args);
nvlist_free(hidden_args);
nvlist_free(result);
free(pool);

libzfs_core_fini();

return (ret);
}
@@ -0,0 +1,56 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# 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.
#
# CDDL HEADER END
#

#
# Copyright 2020 Joyent, Inc.
#

. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/cli_root/zfs_load-key/zfs_load-key_common.kshlib
. $STF_SUITE/tests/functional/channel_program/channel_common.kshlib

#
# DESCRIPTION:
# Try to change an encrypted dataset key via a ZFS channel program

verify_runnable "both"

function cleanup
{
datasetexists $TESTPOOL/$TESTFS1 && \
log_must zfs destroy -f $TESTPOOL/$TESTFS1
}
log_onexit cleanup

log_assert "zfs.sync.change_key should change key material"

log_must eval "echo $HEXKEY | zfs create -o encryption=on" \
"-o keyformat=hex -o keylocation=prompt $TESTPOOL/$TESTFS1"

log_must $ZCP_ROOT/synctask_core/change_key.exe $TESTPOOL/$TESTFS1 $HEXKEY1

# Key shouldn't appear in zpool history when using change_key.exe
log_mustnot eval "zfs history -il $TESTPOOL | grep $HEXKEY1"

log_must zfs unmount $TESTPOOL/$TESTFS1
log_must zfs unload-key $TESTPOOL/$TESTFS1

log_mustnot eval "echo $HEXKEY | zfs load-key $TESTPOOL/$TESTFS1"
log_must key_unavailable $TESTPOOL/$TESTFS1

log_must eval "echo $HEXKEY1 | zfs load-key $TESTPOOL/$TESTFS1"

log_pass "zfs.sync.change_key should change key material"
1 change: 1 addition & 0 deletions usr/src/uts/common/Makefile.files
Expand Up @@ -1431,6 +1431,7 @@ ZFS_COMMON_OBJS += \
zap_leaf.o \
zap_micro.o \
zcp.o \
zcp_change_key.o \
zcp_get.o \
zcp_set.o \
zcp_global.o \
Expand Down
9 changes: 2 additions & 7 deletions usr/src/uts/common/fs/zfs/dsl_crypt.c
Expand Up @@ -1220,12 +1220,7 @@ dsl_crypto_key_sync(dsl_crypto_key_t *dck, dmu_tx_t *tx)
tx);
}

typedef struct spa_keystore_change_key_args {
const char *skcka_dsname;
dsl_crypto_params_t *skcka_cp;
} spa_keystore_change_key_args_t;

static int
int
spa_keystore_change_key_check(void *arg, dmu_tx_t *tx)
{
int ret;
Expand Down Expand Up @@ -1501,7 +1496,7 @@ spa_keystore_change_key_sync_impl(uint64_t rddobj, uint64_t ddobj,
dsl_dir_rele(dd, FTAG);
}

static void
void
spa_keystore_change_key_sync(void *arg, dmu_tx_t *tx)
{
dsl_dataset_t *ds;
Expand Down
7 changes: 7 additions & 0 deletions usr/src/uts/common/fs/zfs/sys/dsl_crypt.h
Expand Up @@ -164,6 +164,11 @@ typedef struct spa_keystore {
avl_tree_t sk_wkeys;
} spa_keystore_t;

typedef struct spa_keystore_change_key_args {
const char *skcka_dsname;
dsl_crypto_params_t *skcka_cp;
} spa_keystore_change_key_args_t;

int dsl_crypto_params_create_nvlist(dcp_cmd_t cmd, nvlist_t *props,
nvlist_t *crypto_args, dsl_crypto_params_t **dcp_out);
void dsl_crypto_params_free(dsl_crypto_params_t *dcp, boolean_t unload);
Expand Down Expand Up @@ -199,6 +204,8 @@ int dsl_crypto_recv_raw(const char *poolname, uint64_t dsobj, uint64_t fromobj,
dmu_objset_type_t ostype, nvlist_t *nvl, boolean_t do_key);

int spa_keystore_change_key(const char *dsname, dsl_crypto_params_t *dcp);
int spa_keystore_change_key_check(void *arg, dmu_tx_t *tx);
void spa_keystore_change_key_sync(void *arg, dmu_tx_t *tx);
int dsl_dir_rename_crypt_check(dsl_dir_t *dd, dsl_dir_t *newparent);
int dsl_dataset_promote_crypt_check(dsl_dir_t *target, dsl_dir_t *origin);
void dsl_dataset_promote_crypt_sync(dsl_dir_t *target, dsl_dir_t *origin,
Expand Down

0 comments on commit d8f839f

Please sign in to comment.