summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorRyan Moeller <[email protected]>2020-03-18 15:54:12 -0400
committerGitHub <[email protected]>2020-03-18 12:54:12 -0700
commit22df2457a7b8265d999a2fe48f3e8e941c8fdde5 (patch)
tree78a33a544b885b5cdbfcff1d2c7c16c44e35f529 /lib
parent4df8b2c3739c50be2e0a5aa5b6d0d131e8b8e3f3 (diff)
Avoid core dump on invalid redaction bookmark
libzfs aborts and dumps core on EINVAL from the kernel when trying to do a redacted send with a bookmark that is not a redaction bookmark. Move redacted bookmark validation into libzfs. Check if the bookmark given for redactions is actually a redaction bookmark. Print an error message and exit gracefully if it is not. Don't abort on EINVAL in zfs_send_one. Reviewed-by: Paul Dagnelie <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Ryan Moeller <[email protected]> Closes #10138
Diffstat (limited to 'lib')
-rw-r--r--lib/libzfs/libzfs_sendrecv.c48
1 files changed, 44 insertions, 4 deletions
diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c
index 457154171..ce6a2737b 100644
--- a/lib/libzfs/libzfs_sendrecv.c
+++ b/lib/libzfs/libzfs_sendrecv.c
@@ -2816,6 +2816,7 @@ zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,
{
int err;
libzfs_handle_t *hdl = zhp->zfs_hdl;
+ char *name = zhp->zfs_name;
int orig_fd = fd;
pthread_t ddtid, ptid;
progress_arg_t pa = { 0 };
@@ -2823,7 +2824,7 @@ zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,
char errbuf[1024];
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
- "warning: cannot send '%s'"), zhp->zfs_name);
+ "warning: cannot send '%s'"), name);
if (from != NULL && strchr(from, '@')) {
zfs_handle_t *from_zhp = zfs_open(hdl, from,
@@ -2839,6 +2840,44 @@ zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,
zfs_close(from_zhp);
}
+ if (redactbook != NULL) {
+ char bookname[ZFS_MAX_DATASET_NAME_LEN];
+ nvlist_t *redact_snaps;
+ zfs_handle_t *book_zhp;
+ char *at, *pound;
+ int dsnamelen;
+
+ pound = strchr(redactbook, '#');
+ if (pound != NULL)
+ redactbook = pound + 1;
+ at = strchr(name, '@');
+ if (at == NULL) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "cannot do a redacted send to a filesystem"));
+ return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
+ }
+ dsnamelen = at - name;
+ if (snprintf(bookname, sizeof (bookname), "%.*s#%s",
+ dsnamelen, name, redactbook)
+ >= sizeof (bookname)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid bookmark name"));
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+ }
+ book_zhp = zfs_open(hdl, bookname, ZFS_TYPE_BOOKMARK);
+ if (book_zhp == NULL)
+ return (-1);
+ if (nvlist_lookup_nvlist(book_zhp->zfs_props,
+ zfs_prop_to_name(ZFS_PROP_REDACT_SNAPS),
+ &redact_snaps) != 0 || redact_snaps == NULL) {
+ zfs_close(book_zhp);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "not a redaction bookmark"));
+ return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
+ }
+ zfs_close(book_zhp);
+ }
+
/*
* Send fs properties
*/
@@ -2909,7 +2948,7 @@ zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,
}
}
- err = lzc_send_redacted(zhp->zfs_name, from, fd,
+ err = lzc_send_redacted(name, from, fd,
lzc_flags_from_sendflags(flags), redactbook);
if (flags->progress) {
@@ -2948,7 +2987,7 @@ zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,
case ENOENT:
case ESRCH:
- if (lzc_exists(zhp->zfs_name)) {
+ if (lzc_exists(name)) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"incremental source (%s) does not exist"),
from);
@@ -2967,7 +3006,9 @@ zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,
return (zfs_error(hdl, EZFS_BUSY, errbuf));
case EDQUOT:
+ case EFAULT:
case EFBIG:
+ case EINVAL:
case EIO:
case ENOLINK:
case ENOSPC:
@@ -2975,7 +3016,6 @@ zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,
case ENXIO:
case EPIPE:
case ERANGE:
- case EFAULT:
case EROFS:
zfs_error_aux(hdl, strerror(errno));
return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));