diff options
197 files changed, 6282 insertions, 1691 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index e62b172efea9..b5c96820c192 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -4,7 +4,7 @@ compute_engine_instance: # gcloud compute images list --project freebsd-org-cloud-dev --no-standard-images platform: freebsd image_project: freebsd-org-cloud-dev - image: freebsd-14-2-release-amd64-ufs + image: freebsd-14-3-release-amd64-ufs cpu: 8 memory: 8G disk: 40 diff --git a/Makefile.inc1 b/Makefile.inc1 index dfd31456ad5a..6ace6a6b5eaf 100644 --- a/Makefile.inc1 +++ b/Makefile.inc1 @@ -523,25 +523,6 @@ BUILDENV_SHELL?=/bin/sh .endif .if !defined(_MKSHOWCONFIG) -.if !defined(VCS_REVISION) || empty(VCS_REVISION) -.if !defined(SVNVERSION_CMD) || empty(SVNVERSION_CMD) -. for _D in ${PATH:S,:, ,g} -. if exists(${_D}/svnversion) -SVNVERSION_CMD?=${_D}/svnversion -. endif -. if exists(${_D}/svnliteversion) -SVNVERSION_CMD?=${_D}/svnliteversion -. endif -. endfor -.endif -.if defined(SVNVERSION_CMD) && !empty(SVNVERSION_CMD) -_VCS_REVISION?= $$(eval ${SVNVERSION_CMD} ${SRCDIR}) -. if !empty(_VCS_REVISION) -VCS_REVISION= $$(echo r${_VCS_REVISION}) -.export VCS_REVISION -. endif -.endif -.endif .if !defined(GIT_CMD) || empty(GIT_CMD) . for _P in /usr/bin /usr/local/bin @@ -603,6 +584,7 @@ EXTRA_REVISION= p${_BRANCH:C/.*-p([0-9]+$)/\1/} .if !defined(PKG_VERSION) PKG_VERSION:= ${_PKG_REVISION}${EXTRA_REVISION:C/[[:space:]]//g} .endif + .endif # !defined(_MKSHOWCONFIG) .if make(*package*) @@ -2225,9 +2207,6 @@ create-world-package-${pkgname}: .PHONY /^name/ { printf("===> Creating %s-", $$2); next } \ /^version/ { print $$2; next } \ ' ${WSTAGEDIR}/${pkgname}.ucl - @if [ "${pkgname}" == "runtime" ]; then \ - sed -i '' -e "s/%VCS_REVISION%/${VCS_REVISION}/" ${WSTAGEDIR}/${pkgname}.ucl ; \ - fi ${PKG_CMD} -o ABI=${PKG_ABI} -o ALLOW_BASE_SHLIBS=yes \ -o OSVERSION="${SRCRELDATE}" \ create -f ${PKG_FORMAT} ${PKG_CLEVEL} \ @@ -2548,6 +2527,10 @@ ${_bt}-usr.sbin/kldxref: ${_bt_libelf_depend} ${_bt_libkldelf_depend} .if ${BOOTSTRAPPING} < 1300059 ${_bt}-libexec/flua: ${_bt}-lib/liblua _flua= lib/liblua libexec/flua +.if ${BOOTSTRAPPING} == 0 +_flua+= lib/libmd lib/libucl lib/libyaml +${_bt}-libexec/flua: ${_bt}-lib/libmd ${_bt}-lib/libucl ${_bt}-lib/libyaml +.endif # BOOTSTRAPPING == 0 .endif # r245440 mtree -N support added diff --git a/cddl/share/zfs/compatibility.d/Makefile b/cddl/share/zfs/compatibility.d/Makefile index 6cdb64b0fccb..6d3663081ae6 100644 --- a/cddl/share/zfs/compatibility.d/Makefile +++ b/cddl/share/zfs/compatibility.d/Makefile @@ -24,6 +24,7 @@ FILES= \ openzfs-2.1-linux \ openzfs-2.2 \ openzfs-2.3 \ + openzfs-2.4 \ zol-0.6.1 \ zol-0.6.4 \ zol-0.6.5 \ @@ -60,7 +61,9 @@ LINKS= \ ${FILESDIR}/openzfs-2.2 ${FILESDIR}/openzfs-2.2-linux \ ${FILESDIR}/openzfs-2.2 ${FILESDIR}/openzfs-2.2-freebsd \ ${FILESDIR}/openzfs-2.3 ${FILESDIR}/openzfs-2.3-linux \ - ${FILESDIR}/openzfs-2.3 ${FILESDIR}/openzfs-2.3-freebsd + ${FILESDIR}/openzfs-2.3 ${FILESDIR}/openzfs-2.3-freebsd \ + ${FILESDIR}/openzfs-2.4 ${FILESDIR}/openzfs-2.4-linux \ + ${FILESDIR}/openzfs-2.4 ${FILESDIR}/openzfs-2.4-freebsd LINKMODE= ${NOBINMODE} diff --git a/crypto/heimdal/kadmin/dump.c b/crypto/heimdal/kadmin/dump.c index 91a5ada86607..2c302eced210 100644 --- a/crypto/heimdal/kadmin/dump.c +++ b/crypto/heimdal/kadmin/dump.c @@ -42,32 +42,51 @@ dump(struct dump_options *opt, int argc, char **argv) { krb5_error_code ret; FILE *f; + struct hdb_print_entry_arg parg; HDB *db = NULL; - if(!local_flag) { + if (!local_flag) { krb5_warnx(context, "dump is only available in local (-l) mode"); return 0; } db = _kadm5_s_get_db(kadm_handle); - if(argc == 0) + if (argc == 0) f = stdout; else f = fopen(argv[0], "w"); - if(f == NULL) { + if (f == NULL) { krb5_warn(context, errno, "open: %s", argv[0]); goto out; } ret = db->hdb_open(context, db, O_RDONLY, 0600); - if(ret) { + if (ret) { krb5_warn(context, ret, "hdb_open"); goto out; } + if (!opt->format_string || strcmp(opt->format_string, "Heimdal") == 0) { + parg.fmt = HDB_DUMP_HEIMDAL; + } else if (opt->format_string && strcmp(opt->format_string, "MIT") == 0) { + parg.fmt = HDB_DUMP_MIT; + fprintf(f, "kdb5_util load_dump version 5\n"); /* 5||6, either way */ + } else if (opt->format_string) { + /* Open the format string as a MIT mkey file. */ + ret = hdb_read_master_key(context, opt->format_string, &db->hdb_mit_key); + if (ret) + krb5_errx(context, 1, "Cannot open MIT mkey file"); + db->hdb_mit_key_set = 1; + parg.fmt = HDB_DUMP_MIT; + opt->decrypt_flag = 1; + fprintf(f, "kdb5_util load_dump version 5\n"); /* 5||6, either way */ + } else { + krb5_errx(context, 1, "Supported dump formats: Heimdal and MIT"); + } + parg.out = f; hdb_foreach(context, db, opt->decrypt_flag ? HDB_F_DECRYPT : 0, - hdb_print_entry, f); + hdb_print_entry, &parg); db->hdb_close(context, db); out: diff --git a/crypto/heimdal/kadmin/kadmin-commands.in b/crypto/heimdal/kadmin/kadmin-commands.in index 4396ff800441..dc36db4e0a00 100644 --- a/crypto/heimdal/kadmin/kadmin-commands.in +++ b/crypto/heimdal/kadmin/kadmin-commands.in @@ -76,6 +76,12 @@ command = { type = "flag" help = "decrypt keys" } + option = { + long = "format" + short = "f" + type = "string" + help = "dump format, mit or heimdal (default: heimdal)" + } argument = "[dump-file]" min_args = "0" max_args = "1" diff --git a/crypto/heimdal/kadmin/kadmin.8 b/crypto/heimdal/kadmin/kadmin.8 index bd2fd4e7363f..e4555cd529f4 100644 --- a/crypto/heimdal/kadmin/kadmin.8 +++ b/crypto/heimdal/kadmin/kadmin.8 @@ -31,7 +31,7 @@ .\" .\" $Id$ .\" -.Dd Feb 22, 2007 +.Dd October 5, 2025 .Dt KADMIN 8 .Os HEIMDAL .Sh NAME @@ -286,14 +286,39 @@ When running in local mode, the following commands can also be used: .Pp .Nm dump .Op Fl d | Fl Fl decrypt +.Op Fl f Ns Ar format | Fl Fl format= Ns Ar format .Op Ar dump-file .Bd -ragged -offset indent Writes the database in -.Dq human readable +.Dq machine readable text form to the specified file, or standard out. If the database is encrypted, the dump will also have encrypted keys, unless .Fl Fl decrypt is used. +.Pp +If +.Fl Fl format=MIT +is used then the dump will be in MIT format. +This option may be used if you require that all principal +passwords be changed after loading the dump into an MIT KDC database. +.Pp +If +.Fl Fl format=<keytab-file> +is used, the +.Dq <keytab-file> +should hold the master key for the +MIT KDC (usually a file called /var/db/krb5kdc/.k5.YOUR.REALM). +This will cause the keys to be re-encrypted in the MIT master +key as well as doing the dump in MIT format. +When this dump is loaded into the MIT KDC's database, +the principals that had at least one strong encryption type +key should work and any keytabs for those principals should still work. +The principcals with only weak encryption keys will require a +.Dq change_password +be done on the MIT KDC to get them working. +The +.Fl Fl decrypt +flag is meaningless for this case. .Ed .Pp .Nm init diff --git a/crypto/heimdal/kdc/hpropd.c b/crypto/heimdal/kdc/hpropd.c index 1cfc688b2a6c..c76be0446705 100644 --- a/crypto/heimdal/kdc/hpropd.c +++ b/crypto/heimdal/kdc/hpropd.c @@ -85,23 +85,23 @@ main(int argc, char **argv) setprogname(argv[0]); ret = krb5_init_context(&context); - if(ret) + if (ret) exit(1); ret = krb5_openlog(context, "hpropd", &fac); - if(ret) + if (ret) errx(1, "krb5_openlog"); krb5_set_warn_dest(context, fac); - if(getarg(args, num_args, argc, argv, &optidx)) + if (getarg(args, num_args, argc, argv, &optidx)) usage(1); - if(local_realm != NULL) + if (local_realm != NULL) krb5_set_default_realm(context, local_realm); - if(help_flag) + if (help_flag) usage(0); - if(version_flag) { + if (version_flag) { print_version(NULL); exit(0); } @@ -117,7 +117,7 @@ main(int argc, char **argv) if (database == NULL) database = hdb_default_db(context); - if(from_stdin) { + if (from_stdin) { sock = STDIN_FILENO; } else { struct sockaddr_storage ss; @@ -145,7 +145,7 @@ main(int argc, char **argv) HPROP_PORT), &sock); } sin_len = sizeof(ss); - if(getpeername(sock, sa, &sin_len) < 0) + if (getpeername(sock, sa, &sin_len) < 0) krb5_err(context, 1, errno, "getpeername"); if (inet_ntop(sa->sa_family, @@ -158,7 +158,7 @@ main(int argc, char **argv) krb5_log(context, fac, 0, "Connection from %s", addr_name); ret = krb5_kt_register(context, &hdb_kt_ops); - if(ret) + if (ret) krb5_err(context, 1, ret, "krb5_kt_register"); if (ktname != NULL) { @@ -173,7 +173,7 @@ main(int argc, char **argv) ret = krb5_recvauth(context, &ac, &sock, HPROP_VERSION, NULL, 0, keytab, &ticket); - if(ret) + if (ret) krb5_err(context, 1, ret, "krb5_recvauth"); ret = krb5_unparse_name(context, ticket->server, &server); @@ -186,15 +186,15 @@ main(int argc, char **argv) krb5_free_ticket (context, ticket); ret = krb5_auth_con_getauthenticator(context, ac, &authent); - if(ret) + if (ret) krb5_err(context, 1, ret, "krb5_auth_con_getauthenticator"); ret = krb5_make_principal(context, &c1, NULL, "kadmin", "hprop", NULL); - if(ret) + if (ret) krb5_err(context, 1, ret, "krb5_make_principal"); _krb5_principalname2krb5_principal(context, &c2, authent->cname, authent->crealm); - if(!krb5_principal_compare(context, c1, c2)) { + if (!krb5_principal_compare(context, c1, c2)) { char *s; ret = krb5_unparse_name(context, c2, &s); if (ret) @@ -205,48 +205,48 @@ main(int argc, char **argv) krb5_free_principal(context, c2); ret = krb5_kt_close(context, keytab); - if(ret) + if (ret) krb5_err(context, 1, ret, "krb5_kt_close"); } - if(!print_dump) { + if (!print_dump) { asprintf(&tmp_db, "%s~", database); ret = hdb_create(context, &db, tmp_db); - if(ret) + if (ret) krb5_err(context, 1, ret, "hdb_create(%s)", tmp_db); ret = db->hdb_open(context, db, O_RDWR | O_CREAT | O_TRUNC, 0600); - if(ret) + if (ret) krb5_err(context, 1, ret, "hdb_open(%s)", tmp_db); } nprincs = 0; - while(1){ + while (1){ krb5_data data; hdb_entry_ex entry; - if(from_stdin) { + if (from_stdin) { ret = krb5_read_message(context, &sock, &data); - if(ret != 0 && ret != HEIM_ERR_EOF) + if (ret != 0 && ret != HEIM_ERR_EOF) krb5_err(context, 1, ret, "krb5_read_message"); } else { ret = krb5_read_priv_message(context, ac, &sock, &data); - if(ret) + if (ret) krb5_err(context, 1, ret, "krb5_read_priv_message"); } - if(ret == HEIM_ERR_EOF || data.length == 0) { - if(!from_stdin) { + if (ret == HEIM_ERR_EOF || data.length == 0) { + if (!from_stdin) { data.data = NULL; data.length = 0; krb5_write_priv_message(context, ac, &sock, &data); } - if(!print_dump) { + if (!print_dump) { ret = db->hdb_close(context, db); - if(ret) + if (ret) krb5_err(context, 1, ret, "db_close"); ret = db->hdb_rename(context, db, database); - if(ret) + if (ret) krb5_err(context, 1, ret, "db_rename"); } break; @@ -254,20 +254,24 @@ main(int argc, char **argv) memset(&entry, 0, sizeof(entry)); ret = hdb_value2entry(context, &data, &entry.entry); krb5_data_free(&data); - if(ret) + if (ret) krb5_err(context, 1, ret, "hdb_value2entry"); - if(print_dump) - hdb_print_entry(context, db, &entry, stdout); - else { + if (print_dump) { + struct hdb_print_entry_arg parg; + + parg.out = stdout; + parg.fmt = HDB_DUMP_HEIMDAL; + hdb_print_entry(context, db, &entry, &parg); + } else { ret = db->hdb_store(context, db, 0, &entry); - if(ret == HDB_ERR_EXISTS) { + if (ret == HDB_ERR_EXISTS) { char *s; ret = krb5_unparse_name(context, entry.entry.principal, &s); if (ret) s = strdup(unparseable_name); krb5_warnx(context, "Entry exists: %s", s); free(s); - } else if(ret) + } else if (ret) krb5_err(context, 1, ret, "db_store"); else nprincs++; diff --git a/crypto/heimdal/kdc/mit_dump.c b/crypto/heimdal/kdc/mit_dump.c index f28e932b15b4..4397d1ad897d 100644 --- a/crypto/heimdal/kdc/mit_dump.c +++ b/crypto/heimdal/kdc/mit_dump.c @@ -33,6 +33,17 @@ #include "hprop.h" +extern krb5_error_code _hdb_mdb_value2entry(krb5_context context, + krb5_data *data, + krb5_kvno target_kvno, + hdb_entry *entry); + +extern int _hdb_mit_dump2mitdb_entry(krb5_context context, + char *line, + krb5_storage *sp); + + + /* can have any number of princ stanzas. format is as follows (only \n indicates newlines) @@ -74,19 +85,6 @@ unless no extra data */ -static int -hex_to_octet_string(const char *ptr, krb5_data *data) -{ - size_t i; - unsigned int v; - for(i = 0; i < data->length; i++) { - if(sscanf(ptr + 2 * i, "%02x", &v) != 1) - return -1; - ((unsigned char*)data->data)[i] = v; - } - return 2 * i; -} - static char * nexttoken(char **p) { @@ -97,321 +95,116 @@ nexttoken(char **p) return q; } -static size_t -getdata(char **p, unsigned char *buf, size_t len) -{ - size_t i; - int v; - char *q = nexttoken(p); - i = 0; - while(*q && i < len) { - if(sscanf(q, "%02x", &v) != 1) - break; - buf[i++] = v; - q += 2; - } - return i; -} - -static int -getint(char **p) -{ - int val; - char *q = nexttoken(p); - sscanf(q, "%d", &val); - return val; -} - #include <kadm5/admin.h> -static void -attr_to_flags(unsigned attr, HDBFlags *flags) -{ - flags->postdate = !(attr & KRB5_KDB_DISALLOW_POSTDATED); - flags->forwardable = !(attr & KRB5_KDB_DISALLOW_FORWARDABLE); - flags->initial = !!(attr & KRB5_KDB_DISALLOW_TGT_BASED); - flags->renewable = !(attr & KRB5_KDB_DISALLOW_RENEWABLE); - flags->proxiable = !(attr & KRB5_KDB_DISALLOW_PROXIABLE); - /* DUP_SKEY */ - flags->invalid = !!(attr & KRB5_KDB_DISALLOW_ALL_TIX); - flags->require_preauth = !!(attr & KRB5_KDB_REQUIRES_PRE_AUTH); - flags->require_hwauth = !!(attr & KRB5_KDB_REQUIRES_HW_AUTH); - flags->server = !(attr & KRB5_KDB_DISALLOW_SVR); - flags->change_pw = !!(attr & KRB5_KDB_PWCHANGE_SERVICE); - flags->client = 1; /* XXX */ -} - -#define KRB5_KDB_SALTTYPE_NORMAL 0 -#define KRB5_KDB_SALTTYPE_V4 1 -#define KRB5_KDB_SALTTYPE_NOREALM 2 -#define KRB5_KDB_SALTTYPE_ONLYREALM 3 -#define KRB5_KDB_SALTTYPE_SPECIAL 4 -#define KRB5_KDB_SALTTYPE_AFS3 5 - -static krb5_error_code -fix_salt(krb5_context context, hdb_entry *ent, int key_num) +static int +my_fgetln(FILE *f, char **buf, size_t *sz, size_t *len) { - krb5_error_code ret; - Salt *salt = ent->keys.val[key_num].salt; - /* fix salt type */ - switch((int)salt->type) { - case KRB5_KDB_SALTTYPE_NORMAL: - salt->type = KRB5_PADATA_PW_SALT; - break; - case KRB5_KDB_SALTTYPE_V4: - krb5_data_free(&salt->salt); - salt->type = KRB5_PADATA_PW_SALT; - break; - case KRB5_KDB_SALTTYPE_NOREALM: - { - size_t len; - size_t i; - char *p; - - len = 0; - for (i = 0; i < ent->principal->name.name_string.len; ++i) - len += strlen(ent->principal->name.name_string.val[i]); - ret = krb5_data_alloc (&salt->salt, len); - if (ret) - return ret; - p = salt->salt.data; - for (i = 0; i < ent->principal->name.name_string.len; ++i) { - memcpy (p, - ent->principal->name.name_string.val[i], - strlen(ent->principal->name.name_string.val[i])); - p += strlen(ent->principal->name.name_string.val[i]); - } - - salt->type = KRB5_PADATA_PW_SALT; - break; + char *p, *n; + + if (!*buf) { + *buf = malloc(*sz ? *sz : 2048); + if (!*buf) + return ENOMEM; + if (!*sz) + *sz = 2048; } - case KRB5_KDB_SALTTYPE_ONLYREALM: - krb5_data_free(&salt->salt); - ret = krb5_data_copy(&salt->salt, - ent->principal->realm, - strlen(ent->principal->realm)); - if(ret) - return ret; - salt->type = KRB5_PADATA_PW_SALT; - break; - case KRB5_KDB_SALTTYPE_SPECIAL: - salt->type = KRB5_PADATA_PW_SALT; - break; - case KRB5_KDB_SALTTYPE_AFS3: - krb5_data_free(&salt->salt); - ret = krb5_data_copy(&salt->salt, - ent->principal->realm, - strlen(ent->principal->realm)); - if(ret) - return ret; - salt->type = KRB5_PADATA_AFS3_SALT; - break; - default: - abort(); + *len = 0; + while ((p = fgets(&(*buf)[*len], *sz, f))) { + if (strcspn(*buf, "\r\n") || feof(f)) { + *len = strlen(*buf); + return 0; + } + *len += strlen(&(*buf)[*len]); /* *len should be == *sz */ + n = realloc(buf, *sz + (*sz >> 1)); + if (!n) { + free(*buf); + *buf = NULL; + *sz = 0; + *len = 0; + return ENOMEM; + } + *buf = n; + *sz += *sz >> 1; } - return 0; + return 0; /* *len == 0 || no EOL -> EOF */ } int mit_prop_dump(void *arg, const char *file) { krb5_error_code ret; - char line [2048]; - FILE *f; + size_t line_bufsz = 0; + size_t line_len = 0; + char *line = NULL; int lineno = 0; + FILE *f; struct hdb_entry_ex ent; - struct prop_data *pd = arg; + krb5_storage *sp = NULL; + krb5_data kdb_ent; + memset(&ent, 0, sizeof (ent)); f = fopen(file, "r"); - if(f == NULL) + if (f == NULL) return errno; - while(fgets(line, sizeof(line), f)) { - char *p = line, *q; - - int i; - - int num_tl_data; - int num_key_data; - int high_kvno; - int attributes; + ret = ENOMEM; + sp = krb5_storage_emem(); + if (!sp) + goto out; + while ((ret = my_fgetln(f, &line, &line_bufsz, &line_len)) == 0) { + char *p = line; + char *q; + lineno++; - int tmp; - - lineno++; - - memset(&ent, 0, sizeof(ent)); - - q = nexttoken(&p); - if(strcmp(q, "kdb5_util") == 0) { + if(strncmp(line, "kdb5_util", strlen("kdb5_util")) == 0) { int major; + q = nexttoken(&p); + if (strcmp(q, "kdb5_util")) + errx(1, "line %d: unknown version", lineno); q = nexttoken(&p); /* load_dump */ - if(strcmp(q, "load_dump")) + if (strcmp(q, "load_dump")) errx(1, "line %d: unknown version", lineno); q = nexttoken(&p); /* load_dump */ - if(strcmp(q, "version")) + if (strcmp(q, "version")) errx(1, "line %d: unknown version", lineno); q = nexttoken(&p); /* x.0 */ - if(sscanf(q, "%d", &major) != 1) + if (sscanf(q, "%d", &major) != 1) errx(1, "line %d: unknown version", lineno); - if(major != 4 && major != 5 && major != 6) + if (major != 4 && major != 5 && major != 6) errx(1, "unknown dump file format, got %d, expected 4-6", major); continue; - } else if(strcmp(q, "policy") == 0) { + } else if(strncmp(p, "policy", strlen("policy")) == 0) { + warnx("line: %d: ignoring policy (not supported)", lineno); continue; - } else if(strcmp(q, "princ") != 0) { + } else if(strncmp(p, "princ", strlen("princ")) != 0) { warnx("line %d: not a principal", lineno); continue; } - tmp = getint(&p); - if(tmp != 38) { - warnx("line %d: bad base length %d != 38", lineno, tmp); - continue; - } - nexttoken(&p); /* length of principal */ - num_tl_data = getint(&p); /* number of tl-data */ - num_key_data = getint(&p); /* number of key-data */ - getint(&p); /* length of extra data */ - q = nexttoken(&p); /* principal name */ - krb5_parse_name(pd->context, q, &ent.entry.principal); - attributes = getint(&p); /* attributes */ - attr_to_flags(attributes, &ent.entry.flags); - tmp = getint(&p); /* max life */ - if(tmp != 0) { - ALLOC(ent.entry.max_life); - *ent.entry.max_life = tmp; - } - tmp = getint(&p); /* max renewable life */ - if(tmp != 0) { - ALLOC(ent.entry.max_renew); - *ent.entry.max_renew = tmp; - } - tmp = getint(&p); /* expiration */ - if(tmp != 0 && tmp != 2145830400) { - ALLOC(ent.entry.valid_end); - *ent.entry.valid_end = tmp; - } - tmp = getint(&p); /* pw expiration */ - if(tmp != 0) { - ALLOC(ent.entry.pw_end); - *ent.entry.pw_end = tmp; - } - nexttoken(&p); /* last auth */ - nexttoken(&p); /* last failed auth */ - nexttoken(&p); /* fail auth count */ - for(i = 0; i < num_tl_data; i++) { - unsigned long val; - int tl_type, tl_length; - unsigned char *buf; - krb5_principal princ; - - tl_type = getint(&p); /* data type */ - tl_length = getint(&p); /* data length */ - -#define mit_KRB5_TL_LAST_PWD_CHANGE 1 -#define mit_KRB5_TL_MOD_PRINC 2 - switch(tl_type) { - case mit_KRB5_TL_LAST_PWD_CHANGE: - buf = malloc(tl_length); - if (buf == NULL) - errx(ENOMEM, "malloc"); - getdata(&p, buf, tl_length); /* data itself */ - val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); - free(buf); - ALLOC(ent.entry.extensions); - ALLOC_SEQ(ent.entry.extensions, 1); - ent.entry.extensions->val[0].mandatory = 0; - ent.entry.extensions->val[0].data.element - = choice_HDB_extension_data_last_pw_change; - ent.entry.extensions->val[0].data.u.last_pw_change = val; - break; - case mit_KRB5_TL_MOD_PRINC: - buf = malloc(tl_length); - if (buf == NULL) - errx(ENOMEM, "malloc"); - getdata(&p, buf, tl_length); /* data itself */ - val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); - ret = krb5_parse_name(pd->context, (char *)buf + 4, &princ); - if (ret) - krb5_err(pd->context, 1, ret, - "parse_name: %s", (char *)buf + 4); - free(buf); - ALLOC(ent.entry.modified_by); - ent.entry.modified_by->time = val; - ent.entry.modified_by->principal = princ; - break; - default: - nexttoken(&p); - break; - } - } - ALLOC_SEQ(&ent.entry.keys, num_key_data); - high_kvno = -1; - for(i = 0; i < num_key_data; i++) { - int key_versions; - int kvno; - key_versions = getint(&p); /* key data version */ - kvno = getint(&p); - - /* - * An MIT dump file may contain multiple sets of keys with - * different kvnos. Since the Heimdal database can only represent - * one kvno per principal, we only want the highest set. Assume - * that set will be given first, and discard all keys with lower - * kvnos. - */ - if (kvno > high_kvno && high_kvno != -1) - errx(1, "line %d: high kvno keys given after low kvno keys", - lineno); - else if (kvno < high_kvno) { - nexttoken(&p); /* key type */ - nexttoken(&p); /* key length */ - nexttoken(&p); /* key */ - if (key_versions > 1) { - nexttoken(&p); /* salt type */ - nexttoken(&p); /* salt length */ - nexttoken(&p); /* salt */ - } - ent.entry.keys.len--; - continue; - } - ent.entry.kvno = kvno; - high_kvno = kvno; - ALLOC(ent.entry.keys.val[i].mkvno); - *ent.entry.keys.val[i].mkvno = 1; - - /* key version 0 -- actual key */ - ent.entry.keys.val[i].key.keytype = getint(&p); /* key type */ - tmp = getint(&p); /* key length */ - /* the first two bytes of the key is the key length -- - skip it */ - krb5_data_alloc(&ent.entry.keys.val[i].key.keyvalue, tmp - 2); - q = nexttoken(&p); /* key itself */ - hex_to_octet_string(q + 4, &ent.entry.keys.val[i].key.keyvalue); - - if(key_versions > 1) { - /* key version 1 -- optional salt */ - ALLOC(ent.entry.keys.val[i].salt); - ent.entry.keys.val[i].salt->type = getint(&p); /* salt type */ - tmp = getint(&p); /* salt length */ - if(tmp > 0) { - krb5_data_alloc(&ent.entry.keys.val[i].salt->salt, tmp - 2); - q = nexttoken(&p); /* salt itself */ - hex_to_octet_string(q + 4, - &ent.entry.keys.val[i].salt->salt); - } else { - ent.entry.keys.val[i].salt->salt.length = 0; - ent.entry.keys.val[i].salt->salt.data = NULL; - getint(&p); /* -1, if no data. */ - } - fix_salt(pd->context, &ent.entry, i); - } - } - nexttoken(&p); /* extra data */ - v5_prop(pd->context, NULL, &ent, arg); + krb5_storage_truncate(sp, 0); + ret = _hdb_mit_dump2mitdb_entry(pd->context, line, sp); + if (ret) break; + ret = krb5_storage_to_data(sp, &kdb_ent); + if (ret) break; + ret = _hdb_mdb_value2entry(pd->context, &kdb_ent, 0, &ent.entry); + krb5_data_free(&kdb_ent); + if (ret) break; + ret = v5_prop(pd->context, NULL, &ent, arg); + hdb_free_entry(pd->context, &ent); + if (ret) break; } + +out: fclose(f); - return 0; + free(line); + if (sp) + krb5_storage_free(sp); + if (ret && ret == ENOMEM) + errx(1, "out of memory"); + if (ret) + errx(1, "line %d: problem parsing dump line", lineno); + return ret; } + diff --git a/crypto/heimdal/lib/hdb/Makefile.am b/crypto/heimdal/lib/hdb/Makefile.am index b629f56258d2..fd009bd26867 100644 --- a/crypto/heimdal/lib/hdb/Makefile.am +++ b/crypto/heimdal/lib/hdb/Makefile.am @@ -29,6 +29,7 @@ gen_files_hdb = \ asn1_HDB_Ext_Lan_Manager_OWF.x \ asn1_HDB_Ext_Password.x \ asn1_HDB_Ext_Aliases.x \ + asn1_HDB_Ext_KeySet.x \ asn1_HDB_extension.x \ asn1_HDB_extensions.x \ asn1_hdb_entry.x \ diff --git a/crypto/heimdal/lib/hdb/common.c b/crypto/heimdal/lib/hdb/common.c index 2715adf63dca..80482e7a4c1c 100644 --- a/crypto/heimdal/lib/hdb/common.c +++ b/crypto/heimdal/lib/hdb/common.c @@ -105,7 +105,6 @@ _hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, krb5_principal enterprise_principal = NULL; krb5_data key, value; krb5_error_code ret; - int code; if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) { if (principal->name.name_string.len != 1) { @@ -125,43 +124,74 @@ _hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, hdb_principal2key(context, principal, &key); if (enterprise_principal) krb5_free_principal(context, enterprise_principal); - code = db->hdb__get(context, db, key, &value); + ret = db->hdb__get(context, db, key, &value); krb5_data_free(&key); - if(code) - return code; - code = hdb_value2entry(context, &value, &entry->entry); - if (code == ASN1_BAD_ID && (flags & HDB_F_CANON) == 0) { + if(ret) + return ret; + ret = hdb_value2entry(context, &value, &entry->entry); + if (ret == ASN1_BAD_ID && (flags & HDB_F_CANON) == 0) { krb5_data_free(&value); return HDB_ERR_NOENTRY; - } else if (code == ASN1_BAD_ID) { + } else if (ret == ASN1_BAD_ID) { hdb_entry_alias alias; - code = hdb_value2entry_alias(context, &value, &alias); - if (code) { + ret = hdb_value2entry_alias(context, &value, &alias); + if (ret) { krb5_data_free(&value); - return code; + return ret; } hdb_principal2key(context, alias.principal, &key); krb5_data_free(&value); free_hdb_entry_alias(&alias); - code = db->hdb__get(context, db, key, &value); + ret = db->hdb__get(context, db, key, &value); krb5_data_free(&key); - if (code) - return code; - code = hdb_value2entry(context, &value, &entry->entry); - if (code) { + if (ret) + return ret; + ret = hdb_value2entry(context, &value, &entry->entry); + if (ret) { krb5_data_free(&value); - return code; + return ret; } } krb5_data_free(&value); if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { - code = hdb_unseal_keys (context, db, &entry->entry); - if (code) +#ifdef notnow + if ((flags & HDB_F_KVNO_SPECIFIED) == 0 && + (flags & HDB_F_CURRENT_KVNO) == 0) { + + /* + * Decrypt all the old keys too, since we don't know which + * the caller will need. + */ + ret = hdb_unseal_keys_kvno(context, db, 0, &entry->entry); + if (ret) { + hdb_free_entry(context, entry); + return ret; + } + } else if ((flags & HDB_F_KVNO_SPECIFIED) != 0 && + kvno != entry->entry.kvno && + kvno < entry->entry.kvno && + kvno > 0) { + + /* Decrypt the keys we were asked for, if not the current ones */ + ret = hdb_unseal_keys_kvno(context, db, kvno, &entry->entry); + if (ret) { + hdb_free_entry(context, entry); + return ret; + } + } +#endif + + /* Always decrypt the current keys too */ + ret = hdb_unseal_keys(context, db, &entry->entry); + if (ret) { hdb_free_entry(context, entry); + return ret; + } } - return code; + + return ret; } static krb5_error_code diff --git a/crypto/heimdal/lib/hdb/ext.c b/crypto/heimdal/lib/hdb/ext.c index d2a4373b9b38..5f7a19a55e04 100644 --- a/crypto/heimdal/lib/hdb/ext.c +++ b/crypto/heimdal/lib/hdb/ext.c @@ -432,3 +432,34 @@ hdb_entry_get_aliases(const hdb_entry *entry, const HDB_Ext_Aliases **a) return 0; } + +krb5_error_code +hdb_set_last_modified_by(krb5_context context, hdb_entry *entry, + krb5_principal modby, time_t modtime) +{ + krb5_error_code ret; + Event *old_ev; + Event *ev; + + old_ev = entry->modified_by; + + ev = calloc(1, sizeof (*ev)); + if (!ev) + return ENOMEM; + if (modby) + ret = krb5_copy_principal(context, modby, &ev->principal); + else + ret = krb5_parse_name(context, "root/admin", &ev->principal); + if (ret) { + free(ev); + return ret; + } + ev->time = modtime; + if (!ev->time) + time(&ev->time); + + entry->modified_by = ev; + if (old_ev) + free_Event(old_ev); + return 0; +} diff --git a/crypto/heimdal/lib/hdb/hdb-mitdb.c b/crypto/heimdal/lib/hdb/hdb-mitdb.c index 02c575050fe2..1dfe7835cb4d 100644 --- a/crypto/heimdal/lib/hdb/hdb-mitdb.c +++ b/crypto/heimdal/lib/hdb/hdb-mitdb.c @@ -91,18 +91,28 @@ salt: #include "hdb_locl.h" -#define KDB_V1_BASE_LENGTH 38 - -#if HAVE_DB1 +static void +attr_to_flags(unsigned attr, HDBFlags *flags) +{ + flags->postdate = !(attr & KRB5_KDB_DISALLOW_POSTDATED); + flags->forwardable = !(attr & KRB5_KDB_DISALLOW_FORWARDABLE); + flags->initial = !!(attr & KRB5_KDB_DISALLOW_TGT_BASED); + flags->renewable = !(attr & KRB5_KDB_DISALLOW_RENEWABLE); + flags->proxiable = !(attr & KRB5_KDB_DISALLOW_PROXIABLE); + /* DUP_SKEY */ + flags->invalid = !!(attr & KRB5_KDB_DISALLOW_ALL_TIX); + flags->require_preauth = !!(attr & KRB5_KDB_REQUIRES_PRE_AUTH); + flags->require_hwauth = !!(attr & KRB5_KDB_REQUIRES_HW_AUTH); + flags->server = !(attr & KRB5_KDB_DISALLOW_SVR); + flags->change_pw = !!(attr & KRB5_KDB_PWCHANGE_SERVICE); + flags->client = 1; /* XXX */ +} -#if defined(HAVE_DB_185_H) -#include <db_185.h> -#elif defined(HAVE_DB_H) -#include <db.h> -#endif +#define KDB_V1_BASE_LENGTH 38 #define CHECK(x) do { if ((x)) goto out; } while(0) +#ifdef HAVE_DB1 static krb5_error_code mdb_principal2key(krb5_context context, krb5_const_principal principal, @@ -118,6 +128,7 @@ mdb_principal2key(krb5_context context, key->length = strlen(str) + 1; return 0; } +#endif /* HAVE_DB1 */ #define KRB5_KDB_SALTTYPE_NORMAL 0 #define KRB5_KDB_SALTTYPE_V4 1 @@ -197,13 +208,15 @@ fix_salt(krb5_context context, hdb_entry *ent, int key_num) } -static krb5_error_code -mdb_value2entry(krb5_context context, krb5_data *data, krb5_kvno kvno, hdb_entry *entry) +krb5_error_code +_hdb_mdb_value2entry(krb5_context context, krb5_data *data, + krb5_kvno kvno, hdb_entry *entry) { krb5_error_code ret; krb5_storage *sp; uint32_t u32; uint16_t u16, num_keys, num_tl; + ssize_t sz; size_t i, j; char *p; @@ -234,18 +247,7 @@ mdb_value2entry(krb5_context context, krb5_data *data, krb5_kvno kvno, hdb_entry if (u16 != KDB_V1_BASE_LENGTH) { ret = EINVAL; goto out; } /* 32: attributes */ CHECK(ret = krb5_ret_uint32(sp, &u32)); - entry->flags.postdate = !(u32 & KRB5_KDB_DISALLOW_POSTDATED); - entry->flags.forwardable = !(u32 & KRB5_KDB_DISALLOW_FORWARDABLE); - entry->flags.initial = !!(u32 & KRB5_KDB_DISALLOW_TGT_BASED); - entry->flags.renewable = !(u32 & KRB5_KDB_DISALLOW_RENEWABLE); - entry->flags.proxiable = !(u32 & KRB5_KDB_DISALLOW_PROXIABLE); - /* DUP_SKEY */ - entry->flags.invalid = !!(u32 & KRB5_KDB_DISALLOW_ALL_TIX); - entry->flags.require_preauth =!!(u32 & KRB5_KDB_REQUIRES_PRE_AUTH); - entry->flags.require_hwauth =!!(u32 & KRB5_KDB_REQUIRES_HW_AUTH); - entry->flags.server = !(u32 & KRB5_KDB_DISALLOW_SVR); - entry->flags.change_pw = !!(u32 & KRB5_KDB_PWCHANGE_SERVICE); - entry->flags.client = 1; /* XXX */ + attr_to_flags(u32, &entry->flags); /* 32: max time */ CHECK(ret = krb5_ret_uint32(sp, &u32)); @@ -296,7 +298,11 @@ mdb_value2entry(krb5_context context, krb5_data *data, krb5_kvno kvno, hdb_entry ret = ENOMEM; goto out; } - krb5_storage_read(sp, p, u16); + sz = krb5_storage_read(sp, p, u16); + if (sz != u16) { + ret = EINVAL; /* XXX */ + goto out; + } p[u16] = '\0'; CHECK(ret = krb5_parse_name(context, p, &entry->principal)); free(p); @@ -305,12 +311,53 @@ mdb_value2entry(krb5_context context, krb5_data *data, krb5_kvno kvno, hdb_entry 16: tl data type 16: tl data length length: length */ +#define mit_KRB5_TL_LAST_PWD_CHANGE 1 +#define mit_KRB5_TL_MOD_PRINC 2 for (i = 0; i < num_tl; i++) { + int tl_type; + krb5_principal modby; /* 16: TL data type */ CHECK(ret = krb5_ret_uint16(sp, &u16)); + tl_type = u16; /* 16: TL data length */ CHECK(ret = krb5_ret_uint16(sp, &u16)); - krb5_storage_seek(sp, u16, SEEK_CUR); + /* + * For rollback to MIT purposes we really must understand some + * TL data! + * + * XXX Move all this to separate functions, one per-TL type. + */ + switch (tl_type) { + case mit_KRB5_TL_LAST_PWD_CHANGE: + CHECK(ret = krb5_ret_uint32(sp, &u32)); + CHECK(ret = hdb_entry_set_pw_change_time(context, entry, u32)); + break; + case mit_KRB5_TL_MOD_PRINC: + if (u16 < 5) { + ret = EINVAL; /* XXX */ + goto out; + } + CHECK(ret = krb5_ret_uint32(sp, &u32)); /* mod time */ + p = malloc(u16 - 4 + 1); + if (!p) { + ret = ENOMEM; + goto out; + } + p[u16 - 4] = '\0'; + sz = krb5_storage_read(sp, p, u16 - 4); + if (sz != u16 - 4) { + ret = EINVAL; /* XXX */ + goto out; + } + CHECK(ret = krb5_parse_name(context, p, &modby)); + ret = hdb_set_last_modified_by(context, entry, modby, u32); + krb5_free_principal(context, modby); + free(p); + break; + default: + krb5_storage_seek(sp, u16, SEEK_CUR); + break; + } } /* * for num key data times @@ -471,6 +518,14 @@ mdb_entry2value(krb5_context context, hdb_entry *entry, krb5_data *data) } #endif +#if HAVE_DB1 + +#if defined(HAVE_DB_185_H) +#include <db_185.h> +#elif defined(HAVE_DB_H) +#include <db.h> +#endif + static krb5_error_code mdb_close(krb5_context context, HDB *db) @@ -551,7 +606,7 @@ mdb_seq(krb5_context context, HDB *db, data.length = value.size; memset(entry, 0, sizeof(*entry)); - if (mdb_value2entry(context, &data, 0, &entry->entry)) + if (_hdb_mdb_value2entry(context, &data, 0, &entry->entry)) return mdb_seq(context, db, flags, entry, R_NEXT); if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { @@ -684,24 +739,26 @@ mdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry) { krb5_data key, value; - krb5_error_code code; + krb5_error_code ret; - code = mdb_principal2key(context, principal, &key); - if (code) - return code; - code = db->hdb__get(context, db, key, &value); + ret = mdb_principal2key(context, principal, &key); + if (ret) + return ret; + ret = db->hdb__get(context, db, key, &value); krb5_data_free(&key); - if(code) - return code; - code = mdb_value2entry(context, &value, kvno, &entry->entry); + if(ret) + return ret; + ret = _hdb_mdb_value2entry(context, &value, kvno, &entry->entry); krb5_data_free(&value); - if (code) - return code; + if (ret) + return ret; if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { - code = hdb_unseal_keys (context, db, &entry->entry); - if (code) + ret = hdb_unseal_keys (context, db, &entry->entry); + if (ret) { hdb_free_entry(context, entry); + return ret; + } } return 0; @@ -710,8 +767,48 @@ mdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, static krb5_error_code mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) { - krb5_set_error_message(context, EINVAL, "can't set principal in mdb"); - return EINVAL; + krb5_error_code ret; + krb5_storage *sp = NULL; + krb5_storage *spent = NULL; + krb5_data line = { 0, 0 }; + krb5_data kdb_ent = { 0, 0 }; + krb5_data key = { 0, 0 }; + ssize_t sz; + + sp = krb5_storage_emem(); + if (!sp) return ENOMEM; + ret = _hdb_set_master_key_usage(context, db, 0); /* MIT KDB uses KU 0 */ + ret = hdb_seal_keys(context, db, &entry->entry); + if (ret) return ret; + ret = entry2mit_string_int(context, sp, &entry->entry); + if (ret) goto out; + sz = krb5_storage_write(sp, "\n", 2); /* NUL-terminate */ + ret = ENOMEM; + if (sz == -1) goto out; + ret = krb5_storage_to_data(sp, &line); + if (ret) goto out; + + ret = ENOMEM; + spent = krb5_storage_emem(); + if (!spent) goto out; + ret = _hdb_mit_dump2mitdb_entry(context, line.data, spent); + if (ret) goto out; + ret = krb5_storage_to_data(spent, &kdb_ent); + if (ret) goto out; + ret = mdb_principal2key(context, entry->entry.principal, &key); + if (ret) goto out; + ret = mdb__put(context, db, 1, key, kdb_ent); + +out: + if (sp) + krb5_storage_free(sp); + if (spent) + krb5_storage_free(spent); + krb5_data_free(&line); + krb5_data_free(&kdb_ent); + krb5_data_free(&key); + + return ret; } static krb5_error_code @@ -729,25 +826,31 @@ static krb5_error_code mdb_open(krb5_context context, HDB *db, int flags, mode_t mode) { char *fn; + char *actual_fn; krb5_error_code ret; + struct stat st; asprintf(&fn, "%s.db", db->hdb_name); if (fn == NULL) { krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } - db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL); - free(fn); + if (stat(fn, &st) == 0) + actual_fn = fn; + else + actual_fn = db->hdb_name; + db->hdb_db = dbopen(actual_fn, flags, mode, DB_BTREE, NULL); if (db->hdb_db == NULL) { switch (errno) { #ifdef EFTYPE case EFTYPE: #endif case EINVAL: - db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL); + db->hdb_db = dbopen(actual_fn, flags, mode, DB_BTREE, NULL); } } + free(fn); /* try to open without .db extension */ if(db->hdb_db == NULL && errno == ENOENT) @@ -758,11 +861,16 @@ mdb_open(krb5_context context, HDB *db, int flags, mode_t mode) db->hdb_name, strerror(ret)); return ret; } - if((flags & O_ACCMODE) == O_RDONLY) - ret = hdb_check_db_format(context, db); - else +#if 0 + /* + * Don't do this -- MIT won't be able to handle the + * HDB_DB_FORMAT_ENTRY key. + */ + if ((flags & O_ACCMODE) != O_RDONLY) ret = hdb_init_db(context, db); - if(ret == HDB_ERR_NOENTRY) { +#endif + ret = hdb_check_db_format(context, db); + if (ret == HDB_ERR_NOENTRY) { krb5_clear_error_message(context); return 0; } @@ -815,3 +923,280 @@ hdb_mdb_create(krb5_context context, HDB **db, } #endif /* HAVE_DB1 */ + +/* +can have any number of princ stanzas. +format is as follows (only \n indicates newlines) +princ\t%d\t (%d is KRB5_KDB_V1_BASE_LENGTH, always 38) +%d\t (strlen of principal e.g. shadow/foo@ANDREW.CMU.EDU) +%d\t (number of tl_data) +%d\t (number of key data, e.g. how many keys for this user) +%d\t (extra data length) +%s\t (principal name) +%d\t (attributes) +%d\t (max lifetime, seconds) +%d\t (max renewable life, seconds) +%d\t (expiration, seconds since epoch or 2145830400 for never) +%d\t (password expiration, seconds, 0 for never) +%d\t (last successful auth, seconds since epoch) +%d\t (last failed auth, per above) +%d\t (failed auth count) +foreach tl_data 0 to number of tl_data - 1 as above + %d\t%d\t (data type, data length) + foreach tl_data 0 to length-1 + %02x (tl data contents[element n]) + except if tl_data length is 0 + %d (always -1) + \t +foreach key 0 to number of keys - 1 as above + %d\t%d\t (key data version, kvno) + foreach version 0 to key data version - 1 (a key or a salt) + %d\t%d\t(data type for this key, data length for this key) + foreach key data length 0 to length-1 + %02x (key data contents[element n]) + except if key_data length is 0 + %d (always -1) + \t +foreach extra data length 0 to length - 1 + %02x (extra data part) +unless no extra data + %d (always -1) +;\n + +*/ + +static char * +nexttoken(char **p) +{ + char *q; + do { + q = strsep(p, " \t"); + } while(q && *q == '\0'); + return q; +} + +static size_t +getdata(char **p, unsigned char *buf, size_t len) +{ + size_t i; + int v; + char *q = nexttoken(p); + i = 0; + while(*q && i < len) { + if(sscanf(q, "%02x", &v) != 1) + break; + buf[i++] = v; + q += 2; + } + return i; +} + +static int +getint(char **p) +{ + int val; + char *q = nexttoken(p); + sscanf(q, "%d", &val); + return val; +} + +static unsigned int +getuint(char **p) +{ + int val; + char *q = nexttoken(p); + sscanf(q, "%u", &val); + return val; +} + +#define KRB5_KDB_SALTTYPE_NORMAL 0 +#define KRB5_KDB_SALTTYPE_V4 1 +#define KRB5_KDB_SALTTYPE_NOREALM 2 +#define KRB5_KDB_SALTTYPE_ONLYREALM 3 +#define KRB5_KDB_SALTTYPE_SPECIAL 4 +#define KRB5_KDB_SALTTYPE_AFS3 5 + +#define CHECK_UINT(num) \ + if ((num) < 0 || (num) > INT_MAX) return EINVAL +#define CHECK_UINT16(num) \ + if ((num) < 0 || (num) > 1<<15) return EINVAL +#define CHECK_NUM(num, maxv) \ + if ((num) > (maxv)) return EINVAL + +/* + * This utility function converts an MIT dump entry to an MIT on-disk + * encoded entry, which can then be decoded with _hdb_mdb_value2entry(). + * This allows us to have a single decoding function (_hdb_mdb_value2entry), + * which makes the code cleaner (less code duplication), if a bit less + * efficient. It also will allow us to have a function to dump an HDB + * entry in MIT format so we can dump HDB into MIT format for rollback + * purposes. And that will allow us to write to MIT KDBs, again + * somewhat inefficiently, also for migration/rollback purposes. + */ +int +_hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp) +{ + krb5_error_code ret = EINVAL; + char *p = line, *q; + char *princ; + ssize_t sz; + size_t i; + size_t princ_len; + unsigned int num_tl_data; + size_t num_key_data; + unsigned int attributes; + int tmp; + + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); + + q = nexttoken(&p); + if (strcmp(q, "kdb5_util") == 0 || strcmp(q, "policy") == 0 || + strcmp(q, "princ") != 0) { + return -1; + } + if (getint(&p) != 38) + return EINVAL; +#define KDB_V1_BASE_LENGTH 38 + ret = krb5_store_int16(sp, KDB_V1_BASE_LENGTH); + if (ret) return ret; + + nexttoken(&p); /* length of principal */ + num_tl_data = getuint(&p); /* number of tl-data */ + num_key_data = getuint(&p); /* number of key-data */ + getint(&p); /* length of extra data */ + princ = nexttoken(&p); /* principal name */ + + attributes = getuint(&p); /* attributes */ + ret = krb5_store_uint32(sp, attributes); + if (ret) return ret; + + tmp = getint(&p); /* max life */ + CHECK_UINT(tmp); + ret = krb5_store_uint32(sp, tmp); + if (ret) return ret; + + tmp = getint(&p); /* max renewable life */ + CHECK_UINT(tmp); + ret = krb5_store_uint32(sp, tmp); + if (ret) return ret; + + tmp = getint(&p); /* expiration */ + CHECK_UINT(tmp); + ret = krb5_store_uint32(sp, tmp); + if (ret) return ret; + + tmp = getint(&p); /* pw expiration */ + CHECK_UINT(tmp); + ret = krb5_store_uint32(sp, tmp); + if (ret) return ret; + + tmp = getint(&p); /* last auth */ + CHECK_UINT(tmp); + ret = krb5_store_uint32(sp, tmp); + if (ret) return ret; + + tmp = getint(&p); /* last failed auth */ + CHECK_UINT(tmp); + ret = krb5_store_uint32(sp, tmp); + if (ret) return ret; + + tmp = getint(&p); /* fail auth count */ + CHECK_UINT(tmp); + ret = krb5_store_uint32(sp, tmp); + if (ret) return ret; + + /* add TL data count */ + CHECK_NUM(num_tl_data, 1023); + ret = krb5_store_uint16(sp, num_tl_data); + if (ret) return ret; + + /* add key count */ + CHECK_NUM(num_key_data, 1023); + ret = krb5_store_uint16(sp, num_key_data); + if (ret) return ret; + + /* add principal unparsed name length and unparsed name */ + princ_len = strlen(princ); + if (princ_len > (1<<15) - 1) return EINVAL; + princ_len++; /* must count and write the NUL in the on-disk encoding */ + ret = krb5_store_uint16(sp, princ_len); + if (ret) return ret; + sz = krb5_storage_write(sp, princ, princ_len); + if (sz == -1) return ENOMEM; + + /* scan and write TL data */ + for (i = 0; i < num_tl_data; i++) { + int tl_type, tl_length; + unsigned char *buf; + + tl_type = getint(&p); /* data type */ + tl_length = getint(&p); /* data length */ + + CHECK_UINT16(tl_type); + ret = krb5_store_uint16(sp, tl_type); + if (ret) return ret; + CHECK_UINT16(tl_length); + ret = krb5_store_uint16(sp, tl_length); + if (ret) return ret; + + if (tl_length) { + buf = malloc(tl_length); + if (!buf) return ENOMEM; + if (getdata(&p, buf, tl_length) != tl_length) return EINVAL; + sz = krb5_storage_write(sp, buf, tl_length); + free(buf); + if (sz == -1) return ENOMEM; + } else { + if (strcmp(nexttoken(&p), "-1") != 0) return EINVAL; + } + } + + for (i = 0; i < num_key_data; i++) { + unsigned char *buf; + int key_versions; + int kvno; + int keytype; + int keylen; + size_t k; + + key_versions = getint(&p); /* key data version */ + CHECK_UINT16(key_versions); + ret = krb5_store_int16(sp, key_versions); + if (ret) return ret; + + kvno = getint(&p); + CHECK_UINT16(kvno); + ret = krb5_store_int16(sp, kvno); + if (ret) return ret; + + for (k = 0; k < key_versions; k++) { + keytype = getint(&p); + CHECK_UINT16(keytype); + ret = krb5_store_int16(sp, keytype); + if (ret) return ret; + + keylen = getint(&p); + CHECK_UINT16(keylen); + ret = krb5_store_int16(sp, keylen); + if (ret) return ret; + + if (keylen) { + buf = malloc(keylen); + if (!buf) return ENOMEM; + if (getdata(&p, buf, keylen) != keylen) return EINVAL; + sz = krb5_storage_write(sp, buf, keylen); + free(buf); + if (sz == -1) return ENOMEM; + } else { + if (strcmp(nexttoken(&p), "-1") != 0) return EINVAL; + } + } + } + /* + * The rest is "extra data", but there's never any and we wouldn't + * know what to do with it. + */ + /* nexttoken(&p); */ + return 0; +} + diff --git a/crypto/heimdal/lib/hdb/hdb-protos.h b/crypto/heimdal/lib/hdb/hdb-protos.h index 44a1bddc7625..2b692855c405 100644 --- a/crypto/heimdal/lib/hdb/hdb-protos.h +++ b/crypto/heimdal/lib/hdb/hdb-protos.h @@ -9,6 +9,17 @@ extern "C" { #endif krb5_error_code +entry2mit_string_int ( + krb5_context /*context*/, + krb5_storage */*sp*/, + hdb_entry */*ent*/); + +krb5_error_code +hdb_add_current_keys_to_history ( + krb5_context /*context*/, + hdb_entry */*entry*/); + +krb5_error_code hdb_add_master_key ( krb5_context /*context*/, krb5_keyblock */*key*/, @@ -347,6 +358,13 @@ hdb_seal_keys_mkey ( hdb_master_key /*mkey*/); krb5_error_code +hdb_set_last_modified_by ( + krb5_context /*context*/, + hdb_entry */*entry*/, + krb5_principal /*modby*/, + time_t /*modtime*/); + +krb5_error_code hdb_set_master_key ( krb5_context /*context*/, HDB */*db*/, @@ -386,6 +404,13 @@ hdb_unseal_keys ( hdb_entry */*ent*/); krb5_error_code +hdb_unseal_keys_kvno ( + krb5_context /*context*/, + HDB */*db*/, + krb5_kvno /*kvno*/, + hdb_entry */*ent*/); + +krb5_error_code hdb_unseal_keys_mkey ( krb5_context /*context*/, hdb_entry */*ent*/, diff --git a/crypto/heimdal/lib/hdb/hdb.asn1 b/crypto/heimdal/lib/hdb/hdb.asn1 index a72851c9f201..d24737fbf6e8 100644 --- a/crypto/heimdal/lib/hdb/hdb.asn1 +++ b/crypto/heimdal/lib/hdb/hdb.asn1 @@ -87,6 +87,14 @@ HDB-Ext-Aliases ::= SEQUENCE { aliases[1] SEQUENCE OF Principal -- all names, inc primary } +hdb_keyset ::= SEQUENCE { + kvno[0] INTEGER (0..4294967295), + replace-time[1] KerberosTime, -- time this key was replaced + keys[2] SEQUENCE OF Key +} + +HDB-Ext-KeySet ::= SEQUENCE OF hdb_keyset + HDB-extension ::= SEQUENCE { mandatory[0] BOOLEAN, -- kdc MUST understand this extension, @@ -102,6 +110,7 @@ HDB-extension ::= SEQUENCE { aliases[6] HDB-Ext-Aliases, last-pw-change[7] KerberosTime, pkinit-cert[8] HDB-Ext-PKINIT-cert, + hist-keys[9] HDB-Ext-KeySet, ... }, ... @@ -109,11 +118,6 @@ HDB-extension ::= SEQUENCE { HDB-extensions ::= SEQUENCE OF HDB-extension -hdb_keyset ::= SEQUENCE { - kvno[1] INTEGER (0..4294967295), - keys[0] SEQUENCE OF Key -} - hdb_entry ::= SEQUENCE { principal[0] Principal OPTIONAL, -- this is optional only -- for compatibility with libkrb5 diff --git a/crypto/heimdal/lib/hdb/hdb.c b/crypto/heimdal/lib/hdb/hdb.c index ca05cc4a1785..aff576a30d37 100644 --- a/crypto/heimdal/lib/hdb/hdb.c +++ b/crypto/heimdal/lib/hdb/hdb.c @@ -168,13 +168,14 @@ hdb_unlock(int fd) void hdb_free_entry(krb5_context context, hdb_entry_ex *ent) { - size_t i; + Key *k; + int i; if (ent->free_entry) (*ent->free_entry)(context, ent); - for(i = 0; i < ent->entry.keys.len; ++i) { - Key *k = &ent->entry.keys.val[i]; + for(i = 0; i < ent->entry.keys.len; i++) { + k = &ent->entry.keys.val[i]; memset (k->key.keyvalue.data, 0, k->key.keyvalue.length); } diff --git a/crypto/heimdal/lib/hdb/hdb.h b/crypto/heimdal/lib/hdb/hdb.h index a1692ce82ca2..4c4c2c2b1a5c 100644 --- a/crypto/heimdal/lib/hdb/hdb.h +++ b/crypto/heimdal/lib/hdb/hdb.h @@ -99,7 +99,7 @@ typedef struct hdb_entry_ex { * query the backend database when talking about principals. */ -typedef struct HDB{ +typedef struct HDB { void *hdb_db; void *hdb_dbc; /** don't use, only for DB3 */ char *hdb_name; @@ -256,6 +256,8 @@ typedef struct HDB{ * Check if s4u2self is allowed from this client to this server */ krb5_error_code (*hdb_check_s4u2self)(krb5_context, struct HDB *, hdb_entry_ex *, krb5_const_principal); + int hdb_mit_key_set; + hdb_master_key hdb_mit_key; }HDB; #define HDB_INTERFACE_VERSION 7 @@ -266,6 +268,17 @@ struct hdb_so_method { krb5_error_code (*create)(krb5_context, HDB **, const char *filename); }; +/* dump entry format, for hdb_print_entry() */ +typedef enum hdb_dump_format { + HDB_DUMP_HEIMDAL = 0, + HDB_DUMP_MIT = 1, +} hdb_dump_format_t; + +struct hdb_print_entry_arg { + FILE *out; + hdb_dump_format_t fmt; +}; + typedef krb5_error_code (*hdb_foreach_func_t)(krb5_context, HDB*, hdb_entry_ex*, void*); extern krb5_kt_ops hdb_kt_ops; diff --git a/crypto/heimdal/lib/hdb/hdb_locl.h b/crypto/heimdal/lib/hdb/hdb_locl.h index e896b5802575..5aad504589df 100644 --- a/crypto/heimdal/lib/hdb/hdb_locl.h +++ b/crypto/heimdal/lib/hdb/hdb_locl.h @@ -38,6 +38,8 @@ #include <config.h> +#include <heimbase.h> + #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -67,4 +69,9 @@ #define HDB_DEFAULT_DB HDB_DB_DIR "/heimdal" #define HDB_DB_FORMAT_ENTRY "hdb/db-format" +/* Test for strong key etypes accepted by MIT's KDC. */ +#define mit_strong_etype(t) \ + ((t) == ETYPE_AES128_CTS_HMAC_SHA1_96 || \ + (t) == ETYPE_AES256_CTS_HMAC_SHA1_96) + #endif /* __HDB_LOCL_H__ */ diff --git a/crypto/heimdal/lib/hdb/keys.c b/crypto/heimdal/lib/hdb/keys.c index 3d0b9d7c1b31..9c0af5c47f23 100644 --- a/crypto/heimdal/lib/hdb/keys.c +++ b/crypto/heimdal/lib/hdb/keys.c @@ -39,7 +39,7 @@ */ void -hdb_free_keys (krb5_context context, int len, Key *keys) +hdb_free_keys(krb5_context context, int len, Key *keys) { int i; @@ -56,6 +56,19 @@ hdb_free_keys (krb5_context context, int len, Key *keys) free (keys); } +void +hdb_free_keysets(krb5_context context, int len, hdb_keyset *keysets) +{ + int i; + + for (i = 0; i < len; i++) { + hdb_free_keys(context, keysets[i].keys.len, keysets[i].keys.val); + keysets[i].keys.val = NULL; + keysets[i].keys.len = 0; + } + free (keysets); +} + /* * for each entry in `default_keys' try to parse it as a sequence * of etype:salttype:salt, syntax of this if something like: @@ -196,6 +209,60 @@ parse_key_set(krb5_context context, const char *key, return 0; } + +krb5_error_code +hdb_add_current_keys_to_history(krb5_context context, hdb_entry *entry) +{ + krb5_error_code ret; + HDB_extension *ext; + HDB_Ext_KeySet *hist_keys; + hdb_keyset *tmp_keysets; + int add = 0; + + ext = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys); + if (ext != NULL) { + hist_keys = &ext->data.u.hist_keys; + tmp_keysets = realloc(hist_keys->val, + sizeof (*hist_keys->val) * (hist_keys->len + 1)); + if (tmp_keysets == NULL) + return ENOMEM; + hist_keys->val = tmp_keysets; + memmove(&hist_keys->val[1], hist_keys->val, + sizeof (*hist_keys->val) * hist_keys->len++); + } else { + add = 1; + ext = calloc(1, sizeof (*ext)); + if (ext == NULL) + return ENOMEM; + ext->data.element = choice_HDB_extension_data_hist_keys; + hist_keys = &ext->data.u.hist_keys; + hist_keys->val = calloc(1, sizeof (*hist_keys->val)); + if (hist_keys->val == NULL) { + free(hist_keys); + return ENOMEM; + } + hist_keys->len = 1; + } + + hist_keys->val[0].keys.val = entry->keys.val; + hist_keys->val[0].keys.len = entry->keys.len; + hist_keys->val[0].kvno = entry->kvno; + hist_keys->val[0].replace_time = time(NULL); + + if (add) { + ret = hdb_replace_extension(context, entry, ext); + if (ret) { + free_HDB_extension(ext); + return ret; + } + } + + /* hdb_replace_extension() copies ext, so we have to free it */ + free_HDB_extension(ext); + return 0; +} + + static krb5_error_code add_enctype_to_key_set(Key **key_set, size_t *nkeyset, krb5_enctype enctype, krb5_salt *salt) diff --git a/crypto/heimdal/lib/hdb/mkey.c b/crypto/heimdal/lib/hdb/mkey.c index 9eb98fca32c0..78a9e51a132c 100644 --- a/crypto/heimdal/lib/hdb/mkey.c +++ b/crypto/heimdal/lib/hdb/mkey.c @@ -32,6 +32,7 @@ */ #include "hdb_locl.h" +#include <assert.h> #ifndef O_BINARY #define O_BINARY 0 #endif @@ -40,6 +41,7 @@ struct hdb_master_key_data { krb5_keytab_entry keytab; krb5_crypto crypto; struct hdb_master_key_data *next; + unsigned int key_usage; }; void @@ -68,6 +70,7 @@ hdb_process_master_key(krb5_context context, krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } + (*mkey)->key_usage = HDB_KU_MKEY; (*mkey)->keytab.vno = kvno; ret = krb5_parse_name(context, "K/M", &(*mkey)->keytab.principal); if(ret) @@ -362,6 +365,15 @@ hdb_write_master_key(krb5_context context, const char *filename, return ret; } +krb5_error_code +_hdb_set_master_key_usage(krb5_context context, HDB *db, unsigned int key_usage) +{ + if (db->hdb_master_key_set == 0) + return HDB_ERR_NO_MKEY; + db->hdb_master_key->key_usage = key_usage; + return 0; +} + hdb_master_key _hdb_find_master_key(uint32_t *mkvno, hdb_master_key mkey) { @@ -403,15 +415,20 @@ _hdb_mkey_encrypt(krb5_context context, hdb_master_key key, ptr, size, res); } -krb5_error_code -hdb_unseal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey) +/* + * Unseal and optionally reseal the key in the MIT KDC master key. + * If mit_key != NULL, the key is sealed using this key. + */ +static krb5_error_code +_hdb_reseal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey, + hdb_master_key mit_key) { krb5_error_code ret; - krb5_data res; + krb5_data mitres, res; size_t keysize; - hdb_master_key key; + hdb_master_key key, mitkey; if(k->mkvno == NULL) return 0; @@ -428,9 +445,9 @@ hdb_unseal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey) if(ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) { /* try to decrypt with MIT key usage */ ret = _hdb_mkey_decrypt(context, key, 0, - k->key.keyvalue.data, - k->key.keyvalue.length, - &res); + k->key.keyvalue.data, + k->key.keyvalue.length, + &res); } if (ret) return ret; @@ -446,25 +463,81 @@ hdb_unseal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey) return KRB5_BAD_KEYSIZE; } - memset(k->key.keyvalue.data, 0, k->key.keyvalue.length); - free(k->key.keyvalue.data); - k->key.keyvalue = res; - k->key.keyvalue.length = keysize; - free(k->mkvno); - k->mkvno = NULL; + /* For mit_key != NULL, re-encrypt the key using the mitkey. */ + if (mit_key != NULL) { + mitkey = _hdb_find_master_key(NULL, mit_key); + if (mitkey == NULL) { + krb5_data_free(&res); + return HDB_ERR_NO_MKEY; + } + + ret = _hdb_mkey_encrypt(context, mitkey, 0, + res.data, + keysize, + &mitres); + krb5_data_free(&res); + if (ret) + return ret; + } + + krb5_data_free(&k->key.keyvalue); + if (mit_key == NULL) { + k->key.keyvalue = res; + k->key.keyvalue.length = keysize; + free(k->mkvno); + k->mkvno = NULL; + } else { + k->key.keyvalue = mitres; + *k->mkvno = mitkey->keytab.vno; + } return 0; } krb5_error_code -hdb_unseal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey) +hdb_unseal_key_mkey(krb5_context context, Key *k, hdb_master_key mkey) +{ + + krb5_error_code ret; + + ret = _hdb_reseal_key_mkey(context, k, mkey, NULL); + return ret; +} + +static krb5_error_code +_hdb_unseal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey, + hdb_master_key mitkey) { + krb5_error_code ret; size_t i; + int got_one = 0; for(i = 0; i < ent->keys.len; i++){ - krb5_error_code ret; + if (mitkey == NULL || mit_strong_etype(ent->keys.val[i].key.keytype)) { + ret = _hdb_reseal_key_mkey(context, &ent->keys.val[i], mkey, + mitkey); + if (ret) + return ret; + got_one = 1; + } + } - ret = hdb_unseal_key_mkey(context, &ent->keys.val[i], mkey); + /* + * If none of the keys were string enough, create a strong key, + * but one that is not encrypted in the MIT master key. As such, + * it will require a "change_password" once in the MIT KDC to + * make it work. + */ + if (got_one == 0 && mitkey != NULL && ent->keys.len > 0) { + krb5_keyblock key; + krb5_salt salt; + + krb5_free_keyblock_contents(context, &ent->keys.val[0].key); + salt.salttype = KRB5_PW_SALT; + salt.saltvalue.data = NULL; + salt.saltvalue.length = 0; + ret = krb5_string_to_key_salt(context, ETYPE_AES256_CTS_HMAC_SHA1_96, + "XXXX", salt, &ent->keys.val[0].key); if (ret) return ret; } @@ -472,19 +545,114 @@ hdb_unseal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey) } krb5_error_code +hdb_unseal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey) +{ + krb5_error_code ret; + + ret = _hdb_unseal_keys_mkey(context, ent, mkey, NULL); + return ret; +} + +krb5_error_code hdb_unseal_keys(krb5_context context, HDB *db, hdb_entry *ent) { if (db->hdb_master_key_set == 0) return 0; - return hdb_unseal_keys_mkey(context, ent, db->hdb_master_key); + if (db->hdb_mit_key_set != 0) + return _hdb_unseal_keys_mkey(context, ent, db->hdb_master_key, + db->hdb_mit_key); + else + return _hdb_unseal_keys_mkey(context, ent, db->hdb_master_key, + NULL); +} + +#ifdef notnow +krb5_error_code +hdb_unseal_keys_kvno(krb5_context context, HDB *db, krb5_kvno kvno, + hdb_entry *ent) +{ + krb5_error_code ret = KRB5KRB_AP_ERR_NOKEY; /* XXX need a better code? */ + HDB_extension *tmp; + HDB_Ext_KeySet *hist_keys; + hdb_keyset *tmp_keys; + Key *tmp_val; + unsigned int tmp_len; + krb5_kvno tmp_kvno; + int i, k; + + assert(kvno == 0 || kvno < ent->kvno); + + tmp = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys); + if (tmp == NULL) + return ret; + + tmp_len = ent->keys.len; + tmp_val = ent->keys.val; + tmp_kvno = ent->kvno; + + hist_keys = &tmp->data.u.hist_keys; + + for (i = hist_keys->len - 1; i >= 0; i++) { + if (kvno != 0 && hist_keys->val[i].kvno != kvno) + continue; + for (k = 0; k < hist_keys->val[i].keys.len; k++) { + ret = _hdb_reseal_key_mkey(context, + &hist_keys->val[i].keys.val[k], + db->hdb_master_key, NULL); + if (ret) + return (ret); + } + + if (kvno == 0) + continue; + + /* + * NOTE: What follows is a bit of an ugly hack. + * + * This is the keyset we're being asked for, so we add the + * current keyset to the history, leave the one we were asked + * for in the history, and pretend the one we were asked for is + * also the current keyset. + * + * This is a bit of a defensive hack in case an entry fetched + * this way ever gets modified then stored: if the keyset is not + * changed we can detect this and put things back, else we won't + * drop any keysets from history by accident. + * + * Note too that we only ever get called with a non-zero kvno + * either in the KDC or in cases where we aren't changing the + * HDB entry anyways, which is why this is just a defensive + * hack. We also don't fetch specific kvnos in the dump case, + * so there's no danger that we'll dump this entry and load it + * again, repeatedly causing the history to grow boundelessly. + */ + tmp_keys = realloc(hist_keys->val, + sizeof (*hist_keys->val) * (hist_keys->len + 1)); + if (tmp_keys == NULL) + return ENOMEM; + + memmove(&tmp_keys[1], tmp_keys, + sizeof (*hist_keys->val) * hist_keys->len++); + tmp_keys[0].keys.len = ent->keys.len; + tmp_keys[0].keys.val = ent->keys.val; + tmp_keys[0].kvno = ent->kvno; + tmp_keys[0].replace_time = time(NULL); + i++; + ent->keys.len = hist_keys->val[i].keys.len; + ent->keys.val = hist_keys->val[i].keys.val; + ent->kvno = kvno; + } + + return (ret); } +#endif krb5_error_code hdb_unseal_key(krb5_context context, HDB *db, Key *k) { if (db->hdb_master_key_set == 0) return 0; - return hdb_unseal_key_mkey(context, k, db->hdb_master_key); + return _hdb_reseal_key_mkey(context, k, db->hdb_master_key, NULL); } krb5_error_code @@ -556,9 +724,9 @@ hdb_seal_key(krb5_context context, HDB *db, Key *k) } krb5_error_code -hdb_set_master_key (krb5_context context, - HDB *db, - krb5_keyblock *key) +hdb_set_master_key(krb5_context context, + HDB *db, + krb5_keyblock *key) { krb5_error_code ret; hdb_master_key mkey; @@ -571,6 +739,7 @@ hdb_set_master_key (krb5_context context, des_set_random_generator_seed(key.keyvalue.data); #endif db->hdb_master_key_set = 1; + db->hdb_master_key->key_usage = HDB_KU_MKEY; return 0; } diff --git a/crypto/heimdal/lib/hdb/print.c b/crypto/heimdal/lib/hdb/print.c index 697d32d2909c..d5359f538056 100644 --- a/crypto/heimdal/lib/hdb/print.c +++ b/crypto/heimdal/lib/hdb/print.c @@ -57,44 +57,57 @@ generation number */ -static krb5_error_code +/* + * These utility functions return the number of bytes written or -1, and + * they set an error in the context. + */ +static ssize_t append_string(krb5_context context, krb5_storage *sp, const char *fmt, ...) { - krb5_error_code ret; + ssize_t sz; char *s; + int rc; va_list ap; va_start(ap, fmt); - vasprintf(&s, fmt, ap); + rc = vasprintf(&s, fmt, ap); va_end(ap); - if(s == NULL) { + if(rc < 0) { krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); - return ENOMEM; + return -1; } - ret = krb5_storage_write(sp, s, strlen(s)); + sz = krb5_storage_write(sp, s, strlen(s)); free(s); - return ret; + return sz; } static krb5_error_code -append_hex(krb5_context context, krb5_storage *sp, krb5_data *data) +append_hex(krb5_context context, krb5_storage *sp, + int always_encode, int lower, krb5_data *data) { + ssize_t sz; int printable = 1; size_t i; char *p; p = data->data; - for(i = 0; i < data->length; i++) - if(!isalnum((unsigned char)p[i]) && p[i] != '.'){ - printable = 0; - break; - } - if(printable) + if (!always_encode) { + for (i = 0; i < data->length; i++) { + if (!isalnum((unsigned char)p[i]) && p[i] != '.'){ + printable = 0; + break; + } + } + } + if (printable && !always_encode) return append_string(context, sp, "\"%.*s\"", data->length, data->data); - hex_encode(data->data, data->length, &p); - append_string(context, sp, "%s", p); + sz = hex_encode(data->data, data->length, &p); + if (sz == -1) return sz; + if (lower) + strlwr(p); + sz = append_string(context, sp, "%s", p); free(p); - return 0; + return sz; } static char * @@ -105,29 +118,97 @@ time2str(time_t t) return buf; } -static krb5_error_code +static ssize_t append_event(krb5_context context, krb5_storage *sp, Event *ev) { - char *pr = NULL; krb5_error_code ret; + ssize_t sz; + char *pr = NULL; if(ev == NULL) return append_string(context, sp, "- "); if (ev->principal != NULL) { ret = krb5_unparse_name(context, ev->principal, &pr); - if(ret) - return ret; + if (ret) return -1; /* krb5_unparse_name() sets error info */ } - ret = append_string(context, sp, "%s:%s ", - time2str(ev->time), pr ? pr : "UNKNOWN"); + sz = append_string(context, sp, "%s:%s ", time2str(ev->time), + pr ? pr : "UNKNOWN"); free(pr); - return ret; + return sz; +} + +#define KRB5_KDB_SALTTYPE_NORMAL 0 +#define KRB5_KDB_SALTTYPE_V4 1 +#define KRB5_KDB_SALTTYPE_NOREALM 2 +#define KRB5_KDB_SALTTYPE_ONLYREALM 3 +#define KRB5_KDB_SALTTYPE_SPECIAL 4 +#define KRB5_KDB_SALTTYPE_AFS3 5 + +static ssize_t +append_mit_key(krb5_context context, krb5_storage *sp, + krb5_const_principal princ, + unsigned int kvno, Key *key) +{ + krb5_error_code ret; + ssize_t sz; + size_t key_versions = key->salt ? 2 : 1; + size_t decrypted_key_length; + char buf[2]; + krb5_data keylenbytes; + unsigned int salttype; + + sz = append_string(context, sp, "\t%u\t%u\t%d\t%d\t", key_versions, kvno, + key->key.keytype, key->key.keyvalue.length + 2); + if (sz == -1) return sz; + ret = krb5_enctype_keysize(context, key->key.keytype, &decrypted_key_length); + if (ret) return -1; /* XXX we lose the error code */ + buf[0] = decrypted_key_length & 0xff; + buf[1] = (decrypted_key_length & 0xff00) >> 8; + keylenbytes.data = buf; + keylenbytes.length = sizeof (buf); + sz = append_hex(context, sp, 1, 1, &keylenbytes); + if (sz == -1) return sz; + sz = append_hex(context, sp, 1, 1, &key->key.keyvalue); + if (!key->salt) + return sz; + + /* Map salt to MIT KDB style */ + if (key->salt->type == KRB5_PADATA_PW_SALT) { + krb5_salt k5salt; + + /* + * Compute normal salt and then see whether it matches the stored one + */ + ret = krb5_get_pw_salt(context, princ, &k5salt); + if (ret) return -1; + if (k5salt.saltvalue.length == key->salt->salt.length && + memcmp(k5salt.saltvalue.data, key->salt->salt.data, + k5salt.saltvalue.length) == 0) + salttype = KRB5_KDB_SALTTYPE_NORMAL; /* matches */ + else if (key->salt->salt.length == strlen(princ->realm) && + memcmp(key->salt->salt.data, princ->realm, + key->salt->salt.length) == 0) + salttype = KRB5_KDB_SALTTYPE_ONLYREALM; /* matches realm */ + else if (key->salt->salt.length == k5salt.saltvalue.length - strlen(princ->realm) && + memcmp((char *)k5salt.saltvalue.data + strlen(princ->realm), + key->salt->salt.data, key->salt->salt.length) == 0) + salttype = KRB5_KDB_SALTTYPE_NOREALM; /* matches w/o realm */ + else + salttype = KRB5_KDB_SALTTYPE_NORMAL; /* hope for best */ + + } else if (key->salt->type == KRB5_PADATA_AFS3_SALT) { + salttype = KRB5_KDB_SALTTYPE_AFS3; + } + sz = append_string(context, sp, "\t%u\t%u\t", salttype, + key->salt->salt.length); + if (sz == -1) return sz; + return append_hex(context, sp, 1, 1, &key->salt->salt); } static krb5_error_code entry2string_int (krb5_context context, krb5_storage *sp, hdb_entry *ent) { char *p; - size_t i; + int i; krb5_error_code ret; /* --- principal */ @@ -149,12 +230,12 @@ entry2string_int (krb5_context context, krb5_storage *sp, hdb_entry *ent) append_string(context, sp, "::%d:", ent->keys.val[i].key.keytype); /* --- keydata */ - append_hex(context, sp, &ent->keys.val[i].key.keyvalue); + append_hex(context, sp, 0, 0, &ent->keys.val[i].key.keyvalue); append_string(context, sp, ":"); /* --- salt */ if(ent->keys.val[i].salt){ append_string(context, sp, "%u/", ent->keys.val[i].salt->type); - append_hex(context, sp, &ent->keys.val[i].salt->salt); + append_hex(context, sp, 0, 0, &ent->keys.val[i].salt->salt); }else append_string(context, sp, "-"); } @@ -234,25 +315,266 @@ entry2string_int (krb5_context context, krb5_storage *sp, hdb_entry *ent) } else append_string(context, sp, "-"); + return 0; +} + +#define KRB5_KDB_DISALLOW_POSTDATED 0x00000001 +#define KRB5_KDB_DISALLOW_FORWARDABLE 0x00000002 +#define KRB5_KDB_DISALLOW_TGT_BASED 0x00000004 +#define KRB5_KDB_DISALLOW_RENEWABLE 0x00000008 +#define KRB5_KDB_DISALLOW_PROXIABLE 0x00000010 +#define KRB5_KDB_DISALLOW_DUP_SKEY 0x00000020 +#define KRB5_KDB_DISALLOW_ALL_TIX 0x00000040 +#define KRB5_KDB_REQUIRES_PRE_AUTH 0x00000080 +#define KRB5_KDB_REQUIRES_HW_AUTH 0x00000100 +#define KRB5_KDB_REQUIRES_PWCHANGE 0x00000200 +#define KRB5_KDB_DISALLOW_SVR 0x00001000 +#define KRB5_KDB_PWCHANGE_SERVICE 0x00002000 +#define KRB5_KDB_SUPPORT_DESMD5 0x00004000 +#define KRB5_KDB_NEW_PRINC 0x00008000 + +static int +flags_to_attr(HDBFlags flags) +{ + int a = 0; + + if (!flags.postdate) + a |= KRB5_KDB_DISALLOW_POSTDATED; + if (!flags.forwardable) + a |= KRB5_KDB_DISALLOW_FORWARDABLE; + if (flags.initial) + a |= KRB5_KDB_DISALLOW_TGT_BASED; + if (!flags.renewable) + a |= KRB5_KDB_DISALLOW_RENEWABLE; + if (!flags.proxiable) + a |= KRB5_KDB_DISALLOW_PROXIABLE; + if (flags.invalid) + a |= KRB5_KDB_DISALLOW_ALL_TIX; + if (flags.require_preauth) + a |= KRB5_KDB_REQUIRES_PRE_AUTH; + if (flags.require_hwauth) + a |= KRB5_KDB_REQUIRES_HW_AUTH; + if (!flags.server) + a |= KRB5_KDB_DISALLOW_SVR; + if (flags.change_pw) + a |= KRB5_KDB_PWCHANGE_SERVICE; + return a; +} +krb5_error_code +entry2mit_string_int(krb5_context context, krb5_storage *sp, hdb_entry *ent) +{ + krb5_error_code ret; + ssize_t sz; + size_t i, k; + size_t num_tl_data = 0; + size_t num_key_data = 0; + char *p; + HDB_Ext_KeySet *hist_keys = NULL; + HDB_extension *extp; + time_t last_pw_chg = 0; + time_t exp = 0; + time_t pwexp = 0; + unsigned int max_life = 0; + unsigned int max_renew = 0; + + /* Always create a modified_by entry. */ + num_tl_data++; + + ret = hdb_entry_get_pw_change_time(ent, &last_pw_chg); + if (ret) return ret; + if (last_pw_chg) + num_tl_data++; + + extp = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys); + if (extp) + hist_keys = &extp->data.u.hist_keys; + + for (i = 0; i < ent->keys.len;i++) { + if (!mit_strong_etype(ent->keys.val[i].key.keytype)) + continue; + num_key_data++; + } + if (hist_keys) { + for (i = 0; i < hist_keys->len; i++) { + /* + * MIT uses the highest kvno as the current kvno instead of + * tracking kvno separately, so we can't dump keysets with kvno + * higher than the entry's kvno. + */ + if (hist_keys->val[i].kvno >= ent->kvno) + continue; + for (k = 0; k < hist_keys->val[i].keys.len; k++) { + if (ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD4 || + ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD5) + continue; + num_key_data++; + } + } + } + + ret = krb5_unparse_name(context, ent->principal, &p); + if (ret) return ret; + sz = append_string(context, sp, "princ\t38\t%u\t%u\t%u\t0\t%s\t%d", + strlen(p), num_tl_data, num_key_data, p, + flags_to_attr(ent->flags)); + if (sz == -1) { + free(p); + return ENOMEM; + } + + if (ent->max_life) + max_life = *ent->max_life; + if (ent->max_renew) + max_renew = *ent->max_renew; + if (ent->valid_end) + exp = *ent->valid_end; + if (ent->pw_end) + pwexp = *ent->pw_end; + + sz = append_string(context, sp, "\t%u\t%u\t%u\t%u\t0\t0\t0", + max_life, max_renew, exp, pwexp); + if (sz == -1) { + free(p); + return ENOMEM; + } + + /* Dump TL data we know: last pw chg and modified_by */ +#define mit_KRB5_TL_LAST_PWD_CHANGE 1 +#define mit_KRB5_TL_MOD_PRINC 2 + if (last_pw_chg) { + krb5_data d; + time_t val; + unsigned char *ptr; + + ptr = (unsigned char *)&last_pw_chg; + val = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); + d.data = &val; + d.length = sizeof (last_pw_chg); + sz = append_string(context, sp, "\t%u\t%u\t", + mit_KRB5_TL_LAST_PWD_CHANGE, d.length); + if (sz == -1) { + free(p); + return ENOMEM; + } + sz = append_hex(context, sp, 1, 1, &d); + if (sz == -1) { + free(p); + return ENOMEM; + } + } + if (ent->modified_by) { + krb5_data d; + unsigned int val; + size_t plen; + unsigned char *ptr; + char *modby_p; + + free(p); + ptr = (unsigned char *)&ent->modified_by->time; + val = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); + d.data = &val; + d.length = sizeof (ent->modified_by->time); + ret = krb5_unparse_name(context, ent->modified_by->principal, &modby_p); + if (ret) return ret; + plen = strlen(modby_p); + sz = append_string(context, sp, "\t%u\t%u\t", + mit_KRB5_TL_MOD_PRINC, + d.length + plen + 1 /* NULL counted */); + if (sz == -1) { + free(modby_p); + return ENOMEM; + } + sz = append_hex(context, sp, 1, 1, &d); + if (sz == -1) { + free(modby_p); + return ENOMEM; + } + d.data = modby_p; + d.length = plen + 1; + sz = append_hex(context, sp, 1, 1, &d); + free(modby_p); + if (sz == -1) return ENOMEM; + } else { + krb5_data d; + unsigned int val; + size_t plen; + unsigned char *ptr; + + /* Fake the entry to make MIT happy. */ + ptr = (unsigned char *)&last_pw_chg; + val = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); + d.data = &val; + d.length = sizeof (last_pw_chg); + plen = strlen(p); + sz = append_string(context, sp, "\t%u\t%u\t", + mit_KRB5_TL_MOD_PRINC, + d.length + plen + 1 /* NULL counted */); + if (sz == -1) { + free(p); + return ENOMEM; + } + sz = append_hex(context, sp, 1, 1, &d); + if (sz == -1) { + free(p); + return ENOMEM; + } + d.data = p; + d.length = plen + 1; + sz = append_hex(context, sp, 1, 1, &d); + free(p); + if (sz == -1) return ENOMEM; + } + /* + * Dump keys (remembering to not include any with kvno higher than + * the entry's because MIT doesn't track entry kvno separately from + * the entry's keys -- max kvno is it) + */ + for (i = 0; i < ent->keys.len; i++) { + if (!mit_strong_etype(ent->keys.val[i].key.keytype)) + continue; + sz = append_mit_key(context, sp, ent->principal, ent->kvno, + &ent->keys.val[i]); + if (sz == -1) return ENOMEM; + } + for (i = 0; hist_keys && i < ent->kvno; i++) { + size_t m; + + /* dump historical keys */ + for (k = 0; k < hist_keys->len; k++) { + if (hist_keys->val[k].kvno != ent->kvno - i) + continue; + for (m = 0; m < hist_keys->val[k].keys.len; m++) { + if (ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD4 || + ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD5) + continue; + sz = append_mit_key(context, sp, ent->principal, + hist_keys->val[k].kvno, + &hist_keys->val[k].keys.val[m]); + if (sz == -1) return ENOMEM; + } + } + } + sz = append_string(context, sp, "\t-1;"); /* "extra data" */ + if (sz == -1) return ENOMEM; return 0; } krb5_error_code -hdb_entry2string (krb5_context context, hdb_entry *ent, char **str) +hdb_entry2string(krb5_context context, hdb_entry *ent, char **str) { krb5_error_code ret; krb5_data data; krb5_storage *sp; sp = krb5_storage_emem(); - if(sp == NULL) { + if (sp == NULL) { krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } ret = entry2string_int(context, sp, ent); - if(ret) { + if (ret) { krb5_storage_free(sp); return ret; } @@ -267,22 +589,31 @@ hdb_entry2string (krb5_context context, hdb_entry *ent, char **str) /* print a hdb_entry to (FILE*)data; suitable for hdb_foreach */ krb5_error_code -hdb_print_entry(krb5_context context, HDB *db, hdb_entry_ex *entry, void *data) +hdb_print_entry(krb5_context context, HDB *db, hdb_entry_ex *entry, + void *data) { + struct hdb_print_entry_arg *parg = data; krb5_error_code ret; krb5_storage *sp; - FILE *f = data; - - fflush(f); - sp = krb5_storage_from_fd(fileno(f)); - if(sp == NULL) { + fflush(parg->out); + sp = krb5_storage_from_fd(fileno(parg->out)); + if (sp == NULL) { krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } - ret = entry2string_int(context, sp, &entry->entry); - if(ret) { + switch (parg->fmt) { + case HDB_DUMP_HEIMDAL: + ret = entry2string_int(context, sp, &entry->entry); + break; + case HDB_DUMP_MIT: + ret = entry2mit_string_int(context, sp, &entry->entry); + break; + default: + heim_abort("Only two dump formats supported: Heimdal and MIT"); + } + if (ret) { krb5_storage_free(sp); return ret; } diff --git a/crypto/heimdal/lib/hdb/version-script.map b/crypto/heimdal/lib/hdb/version-script.map index 50a36cec0aa9..42e2043b4b47 100644 --- a/crypto/heimdal/lib/hdb/version-script.map +++ b/crypto/heimdal/lib/hdb/version-script.map @@ -4,6 +4,7 @@ HEIMDAL_HDB_1.0 { global: encode_hdb_keyset; hdb_add_master_key; + hdb_add_current_keys_to_history; hdb_check_db_format; hdb_clear_extension; hdb_clear_master_key; @@ -57,6 +58,7 @@ HEIMDAL_HDB_1.0 { hdb_seal_key_mkey; hdb_seal_keys; hdb_seal_keys_mkey; + hdb_set_last_modified_by; hdb_set_master_key; hdb_set_master_keyfile; hdb_unlock; @@ -71,6 +73,10 @@ HEIMDAL_HDB_1.0 { hdb_interface_version; initialize_hdb_error_table_r; + # MIT KDB related entries + _hdb_mdb_value2entry; + _hdb_mit_dump2mitdb_entry; + hdb_kt_ops; # some random bits needed for libkadm diff --git a/crypto/heimdal/lib/kadm5/chpass_s.c b/crypto/heimdal/lib/kadm5/chpass_s.c index 624293e5c3a3..22f65517fcc5 100644 --- a/crypto/heimdal/lib/kadm5/chpass_s.c +++ b/crypto/heimdal/lib/kadm5/chpass_s.c @@ -58,6 +58,10 @@ change(void *server_handle, if(ret) goto out; + ret = hdb_add_current_keys_to_history(context->context, &ent.entry); + if (ret) + goto out; + if (context->db->hdb_capability_flags & HDB_CAP_F_HANDLE_PASSWORDS) { ret = context->db->hdb_password(context->context, context->db, &ent, password, cond); @@ -170,6 +174,9 @@ kadm5_s_chpass_principal_with_key(void *server_handle, HDB_F_GET_ANY|HDB_F_ADMIN_DATA, &ent); if(ret) goto out; + ret = hdb_add_current_keys_to_history(context->context, &ent.entry); + if (ret) + goto out2; ret = _kadm5_set_keys2(context, &ent.entry, n_key_data, key_data); if(ret) goto out2; diff --git a/crypto/heimdal/lib/kadm5/randkey_s.c b/crypto/heimdal/lib/kadm5/randkey_s.c index dcb179aac40f..adb3564be719 100644 --- a/crypto/heimdal/lib/kadm5/randkey_s.c +++ b/crypto/heimdal/lib/kadm5/randkey_s.c @@ -59,6 +59,10 @@ kadm5_s_randkey_principal(void *server_handle, if(ret) goto out; + ret = hdb_add_current_keys_to_history(context->context, &ent.entry); + if (ret) + goto out2; + ret = _kadm5_set_keys_randomly (context, &ent.entry, new_keys, diff --git a/crypto/openssl/CHANGES.md b/crypto/openssl/CHANGES.md index 5f5ba3ef1751..b991285aedb2 100644 --- a/crypto/openssl/CHANGES.md +++ b/crypto/openssl/CHANGES.md @@ -28,6 +28,72 @@ OpenSSL Releases OpenSSL 3.5 ----------- +### Changes between 3.5.3 and 3.5.4 [30 Sep 2025] + + * Fix Out-of-bounds read & write in RFC 3211 KEK Unwrap + + Issue summary: An application trying to decrypt CMS messages encrypted using + password based encryption can trigger an out-of-bounds read and write. + + Impact summary: This out-of-bounds read may trigger a crash which leads to + Denial of Service for an application. The out-of-bounds write can cause + a memory corruption which can have various consequences including + a Denial of Service or Execution of attacker-supplied code. + + The issue was reported by Stanislav Fort (Aisle Research). + + ([CVE-2025-9230]) + + *Viktor Dukhovni* + + * Fix Timing side-channel in SM2 algorithm on 64 bit ARM + + Issue summary: A timing side-channel which could potentially allow remote + recovery of the private key exists in the SM2 algorithm implementation on + 64 bit ARM platforms. + + Impact summary: A timing side-channel in SM2 signature computations on + 64 bit ARM platforms could allow recovering the private key by an attacker. + + The issue was reported by Stanislav Fort (Aisle Research). + + ([CVE-2025-9231]) + + *Stanislav Fort and Tomáš Mráz* + + * Fix Out-of-bounds read in HTTP client no_proxy handling + + Issue summary: An application using the OpenSSL HTTP client API functions + may trigger an out-of-bounds read if the "no_proxy" environment variable is + set and the host portion of the authority component of the HTTP URL is an + IPv6 address. + + Impact summary: An out-of-bounds read can trigger a crash which leads to + Denial of Service for an application. + + The issue was reported by Stanislav Fort (Aisle Research). + + ([CVE-2025-9232]) + + *Stanislav Fort* + + * The FIPS provider no longer performs a PCT on key import for ECX keys + (that was introduced in 3.5.2), following the latest update + on that requirement in FIPS 140-3 IG 10.3.A additional comment 1. + + *Eugene Syromiatnikov* + + * Fixed the length of the ASN.1 sequence for the SM3 digests of RSA-encrypted + signatures. + + *Xiao Lou Dong Feng* + + * Reverted the synthesised `OPENSSL_VERSION_NUMBER` change for the release + builds, as it broke some exiting applications that relied on the previous + 3.x semantics, as documented in `OpenSSL_version(3)`. + + *Richard Levitte* + ### Changes between 3.5.2 and 3.5.3 [16 Sep 2025] * Avoided a potential race condition introduced in 3.5.1, where @@ -21284,6 +21350,9 @@ ndif <!-- Links --> +[CVE-2025-9232]: https://www.openssl.org/news/vulnerabilities.html#CVE-2025-9232 +[CVE-2025-9231]: https://www.openssl.org/news/vulnerabilities.html#CVE-2025-9231 +[CVE-2025-9230]: https://www.openssl.org/news/vulnerabilities.html#CVE-2025-9230 [CVE-2025-4575]: https://www.openssl.org/news/vulnerabilities.html#CVE-2025-4575 [CVE-2024-13176]: https://www.openssl.org/news/vulnerabilities.html#CVE-2024-13176 [CVE-2024-9143]: https://www.openssl.org/news/vulnerabilities.html#CVE-2024-9143 diff --git a/crypto/openssl/NEWS.md b/crypto/openssl/NEWS.md index 5d8a83f43068..b194dfb7cb06 100644 --- a/crypto/openssl/NEWS.md +++ b/crypto/openssl/NEWS.md @@ -23,19 +23,46 @@ OpenSSL Releases OpenSSL 3.5 ----------- +### Major changes between OpenSSL 3.5.3 and OpenSSL 3.5.4 [30 Sep 2025] + +OpenSSL 3.5.4 is a security patch release. The most severe CVE fixed in this +release is Moderate. + +This release incorporates the following bug fixes and mitigations: + + * Fix Out-of-bounds read & write in RFC 3211 KEK Unwrap. + ([CVE-2025-9230]) + + * Fix Timing side-channel in SM2 algorithm on 64 bit ARM. + ([CVE-2025-9231]) + + * Fix Out-of-bounds read in HTTP client no_proxy handling. + ([CVE-2025-9232]) + + * Reverted the synthesised `OPENSSL_VERSION_NUMBER` change for the release + builds, as it broke some exiting applications that relied on the previous + 3.x semantics, as documented in `OpenSSL_version(3)`. + ### Major changes between OpenSSL 3.5.2 and OpenSSL 3.5.3 [16 Sep 2025] - * Added FIPS 140-3 PCT on DH key generation. +OpenSSL 3.5.3 is a bug fix release. + +This release incorporates the following bug fixes and mitigations: - *Nikola Pajkovsky* + * Added FIPS 140-3 PCT on DH key generation. * Fixed the synthesised `OPENSSL_VERSION_NUMBER`. - *Richard Levitte* + * Removed PCT on key import in the FIPS provider as it is not required by + the standard. ### Major changes between OpenSSL 3.5.1 and OpenSSL 3.5.2 [5 Aug 2025] - * none +OpenSSL 3.5.2 is a bug fix release. + +This release incorporates the following bug fixes and mitigations: + + * The FIPS provider now performs a PCT on key import for RSA, EC and ECX. ### Major changes between OpenSSL 3.5.0 and OpenSSL 3.5.1 [1 Jul 2025] @@ -45,7 +72,7 @@ release is Low. This release incorporates the following bug fixes and mitigations: * Fix x509 application adds trusted use instead of rejected use. - ([CVE-2025-4575]) + ([CVE-2025-4575]) ### Major changes between OpenSSL 3.4 and OpenSSL 3.5.0 [8 Apr 2025] @@ -1913,6 +1940,9 @@ OpenSSL 0.9.x * Support for various new platforms <!-- Links --> +[CVE-2025-9232]: https://www.openssl.org/news/vulnerabilities.html#CVE-2025-9232 +[CVE-2025-9231]: https://www.openssl.org/news/vulnerabilities.html#CVE-2025-9231 +[CVE-2025-9230]: https://www.openssl.org/news/vulnerabilities.html#CVE-2025-9230 [CVE-2025-4575]: https://www.openssl.org/news/vulnerabilities.html#CVE-2025-4575 [CVE-2024-13176]: https://www.openssl.org/news/vulnerabilities.html#CVE-2024-13176 [CVE-2024-9143]: https://www.openssl.org/news/vulnerabilities.html#CVE-2024-9143 diff --git a/crypto/openssl/VERSION.dat b/crypto/openssl/VERSION.dat index 8a2893b68006..a8eb3ac9c421 100644 --- a/crypto/openssl/VERSION.dat +++ b/crypto/openssl/VERSION.dat @@ -1,7 +1,7 @@ MAJOR=3 MINOR=5 -PATCH=3 +PATCH=4 PRE_RELEASE_TAG= BUILD_METADATA= -RELEASE_DATE="16 Sep 2025" +RELEASE_DATE="30 Sep 2025" SHLIB_VERSION=3 diff --git a/crypto/openssl/apps/storeutl.c b/crypto/openssl/apps/storeutl.c index 62f0e6135640..f8ebde44481c 100644 --- a/crypto/openssl/apps/storeutl.c +++ b/crypto/openssl/apps/storeutl.c @@ -331,14 +331,22 @@ int storeutl_main(int argc, char *argv[]) static int indent_printf(int indent, BIO *bio, const char *format, ...) { va_list args; - int ret; + int ret, vret; + + ret = BIO_printf(bio, "%*s", indent, ""); + if (ret < 0) + return ret; va_start(args, format); + vret = BIO_vprintf(bio, format, args); + va_end(args); - ret = BIO_printf(bio, "%*s", indent, "") + BIO_vprintf(bio, format, args); + if (vret < 0) + return vret; + if (vret > INT_MAX - ret) + return INT_MAX; - va_end(args); - return ret; + return ret + vret; } static int process(const char *uri, const UI_METHOD *uimeth, PW_CB_DATA *uidata, diff --git a/crypto/openssl/crypto/bio/bss_file.c b/crypto/openssl/crypto/bio/bss_file.c index 2743a14417cf..ddcb4feb6a58 100644 --- a/crypto/openssl/crypto/bio/bss_file.c +++ b/crypto/openssl/crypto/bio/bss_file.c @@ -287,7 +287,7 @@ static long file_ctrl(BIO *b, int cmd, long num, void *ptr) if (fp == NULL) { ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), "calling fopen(%s, %s)", - ptr, p); + (const char *)ptr, p); ERR_raise(ERR_LIB_BIO, ERR_R_SYS_LIB); ret = 0; break; diff --git a/crypto/openssl/crypto/ec/ecp_sm2p256.c b/crypto/openssl/crypto/ec/ecp_sm2p256.c index ffb58399dfd0..4c39be2186fb 100644 --- a/crypto/openssl/crypto/ec/ecp_sm2p256.c +++ b/crypto/openssl/crypto/ec/ecp_sm2p256.c @@ -1,5 +1,5 @@ /* - * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2023-2025 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy diff --git a/crypto/openssl/crypto/evp/bio_ok.c b/crypto/openssl/crypto/evp/bio_ok.c index 20811ffded6f..d7f6c71ee1ad 100644 --- a/crypto/openssl/crypto/evp/bio_ok.c +++ b/crypto/openssl/crypto/evp/bio_ok.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -560,7 +560,7 @@ static int block_in(BIO *b) { BIO_OK_CTX *ctx; EVP_MD_CTX *md; - unsigned long tl = 0; + size_t tl = 0; unsigned char tmp[EVP_MAX_MD_SIZE]; int md_size; @@ -571,15 +571,18 @@ static int block_in(BIO *b) goto berr; assert(sizeof(tl) >= OK_BLOCK_BLOCK); /* always true */ - tl = ctx->buf[0]; - tl <<= 8; - tl |= ctx->buf[1]; - tl <<= 8; - tl |= ctx->buf[2]; - tl <<= 8; - tl |= ctx->buf[3]; - - if (ctx->buf_len < tl + OK_BLOCK_BLOCK + md_size) + tl = ((size_t)ctx->buf[0] << 24) + | ((size_t)ctx->buf[1] << 16) + | ((size_t)ctx->buf[2] << 8) + | ((size_t)ctx->buf[3]); + + if (tl > OK_BLOCK_SIZE) + goto berr; + + if (tl > SIZE_MAX - OK_BLOCK_BLOCK - (size_t)md_size) + goto berr; + + if (ctx->buf_len < tl + OK_BLOCK_BLOCK + (size_t)md_size) return 1; if (!EVP_DigestUpdate(md, @@ -587,7 +590,7 @@ static int block_in(BIO *b) goto berr; if (!EVP_DigestFinal_ex(md, tmp, NULL)) goto berr; - if (memcmp(&(ctx->buf[tl + OK_BLOCK_BLOCK]), tmp, md_size) == 0) { + if (memcmp(&(ctx->buf[tl + OK_BLOCK_BLOCK]), tmp, (size_t)md_size) == 0) { /* there might be parts from next block lurking around ! */ ctx->buf_off_save = tl + OK_BLOCK_BLOCK + md_size; ctx->buf_len_save = ctx->buf_len; diff --git a/crypto/openssl/crypto/evp/ctrl_params_translate.c b/crypto/openssl/crypto/evp/ctrl_params_translate.c index ed73fc0fbb8d..c846353200b2 100644 --- a/crypto/openssl/crypto/evp/ctrl_params_translate.c +++ b/crypto/openssl/crypto/evp/ctrl_params_translate.c @@ -1356,7 +1356,7 @@ static int fix_rsa_padding_mode(enum state state, if (i == OSSL_NELEM(str_value_map)) { ERR_raise_data(ERR_LIB_RSA, RSA_R_UNKNOWN_PADDING_TYPE, "[action:%d, state:%d] padding name %s", - ctx->action_type, state, ctx->p1); + ctx->action_type, state, (const char *)ctx->p2); ctx->p1 = ret = -2; } else if (state == POST_CTRL_TO_PARAMS) { /* EVP_PKEY_CTRL_GET_RSA_PADDING weirdness explained further up */ diff --git a/crypto/openssl/crypto/evp/p_lib.c b/crypto/openssl/crypto/evp/p_lib.c index 7f4508169dfa..63953a84e1f5 100644 --- a/crypto/openssl/crypto/evp/p_lib.c +++ b/crypto/openssl/crypto/evp/p_lib.c @@ -1146,15 +1146,14 @@ int EVP_PKEY_can_sign(const EVP_PKEY *pkey) } else { const OSSL_PROVIDER *prov = EVP_KEYMGMT_get0_provider(pkey->keymgmt); OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov); - const char *supported_sig = - pkey->keymgmt->query_operation_name != NULL - ? pkey->keymgmt->query_operation_name(OSSL_OP_SIGNATURE) - : EVP_KEYMGMT_get0_name(pkey->keymgmt); - EVP_SIGNATURE *signature = NULL; - - signature = EVP_SIGNATURE_fetch(libctx, supported_sig, NULL); - if (signature != NULL) { - EVP_SIGNATURE_free(signature); + EVP_SIGNATURE *sig; + const char *name; + + name = evp_keymgmt_util_query_operation_name(pkey->keymgmt, + OSSL_OP_SIGNATURE); + sig = EVP_SIGNATURE_fetch(libctx, name, NULL); + if (sig != NULL) { + EVP_SIGNATURE_free(sig); return 1; } } diff --git a/crypto/openssl/crypto/info.c b/crypto/openssl/crypto/info.c index 4d70471be255..e760ec094027 100644 --- a/crypto/openssl/crypto/info.c +++ b/crypto/openssl/crypto/info.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -23,6 +23,9 @@ #if defined(__arm__) || defined(__arm) || defined(__aarch64__) # include "arm_arch.h" # define CPU_INFO_STR_LEN 128 +#elif defined(__powerpc__) || defined(__POWERPC__) || defined(_ARCH_PPC) +# include "crypto/ppc_arch.h" +# define CPU_INFO_STR_LEN 128 #elif defined(__s390__) || defined(__s390x__) # include "s390x_arch.h" # define CPU_INFO_STR_LEN 2048 @@ -77,6 +80,15 @@ DEFINE_RUN_ONCE_STATIC(init_info_strings) BIO_snprintf(ossl_cpu_info_str + strlen(ossl_cpu_info_str), sizeof(ossl_cpu_info_str) - strlen(ossl_cpu_info_str), " env:%s", env); +# elif defined(__powerpc__) || defined(__POWERPC__) || defined(_ARCH_PPC) + const char *env; + + BIO_snprintf(ossl_cpu_info_str, sizeof(ossl_cpu_info_str), + CPUINFO_PREFIX "OPENSSL_ppccap=0x%x", OPENSSL_ppccap_P); + if ((env = getenv("OPENSSL_ppccap")) != NULL) + BIO_snprintf(ossl_cpu_info_str + strlen(ossl_cpu_info_str), + sizeof(ossl_cpu_info_str) - strlen(ossl_cpu_info_str), + " env:%s", env); # elif defined(__s390__) || defined(__s390x__) const char *env; diff --git a/crypto/openssl/crypto/ml_dsa/ml_dsa_key.c b/crypto/openssl/crypto/ml_dsa/ml_dsa_key.c index 41df1a956fb8..50e3b5433085 100644 --- a/crypto/openssl/crypto/ml_dsa/ml_dsa_key.c +++ b/crypto/openssl/crypto/ml_dsa/ml_dsa_key.c @@ -311,6 +311,7 @@ int ossl_ml_dsa_key_has(const ML_DSA_KEY *key, int selection) static int public_from_private(const ML_DSA_KEY *key, EVP_MD_CTX *md_ctx, VECTOR *t1, VECTOR *t0) { + int ret = 0; const ML_DSA_PARAMS *params = key->params; uint32_t k = params->k, l = params->l; POLY *polys; @@ -343,9 +344,10 @@ static int public_from_private(const ML_DSA_KEY *key, EVP_MD_CTX *md_ctx, /* Zeroize secret */ vector_zero(&s1_ntt); + ret = 1; err: OPENSSL_free(polys); - return 1; + return ret; } int ossl_ml_dsa_key_public_from_private(ML_DSA_KEY *key) diff --git a/crypto/openssl/crypto/ml_kem/ml_kem.c b/crypto/openssl/crypto/ml_kem/ml_kem.c index 4474af0f87cb..716c3bf4275e 100644 --- a/crypto/openssl/crypto/ml_kem/ml_kem.c +++ b/crypto/openssl/crypto/ml_kem/ml_kem.c @@ -2046,5 +2046,5 @@ int ossl_ml_kem_pubkey_cmp(const ML_KEM_KEY *key1, const ML_KEM_KEY *key2) * No match if just one of the public keys is not available, otherwise both * are unavailable, and for now such keys are considered equal. */ - return (ossl_ml_kem_have_pubkey(key1) ^ ossl_ml_kem_have_pubkey(key2)); + return (!(ossl_ml_kem_have_pubkey(key1) ^ ossl_ml_kem_have_pubkey(key2))); } diff --git a/crypto/openssl/crypto/modes/siv128.c b/crypto/openssl/crypto/modes/siv128.c index 72526b849eaf..4e52d8eb8782 100644 --- a/crypto/openssl/crypto/modes/siv128.c +++ b/crypto/openssl/crypto/modes/siv128.c @@ -202,9 +202,12 @@ int ossl_siv128_init(SIV128_CONTEXT *ctx, const unsigned char *key, int klen, || !EVP_MAC_final(mac_ctx, ctx->d.byte, &out_len, sizeof(ctx->d.byte))) { EVP_CIPHER_CTX_free(ctx->cipher_ctx); + ctx->cipher_ctx = NULL; EVP_MAC_CTX_free(ctx->mac_ctx_init); + ctx->mac_ctx_init = NULL; EVP_MAC_CTX_free(mac_ctx); EVP_MAC_free(ctx->mac); + ctx->mac = NULL; return 0; } EVP_MAC_CTX_free(mac_ctx); diff --git a/crypto/openssl/crypto/property/property_parse.c b/crypto/openssl/crypto/property/property_parse.c index 3a67754224f0..23963c89bc46 100644 --- a/crypto/openssl/crypto/property/property_parse.c +++ b/crypto/openssl/crypto/property/property_parse.c @@ -641,7 +641,7 @@ static void put_str(const char *str, char **buf, size_t *remain, size_t *needed) } quotes = quote != '\0'; - if (*remain == 0) { + if (*remain <= (size_t)quotes) { *needed += 2 * quotes; return; } diff --git a/crypto/openssl/crypto/rsa/rsa_gen.c b/crypto/openssl/crypto/rsa/rsa_gen.c index 033f66714add..f76bb7748369 100644 --- a/crypto/openssl/crypto/rsa/rsa_gen.c +++ b/crypto/openssl/crypto/rsa/rsa_gen.c @@ -734,18 +734,3 @@ err: return ret; } - -#ifdef FIPS_MODULE -int ossl_rsa_key_pairwise_test(RSA *rsa) -{ - OSSL_CALLBACK *stcb; - void *stcbarg; - int res; - - OSSL_SELF_TEST_get_callback(rsa->libctx, &stcb, &stcbarg); - res = rsa_keygen_pairwise_test(rsa, stcb, stcbarg); - if (res <= 0) - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT_IMPORT); - return res; -} -#endif /* FIPS_MODULE */ diff --git a/crypto/openssl/crypto/rsa/rsa_sign.c b/crypto/openssl/crypto/rsa/rsa_sign.c index 78e4bad69e49..bb6e99acf9d3 100644 --- a/crypto/openssl/crypto/rsa/rsa_sign.c +++ b/crypto/openssl/crypto/rsa/rsa_sign.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -129,7 +129,7 @@ static const unsigned char digestinfo_ripemd160_der[] = { # ifndef OPENSSL_NO_SM3 /* SM3 (1 2 156 10197 1 401) */ static const unsigned char digestinfo_sm3_der[] = { - ASN1_SEQUENCE, 0x0f + SM3_DIGEST_LENGTH, + ASN1_SEQUENCE, 0x10 + SM3_DIGEST_LENGTH, ASN1_SEQUENCE, 0x0c, ASN1_OID, 0x08, 1 * 40 + 2, 0x81, 0x1c, 0xcf, 0x55, 1, 0x83, 0x78, ASN1_NULL, 0x00, diff --git a/crypto/openssl/crypto/threads_pthread.c b/crypto/openssl/crypto/threads_pthread.c index 44d6ebe09231..ace2dc499061 100644 --- a/crypto/openssl/crypto/threads_pthread.c +++ b/crypto/openssl/crypto/threads_pthread.c @@ -62,8 +62,10 @@ __tsan_mutex_post_lock((x), 0, 0) /* * The Non-Stop KLT thread model currently seems broken in its rwlock * implementation + * Likewise is there a problem with the glibc implementation on riscv. */ -# if defined(PTHREAD_RWLOCK_INITIALIZER) && !defined(_KLT_MODEL_) +# if defined(PTHREAD_RWLOCK_INITIALIZER) && !defined(_KLT_MODEL_) \ + && !defined(__riscv) # define USE_RWLOCK # endif @@ -279,7 +281,7 @@ static struct rcu_qp *get_hold_current_qp(struct rcu_lock_st *lock) /* if the idx hasn't changed, we're good, else try again */ if (qp_idx == ATOMIC_LOAD_N(uint32_t, &lock->reader_idx, - __ATOMIC_RELAXED)) + __ATOMIC_ACQUIRE)) break; ATOMIC_SUB_FETCH(&lock->qp_group[qp_idx].users, (uint64_t)1, @@ -403,8 +405,12 @@ static struct rcu_qp *update_qp(CRYPTO_RCU_LOCK *lock, uint32_t *curr_id) *curr_id = lock->id_ctr; lock->id_ctr++; + /* + * make the current state of everything visible by this release + * when get_hold_current_qp acquires the next qp + */ ATOMIC_STORE_N(uint32_t, &lock->reader_idx, lock->current_alloc_idx, - __ATOMIC_RELAXED); + __ATOMIC_RELEASE); /* * this should make sure that the new value of reader_idx is visible in diff --git a/crypto/openssl/crypto/x509/t_x509.c b/crypto/openssl/crypto/x509/t_x509.c index 7d693669cd36..d849e642ce8b 100644 --- a/crypto/openssl/crypto/x509/t_x509.c +++ b/crypto/openssl/crypto/x509/t_x509.c @@ -219,7 +219,8 @@ int X509_ocspid_print(BIO *bp, X509 *x) goto err; if ((der = dertmp = OPENSSL_malloc(derlen)) == NULL) goto err; - i2d_X509_NAME(subj, &dertmp); + if (i2d_X509_NAME(subj, &dertmp) < 0) + goto err; md = EVP_MD_fetch(x->libctx, SN_sha1, x->propq); if (md == NULL) diff --git a/crypto/openssl/crypto/x509/x509_lu.c b/crypto/openssl/crypto/x509/x509_lu.c index 05ee7c8c6b51..eb2d47955b2e 100644 --- a/crypto/openssl/crypto/x509/x509_lu.c +++ b/crypto/openssl/crypto/x509/x509_lu.c @@ -408,7 +408,6 @@ static int x509_store_add(X509_STORE *store, void *x, int crl) } if (!X509_STORE_lock(store)) { - obj->type = X509_LU_NONE; X509_OBJECT_free(obj); return 0; } diff --git a/crypto/openssl/doc/man3/DEFINE_STACK_OF.pod b/crypto/openssl/doc/man3/DEFINE_STACK_OF.pod index ff2074820f68..eeb882f291e4 100644 --- a/crypto/openssl/doc/man3/DEFINE_STACK_OF.pod +++ b/crypto/openssl/doc/man3/DEFINE_STACK_OF.pod @@ -170,15 +170,14 @@ B<sk_I<TYPE>_set>() sets element I<idx> of I<sk> to I<ptr> replacing the current element. The new element value is returned or NULL if an error occurred: this will only happen if I<sk> is NULL or I<idx> is out of range. -B<sk_I<TYPE>_find>() searches I<sk> for the element I<ptr>. In the case -where no comparison function has been specified, the function performs -a linear search for a pointer equal to I<ptr>. The index of the first -matching element is returned or B<-1> if there is no match. In the case -where a comparison function has been specified, I<sk> is sorted and -B<sk_I<TYPE>_find>() returns the index of a matching element or B<-1> if there -is no match. Note that, in this case the comparison function will usually -compare the values pointed to rather than the pointers themselves and -the order of elements in I<sk> can change. +B<sk_I<TYPE>_find>() searches I<sk> for the element I<ptr>. In the +case where no comparison function has been specified, the function +performs a linear search for a pointer equal to I<ptr>. In the case +where a comparison function has been specified, the function performs +a search for a element that the comparison function indicates is a +match. If the stack is sorted, a binary search is used, otherwise, a +linear search is used. B<sk_I<TYPE>_find>() returns the index of a +matching element or B<-1> if there is no match. B<sk_I<TYPE>_find_ex>() operates like B<sk_I<TYPE>_find>() except when a comparison function has been specified and no matching element is found. @@ -301,7 +300,7 @@ was changed to return 0 in this condition as for other errors. =head1 COPYRIGHT -Copyright 2000-2024 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2000-2025 The OpenSSL Project Authors. All Rights Reserved. Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy diff --git a/crypto/openssl/doc/man3/OpenSSL_version.pod b/crypto/openssl/doc/man3/OpenSSL_version.pod index e5dff33dcdda..6b899cbe5438 100644 --- a/crypto/openssl/doc/man3/OpenSSL_version.pod +++ b/crypto/openssl/doc/man3/OpenSSL_version.pod @@ -256,9 +256,16 @@ L<crypto(7)> The macros and functions described here were added in OpenSSL 3.0, except for OPENSSL_VERSION_NUMBER and OpenSSL_version_num(). +=head1 BUGS + +There was a discrepancy between this manual and commentary + code +in F<< <openssl/opensslv.h> >>, where the latter suggested that the +four least significant bits of B<OPENSSL_VERSION_NUMBER> could be +C<0x0f> in released OpenSSL versions. + =head1 COPYRIGHT -Copyright 2018-2022 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2018-2025 The OpenSSL Project Authors. All Rights Reserved. Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy diff --git a/crypto/openssl/doc/man3/SSL_CIPHER_get_name.pod b/crypto/openssl/doc/man3/SSL_CIPHER_get_name.pod index 09b7280bdd58..a10942433aa7 100644 --- a/crypto/openssl/doc/man3/SSL_CIPHER_get_name.pod +++ b/crypto/openssl/doc/man3/SSL_CIPHER_get_name.pod @@ -37,7 +37,7 @@ SSL_CIPHER_get_protocol_id int SSL_CIPHER_is_aead(const SSL_CIPHER *c); const SSL_CIPHER *SSL_CIPHER_find(SSL *ssl, const unsigned char *ptr); uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *c); - uint32_t SSL_CIPHER_get_protocol_id(const SSL_CIPHER *c); + uint16_t SSL_CIPHER_get_protocol_id(const SSL_CIPHER *c); =head1 DESCRIPTION @@ -203,7 +203,7 @@ The OPENSSL_cipher_name() function was added in OpenSSL 1.1.1. =head1 COPYRIGHT -Copyright 2000-2024 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2000-2025 The OpenSSL Project Authors. All Rights Reserved. Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy diff --git a/crypto/openssl/doc/man3/SSL_SESSION_get0_hostname.pod b/crypto/openssl/doc/man3/SSL_SESSION_get0_hostname.pod index f7add16d7bdd..0140deee9a5e 100644 --- a/crypto/openssl/doc/man3/SSL_SESSION_get0_hostname.pod +++ b/crypto/openssl/doc/man3/SSL_SESSION_get0_hostname.pod @@ -23,9 +23,10 @@ SSL_SESSION_set1_alpn_selected =head1 DESCRIPTION -SSL_SESSION_get0_hostname() retrieves the SNI value that was sent by the -client when the session was created if it was accepted by the server. Otherwise -NULL is returned. +SSL_SESSION_get0_hostname() retrieves the Server Name Indication (SNI) value +that was sent by the client when the session was created if the server +acknowledged the client's SNI extension by including an empty SNI extension +in response. Otherwise NULL is returned. The value returned is a pointer to memory maintained within B<s> and should not be free'd. @@ -44,8 +45,7 @@ B<alpn>. =head1 RETURN VALUES -SSL_SESSION_get0_hostname() returns either a string or NULL based on if there -is the SNI value sent by client. +SSL_SESSION_get0_hostname() returns the SNI string if available, or NULL if not. SSL_SESSION_set1_hostname() returns 1 on success or 0 on error. diff --git a/crypto/openssl/include/crypto/rsa.h b/crypto/openssl/include/crypto/rsa.h index ffbc95a77888..55cc814ce913 100644 --- a/crypto/openssl/include/crypto/rsa.h +++ b/crypto/openssl/include/crypto/rsa.h @@ -124,10 +124,6 @@ ASN1_STRING *ossl_rsa_ctx_to_pss_string(EVP_PKEY_CTX *pkctx); int ossl_rsa_pss_to_ctx(EVP_MD_CTX *ctx, EVP_PKEY_CTX *pkctx, const X509_ALGOR *sigalg, EVP_PKEY *pkey); -# ifdef FIPS_MODULE -int ossl_rsa_key_pairwise_test(RSA *rsa); -# endif /* FIPS_MODULE */ - # if defined(FIPS_MODULE) && !defined(OPENSSL_NO_ACVP_TESTS) int ossl_rsa_acvp_test_gen_params_new(OSSL_PARAM **dst, const OSSL_PARAM src[]); void ossl_rsa_acvp_test_gen_params_free(OSSL_PARAM *dst); diff --git a/crypto/openssl/include/openssl/opensslv.h.in b/crypto/openssl/include/openssl/opensslv.h.in index e547281ff527..69b9caacf4dc 100644 --- a/crypto/openssl/include/openssl/opensslv.h.in +++ b/crypto/openssl/include/openssl/opensslv.h.in @@ -89,12 +89,12 @@ extern "C" { # define OPENSSL_VERSION_TEXT "OpenSSL {- "$config{full_version} $config{release_date}" -}" -/* Synthesize OPENSSL_VERSION_NUMBER with the layout 0xMNN00PPSL */ +/* Synthesize OPENSSL_VERSION_NUMBER with the layout 0xMNN00PP0L */ # define OPENSSL_VERSION_NUMBER \ ( (OPENSSL_VERSION_MAJOR<<28) \ |(OPENSSL_VERSION_MINOR<<20) \ |(OPENSSL_VERSION_PATCH<<4) \ - |{- @config{prerelease} ? "0x0L" : "0xfL" -} ) + |0x0L ) # ifdef __cplusplus } diff --git a/crypto/openssl/providers/fips-sources.checksums b/crypto/openssl/providers/fips-sources.checksums index d48a9c85f57b..334b4ad6b7f2 100644 --- a/crypto/openssl/providers/fips-sources.checksums +++ b/crypto/openssl/providers/fips-sources.checksums @@ -250,7 +250,7 @@ c685813be6ad35b0861ba888670ef54aa2b399d003472698e39426de6e52db59 crypto/initthr f866aafae928db1b439ac950dc90744a2397dfe222672fe68b3798396190c8b0 crypto/mem_clr.c 18127868d868ca5705444c24f7dc385391ba31154fc04ff54949739e8fa7fdfc crypto/ml_dsa/ml_dsa_encoders.c 825105b0a2c4844b2b4229001650ff7e61e1348e52f1072210f70b97cd4adb71 crypto/ml_dsa/ml_dsa_hash.h -c82201cf1a17ff2d4b169dcd4402d3d56f4685e460a1447e021db4abd67f7f0e crypto/ml_dsa/ml_dsa_key.c +c467f4400d399aad6b51746ef2575d1e04d260a1bf901b35ca55624fe62e650e crypto/ml_dsa/ml_dsa_key.c 579c1a12a5c5f014476a6bf695dc271f63074fb187e23ffc3f9ccb5b7ea044f1 crypto/ml_dsa/ml_dsa_key.h 3f98eb0467033d0a40867ef1c1036dcfea5d231eeac2321196f7d7c7243edace crypto/ml_dsa/ml_dsa_key_compress.c 983d164bfa3dbe8d85ad1fdc24d897e79d9246d96d9c1862855c6c538b387ad9 crypto/ml_dsa/ml_dsa_local.h @@ -263,7 +263,7 @@ ff65c82c56e341f47df03d0c74de7fb537de0e68a4fa23fa07a9fdb51c511f1c crypto/ml_dsa/ 1d7f57a41034988a4e7d4c9a998760d2ef802c5e90275d09a3ca31c5f3403d94 crypto/ml_dsa/ml_dsa_sign.c 5217ef237e21872205703b95577290c34898423466a465c7bd609b2eb4627964 crypto/ml_dsa/ml_dsa_sign.h abd934284bcd8061027a69f437fa4410c6b72cd950be1ebe048244d036371208 crypto/ml_dsa/ml_dsa_vector.h -defc2e4e81ff1b78056c795bc0565f4241a259c2957abe84a51bcbc1e4ace3f1 crypto/ml_kem/ml_kem.c +8c4f7238f68f959f2ad1e2529c567364c5a8818898355c82818521e03239ea76 crypto/ml_kem/ml_kem.c 36e24eae5d38cc9666ae40e4e8a2dc12328e1159fea68447cb19dab174d25adf crypto/modes/asm/aes-gcm-armv8-unroll8_64.pl 33357356cd739d4ae89d52f0804b6900e4b94d8829323819c6f64c8908e978df crypto/modes/asm/aes-gcm-armv8_64.pl bcc09bdb474f045d04c983fa09c31a010c5a25513f53a5d3653ade91304f0f96 crypto/modes/asm/aes-gcm-avx512.pl @@ -306,7 +306,7 @@ f50450f7e5f6896fb8e3cde2fdc11cc543124c854ef9d88252a166606ca80081 crypto/params_ 467c416422ecf61e3b713c5eb259fdbcb4aa73ae8dee61804d0b85cfd3fff4f7 crypto/property/defn_cache.c 91c1f1f8eb5588ed9da17386c244ae68a6a81717b1c7ab6c9f1a6a57973a039f crypto/property/property.c 66da4f28d408133fb544b14aeb9ad4913e7c5c67e2826e53f0dc5bf4d8fada26 crypto/property/property_local.h -d32105cb087d708d0504a787f74bc163cc398c299faf2e98d6bb5ae02f5ce9b7 crypto/property/property_parse.c +1e99a3934812f99dad79cbfbb6727ad61b6093711c1a6c74d4b50f9318152611 crypto/property/property_parse.c a7cefda6a117550e2c76e0f307565ce1e11640b11ba10c80e469a837fd1212a3 crypto/property/property_query.c 20e69b9d594dfc443075eddbb0e6bcc0ed36ca51993cd50cc5a4f86eb31127f8 crypto/property/property_string.c 10644e9d20214660706de58d34edf635c110d4e4f2628cd5284a08c60ed9aff8 crypto/provider_core.c @@ -322,7 +322,7 @@ f0c8792a99132e0b9c027cfa7370f45594a115934cdc9e8f23bdd64abecaf7fd crypto/rsa/rsa 1b828f428f0e78b591378f7b780164c4574620c68f9097de041cbd576f811bf6 crypto/rsa/rsa_backend.c 38a102cd1da1f6ca5a46e6a22f018237964336274385f5c70cbedcaa6997647e crypto/rsa/rsa_chk.c e762c599b17d5c89f4b1c9eb7d0ca1f04a95d815c86a3e72c30b231ce57fb199 crypto/rsa/rsa_crpt.c -0fa3e4687510e2d91c8f4b1c460b1d51375d9855ed825b3d6697620b146b52d1 crypto/rsa/rsa_gen.c +a3d20f27ae3cb41af5b62febd0bb19025e59d401b136306d570cdba103b15542 crypto/rsa/rsa_gen.c f22bc4e2c3acab83e67820c906c1caf048ec1f0d4fcb7472c1bec753c75f8e93 crypto/rsa/rsa_lib.c 5ae8edaf654645996385fbd420ef73030762fc146bf41deb5294d6d83e257a16 crypto/rsa/rsa_local.h cf0b75cd54b61b9b9a290ef18d0ddce9fb26a029a54eb3f720d9b25188440f00 crypto/rsa/rsa_mp_names.c @@ -416,7 +416,7 @@ a00e16963e1e2a0126c6a8e62da8a14f98de9736027654c925925dadd0ca3cc1 crypto/thread/ 27ec0090f4243c96e4fbe1babfd4320c2a16615ffa368275433217d50a1ef76c crypto/thread/internal.c 67ba8d87fbbb7c9a9e438018e7ecfd1cedd4d00224be05755580d044f5f1317a crypto/threads_lib.c b1a828491d9ce305802662561788facac92dff70cca9ead807f3e28741ff21e0 crypto/threads_none.c -c659f7ce5c4b59d2a1cff78485fa8e89c8d20d5798df4afc1b94ff635ffc0262 crypto/threads_pthread.c +491e9c29d4a7b4dd627ea25c20ce4a33103565b3108b618c41c6816dfc675569 crypto/threads_pthread.c 9c3bf7b4baa302a4017150fbcaa114ee9df935b18d5a3a8c8015003780d4e7de crypto/threads_win.c 7edd638df588b14711a50c98d458c4fc83f223ed03bc6c39c7c8edf7915b7cfa crypto/time.c 88c5f9f4d2611223d283ebd2ae10ae5ecbb9972d00f747d93fcb74b62641e3f9 crypto/x86_64cpuid.pl @@ -445,7 +445,7 @@ bbe5e52d84e65449a13e42cd2d6adce59b8ed6e73d6950917aa77dc1f3f5dff6 include/crypto 6e7762e7fb63f56d25b24f70209f4dc834c59a87f74467531ec81646f565dbe3 include/crypto/modes.h 920bc48a4dad3712bdcef188c0ce8e8a8304e0ce332b54843bab366fc5eab472 include/crypto/rand.h 71f23915ea74e93971fb0205901031be3abea7ffef2c52e4cc4848515079f68d include/crypto/rand_pool.h -b1df067691f9741ef9c42b2e5f12461bcd87b745514fc5701b9c9402fb10b224 include/crypto/rsa.h +6f16685ffbc97dc2ac1240bfddf4bbac2dd1ad83fff6da91aee6f3f64c6ee8ff include/crypto/rsa.h 32f0149ab1d82fddbdfbbc44e3078b4a4cc6936d35187e0f8d02cc0bc19f2401 include/crypto/security_bits.h 80338f3865b7c74aab343879432a6399507b834e2f55dd0e9ee7a5eeba11242a include/crypto/sha.h dc7808729c3231a08bbe470b3e1b562420030f59f7bc05b14d7b516fa77b4f3a include/crypto/slh_dsa.h @@ -546,7 +546,7 @@ a8a45996fd21411cb7ed610bc202dbd06570cdfa0a2d14f7dfc8bfadc820e636 include/openss cb6bca3913c60a57bac39583eee0f789d49c3d29be3ecde9aecc7f3287117aa5 include/openssl/objects.h d25537af264684dff033dd8ae62b0348f868fcfec4aa51fa8f07bcfa4bd807ad include/openssl/objectserr.h fe6acd42c3e90db31aaafc2236a7d30ebfa53c4c07ea4d8265064c7fcb951970 include/openssl/opensslconf.h -fc914a750d798ac9fc9287e6359cfa1da214b91651deaaaa7e1a46b595cd0425 include/openssl/opensslv.h.in +6c1a8837bbba633db2a8951ff29ccfe09e7d2a24a37ee2af90f2d897c190da9a include/openssl/opensslv.h.in 767d9d7d5051c937a3ce8a268c702902fda93eeaa210a94dfde1f45c23277d20 include/openssl/param_build.h 1c442aaaa4dda7fbf727a451bc676fb4d855ef617c14dc77ff2a5e958ae33c3e include/openssl/params.h 44f178176293c6ce8142890ff9dc2d466364c734e4e811f56bd62010c5403183 include/openssl/pkcs7.h.in @@ -618,8 +618,8 @@ f2581d7b4e105f2bb6d30908f3c2d9959313be08cec6dbeb49030c125a7676d3 providers/fips 669f76f742bcaaf28846b057bfab97da7c162d69da244de71b7c743bf16e430f providers/fips/include/fipscommon.h f111fd7e016af8cc6f96cd8059c28227b328dd466ed137ae0c0bc0c3c3eec3ba providers/fips/self_test.c 5c2c6c2f69e2eb01b88fa35630f27948e00dd2c2fd351735c74f34ccb2005cbe providers/fips/self_test.h -663441de9aba1d1b81ce02b3acded520b88cc460330d4d98adb7450d9664c474 providers/fips/self_test_data.inc -2e568e2b161131240e97bd77a730c2299f961c2f1409ea8466422fc07f9be23f providers/fips/self_test_kats.c +df83c901ad13675fbbb4708b6087feba6099870ad3dd0e8d09cfdb6798419770 providers/fips/self_test_data.inc +6779d5afb3f48d82868b247ffb0a6a572f6e3964738296ad47e7ccafdb263c88 providers/fips/self_test_kats.c dde79dfdedfe0e73006a0cf912fdde1ff109dfbc5ba6ecab319c938bc4275950 providers/implementations/asymciphers/rsa_enc.c c2f1b12c64fc369dfc3b9bc9e76a76de7280e6429adaee55d332eb1971ad1879 providers/implementations/ciphers/cipher_aes.c 6ba7d817081cf0d87ba7bfb38cd9d70e41505480bb8bc796ef896f68d4514ea6 providers/implementations/ciphers/cipher_aes.h @@ -699,7 +699,7 @@ c764555b9dc9b273c280514a5d2d44156f82f3e99155a77c627f2c773209bcd7 providers/impl 24cc3cc8e8681c77b7f96c83293bd66045fd8ad69f756e673ca7f8ca9e82b0af providers/implementations/keymgmt/dsa_kmgmt.c 36a9c1c8658ce7918453827cb58ed52787e590e3f148c5510deeb2c16c25a29d providers/implementations/keymgmt/ec_kmgmt.c 258ae17bb2dd87ed1511a8eb3fe99eed9b77f5c2f757215ff6b3d0e8791fc251 providers/implementations/keymgmt/ec_kmgmt_imexport.inc -9728d696d249b2d224724c9872138a60e1998e5cfa5c49f3f48ad0666f7eed34 providers/implementations/keymgmt/ecx_kmgmt.c +11c27cc3c9f38885c484f25d11987e93f197aa90bef2fc1d6e8f508c2d014d4d providers/implementations/keymgmt/ecx_kmgmt.c daf35a7ab961ef70aefca981d80407935904c5da39dca6692432d6e6bc98759d providers/implementations/keymgmt/kdf_legacy_kmgmt.c d97d7c8d3410b3e560ef2becaea2a47948e22205be5162f964c5e51a7eef08cb providers/implementations/keymgmt/mac_legacy_kmgmt.c a428de71082fd01e5dcfa030a6fc34f6700b86d037b4e22f015c917862a158ce providers/implementations/keymgmt/ml_dsa_kmgmt.c diff --git a/crypto/openssl/providers/fips.checksum b/crypto/openssl/providers/fips.checksum index 7fa4ea19bba3..5d1117361d27 100644 --- a/crypto/openssl/providers/fips.checksum +++ b/crypto/openssl/providers/fips.checksum @@ -1 +1 @@ -8d0c2c2b986f4c98f511c9aa020e98aa984dce5976d8e1966a7721f8b559cda8 providers/fips-sources.checksums +c342f9dc7075a6ecd0e4b3c9db06e180765278a7bbae233ec1a65095a0e524ec providers/fips-sources.checksums diff --git a/crypto/openssl/providers/fips/self_test_data.inc b/crypto/openssl/providers/fips/self_test_data.inc index b6aa433ca93c..6abab0a7a173 100644 --- a/crypto/openssl/providers/fips/self_test_data.inc +++ b/crypto/openssl/providers/fips/self_test_data.inc @@ -1308,6 +1308,18 @@ static const ST_KAT_PARAM rsa_priv_key[] = { ST_KAT_PARAM_END() }; +/*- + * Using OSSL_PKEY_RSA_PAD_MODE_NONE directly in the expansion of the + * ST_KAT_PARAM_UTF8STRING macro below causes a failure on ancient + * HP/UX PA-RISC compilers. + */ +static const char pad_mode_none[] = OSSL_PKEY_RSA_PAD_MODE_NONE; + +static const ST_KAT_PARAM rsa_enc_params[] = { + ST_KAT_PARAM_UTF8STRING(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, pad_mode_none), + ST_KAT_PARAM_END() +}; + static const unsigned char rsa_sig_msg[] = "Hello World!"; static const unsigned char rsa_expected_sig[256] = { @@ -3497,3 +3509,33 @@ static const ST_KAT_ASYM_KEYGEN st_kat_asym_keygen_tests[] = { # endif }; #endif /* !OPENSSL_NO_ML_DSA || !OPENSSL_NO_SLH_DSA */ + +static const ST_KAT_ASYM_CIPHER st_kat_asym_cipher_tests[] = { + { + OSSL_SELF_TEST_DESC_ASYM_RSA_ENC, + "RSA", + 1, + rsa_pub_key, + rsa_enc_params, + ITM(rsa_asym_plaintext_encrypt), + ITM(rsa_asym_expected_encrypt), + }, + { + OSSL_SELF_TEST_DESC_ASYM_RSA_DEC, + "RSA", + 0, + rsa_priv_key, + rsa_enc_params, + ITM(rsa_asym_expected_encrypt), + ITM(rsa_asym_plaintext_encrypt), + }, + { + OSSL_SELF_TEST_DESC_ASYM_RSA_DEC, + "RSA", + 0, + rsa_crt_key, + rsa_enc_params, + ITM(rsa_asym_expected_encrypt), + ITM(rsa_asym_plaintext_encrypt), + }, +}; diff --git a/crypto/openssl/providers/fips/self_test_kats.c b/crypto/openssl/providers/fips/self_test_kats.c index 35ecb43598ee..acb0b85f7343 100644 --- a/crypto/openssl/providers/fips/self_test_kats.c +++ b/crypto/openssl/providers/fips/self_test_kats.c @@ -813,6 +813,93 @@ err: #endif /* + * Test an encrypt or decrypt KAT.. + * + * FIPS 140-2 IG D.9 states that separate KAT tests are needed for encrypt + * and decrypt.. + */ +static int self_test_asym_cipher(const ST_KAT_ASYM_CIPHER *t, OSSL_SELF_TEST *st, + OSSL_LIB_CTX *libctx) +{ + int ret = 0; + OSSL_PARAM *keyparams = NULL, *initparams = NULL; + OSSL_PARAM_BLD *keybld = NULL, *initbld = NULL; + EVP_PKEY_CTX *encctx = NULL, *keyctx = NULL; + EVP_PKEY *key = NULL; + BN_CTX *bnctx = NULL; + unsigned char out[256]; + size_t outlen = sizeof(out); + + OSSL_SELF_TEST_onbegin(st, OSSL_SELF_TEST_TYPE_KAT_ASYM_CIPHER, t->desc); + + bnctx = BN_CTX_new_ex(libctx); + if (bnctx == NULL) + goto err; + + /* Load a public or private key from data */ + keybld = OSSL_PARAM_BLD_new(); + if (keybld == NULL + || !add_params(keybld, t->key, bnctx)) + goto err; + keyparams = OSSL_PARAM_BLD_to_param(keybld); + keyctx = EVP_PKEY_CTX_new_from_name(libctx, t->algorithm, NULL); + if (keyctx == NULL || keyparams == NULL) + goto err; + if (EVP_PKEY_fromdata_init(keyctx) <= 0 + || EVP_PKEY_fromdata(keyctx, &key, EVP_PKEY_KEYPAIR, keyparams) <= 0) + goto err; + + /* Create a EVP_PKEY_CTX to use for the encrypt or decrypt operation */ + encctx = EVP_PKEY_CTX_new_from_pkey(libctx, key, NULL); + if (encctx == NULL + || (t->encrypt && EVP_PKEY_encrypt_init(encctx) <= 0) + || (!t->encrypt && EVP_PKEY_decrypt_init(encctx) <= 0)) + goto err; + + /* Add any additional parameters such as padding */ + if (t->postinit != NULL) { + initbld = OSSL_PARAM_BLD_new(); + if (initbld == NULL) + goto err; + if (!add_params(initbld, t->postinit, bnctx)) + goto err; + initparams = OSSL_PARAM_BLD_to_param(initbld); + if (initparams == NULL) + goto err; + if (EVP_PKEY_CTX_set_params(encctx, initparams) <= 0) + goto err; + } + + if (t->encrypt) { + if (EVP_PKEY_encrypt(encctx, out, &outlen, + t->in, t->in_len) <= 0) + goto err; + } else { + if (EVP_PKEY_decrypt(encctx, out, &outlen, + t->in, t->in_len) <= 0) + goto err; + } + /* Check the KAT */ + OSSL_SELF_TEST_oncorrupt_byte(st, out); + if (outlen != t->expected_len + || memcmp(out, t->expected, t->expected_len) != 0) + goto err; + + ret = 1; +err: + BN_CTX_free(bnctx); + EVP_PKEY_free(key); + EVP_PKEY_CTX_free(encctx); + EVP_PKEY_CTX_free(keyctx); + OSSL_PARAM_free(keyparams); + OSSL_PARAM_BLD_free(keybld); + OSSL_PARAM_free(initparams); + OSSL_PARAM_BLD_free(initbld); + OSSL_SELF_TEST_onend(st, ret); + return ret; +} + +/* * Test a data driven list of KAT's for digest algorithms. * All tests are run regardless of if they fail or not. * Return 0 if any test fails. @@ -853,6 +940,17 @@ static int self_test_kems(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx) return ret; } +static int self_test_asym_ciphers(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx) +{ + int i, ret = 1; + + for (i = 0; i < (int)OSSL_NELEM(st_kat_asym_cipher_tests); ++i) { + if (!self_test_asym_cipher(&st_kat_asym_cipher_tests[i], st, libctx)) + ret = 0; + } + return ret; +} + static int self_test_kdfs(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx) { int i, ret = 1; @@ -1092,6 +1190,8 @@ int SELF_TEST_kats(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx) ret = 0; if (!self_test_kems(st, libctx)) ret = 0; + if (!self_test_asym_ciphers(st, libctx)) + ret = 0; RAND_set0_private(libctx, saved_rand); return ret; diff --git a/crypto/openssl/providers/implementations/kdfs/krb5kdf.c b/crypto/openssl/providers/implementations/kdfs/krb5kdf.c index 566afa74fece..13623ec7302e 100644 --- a/crypto/openssl/providers/implementations/kdfs/krb5kdf.c +++ b/crypto/openssl/providers/implementations/kdfs/krb5kdf.c @@ -1,5 +1,5 @@ /* - * Copyright 2018-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2018-2025 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -350,7 +350,7 @@ static int cipher_init(EVP_CIPHER_CTX *ctx, { int klen, ret; - ret = EVP_EncryptInit_ex(ctx, cipher, engine, key, NULL); + ret = EVP_EncryptInit_ex(ctx, cipher, engine, NULL, NULL); if (!ret) goto out; /* set the key len for the odd variable key len cipher */ @@ -362,6 +362,9 @@ static int cipher_init(EVP_CIPHER_CTX *ctx, goto out; } } + ret = EVP_EncryptInit_ex(ctx, NULL, NULL, key, NULL); + if (!ret) + goto out; /* we never want padding, either the length requested is a multiple of * the cipher block size or we are passed a cipher that can cope with * partial blocks via techniques like cipher text stealing */ diff --git a/crypto/openssl/providers/implementations/keymgmt/ecx_kmgmt.c b/crypto/openssl/providers/implementations/keymgmt/ecx_kmgmt.c index e6d326a90705..0ebe8b4d59b1 100644 --- a/crypto/openssl/providers/implementations/keymgmt/ecx_kmgmt.c +++ b/crypto/openssl/providers/implementations/keymgmt/ecx_kmgmt.c @@ -218,14 +218,6 @@ static int ecx_import(void *keydata, int selection, const OSSL_PARAM params[]) include_private = selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0; ok = ok && ossl_ecx_key_fromdata(key, params, include_private); -#ifdef FIPS_MODULE - if (ok > 0 && ecx_key_type_is_ed(key->type) && !ossl_fips_self_testing()) - if (key->haspubkey && key->privkey != NULL) { - ok = ecd_fips140_pairwise_test(key, key->type, 1); - if (ok <= 0) - ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT_IMPORT); - } -#endif /* FIPS_MODULE */ return ok; } diff --git a/crypto/openssl/ssl/quic/quic_impl.c b/crypto/openssl/ssl/quic/quic_impl.c index c44e6b33c2a8..cec05d5bd37b 100644 --- a/crypto/openssl/ssl/quic/quic_impl.c +++ b/crypto/openssl/ssl/quic/quic_impl.c @@ -3197,6 +3197,7 @@ int ossl_quic_conn_stream_conclude(SSL *s) QCTX ctx; QUIC_STREAM *qs; int err; + int ret; if (!expect_quic_with_stream_lock(s, /*remote_init=*/0, /*io=*/0, &ctx)) return 0; @@ -3204,13 +3205,15 @@ int ossl_quic_conn_stream_conclude(SSL *s) qs = ctx.xso->stream; if (!quic_mutation_allowed(ctx.qc, /*req_active=*/1)) { + ret = QUIC_RAISE_NON_NORMAL_ERROR(&ctx, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL); qctx_unlock(&ctx); - return QUIC_RAISE_NON_NORMAL_ERROR(&ctx, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL); + return ret; } if (!quic_validate_for_write(ctx.xso, &err)) { + ret = QUIC_RAISE_NON_NORMAL_ERROR(&ctx, err, NULL); qctx_unlock(&ctx); - return QUIC_RAISE_NON_NORMAL_ERROR(&ctx, err, NULL); + return ret; } if (ossl_quic_sstream_get_final_size(qs->sstream, NULL)) { diff --git a/crypto/openssl/ssl/record/methods/tls_common.c b/crypto/openssl/ssl/record/methods/tls_common.c index 80d4477bd0c0..b9c79099462d 100644 --- a/crypto/openssl/ssl/record/methods/tls_common.c +++ b/crypto/openssl/ssl/record/methods/tls_common.c @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -1093,9 +1093,12 @@ int tls13_common_post_process_record(OSSL_RECORD_LAYER *rl, TLS_RL_RECORD *rec) return 0; } - if (rl->msg_callback != NULL) - rl->msg_callback(0, rl->version, SSL3_RT_INNER_CONTENT_TYPE, &rec->type, - 1, rl->cbarg); + if (rl->msg_callback != NULL) { + unsigned char ctype = (unsigned char)rec->type; + + rl->msg_callback(0, rl->version, SSL3_RT_INNER_CONTENT_TYPE, &ctype, + 1, rl->cbarg); + } /* * TLSv1.3 alert and handshake records are required to be non-zero in diff --git a/crypto/openssl/ssl/ssl_rsa.c b/crypto/openssl/ssl/ssl_rsa.c index e833bcdbc377..f4731a87af90 100644 --- a/crypto/openssl/ssl/ssl_rsa.c +++ b/crypto/openssl/ssl/ssl_rsa.c @@ -1056,10 +1056,13 @@ static int ssl_set_cert_and_key(SSL *ssl, SSL_CTX *ctx, X509 *x509, EVP_PKEY *pr } } - if (!X509_up_ref(x509)) + if (!X509_up_ref(x509)) { + OSSL_STACK_OF_X509_free(dup_chain); goto out; + } if (!EVP_PKEY_up_ref(privatekey)) { + OSSL_STACK_OF_X509_free(dup_chain); X509_free(x509); goto out; } diff --git a/crypto/openssl/ssl/t1_trce.c b/crypto/openssl/ssl/t1_trce.c index 35c60feb4371..73fd4ebaa4b0 100644 --- a/crypto/openssl/ssl/t1_trce.c +++ b/crypto/openssl/ssl/t1_trce.c @@ -549,8 +549,12 @@ static const ssl_trace_tbl ssl_groups_tbl[] = { {258, "ffdhe4096"}, {259, "ffdhe6144"}, {260, "ffdhe8192"}, + {512, "MLKEM512"}, + {513, "MLKEM768"}, + {514, "MLKEM1024"}, {4587, "SecP256r1MLKEM768"}, {4588, "X25519MLKEM768"}, + {4589, "SecP384r1MLKEM1024"}, {25497, "X25519Kyber768Draft00"}, {25498, "SecP256r1Kyber768Draft00"}, {0xFF01, "arbitrary_explicit_prime_curves"}, diff --git a/crypto/openssl/test/build.info b/crypto/openssl/test/build.info index 9d9be6b642e9..3dca6117796b 100644 --- a/crypto/openssl/test/build.info +++ b/crypto/openssl/test/build.info @@ -31,7 +31,8 @@ IF[{- !$disabled{tests} -}] testutil/format_output.c testutil/load.c testutil/fake_random.c \ testutil/test_cleanup.c testutil/main.c testutil/testutil_init.c \ testutil/options.c testutil/test_options.c testutil/provider.c \ - testutil/apps_shims.c testutil/random.c testutil/helper.c $LIBAPPSSRC + testutil/apps_shims.c testutil/random.c testutil/helper.c \ + testutil/compare.c $LIBAPPSSRC INCLUDE[libtestutil.a]=../include ../apps/include .. DEPEND[libtestutil.a]=../libcrypto diff --git a/crypto/openssl/test/fake_rsaprov.c b/crypto/openssl/test/fake_rsaprov.c index 46fc9104ef95..6ed121554336 100644 --- a/crypto/openssl/test/fake_rsaprov.c +++ b/crypto/openssl/test/fake_rsaprov.c @@ -35,6 +35,8 @@ static int exptypes_selection; static int query_id; static int key_deleted; +unsigned fake_rsa_query_operation_name = 0; + typedef struct { OSSL_LIB_CTX *libctx; } PROV_FAKE_RSA_CTX; @@ -90,7 +92,7 @@ static const char *fake_rsa_keymgmt_query(int id) /* record global for checking */ query_id = id; - return "RSA"; + return fake_rsa_query_operation_name ? NULL: "RSA"; } static int fake_rsa_keymgmt_import(void *keydata, int selection, diff --git a/crypto/openssl/test/fake_rsaprov.h b/crypto/openssl/test/fake_rsaprov.h index cb2e66eb68ef..00e7dccb4872 100644 --- a/crypto/openssl/test/fake_rsaprov.h +++ b/crypto/openssl/test/fake_rsaprov.h @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2021-2025 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -14,5 +14,14 @@ /* Fake RSA provider implementation */ OSSL_PROVIDER *fake_rsa_start(OSSL_LIB_CTX *libctx); void fake_rsa_finish(OSSL_PROVIDER *p); + OSSL_PARAM *fake_rsa_key_params(int priv); void fake_rsa_restore_store_state(void); + +/* + * When fake_rsa_query_operation_name is set to a non-zero value, + * query_operation_name() will return NULL. + * + * By default, it is 0, in which case query_operation_name() will return "RSA". + */ +extern unsigned fake_rsa_query_operation_name; diff --git a/crypto/openssl/test/ml_kem_evp_extra_test.c b/crypto/openssl/test/ml_kem_evp_extra_test.c index bfa52c9af2e6..b867b14ad1d4 100644 --- a/crypto/openssl/test/ml_kem_evp_extra_test.c +++ b/crypto/openssl/test/ml_kem_evp_extra_test.c @@ -140,9 +140,19 @@ static int test_ml_kem(void) if (!TEST_int_gt(EVP_PKEY_copy_parameters(bkey, akey), 0)) goto err; + /* Bob's empty key is not equal to Alice's */ + if (!TEST_false(EVP_PKEY_eq(akey, bkey)) + || !TEST_false(EVP_PKEY_eq(bkey, akey))) + goto err; + if (!TEST_true(EVP_PKEY_set1_encoded_public_key(bkey, rawpub, publen))) goto err; + /* Bob's copy of Alice's public key makes the two equal */ + if (!TEST_true(EVP_PKEY_eq(akey, bkey)) + || !TEST_true(EVP_PKEY_eq(bkey, akey))) + goto err; + /* Encapsulate Bob's key */ ctx = EVP_PKEY_CTX_new_from_pkey(testctx, bkey, NULL); if (!TEST_ptr(ctx)) diff --git a/crypto/openssl/test/property_test.c b/crypto/openssl/test/property_test.c index 18f8cc8740e0..e62ff247c42c 100644 --- a/crypto/openssl/test/property_test.c +++ b/crypto/openssl/test/property_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved. * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use @@ -687,6 +687,22 @@ static int test_property_list_to_string(int i) return ret; } +static int test_property_list_to_string_bounds(void) +{ + OSSL_PROPERTY_LIST *pl = NULL; + char buf[16]; + int ret = 0; + + if (!TEST_ptr(pl = ossl_parse_query(NULL, "provider='$1'", 1))) + goto err; + if (!TEST_size_t_eq(ossl_property_list_to_string(NULL, pl, buf, 10), 14)) + goto err; + ret = 1; + err: + ossl_property_free(pl); + return ret; +} + int setup_tests(void) { ADD_TEST(test_property_string); @@ -701,5 +717,6 @@ int setup_tests(void) ADD_TEST(test_query_cache_stochastic); ADD_TEST(test_fips_mode); ADD_ALL_TESTS(test_property_list_to_string, OSSL_NELEM(to_string_tests)); + ADD_TEST(test_property_list_to_string_bounds); return 1; } diff --git a/crypto/openssl/test/provider_pkey_test.c b/crypto/openssl/test/provider_pkey_test.c index cb656a62a650..9ffe3581d62a 100644 --- a/crypto/openssl/test/provider_pkey_test.c +++ b/crypto/openssl/test/provider_pkey_test.c @@ -239,6 +239,77 @@ end: return ret; } +static int test_pkey_can_sign(void) +{ + OSSL_PROVIDER *fake_rsa = NULL; + EVP_PKEY *pkey_fake = NULL; + EVP_PKEY_CTX *ctx = NULL; + OSSL_PARAM *params = NULL; + int ret = 0; + + if (!TEST_ptr(fake_rsa = fake_rsa_start(libctx))) + return 0; + + /* + * Ensure other tests did not forget to reset fake_rsa_query_operation_name + * to its default value: 0 + */ + if (!TEST_int_eq(fake_rsa_query_operation_name, 0)) + goto end; + + if (!TEST_ptr(params = fake_rsa_key_params(0)) + || !TEST_ptr(ctx = EVP_PKEY_CTX_new_from_name(libctx, "RSA", + "provider=fake-rsa")) + || !TEST_true(EVP_PKEY_fromdata_init(ctx)) + || !TEST_true(EVP_PKEY_fromdata(ctx, &pkey_fake, EVP_PKEY_PUBLIC_KEY, + params)) + || !TEST_true(EVP_PKEY_can_sign(pkey_fake)) + || !TEST_ptr(pkey_fake)) + goto end; + + EVP_PKEY_CTX_free(ctx); + ctx = NULL; + EVP_PKEY_free(pkey_fake); + pkey_fake = NULL; + OSSL_PARAM_free(params); + params = NULL; + + /* + * Documented behavior for OSSL_FUNC_keymgmt_query_operation_name() + * allows it to return NULL, in which case the fallback should be to use + * EVP_KEYMGMT_get0_name(). That is exactly the thing we are testing here. + */ + fake_rsa_query_operation_name = 1; + + if (!TEST_ptr(params = fake_rsa_key_params(0)) + || !TEST_ptr(ctx = EVP_PKEY_CTX_new_from_name(libctx, "RSA", + "provider=fake-rsa")) + || !TEST_true(EVP_PKEY_fromdata_init(ctx)) + || !TEST_true(EVP_PKEY_fromdata(ctx, &pkey_fake, EVP_PKEY_PUBLIC_KEY, + params)) + || !TEST_true(EVP_PKEY_can_sign(pkey_fake)) + || !TEST_ptr(pkey_fake)) + goto end; + + EVP_PKEY_CTX_free(ctx); + ctx = NULL; + EVP_PKEY_free(pkey_fake); + pkey_fake = NULL; + OSSL_PARAM_free(params); + params = NULL; + + ret = 1; +end: + + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(pkey_fake); + OSSL_PARAM_free(params); + fake_rsa_query_operation_name = 0; + + fake_rsa_finish(fake_rsa); + return ret; +} + static int test_pkey_store(int idx) { OSSL_PROVIDER *deflt = NULL; @@ -719,6 +790,7 @@ int setup_tests(void) ADD_TEST(test_pkey_sig); ADD_TEST(test_alternative_keygen_init); ADD_TEST(test_pkey_eq); + ADD_TEST(test_pkey_can_sign); ADD_ALL_TESTS(test_pkey_store, 2); ADD_TEST(test_pkey_delete); ADD_TEST(test_pkey_store_open_ex); diff --git a/crypto/openssl/test/quicapitest.c b/crypto/openssl/test/quicapitest.c index f665c511bb72..4e887c13d14c 100644 --- a/crypto/openssl/test/quicapitest.c +++ b/crypto/openssl/test/quicapitest.c @@ -428,91 +428,6 @@ static int test_version(void) } #if defined(DO_SSL_TRACE_TEST) -static void strip_line_ends(char *str) -{ - size_t i; - - for (i = strlen(str); - i > 0 && (str[i - 1] == '\n' || str[i - 1] == '\r'); - i--); - - str[i] = '\0'; -} - -static int compare_with_file(BIO *membio) -{ - BIO *file = NULL, *newfile = NULL; - char buf1[8192], buf2[8192]; - char *reffile; - int ret = 0; - size_t i; - -#ifdef OPENSSL_NO_ZLIB - reffile = test_mk_file_path(datadir, "ssltraceref.txt"); -#else - reffile = test_mk_file_path(datadir, "ssltraceref-zlib.txt"); -#endif - if (!TEST_ptr(reffile)) - goto err; - - file = BIO_new_file(reffile, "rb"); - if (!TEST_ptr(file)) - goto err; - - newfile = BIO_new_file("ssltraceref-new.txt", "wb"); - if (!TEST_ptr(newfile)) - goto err; - - while (BIO_gets(membio, buf2, sizeof(buf2)) > 0) - if (BIO_puts(newfile, buf2) <= 0) { - TEST_error("Failed writing new file data"); - goto err; - } - - if (!TEST_int_ge(BIO_seek(membio, 0), 0)) - goto err; - - while (BIO_gets(file, buf1, sizeof(buf1)) > 0) { - size_t line_len; - - if (BIO_gets(membio, buf2, sizeof(buf2)) <= 0) { - TEST_error("Failed reading mem data"); - goto err; - } - strip_line_ends(buf1); - strip_line_ends(buf2); - line_len = strlen(buf1); - if (line_len > 0 && buf1[line_len - 1] == '?') { - /* Wildcard at the EOL means ignore anything after it */ - if (strlen(buf2) > line_len) - buf2[line_len] = '\0'; - } - if (line_len != strlen(buf2)) { - TEST_error("Actual and ref line data length mismatch"); - TEST_info("%s", buf1); - TEST_info("%s", buf2); - goto err; - } - for (i = 0; i < line_len; i++) { - /* '?' is a wild card character in the reference text */ - if (buf1[i] == '?') - buf2[i] = '?'; - } - if (!TEST_str_eq(buf1, buf2)) - goto err; - } - if (!TEST_true(BIO_eof(file)) - || !TEST_true(BIO_eof(membio))) - goto err; - - ret = 1; - err: - OPENSSL_free(reffile); - BIO_free(file); - BIO_free(newfile); - return ret; -} - /* * Tests that the SSL_trace() msg_callback works as expected with a QUIC * connection. This also provides testing of the msg_callback at the same time. @@ -524,6 +439,7 @@ static int test_ssl_trace(void) QUIC_TSERVER *qtserv = NULL; int testresult = 0; BIO *bio = NULL; + char *reffile = NULL; if (!TEST_ptr(cctx = SSL_CTX_new_ex(libctx, NULL, OSSL_QUIC_client_method())) || !TEST_ptr(bio = BIO_new(BIO_s_mem())) @@ -547,7 +463,13 @@ static int test_ssl_trace(void) if (!TEST_int_gt(BIO_pending(bio), 0)) goto err; } else { - if (!TEST_true(compare_with_file(bio))) + +# ifdef OPENSSL_NO_ZLIB + reffile = test_mk_file_path(datadir, "ssltraceref.txt"); +# else + reffile = test_mk_file_path(datadir, "ssltraceref-zlib.txt"); +# endif + if (!TEST_true(compare_with_reference_file(bio, reffile))) goto err; } @@ -557,6 +479,7 @@ static int test_ssl_trace(void) SSL_free(clientquic); SSL_CTX_free(cctx); BIO_free(bio); + OPENSSL_free(reffile); return testresult; } diff --git a/crypto/openssl/test/radix/terp.c b/crypto/openssl/test/radix/terp.c index 3c83fd9b18b0..41d3bdeb9fd4 100644 --- a/crypto/openssl/test/radix/terp.c +++ b/crypto/openssl/test/radix/terp.c @@ -871,8 +871,10 @@ err: } GEN_SCRIPT_cleanup(&gen_script); - BIO_printf(debug_bio, "Stats:\n Ops executed: %16llu\n\n", - (unsigned long long)terp.ops_executed); + if (have_terp) { + BIO_printf(debug_bio, "Stats:\n Ops executed: %16llu\n\n", + (unsigned long long)terp.ops_executed); + } SCRIPT_INFO_print(script_info, debug_bio, /*error=*/!ok, ok ? "completed" : "failed, exiting"); return ok; diff --git a/crypto/openssl/test/recipes/03-test_fipsinstall.t b/crypto/openssl/test/recipes/03-test_fipsinstall.t index 1f9110ef600a..3dcbe67c6d55 100644 --- a/crypto/openssl/test/recipes/03-test_fipsinstall.t +++ b/crypto/openssl/test/recipes/03-test_fipsinstall.t @@ -63,7 +63,7 @@ my @commandline = ( 'x942kdf_key_check', 'x942kdf-key-check' ) ); -plan tests => 40 + (scalar @pedantic_okay) + (scalar @pedantic_fail) +plan tests => 41 + (scalar @pedantic_okay) + (scalar @pedantic_fail) + 4 * (scalar @commandline); my $infile = bldtop_file('providers', platform->dso('fips')); @@ -392,6 +392,16 @@ SKIP: { "fipsinstall fails when the ML-KEM decapsulate implicit failure result is corrupted"); } +# corrupt an Asymmetric cipher test +SKIP: { + skip "Skipping Asymmetric RSA corruption test because of no rsa in this build", 1 + if disabled("rsa") || disabled("fips-post"); + ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips.cnf', '-module', $infile, + '-corrupt_desc', 'RSA_Encrypt', + '-corrupt_type', 'KAT_AsymmetricCipher'])), + "fipsinstall fails when the asymmetric cipher result is corrupted"); +} + # 'local' ensures that this change is only done in this file. local $ENV{OPENSSL_CONF_INCLUDE} = abs2rel(curdir()); diff --git a/crypto/openssl/test/recipes/25-test_verify.t b/crypto/openssl/test/recipes/25-test_verify.t index 271f499690bf..673c3d5f1772 100644 --- a/crypto/openssl/test/recipes/25-test_verify.t +++ b/crypto/openssl/test/recipes/25-test_verify.t @@ -602,9 +602,10 @@ ok(vfy_root("-CAfile", $rootcert), "CAfile"); ok(vfy_root("-CAstore", $rootcert), "CAstore"); ok(vfy_root("-CAstore", $rootcert, "-CAfile", $rootcert), "CAfile and existing CAstore"); ok(!vfy_root("-CAstore", "non-existing", "-CAfile", $rootcert), "CAfile and non-existing CAstore"); + SKIP: { - skip "file names with colons aren't supported on Windows and VMS", 2 - if $^O =~ /^(MsWin32|VMS)$/; + skip "file names with colons aren't supported on Windows and VMS", 1 + if $^O =~ /^(MSWin32|VMS)$/; my $foo_file = "foo:cert.pem"; copy($rootcert, $foo_file); ok(vfy_root("-CAstore", $foo_file), "CAstore foo:file"); diff --git a/crypto/openssl/test/recipes/30-test_evp_data/evpkdf_krb5.txt b/crypto/openssl/test/recipes/30-test_evp_data/evpkdf_krb5.txt index d8f6aa72a175..e2de4754fa74 100644 --- a/crypto/openssl/test/recipes/30-test_evp_data/evpkdf_krb5.txt +++ b/crypto/openssl/test/recipes/30-test_evp_data/evpkdf_krb5.txt @@ -1,5 +1,5 @@ # -# Copyright 2001-2020 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2001-2025 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -129,3 +129,11 @@ Ctrl.cipher = cipher:DES-EDE3-CBC Ctrl.hexkey = hexkey:dce06b1f64c857a11c3db57c51899b2cc1791008ce973b92 Ctrl.hexconstant = hexconstant:0000000155 Output = 935079d14490a75c3093c4a6e8c3b049c71e6ee705 + +#Erroneous key size for the cipher as XTS has double key size +KDF = KRB5KDF +Ctrl.cipher = cipher:AES-256-XTS +Ctrl.hexkey = hexkey:FE697B52BC0D3CE14432BA036A92E65BBB52280990A2FA27883998D72AF30161 +Ctrl.hexconstant = hexconstant:0000000255 +Output = 97151B4C76945063E2EB0529DC067D97D7BBA90776D8126D91F34F3101AEA8BA +Result = KDF_DERIVE_ERROR diff --git a/crypto/openssl/test/recipes/30-test_evp_data/evppkey_rsa_sigalg.txt b/crypto/openssl/test/recipes/30-test_evp_data/evppkey_rsa_sigalg.txt index 5083cc2bde24..f258700670ab 100644 --- a/crypto/openssl/test/recipes/30-test_evp_data/evppkey_rsa_sigalg.txt +++ b/crypto/openssl/test/recipes/30-test_evp_data/evppkey_rsa_sigalg.txt @@ -1,5 +1,5 @@ # -# Copyright 2001-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2001-2025 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -186,4 +186,4 @@ Output = 6a7fc08e9999fc9d50cda476e973a01a06efeb52eece1c78cb1422950476cbff67408c6 Availablein = default Sign-Message = RSA-SM3:RSA-2048 Input = "Hello World" -Output = 92657e22036214c343d8e95d129c0c47430d5a1ae452371a7847a963f533f96e018aa6658958e6a584cf0d380aa9435175cf2de3dfa60100aca893b76aa6d8f0cc9154ee982cb5ea8f19153fe8a9c801aa2da8bb4451c7ec6fd836e81ecdacf022b68294db068efa47decf3a7c548ea7088a16433029b8733b9573053b7e7122ea10b662726fc97bd149c663617434a9707b672b024f95865d91077edfb79c8ed4c8528032204c46c984a6c82b17794cbf9c4dfe4c1af1d59535f7755540ff36d6a2b55accbf046896c4aae9287a33f38c2a269a02abdac46c17b1b55ee89cc9eb3011a84916596f982c5375dd2110633be6dc43532919466d83bd0f3e406978 +Output = b74e03c18050807541bde949aa0ac91d43fb9730f0b529d5100d5776f4f446d0ca0f0992359dc5f89386ed45bc3bf52cac1f75fbcc088fc2ea77624fd962569d2d317e90886dec424fb6757c4eba1e881ddf4f7942e8003b54e05cc974558dea171ce23a2fc158f71a5621c9a2c3ce45c9af4c706d3f60efe0c0f087a6ec504f771b08e2a1d78e0316c74706c678869bf121d5da00e2e8c8dc1cd273315b4ad8ab9962c62f81cebc5fb393b7f8860ee68545578413feada82b1c2bbfabfa157e298f0354bffc1cc6aa68f058a5d34b6b70ffacd3532c6b2c6a0de059bf605edf392ac8adbf1769555a0a50b2b13c63cae98a461498fae7f0d1729b710f05f39e diff --git a/crypto/openssl/test/recipes/90-test_sslapi.t b/crypto/openssl/test/recipes/90-test_sslapi.t index 650e0d1ffb16..70c2c24d8661 100644 --- a/crypto/openssl/test/recipes/90-test_sslapi.t +++ b/crypto/openssl/test/recipes/90-test_sslapi.t @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2016-2024 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -45,7 +45,10 @@ ok(run(test(["sslapitest", srctop_dir("test", "certs"), srctop_file("test", "recipes", "90-test_sslapi_data", - "dhparams.pem")])), + "dhparams.pem"), + srctop_dir("test", + "recipes", + "90-test_sslapi_data")])), "running sslapitest"); SKIP: { @@ -62,7 +65,10 @@ SKIP: { srctop_file("test", "recipes", "90-test_sslapi_data", - "dhparams.pem")])), + "dhparams.pem"), + srctop_dir("test", + "recipes", + "90-test_sslapi_data")])), "running sslapitest with default fips config"); run(test(["fips_version_test", "-config", $provconf, ">=3.1.0"]), @@ -140,7 +146,10 @@ SKIP: { srctop_file("test", "recipes", "90-test_sslapi_data", - "dhparams.pem")])), + "dhparams.pem"), + srctop_dir("test", + "recipes", + "90-test_sslapi_data")])), "running sslapitest with modified fips config"); } diff --git a/crypto/openssl/test/recipes/90-test_sslapi_data/ssltraceref-zlib.txt b/crypto/openssl/test/recipes/90-test_sslapi_data/ssltraceref-zlib.txt new file mode 100644 index 000000000000..05aed8299b0e --- /dev/null +++ b/crypto/openssl/test/recipes/90-test_sslapi_data/ssltraceref-zlib.txt @@ -0,0 +1,255 @@ +Sent TLS Record +Header: + Version = TLS 1.0 (0x301) + Content Type = Handshake (22) + Length = ? + ClientHello, Length=? + client_version=0x303 (TLS 1.2) + Random: + gmt_unix_time=0x? + random_bytes (len=28): ? + session_id (len=? + cipher_suites (len=2) + {0x13, 0x01} TLS_AES_128_GCM_SHA256 + compression_methods (len=1) + No Compression (0x00) + extensions, length = ? + extension_type=ec_point_formats(11), length=4 + uncompressed (0) + ansiX962_compressed_prime (1) + ansiX962_compressed_char2 (2) + extension_type=supported_groups(10), length=20 + MLKEM512 (512) + MLKEM768 (513) + MLKEM1024 (514) + X25519MLKEM768 (4588) + SecP256r1MLKEM768 (4587) + SecP384r1MLKEM1024 (4589) + secp521r1 (P-521) (25) + secp384r1 (P-384) (24) + secp256r1 (P-256) (23) + extension_type=session_ticket(35), length=0 + extension_type=encrypt_then_mac(22), length=0 + extension_type=extended_master_secret(23), length=0 + extension_type=signature_algorithms(13), length=? + mldsa65 (0x0905) + mldsa87 (0x0906) + mldsa44 (0x0904) + ecdsa_secp256r1_sha256 (0x0403) + ecdsa_secp384r1_sha384 (0x0503) + ecdsa_secp521r1_sha512 (0x0603) + ed25519 (0x0807) + ed448 (0x0808) + ecdsa_brainpoolP256r1tls13_sha256 (0x081a) + ecdsa_brainpoolP384r1tls13_sha384 (0x081b) + ecdsa_brainpoolP512r1tls13_sha512 (0x081c) + rsa_pss_pss_sha256 (0x0809) + rsa_pss_pss_sha384 (0x080a) + rsa_pss_pss_sha512 (0x080b) + rsa_pss_rsae_sha256 (0x0804) + rsa_pss_rsae_sha384 (0x0805) + rsa_pss_rsae_sha512 (0x0806) + rsa_pkcs1_sha256 (0x0401) + rsa_pkcs1_sha384 (0x0501) + rsa_pkcs1_sha512 (0x0601) + extension_type=supported_versions(43), length=3 + TLS 1.3 (772) + extension_type=psk_key_exchange_modes(45), length=2 + psk_dhe_ke (1) + extension_type=key_share(51), length=806 + NamedGroup: MLKEM512 (512) + key_exchange: (len=800): ? + extension_type=compress_certificate(27), length=3 + zlib (1) + +Received TLS Record +Header: + Version = TLS 1.2 (0x303) + Content Type = Handshake (22) + Length = 858 + ServerHello, Length=854 + server_version=0x303 (TLS 1.2) + Random: + gmt_unix_time=0x? + random_bytes (len=28): ? + session_id (len=? + cipher_suite {0x13, 0x01} TLS_AES_128_GCM_SHA256 + compression_method: No Compression (0x00) + extensions, length = ? + extension_type=supported_versions(43), length=2 + TLS 1.3 (772) + extension_type=key_share(51), length=772 + NamedGroup: MLKEM512 (512) + key_exchange: (len=768): ? + +Received TLS Record +Header: + Version = TLS 1.2 (0x303) + Content Type = ChangeCipherSpec (20) + Length = 1 + change_cipher_spec (1) + +Received TLS Record +Header: + Version = TLS 1.2 (0x303) + Content Type = ApplicationData (23) + Length = 23 + Inner Content Type = Handshake (22) + EncryptedExtensions, Length=2 + No extensions + +Received TLS Record +Header: + Version = TLS 1.2 (0x303) + Content Type = ApplicationData (23) + Length = 839 + Inner Content Type = Handshake (22) + Certificate, Length=818 + context (len=0): + certificate_list, length=814 + ASN.1Cert, length=809 +------details----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2 (0x2) + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN = Root CA + Validity + Not Before: Jan 14 22:29:46 2016 GMT + Not After : Jan 15 22:29:46 2116 GMT + Subject: CN = server.example + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:d5:5d:60:6a:df:fc:61:ee:48:aa:8c:11:48:43: + a5:6d:b6:52:5d:aa:98:49:b1:61:92:35:b1:fc:3a: + 04:25:0c:6d:79:ff:b4:d5:c9:e9:5c:1c:3b:e0:ab: + b3:b8:7d:a3:de:6d:bd:e0:dd:d7:5a:bf:14:47:11: + 42:5e:a6:82:d0:61:c1:7f:dd:13:46:e6:09:85:07: + 0e:f2:d4:fc:1a:64:d2:0a:ad:20:ab:20:6b:96:f0: + ad:cc:c4:19:53:55:dc:01:1d:a4:b3:ef:8a:b4:49: + 53:5d:8a:05:1c:f1:dc:e1:44:bf:c5:d7:e2:77:19: + 57:5c:97:0b:75:ee:88:43:71:0f:ca:6c:c1:b4:b2: + 50:a7:77:46:6c:58:0f:11:bf:f1:76:24:5a:ae:39: + 42:b7:51:67:29:e1:d0:55:30:6f:17:e4:91:ea:ad: + f8:28:c2:43:6f:a2:64:a9:fb:9d:98:92:62:48:3e: + eb:0d:4f:82:4a:8a:ff:3f:72:ee:96:b5:ae:a1:c1: + 98:ba:ef:7d:90:75:6d:ff:5a:52:9e:ab:f5:c0:7e: + d0:87:43:db:85:07:07:0f:7d:38:7a:fd:d1:d3:ee: + 65:1d:d3:ea:39:6a:87:37:ee:4a:d3:e0:0d:6e:f5: + 70:ac:c2:bd:f1:6e:f3:92:95:5e:a9:f0:a1:65:95: + 93:8d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + C0:E7:84:BF:E8:59:27:33:10:B0:52:4F:51:52:2F:06:D6:C0:7A:CD + X509v3 Authority Key Identifier: + 70:7F:2E:AE:83:68:59:98:04:23:2A:CD:EB:3E:17:CD:24:DD:01:49 + X509v3 Basic Constraints: + CA:FALSE + X509v3 Extended Key Usage: + TLS Web Server Authentication + X509v3 Subject Alternative Name: + DNS:server.example + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 7b:d3:04:43:75:8a:0f:11:ae:c4:fb:d7:a1:a2:9e:fe:20:18: + d5:f4:2f:31:88:46:b6:75:8c:ee:e5:9b:97:a6:b9:a3:cd:60: + 9a:46:c3:48:97:e5:97:68:f7:5a:86:35:73:d9:69:9e:f9:5f: + 74:b9:e6:94:13:01:cb:6a:dc:e3:c4:04:e9:65:da:9c:a4:8b: + 28:f3:f9:9a:7f:bf:97:1f:45:92:e5:05:b1:56:e6:0b:f6:47: + de:1e:89:b6:2b:e1:4d:df:4a:7e:01:d3:23:dc:97:8c:47:fe: + 5f:c7:cc:98:46:0e:c4:83:5b:ca:8a:f1:52:09:be:6b:ec:3f: + 09:8b:d0:93:02:bf:e1:51:e7:d1:7e:34:56:19:74:d0:ff:28: + 25:de:b7:9f:56:52:91:7d:20:29:85:0a:80:44:5f:71:32:25: + 71:0f:c2:16:e2:5f:6b:1d:3f:32:5b:0a:3c:74:1c:b9:62:f1: + ed:07:50:a3:6d:b4:b4:31:0a:c0:53:44:6a:3a:88:84:8b:2d: + a9:b0:37:8e:e6:18:36:bd:9a:20:40:0f:01:92:8b:3d:aa:61: + e7:ae:2c:ed:36:cd:3a:07:86:74:3a:29:b3:d7:3a:b4:00:a9: + c2:f5:92:78:0e:e2:0f:a3:fe:bb:be:e0:06:53:84:59:1d:90: + 69:e5:b6:f9 +-----BEGIN CERTIFICATE----- +MIIDJTCCAg2gAwIBAgIBAjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290 +IENBMCAXDTE2MDExNDIyMjk0NloYDzIxMTYwMTE1MjIyOTQ2WjAZMRcwFQYDVQQD +DA5zZXJ2ZXIuZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANVdYGrf/GHuSKqMEUhDpW22Ul2qmEmxYZI1sfw6BCUMbXn/tNXJ6VwcO+Crs7h9 +o95tveDd11q/FEcRQl6mgtBhwX/dE0bmCYUHDvLU/Bpk0gqtIKsga5bwrczEGVNV +3AEdpLPvirRJU12KBRzx3OFEv8XX4ncZV1yXC3XuiENxD8pswbSyUKd3RmxYDxG/ +8XYkWq45QrdRZynh0FUwbxfkkeqt+CjCQ2+iZKn7nZiSYkg+6w1PgkqK/z9y7pa1 +rqHBmLrvfZB1bf9aUp6r9cB+0IdD24UHBw99OHr90dPuZR3T6jlqhzfuStPgDW71 +cKzCvfFu85KVXqnwoWWVk40CAwEAAaN9MHswHQYDVR0OBBYEFMDnhL/oWSczELBS +T1FSLwbWwHrNMB8GA1UdIwQYMBaAFHB/Lq6DaFmYBCMqzes+F80k3QFJMAkGA1Ud +EwQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwGQYDVR0RBBIwEIIOc2VydmVyLmV4 +YW1wbGUwDQYJKoZIhvcNAQELBQADggEBAHvTBEN1ig8RrsT716Ginv4gGNX0LzGI +RrZ1jO7lm5emuaPNYJpGw0iX5Zdo91qGNXPZaZ75X3S55pQTActq3OPEBOll2pyk +iyjz+Zp/v5cfRZLlBbFW5gv2R94eibYr4U3fSn4B0yPcl4xH/l/HzJhGDsSDW8qK +8VIJvmvsPwmL0JMCv+FR59F+NFYZdND/KCXet59WUpF9ICmFCoBEX3EyJXEPwhbi +X2sdPzJbCjx0HLli8e0HUKNttLQxCsBTRGo6iISLLamwN47mGDa9miBADwGSiz2q +YeeuLO02zToHhnQ6KbPXOrQAqcL1kngO4g+j/ru+4AZThFkdkGnltvk= +-----END CERTIFICATE----- +------------------ + No extensions + +Received TLS Record +Header: + Version = TLS 1.2 (0x303) + Content Type = ApplicationData (23) + Length = 281 + Inner Content Type = Handshake (22) + CertificateVerify, Length=260 + Signature Algorithm: rsa_pss_rsae_sha256 (0x0804) + Signature (len=256): ? + +Received TLS Record +Header: + Version = TLS 1.2 (0x303) + Content Type = ApplicationData (23) + Length = 53 + Inner Content Type = Handshake (22) + Finished, Length=32 + verify_data (len=32): ? + +Sent TLS Record +Header: + Version = TLS 1.2 (0x303) + Content Type = ChangeCipherSpec (20) + Length = 1 + change_cipher_spec (1) + +Sent TLS Record +Header: + Version = TLS 1.2 (0x303) + Content Type = ApplicationData (23) + Length = 53 + Inner Content Type = Handshake (22) + Finished, Length=32 + verify_data (len=32): ? + +Received TLS Record +Header: + Version = TLS 1.2 (0x303) + Content Type = ApplicationData (23) + Length = 234 + Inner Content Type = Handshake (22) + NewSessionTicket, Length=213 + ticket_lifetime_hint=7200 + ticket_age_add=? + ticket_nonce (len=8): ? + ticket (len=192): ? + No extensions + +Received TLS Record +Header: + Version = TLS 1.2 (0x303) + Content Type = ApplicationData (23) + Length = 234 + Inner Content Type = Handshake (22) + NewSessionTicket, Length=213 + ticket_lifetime_hint=7200 + ticket_age_add=? + ticket_nonce (len=8): ? + ticket (len=192): ? + No extensions + diff --git a/crypto/openssl/test/recipes/90-test_sslapi_data/ssltraceref.txt b/crypto/openssl/test/recipes/90-test_sslapi_data/ssltraceref.txt new file mode 100644 index 000000000000..5d332da235fb --- /dev/null +++ b/crypto/openssl/test/recipes/90-test_sslapi_data/ssltraceref.txt @@ -0,0 +1,253 @@ +Sent TLS Record +Header: + Version = TLS 1.0 (0x301) + Content Type = Handshake (22) + Length = ? + ClientHello, Length=? + client_version=0x303 (TLS 1.2) + Random: + gmt_unix_time=0x? + random_bytes (len=28): ? + session_id (len=? + cipher_suites (len=2) + {0x13, 0x01} TLS_AES_128_GCM_SHA256 + compression_methods (len=1) + No Compression (0x00) + extensions, length = ? + extension_type=ec_point_formats(11), length=4 + uncompressed (0) + ansiX962_compressed_prime (1) + ansiX962_compressed_char2 (2) + extension_type=supported_groups(10), length=20 + MLKEM512 (512) + MLKEM768 (513) + MLKEM1024 (514) + X25519MLKEM768 (4588) + SecP256r1MLKEM768 (4587) + SecP384r1MLKEM1024 (4589) + secp521r1 (P-521) (25) + secp384r1 (P-384) (24) + secp256r1 (P-256) (23) + extension_type=session_ticket(35), length=0 + extension_type=encrypt_then_mac(22), length=0 + extension_type=extended_master_secret(23), length=0 + extension_type=signature_algorithms(13), length=? + mldsa65 (0x0905) + mldsa87 (0x0906) + mldsa44 (0x0904) + ecdsa_secp256r1_sha256 (0x0403) + ecdsa_secp384r1_sha384 (0x0503) + ecdsa_secp521r1_sha512 (0x0603) + ed25519 (0x0807) + ed448 (0x0808) + ecdsa_brainpoolP256r1tls13_sha256 (0x081a) + ecdsa_brainpoolP384r1tls13_sha384 (0x081b) + ecdsa_brainpoolP512r1tls13_sha512 (0x081c) + rsa_pss_pss_sha256 (0x0809) + rsa_pss_pss_sha384 (0x080a) + rsa_pss_pss_sha512 (0x080b) + rsa_pss_rsae_sha256 (0x0804) + rsa_pss_rsae_sha384 (0x0805) + rsa_pss_rsae_sha512 (0x0806) + rsa_pkcs1_sha256 (0x0401) + rsa_pkcs1_sha384 (0x0501) + rsa_pkcs1_sha512 (0x0601) + extension_type=supported_versions(43), length=3 + TLS 1.3 (772) + extension_type=psk_key_exchange_modes(45), length=2 + psk_dhe_ke (1) + extension_type=key_share(51), length=806 + NamedGroup: MLKEM512 (512) + key_exchange: (len=800): ? + +Received TLS Record +Header: + Version = TLS 1.2 (0x303) + Content Type = Handshake (22) + Length = 858 + ServerHello, Length=854 + server_version=0x303 (TLS 1.2) + Random: + gmt_unix_time=0x? + random_bytes (len=28): ? + session_id (len=? + cipher_suite {0x13, 0x01} TLS_AES_128_GCM_SHA256 + compression_method: No Compression (0x00) + extensions, length = ? + extension_type=supported_versions(43), length=2 + TLS 1.3 (772) + extension_type=key_share(51), length=772 + NamedGroup: MLKEM512 (512) + key_exchange: (len=768): ? + +Received TLS Record +Header: + Version = TLS 1.2 (0x303) + Content Type = ChangeCipherSpec (20) + Length = 1 + change_cipher_spec (1) + +Received TLS Record +Header: + Version = TLS 1.2 (0x303) + Content Type = ApplicationData (23) + Length = 23 + Inner Content Type = Handshake (22) + EncryptedExtensions, Length=2 + No extensions + +Received TLS Record +Header: + Version = TLS 1.2 (0x303) + Content Type = ApplicationData (23) + Length = 839 + Inner Content Type = Handshake (22) + Certificate, Length=818 + context (len=0): + certificate_list, length=814 + ASN.1Cert, length=809 +------details----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2 (0x2) + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN = Root CA + Validity + Not Before: Jan 14 22:29:46 2016 GMT + Not After : Jan 15 22:29:46 2116 GMT + Subject: CN = server.example + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:d5:5d:60:6a:df:fc:61:ee:48:aa:8c:11:48:43: + a5:6d:b6:52:5d:aa:98:49:b1:61:92:35:b1:fc:3a: + 04:25:0c:6d:79:ff:b4:d5:c9:e9:5c:1c:3b:e0:ab: + b3:b8:7d:a3:de:6d:bd:e0:dd:d7:5a:bf:14:47:11: + 42:5e:a6:82:d0:61:c1:7f:dd:13:46:e6:09:85:07: + 0e:f2:d4:fc:1a:64:d2:0a:ad:20:ab:20:6b:96:f0: + ad:cc:c4:19:53:55:dc:01:1d:a4:b3:ef:8a:b4:49: + 53:5d:8a:05:1c:f1:dc:e1:44:bf:c5:d7:e2:77:19: + 57:5c:97:0b:75:ee:88:43:71:0f:ca:6c:c1:b4:b2: + 50:a7:77:46:6c:58:0f:11:bf:f1:76:24:5a:ae:39: + 42:b7:51:67:29:e1:d0:55:30:6f:17:e4:91:ea:ad: + f8:28:c2:43:6f:a2:64:a9:fb:9d:98:92:62:48:3e: + eb:0d:4f:82:4a:8a:ff:3f:72:ee:96:b5:ae:a1:c1: + 98:ba:ef:7d:90:75:6d:ff:5a:52:9e:ab:f5:c0:7e: + d0:87:43:db:85:07:07:0f:7d:38:7a:fd:d1:d3:ee: + 65:1d:d3:ea:39:6a:87:37:ee:4a:d3:e0:0d:6e:f5: + 70:ac:c2:bd:f1:6e:f3:92:95:5e:a9:f0:a1:65:95: + 93:8d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + C0:E7:84:BF:E8:59:27:33:10:B0:52:4F:51:52:2F:06:D6:C0:7A:CD + X509v3 Authority Key Identifier: + 70:7F:2E:AE:83:68:59:98:04:23:2A:CD:EB:3E:17:CD:24:DD:01:49 + X509v3 Basic Constraints: + CA:FALSE + X509v3 Extended Key Usage: + TLS Web Server Authentication + X509v3 Subject Alternative Name: + DNS:server.example + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 7b:d3:04:43:75:8a:0f:11:ae:c4:fb:d7:a1:a2:9e:fe:20:18: + d5:f4:2f:31:88:46:b6:75:8c:ee:e5:9b:97:a6:b9:a3:cd:60: + 9a:46:c3:48:97:e5:97:68:f7:5a:86:35:73:d9:69:9e:f9:5f: + 74:b9:e6:94:13:01:cb:6a:dc:e3:c4:04:e9:65:da:9c:a4:8b: + 28:f3:f9:9a:7f:bf:97:1f:45:92:e5:05:b1:56:e6:0b:f6:47: + de:1e:89:b6:2b:e1:4d:df:4a:7e:01:d3:23:dc:97:8c:47:fe: + 5f:c7:cc:98:46:0e:c4:83:5b:ca:8a:f1:52:09:be:6b:ec:3f: + 09:8b:d0:93:02:bf:e1:51:e7:d1:7e:34:56:19:74:d0:ff:28: + 25:de:b7:9f:56:52:91:7d:20:29:85:0a:80:44:5f:71:32:25: + 71:0f:c2:16:e2:5f:6b:1d:3f:32:5b:0a:3c:74:1c:b9:62:f1: + ed:07:50:a3:6d:b4:b4:31:0a:c0:53:44:6a:3a:88:84:8b:2d: + a9:b0:37:8e:e6:18:36:bd:9a:20:40:0f:01:92:8b:3d:aa:61: + e7:ae:2c:ed:36:cd:3a:07:86:74:3a:29:b3:d7:3a:b4:00:a9: + c2:f5:92:78:0e:e2:0f:a3:fe:bb:be:e0:06:53:84:59:1d:90: + 69:e5:b6:f9 +-----BEGIN CERTIFICATE----- +MIIDJTCCAg2gAwIBAgIBAjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290 +IENBMCAXDTE2MDExNDIyMjk0NloYDzIxMTYwMTE1MjIyOTQ2WjAZMRcwFQYDVQQD +DA5zZXJ2ZXIuZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANVdYGrf/GHuSKqMEUhDpW22Ul2qmEmxYZI1sfw6BCUMbXn/tNXJ6VwcO+Crs7h9 +o95tveDd11q/FEcRQl6mgtBhwX/dE0bmCYUHDvLU/Bpk0gqtIKsga5bwrczEGVNV +3AEdpLPvirRJU12KBRzx3OFEv8XX4ncZV1yXC3XuiENxD8pswbSyUKd3RmxYDxG/ +8XYkWq45QrdRZynh0FUwbxfkkeqt+CjCQ2+iZKn7nZiSYkg+6w1PgkqK/z9y7pa1 +rqHBmLrvfZB1bf9aUp6r9cB+0IdD24UHBw99OHr90dPuZR3T6jlqhzfuStPgDW71 +cKzCvfFu85KVXqnwoWWVk40CAwEAAaN9MHswHQYDVR0OBBYEFMDnhL/oWSczELBS +T1FSLwbWwHrNMB8GA1UdIwQYMBaAFHB/Lq6DaFmYBCMqzes+F80k3QFJMAkGA1Ud +EwQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwGQYDVR0RBBIwEIIOc2VydmVyLmV4 +YW1wbGUwDQYJKoZIhvcNAQELBQADggEBAHvTBEN1ig8RrsT716Ginv4gGNX0LzGI +RrZ1jO7lm5emuaPNYJpGw0iX5Zdo91qGNXPZaZ75X3S55pQTActq3OPEBOll2pyk +iyjz+Zp/v5cfRZLlBbFW5gv2R94eibYr4U3fSn4B0yPcl4xH/l/HzJhGDsSDW8qK +8VIJvmvsPwmL0JMCv+FR59F+NFYZdND/KCXet59WUpF9ICmFCoBEX3EyJXEPwhbi +X2sdPzJbCjx0HLli8e0HUKNttLQxCsBTRGo6iISLLamwN47mGDa9miBADwGSiz2q +YeeuLO02zToHhnQ6KbPXOrQAqcL1kngO4g+j/ru+4AZThFkdkGnltvk= +-----END CERTIFICATE----- +------------------ + No extensions + +Received TLS Record +Header: + Version = TLS 1.2 (0x303) + Content Type = ApplicationData (23) + Length = 281 + Inner Content Type = Handshake (22) + CertificateVerify, Length=260 + Signature Algorithm: rsa_pss_rsae_sha256 (0x0804) + Signature (len=256): ? + +Received TLS Record +Header: + Version = TLS 1.2 (0x303) + Content Type = ApplicationData (23) + Length = 53 + Inner Content Type = Handshake (22) + Finished, Length=32 + verify_data (len=32): ? + +Sent TLS Record +Header: + Version = TLS 1.2 (0x303) + Content Type = ChangeCipherSpec (20) + Length = 1 + change_cipher_spec (1) + +Sent TLS Record +Header: + Version = TLS 1.2 (0x303) + Content Type = ApplicationData (23) + Length = 53 + Inner Content Type = Handshake (22) + Finished, Length=32 + verify_data (len=32): ? + +Received TLS Record +Header: + Version = TLS 1.2 (0x303) + Content Type = ApplicationData (23) + Length = 234 + Inner Content Type = Handshake (22) + NewSessionTicket, Length=213 + ticket_lifetime_hint=7200 + ticket_age_add=? + ticket_nonce (len=8): ? + ticket (len=192): ? + No extensions + +Received TLS Record +Header: + Version = TLS 1.2 (0x303) + Content Type = ApplicationData (23) + Length = 234 + Inner Content Type = Handshake (22) + NewSessionTicket, Length=213 + ticket_lifetime_hint=7200 + ticket_age_add=? + ticket_nonce (len=8): ? + ticket (len=192): ? + No extensions + diff --git a/crypto/openssl/test/sslapitest.c b/crypto/openssl/test/sslapitest.c index b83dd6c552de..fbe284b9ff1e 100644 --- a/crypto/openssl/test/sslapitest.c +++ b/crypto/openssl/test/sslapitest.c @@ -98,6 +98,7 @@ static char *privkey8192 = NULL; static char *srpvfile = NULL; static char *tmpfilename = NULL; static char *dhfile = NULL; +static char *datadir = NULL; static int is_fips = 0; static int fips_ems_check = 0; @@ -120,6 +121,15 @@ static X509 *ocspcert = NULL; #define CLIENT_VERSION_LEN 2 +/* The ssltrace test assumes some options are switched on/off */ +#if !defined(OPENSSL_NO_SSL_TRACE) \ + && defined(OPENSSL_NO_BROTLI) && defined(OPENSSL_NO_ZSTD) \ + && !defined(OPENSSL_NO_ECX) && !defined(OPENSSL_NO_DH) \ + && !defined(OPENSSL_NO_ML_DSA) && !defined(OPENSSL_NO_ML_KEM) \ + && !defined(OPENSSL_NO_TLS1_3) +# define DO_SSL_TRACE_TEST +#endif + /* * This structure is used to validate that the correct number of log messages * of various types are emitted when emitting secret logs. @@ -13269,6 +13279,77 @@ static int test_no_renegotiation(int idx) return testresult; } +#if defined(DO_SSL_TRACE_TEST) +/* + * Tests that the SSL_trace() msg_callback works as expected with a PQ Groups. + */ +static int test_ssl_trace(void) +{ + SSL_CTX *sctx = NULL, *cctx = NULL; + SSL *serverssl = NULL, *clientssl = NULL; + int testresult = 0; + BIO *bio = NULL; + char *reffile = NULL; + char *grouplist = "MLKEM512:MLKEM768:MLKEM1024:X25519MLKEM768:SecP256r1MLKEM768" + ":SecP384r1MLKEM1024:secp521r1:secp384r1:secp256r1"; + + if (!fips_provider_version_ge(libctx, 3, 5, 0)) + return TEST_skip("FIPS provider does not support MLKEM algorithms"); + + if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), + TLS_client_method(), + TLS1_3_VERSION, TLS1_3_VERSION, + &sctx, &cctx, cert, privkey)) + || !TEST_ptr(bio = BIO_new(BIO_s_mem())) + || !TEST_true(SSL_CTX_set1_groups_list(sctx, grouplist)) + || !TEST_true(SSL_CTX_set1_groups_list(cctx, grouplist)) + || !TEST_true(SSL_CTX_set_ciphersuites(cctx, + "TLS_AES_128_GCM_SHA256")) + || !TEST_true(SSL_CTX_set_ciphersuites(sctx, + "TLS_AES_128_GCM_SHA256")) +# ifdef SSL_OP_LEGACY_EC_POINT_FORMATS + || !TEST_true(SSL_CTX_set_options(cctx, SSL_OP_LEGACY_EC_POINT_FORMATS)) + || !TEST_true(SSL_CTX_set_options(sctx, SSL_OP_LEGACY_EC_POINT_FORMATS)) +# endif + || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, + NULL, NULL))) + goto err; + + SSL_set_msg_callback(clientssl, SSL_trace); + SSL_set_msg_callback_arg(clientssl, bio); + + if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) + goto err; + + /* Skip the comparison of the trace when the fips provider is used. */ + if (is_fips) { + /* Check whether there was something written. */ + if (!TEST_int_gt(BIO_pending(bio), 0)) + goto err; + } else { + +# ifdef OPENSSL_NO_ZLIB + reffile = test_mk_file_path(datadir, "ssltraceref.txt"); +# else + reffile = test_mk_file_path(datadir, "ssltraceref-zlib.txt"); +# endif + if (!TEST_true(compare_with_reference_file(bio, reffile))) + goto err; + } + + testresult = 1; + err: + BIO_free(bio); + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + OPENSSL_free(reffile); + + return testresult; +} +#endif + OPT_TEST_DECLARE_USAGE("certfile privkeyfile srpvfile tmpfile provider config dhfile\n") int setup_tests(void) @@ -13303,6 +13384,8 @@ int setup_tests(void) || !TEST_ptr(dhfile = test_get_argument(5))) return 0; + datadir = test_get_argument(6); + if (!TEST_true(OSSL_LIB_CTX_load_config(libctx, configfile))) return 0; @@ -13598,6 +13681,10 @@ int setup_tests(void) ADD_TEST(test_quic_tls_early_data); #endif ADD_ALL_TESTS(test_no_renegotiation, 2); +#if defined(DO_SSL_TRACE_TEST) + if (datadir != NULL) + ADD_TEST(test_ssl_trace); +#endif return 1; err: diff --git a/crypto/openssl/test/testutil.h b/crypto/openssl/test/testutil.h index f02dcdfba6f9..a262d9371955 100644 --- a/crypto/openssl/test/testutil.h +++ b/crypto/openssl/test/testutil.h @@ -652,4 +652,6 @@ X509 *load_cert_der(const unsigned char *bytes, int len); STACK_OF(X509) *load_certs_pem(const char *file); X509_REQ *load_csr_der(const char *file, OSSL_LIB_CTX *libctx); time_t test_asn1_string_to_time_t(const char *asn1_string); + +int compare_with_reference_file(BIO *membio, const char *reffile); #endif /* OSSL_TESTUTIL_H */ diff --git a/crypto/openssl/test/testutil/compare.c b/crypto/openssl/test/testutil/compare.c new file mode 100644 index 000000000000..067fb878b58e --- /dev/null +++ b/crypto/openssl/test/testutil/compare.c @@ -0,0 +1,88 @@ +/* + * Copyright 2017-2025 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "../testutil.h" + +static void strip_line_ends(char *str) +{ + size_t i; + + for (i = strlen(str); + i > 0 && (str[i - 1] == '\n' || str[i - 1] == '\r'); + i--); + + str[i] = '\0'; +} + +int compare_with_reference_file(BIO *membio, const char *reffile) +{ + BIO *file = NULL, *newfile = NULL; + char buf1[8192], buf2[8192]; + int ret = 0; + size_t i; + + if (!TEST_ptr(reffile)) + goto err; + + file = BIO_new_file(reffile, "rb"); + if (!TEST_ptr(file)) + goto err; + + newfile = BIO_new_file("ssltraceref-new.txt", "wb"); + if (!TEST_ptr(newfile)) + goto err; + + while (BIO_gets(membio, buf2, sizeof(buf2)) > 0) + if (BIO_puts(newfile, buf2) <= 0) { + TEST_error("Failed writing new file data"); + goto err; + } + + if (!TEST_int_ge(BIO_seek(membio, 0), 0)) + goto err; + + while (BIO_gets(file, buf1, sizeof(buf1)) > 0) { + size_t line_len; + + if (BIO_gets(membio, buf2, sizeof(buf2)) <= 0) { + TEST_error("Failed reading mem data"); + goto err; + } + strip_line_ends(buf1); + strip_line_ends(buf2); + line_len = strlen(buf1); + if (line_len > 0 && buf1[line_len - 1] == '?') { + /* Wildcard at the EOL means ignore anything after it */ + if (strlen(buf2) > line_len) + buf2[line_len] = '\0'; + } + if (line_len != strlen(buf2)) { + TEST_error("Actual and ref line data length mismatch"); + TEST_info("%s", buf1); + TEST_info("%s", buf2); + goto err; + } + for (i = 0; i < line_len; i++) { + /* '?' is a wild card character in the reference text */ + if (buf1[i] == '?') + buf2[i] = '?'; + } + if (!TEST_str_eq(buf1, buf2)) + goto err; + } + if (!TEST_true(BIO_eof(file)) + || !TEST_true(BIO_eof(membio))) + goto err; + + ret = 1; + err: + BIO_free(file); + BIO_free(newfile); + return ret; +} diff --git a/crypto/openssl/test/threadstest.c b/crypto/openssl/test/threadstest.c index 38401911d87f..d33ad46999c6 100644 --- a/crypto/openssl/test/threadstest.c +++ b/crypto/openssl/test/threadstest.c @@ -183,13 +183,16 @@ static void rwreader_fn(int *iterations) CRYPTO_atomic_add(&rwwriter2_done, 0, &lw2, atomiclock); count++; - if (rwwriter_ptr != NULL && old > *rwwriter_ptr) { - TEST_info("rwwriter pointer went backwards\n"); - rw_torture_result = 0; + if (rwwriter_ptr != NULL) { + if (old > *rwwriter_ptr) { + TEST_info("rwwriter pointer went backwards! %d : %d\n", + old, *rwwriter_ptr); + rw_torture_result = 0; + } + old = *rwwriter_ptr; } if (CRYPTO_THREAD_unlock(rwtorturelock) == 0) abort(); - *iterations = count; if (rw_torture_result == 0) { *iterations = count; return; diff --git a/crypto/openssl/test/wpackettest.c b/crypto/openssl/test/wpackettest.c index bd696e007407..c6d6faf5c485 100644 --- a/crypto/openssl/test/wpackettest.c +++ b/crypto/openssl/test/wpackettest.c @@ -588,7 +588,7 @@ static int test_WPACKET_quic_vlint_random(void) for (i = 0; i < 10000; ++i) { if (!TEST_int_gt(RAND_bytes(rand_data, sizeof(rand_data)), 0)) - return cleanup(&pkt); + return 0; memcpy(&expected, rand_data, sizeof(expected)); diff --git a/include/resolv.h b/include/resolv.h index f32f52bab431..6ef79601b5f8 100644 --- a/include/resolv.h +++ b/include/resolv.h @@ -188,7 +188,7 @@ struct __res_state { struct __res_state_ext *ext; /*%< extension for IPv6 */ } _ext; } _u; - u_char *_rnd; /*%< PRIVATE: random state */ + u_char *_rnd; /*%< PRIVATE: random state (unused) */ }; typedef struct __res_state *res_state; @@ -380,7 +380,6 @@ extern const struct res_sym __p_rcode_syms[]; #define res_nisourserver __res_nisourserver #define res_ownok __res_ownok #define res_queriesmatch __res_queriesmatch -#define res_rndinit __res_rndinit #define res_randomid __res_randomid #define res_nrandomid __res_nrandomid #define sym_ntop __sym_ntop @@ -445,7 +444,6 @@ int dn_count_labels(const char *); int dn_comp(const char *, u_char *, int, u_char **, u_char **); int dn_expand(const u_char *, const u_char *, const u_char *, char *, int); -void res_rndinit(res_state); u_int res_randomid(void); u_int res_nrandomid(res_state); int res_nameinquery(const char *, int, int, const u_char *, diff --git a/kerberos5/lib/libhdb/Makefile b/kerberos5/lib/libhdb/Makefile index bcc3f75206bc..14fa242bc9e5 100644 --- a/kerberos5/lib/libhdb/Makefile +++ b/kerberos5/lib/libhdb/Makefile @@ -1,7 +1,9 @@ +PACKAGE= kerberos-lib + LIB= hdb LDFLAGS+= -Wl,--no-undefined ${LDAPLDFLAGS} VERSION_MAP= ${KRB5DIR}/lib/hdb/version-script.map -LIBADD= asn1 com_err krb5 roken sqlite3 +LIBADD= asn1 com_err krb5 roken sqlite3 heimbase LDADD= ${LDAPLDADD} DPADD= ${LDAPDPADD} @@ -74,6 +76,7 @@ GEN= asn1_Salt.x \ asn1_HDB_Ext_Lan_Manager_OWF.x \ asn1_HDB_Ext_Password.x \ asn1_HDB_Ext_Aliases.x \ + asn1_HDB_Ext_KeySet.x \ asn1_HDB_extension.x \ asn1_HDB_extensions.x \ asn1_hdb_entry.x \ diff --git a/lib/libc/Makefile b/lib/libc/Makefile index d0c254e33396..8705568f6d34 100644 --- a/lib/libc/Makefile +++ b/lib/libc/Makefile @@ -109,7 +109,6 @@ NOASM= .include "${LIBC_SRCTOP}/inet/Makefile.inc" .include "${LIBC_SRCTOP}/isc/Makefile.inc" .include "${LIBC_SRCTOP}/locale/Makefile.inc" -.include "${LIBC_SRCTOP}/md/Makefile.inc" .include "${LIBC_SRCTOP}/nameser/Makefile.inc" .include "${LIBC_SRCTOP}/net/Makefile.inc" .include "${LIBC_SRCTOP}/nls/Makefile.inc" diff --git a/lib/libc/gen/fts.3 b/lib/libc/gen/fts.3 index ee558b892c8c..b937607b48e0 100644 --- a/lib/libc/gen/fts.3 +++ b/lib/libc/gen/fts.3 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd June 30, 2025 +.Dd October 1, 2025 .Dt FTS 3 .Os .Sh NAME @@ -376,7 +376,44 @@ The .Fa fts_name field is always .Dv NUL Ns -terminated . -.Sh FTS_OPEN +.Ss Thread Safety +The +.Nm +functions can safely be used in multi-threaded programs provided no +two threads access the same +.Vt FTS +or +.Vt FTSENT +structure simultaneously. +However, unless the +.Dv FTS_NOCHDIR +flag was passed to +.Fn fts_open +or +.Fn fts_open_b , +calls to +.Fn fts_read +and +.Fn fts_children +may change the current working directory, which will affect all +threads. +Conversely, changing the current working directory either during or +between calls to +.Fn fts_read +or +.Fn fts_children +(even in a single-thread program) may cause +.Nm +to malfunction unless the +.Dv FTS_NOCHDIR +flag was passed to +.Fn fts_open +or +.Fn fts_open_b +and all paths in +.Va path_argv +were absolute. +.Ss Fn fts_open The .Fn fts_open function takes a pointer to an array of character pointers naming one @@ -545,7 +582,7 @@ the directory traversal order is in the order listed in .Fa path_argv for the root paths, and in the order listed in the directory for everything else. -.Sh FTS_OPEN_B +.Ss Fn fts_open_b The .Fn fts_open_b function is identical to @@ -554,7 +591,7 @@ except that it takes a block pointer instead of a function pointer. The block is copied before .Fn fts_open_b returns, so the original can safely go out of scope or be released. -.Sh FTS_READ +.Ss Fn fts_read The .Fn fts_read function returns a pointer to an @@ -605,7 +642,7 @@ after the structure has been returned by the function .Fn fts_read in post-order. -.Sh FTS_CHILDREN +.Ss Fn fts_children The .Fn fts_children function returns a pointer to an @@ -679,7 +716,7 @@ and .Fa fts_namelen fields. .El -.Sh FTS_SET +.Ss Fn fts_set The function .Fn fts_set allows the user application to determine further processing for the @@ -749,7 +786,7 @@ The file may be one of those most recently returned by either or .Fn fts_read . .El -.Sh FTS_CLOSE +.Ss Fn fts_close The .Fn fts_close function closes a file hierarchy stream diff --git a/lib/libc/include/port_before.h b/lib/libc/include/port_before.h index cfc43c53f157..aa2cd394104a 100644 --- a/lib/libc/include/port_before.h +++ b/lib/libc/include/port_before.h @@ -5,7 +5,6 @@ #define _LIBC 1 #define DO_PTHREADS 1 #define USE_POLL 1 -#define HAVE_MD5 1 #define ISC_SOCKLEN_T socklen_t #define ISC_FORMAT_PRINTF(fmt, args) \ diff --git a/lib/libc/md/Makefile.inc b/lib/libc/md/Makefile.inc deleted file mode 100644 index 82c5f0670485..000000000000 --- a/lib/libc/md/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ -.PATH: ${SRCTOP}/sys/kern - -SRCS+= md5c.c diff --git a/lib/libc/nls/Makefile.inc b/lib/libc/nls/Makefile.inc index f26e04c187a5..c211026aba72 100644 --- a/lib/libc/nls/Makefile.inc +++ b/lib/libc/nls/Makefile.inc @@ -12,6 +12,11 @@ MAN+= catclose.3 catgets.3 catopen.3 # for translators. NLSNAME= libc +# We don't want libc's NLS catalogues to be installed in the clibs package. +# Put them in locales instead, since anyone interested in NLS will have +# that installed. +NLSPACKAGE= locales + NLS+= be_BY.UTF-8 NLS+= ca_ES.ISO8859-1 NLS+= de_DE.ISO8859-1 diff --git a/lib/libc/resolv/Symbol.map b/lib/libc/resolv/Symbol.map index 6b9c43298fb5..26daecbe2eff 100644 --- a/lib/libc/resolv/Symbol.map +++ b/lib/libc/resolv/Symbol.map @@ -103,6 +103,5 @@ FBSD_1.0 { }; FBSD_1.4 { - __res_rndinit; __res_nrandomid; }; diff --git a/lib/libc/resolv/res_init.c b/lib/libc/resolv/res_init.c index 71ab2dcb7038..5a2fce013c8c 100644 --- a/lib/libc/resolv/res_init.c +++ b/lib/libc/resolv/res_init.c @@ -86,19 +86,6 @@ #include <unistd.h> #include <netdb.h> -#ifndef HAVE_MD5 -# include "../dst/md5.h" -#else -# ifdef SOLARIS2 -# include <sys/md5.h> -# elif _LIBC -# include <md5.h> -# endif -#endif -#ifndef _MD5_H_ -# define _MD5_H_ 1 /*%< make sure we do not include rsaref md5.h file */ -#endif - #include "un-namespace.h" #include "port_after.h" @@ -184,8 +171,6 @@ __res_vinit(res_state statp, int preinit) { statp->options = RES_DEFAULT; } - statp->_rnd = malloc(16); - res_rndinit(statp); statp->id = res_nrandomid(statp); memset(u, 0, sizeof(u)); @@ -733,48 +718,18 @@ net_mask(struct in_addr in) /*!< XXX - should really use system's version of th } #endif -static u_char srnd[16]; - void -res_rndinit(res_state statp) +freebsd15_res_rndinit(res_state statp) { - struct timeval now; - u_int32_t u32; - u_int16_t u16; - u_char *rnd = statp->_rnd == NULL ? srnd : statp->_rnd; - - gettimeofday(&now, NULL); - u32 = now.tv_sec; - memcpy(rnd, &u32, 4); - u32 = now.tv_usec; - memcpy(rnd + 4, &u32, 4); - u32 += now.tv_sec; - memcpy(rnd + 8, &u32, 4); - u16 = getpid(); - memcpy(rnd + 12, &u16, 2); + (void)statp; } +__sym_compat(__res_rndinit, freebsd15_res_rndinit, FBSD_1.4); u_int res_nrandomid(res_state statp) { - struct timeval now; - u_int16_t u16; - MD5_CTX ctx; - u_char *rnd = statp->_rnd == NULL ? srnd : statp->_rnd; - - gettimeofday(&now, NULL); - u16 = (u_int16_t) (now.tv_sec ^ now.tv_usec); - memcpy(rnd + 14, &u16, 2); -#ifndef HAVE_MD5 - MD5_Init(&ctx); - MD5_Update(&ctx, rnd, 16); - MD5_Final(rnd, &ctx); -#else - MD5Init(&ctx); - MD5Update(&ctx, rnd, 16); - MD5Final(rnd, &ctx); -#endif - memcpy(&u16, rnd + 14, 2); - return ((u_int) u16); + (void) statp; + + return ((u_int)(arc4random() & 0xffff)); } /*% @@ -808,10 +763,6 @@ res_ndestroy(res_state statp) { free(statp->_u._ext.ext); statp->_u._ext.ext = NULL; } - if (statp->_rnd != NULL) { - free(statp->_rnd); - statp->_rnd = NULL; - } statp->options &= ~RES_INIT; } diff --git a/libexec/flua/Makefile b/libexec/flua/Makefile index 0d1841f8c3bd..23de404710d0 100644 --- a/libexec/flua/Makefile +++ b/libexec/flua/Makefile @@ -16,11 +16,11 @@ FLUA_MODULES+= libjail .endif FLUA_MODULES+= libucl FLUA_MODULES+= liblyaml -FLUA_MODULES+= lposix .ifdef BOOTSTRAPPING -FLUA_MODULES+= libfreebsd/sys/linker -FLUA_MODULES+= libfreebsd/kenv +# libfreebsd is generally omitted from the bootstrap flua because its +# functionality largely assumes a FreeBSD kernel/system headers, so it doesn't +# really offer functionality that we can use in bootstrap. CFLAGS+= -I${.CURDIR} -DBOOTSTRAPPING SHAREDIR= ${WORLDTMP}/legacy/usr/share/flua @@ -54,6 +54,7 @@ SRCS+= lua.c # FreeBSD Extensions .PATH: ${.CURDIR}/modules SRCS+= linit_flua.c +SRCS+= lposix.c CFLAGS+= -I${SRCTOP}/lib/liblua -I${.CURDIR}/modules -I${LUASRC} CFLAGS+= -DLUA_PROGNAME="\"${PROG}\"" diff --git a/libexec/flua/bootstrap.h b/libexec/flua/bootstrap.h index 74356d8677b3..caf00518c1e0 100644 --- a/libexec/flua/bootstrap.h +++ b/libexec/flua/bootstrap.h @@ -12,10 +12,12 @@ #include <lauxlib.h> -SET_DECLARE(flua_module_set, const luaL_Reg); +#define FLUA_MODULE_SETNAME flua_modules + +SET_DECLARE(FLUA_MODULE_SETNAME, const luaL_Reg); #define FLUA_MODULE_DEF(ident, modname, openfn) \ static const luaL_Reg ident = { modname, openfn }; \ - DATA_SET(flua_module_set, ident) + DATA_SET(FLUA_MODULE_SETNAME, ident) #define FLUA_MODULE_NAMED(mod, name) \ FLUA_MODULE_DEF(module_ ## mod, name, luaopen_ ## mod) diff --git a/libexec/flua/linit_flua.c b/libexec/flua/linit_flua.c index 161f030923d3..65356c938671 100644 --- a/libexec/flua/linit_flua.c +++ b/libexec/flua/linit_flua.c @@ -33,6 +33,7 @@ #include "lualib.h" #include "lauxlib.h" +#include "lposix.h" #include "bootstrap.h" @@ -54,6 +55,8 @@ static const luaL_Reg loadedlibs[] = { #if defined(LUA_COMPAT_BITLIB) {LUA_BITLIBNAME, luaopen_bit32}, #endif + /* FreeBSD Extensions */ + {"posix", luaopen_posix}, {NULL, NULL} }; @@ -72,7 +75,7 @@ static void __attribute__((constructor)) flua_init_env(void) { static void flua_setup_mods (lua_State *L) { const luaL_Reg **flib; - SET_FOREACH(flib, flua_module_set) { + SET_FOREACH(flib, FLUA_MODULE_SETNAME) { luaL_requiref(L, (*flib)->name, (*flib)->func, 1); lua_pop(L, 1); /* remove lib */ } diff --git a/libexec/flua/lposix/Makefile b/libexec/flua/lposix/Makefile deleted file mode 100644 index 92321d51be9a..000000000000 --- a/libexec/flua/lposix/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -SHLIB_NAME= posix.so -WARNS?= 3 - -.include "Makefile.inc" -.include <bsd.lib.mk> diff --git a/libexec/flua/lposix/Makefile.inc b/libexec/flua/lposix/Makefile.inc deleted file mode 100644 index 499e6779e84d..000000000000 --- a/libexec/flua/lposix/Makefile.inc +++ /dev/null @@ -1,2 +0,0 @@ -.PATH: ${.PARSEDIR} -SRCS+= lposix.c diff --git a/libexec/flua/lposix/lposix.c b/libexec/flua/modules/lposix.c index 430bb6f28baf..75cdd345aeaa 100644 --- a/libexec/flua/lposix/lposix.c +++ b/libexec/flua/modules/lposix.c @@ -21,8 +21,6 @@ #include "lauxlib.h" #include "lposix.h" -#include "bootstrap.h" - static void enforce_max_args(lua_State *L, int max) { @@ -699,6 +697,3 @@ luaopen_posix(lua_State *L) return (1); } - -/* Only this one needed in our bootstrap set, it will load the others. */ -FLUA_MODULE(posix); diff --git a/libexec/flua/lposix/lposix.h b/libexec/flua/modules/lposix.h index 1aa33f042571..1aa33f042571 100644 --- a/libexec/flua/lposix/lposix.h +++ b/libexec/flua/modules/lposix.h diff --git a/libexec/nuageinit/nuageinit b/libexec/nuageinit/nuageinit index 29340a3d91ea..f29fa8ba1bac 100755 --- a/libexec/nuageinit/nuageinit +++ b/libexec/nuageinit/nuageinit @@ -6,6 +6,7 @@ -- Copyright(c) 2025 Jesús Daniel Colmenares Oviedo <dtxdf@FreeBSD.org> local nuage = require("nuage") +local lfs = require("lfs") local ucl = require("ucl") local yaml = require("lyaml") diff --git a/libexec/rc/rc.conf b/libexec/rc/rc.conf index 2589e2614c35..c776a815003c 100644 --- a/libexec/rc/rc.conf +++ b/libexec/rc/rc.conf @@ -501,7 +501,8 @@ netwait_timeout="60" # Total number of seconds to perform pings. #netwait_if="" # Wait for active link on each intf in this list. netwait_if_timeout="30" # Total number of seconds to monitor link state. netwait_dad="NO" # Wait for DAD to complete -netwait_dad_timeout="10" # Total number of seconds to wait for DAD. +netwait_dad_timeout="" # Total number of seconds to wait for DAD, zero + # or unset to autodetect ### Miscellaneous network options: ### icmp_bmcastecho="NO" # respond to broadcast ping packets diff --git a/libexec/rc/rc.d/netwait b/libexec/rc/rc.d/netwait index b609440a2e4e..05874552cf1c 100755 --- a/libexec/rc/rc.d/netwait +++ b/libexec/rc/rc.d/netwait @@ -36,13 +36,15 @@ netwait_start() err 1 "Nothing to wait for" fi - if ! [ "${netwait_if_timeout}" -ge 1 ]; then + if ! [ "${netwait_if_timeout:=0}" -ge 1 ]; then err 1 "netwait_if_timeout must be >= 1" fi - if ! [ "${netwait_dad_timeout}" -ge 1 ]; then - err 1 "netwait_dad_timeout must be >= 1" + if ! check_kern_features inet6; then + netwait_dad="NO" + elif ! [ "${netwait_dad_timeout:=0}" -ge 1 ]; then + netwait_dad_timeout=$(($(sysctl -n net.inet6.ip6.dad_count)+1)) fi - if ! [ "${netwait_timeout}" -ge 1 ]; then + if ! [ "${netwait_timeout:=0}" -ge 1 ]; then err 1 "netwait_timeout must be >= 1" fi diff --git a/release/Makefile b/release/Makefile index 76a99ffdf3f3..12f5114f8b22 100644 --- a/release/Makefile +++ b/release/Makefile @@ -116,7 +116,10 @@ DISTRIBUTIONS+= ports.txz DISTRIBUTIONS+= src.txz .endif -RELEASE_TARGETS= ftp +RELEASE_TARGETS= +.if !defined(NODISTSETS) || empty(NODISTSETS) +RELEASE_TARGETS+= ftp +.endif IMAGES= .if exists(${.CURDIR}/${TARGET}/mkisoimages.sh) RELEASE_TARGETS+= cdrom @@ -132,6 +135,9 @@ RELEASE_TARGETS+= mini-memstick.img IMAGES+= memstick.img IMAGES+= mini-memstick.img .endif +.if !defined(NOPKGBASE) || empty(NOPKGBASE) +RELEASE_TARGETS+= pkgbase-repo.tar +.endif CLEANFILES= packagesystem *.txz MANIFEST release ${IMAGES} .if defined(WITH_COMPRESSED_IMAGES) && !empty(WITH_COMPRESSED_IMAGES) @@ -142,7 +148,7 @@ CLEANFILES+= ${I}.xz .if defined(WITH_DVD) && !empty(WITH_DVD) CLEANFILES+= pkg-stage .endif -CLEANDIRS= dist pkgdb-dvd pkgdb-disc1 pkgbase-repo pkgbase-repo-dir ftp disc1 disc1-disc1 disc1-memstick bootonly bootonly-bootonly bootonly-memstick dvd +CLEANDIRS= dist pkgdb-dvd pkgdb-disc1 pkgbase-repo pkgbase-repo-dir ftp disc1 disc1-disc1 disc1-memstick bootonly bootonly-bootonly bootonly-memstick dvd pkgbase-repo.tar beforeclean: chflags -R noschg . .include <bsd.obj.mk> @@ -196,7 +202,7 @@ packagesystem: ${DISTRIBUTIONS} sh ${.CURDIR}/scripts/make-manifest.sh $$(ls *.txz | grep -v container) > MANIFEST touch ${.TARGET} -.if !defined(NODISTSETS) +.if !defined(NODISTSETS) || empty(NODISTSETS) disc1: packagesystem bootonly: packagesystem dvd: packagesystem @@ -213,6 +219,9 @@ pkgbase-repo: ( ${IMAKE} -C ${WORLDDIR} packages REPODIR=${.OBJDIR}/pkgbase-repo \ INCLUDE_PKG_IN_PKGBASE_REPO=YES BOOTSTRAP_PKG_FROM_PORTS=YES ) +pkgbase-repo.tar: pkgbase-repo + tar -cf pkgbase-repo.tar -C pkgbase-repo . + pkgbase-repo-dir: pkgbase-repo mkdir -p pkgbase-repo-dir printf "FreeBSD-base: { url: "file://%s", enabled: yes }" \ @@ -242,7 +251,7 @@ disc1: mtree -C -k type,mode,link,size | \ sed 's|^\.|./usr/freebsd-packages|g' >> ${.TARGET}/METALOG .endif -.if !defined(NODISTSETS) +.if !defined(NODISTSETS) || empty(NODISTSETS) # Copy MANIFEST to provide legacy dist checksums in both modes mkdir -p ${.TARGET}/usr/freebsd-dist echo "./usr/freebsd-dist type=dir uname=root gname=wheel mode=0755" >> ${.TARGET}/METALOG @@ -295,7 +304,7 @@ bootonly: MK_TOOLCHAIN=no \ MK_RESCUE=no MK_DICT=no \ MK_KERNEL_SYMBOLS=no MK_TESTS=no MK_DEBUG_FILES=no) -.if !defined(NODISTSETS) +.if !defined(NODISTSETS) || empty(NODISTSETS) # Copy manifest only (no distfiles) to get checksums mkdir -p ${.TARGET}/usr/freebsd-dist cp MANIFEST ${.TARGET}/usr/freebsd-dist @@ -347,7 +356,7 @@ dvd: mtree -C -k type,mode,link,size | \ sed 's|^\.|./usr/freebsd-packages|g' >> ${.TARGET}/METALOG .endif -.if !defined(NODISTSETS) +.if !defined(NODISTSETS) || empty(NODISTSETS) # Copy MANIFEST to provide legacy dist checksums in both modes mkdir -p ${.TARGET}/usr/freebsd-dist echo "./usr/freebsd-dist type=dir uname=root gname=wheel mode=0755" >> ${.TARGET}/METALOG @@ -449,7 +458,9 @@ release-install: .if defined(DESTDIR) && !empty(DESTDIR) mkdir -p ${DESTDIR} .endif +.if !defined(NODISTSETS) || empty(NODISTSETS) cp -a ftp ${DESTDIR}/ +.endif .if !empty(IMAGES) .for I in ${IMAGES} cp -p ${I} ${DESTDIR}/${OSRELEASE}-${I} @@ -460,6 +471,12 @@ release-install: ( cd ${DESTDIR} && sha512 ${OSRELEASE}* > ${DESTDIR}/CHECKSUM.SHA512 ) ( cd ${DESTDIR} && sha256 ${OSRELEASE}* > ${DESTDIR}/CHECKSUM.SHA256 ) .endif +.if !defined (NOPKGBASE) || empty(NOPKGBASE) + mkdir -p ${DESTDIR}/pkgbase + cp -p pkgbase-repo.tar ${DESTDIR}/pkgbase/ + ( cd ${DESTDIR}/pkgbase && sha256 pkgbase-repo.tar > CHECKSUM.SHA256 ) + ( cd ${DESTDIR}/pkgbase && sha512 pkgbase-repo.tar > CHECKSUM.SHA512 ) +.endif .include "${.CURDIR}/Makefile.inc1" .include "${.CURDIR}/Makefile.vm" diff --git a/release/Makefile.mirrors b/release/Makefile.mirrors index 5e65bfbe8b3f..6778b86873e6 100644 --- a/release/Makefile.mirrors +++ b/release/Makefile.mirrors @@ -63,6 +63,13 @@ STAGE_TARGETS+= oci-images-stage OCI_DIR= ${TLD}/OCI-IMAGES/${REVISION}-${BRANCH}/${TARGET_ARCH} .endif +.if !defined(EMBEDDED) || empty(EMBEDDED) +.if !defined(NOPKGBASE) || empty(NOPKGBASE) +STAGE_TARGETS+= pkgbase-repo-stage +PKGBASE_DIR= ${TLD}/PKGBASE-REPOS/${REVISION}-${BRANCH}/${TARGET_ARCH} +.endif +.endif + CLEANFILES+= ${STAGE_TARGETS} CHECKSUM_FILES?= SHA512 SHA256 SNAP_SUFFIX!= echo ${_SNAP_SUFFIX:S,^-,,1} | tr -d ' ' @@ -366,5 +373,44 @@ oci-images-stage: . endfor .endif +pkgbase-repo-stage: + mkdir -p ${PKGBASE_DIR} +.if defined(SNAPSHOT) && !empty(SNAPSHOT) +. if exists(${PKGBASE_DIR}/Latest) + rm -rf ${PKGBASE_DIR}/Latest +. endif + mkdir -p ${PKGBASE_DIR}/Latest + mkdir -p ${PKGBASE_DIR}/${BUILDDATE} + cd ${RELEASEDIR}/pkgbase && \ + mv pkgbase-repo.tar pkgbase-repo-${SNAP_SUFFIX}.tar + cp -p ${RELEASEDIR}/pkgbase/pkgbase-repo-${SNAP_SUFFIX}.tar \ + ${PKGBASE_DIR}/${BUILDDATE}/pkgbase-repo-${SNAP_SUFFIX}.tar + cd ${PKGBASE_DIR}/Latest && \ + ln -s ../${BUILDDATE}/pkgbase-repo-${SNAP_SUFFIX}.tar \ + pkgbase-repo.tar + cd ${RELEASEDIR}/pkgbase && rm -f CHECKSUM.* +. for CHECKSUM in ${CHECKSUM_FILES} + cd ${RELEASEDIR}/pkgbase && \ + ${CHECKSUM:tl} pkgbase-repo-*.tar > CHECKSUM.${CHECKSUM}-${SNAP_SUFFIX} + cp -p ${RELEASEDIR}/pkgbase/CHECKSUM.${CHECKSUM}-${SNAP_SUFFIX} \ + ${PKGBASE_DIR}/${BUILDDATE}/CHECKSUM.${CHECKSUM}-${SNAP_SUFFIX} + cd ${PKGBASE_DIR}/Latest && \ + ln -s ../${BUILDDATE}/CHECKSUM.${CHECKSUM}-${SNAP_SUFFIX} \ + CHECKSUM.${CHECKSUM} +. endfor +.else # not snapshot +. if exists(${PKGBASE_DIR}/Latest) + rm -rf ${PKGBASE_DIR}/Latest +. endif + mkdir -p ${PKGBASE_DIR}/Latest + cp -p ${RELEASEDIR}/pkgbase/pkgbase-repo.tar \ + ${PKGBASE_DIR}/Latest/pkgbase-repo.tar +. endfor +. for CHECKSUM in ${CHECKSUM_FILES} + cp -p ${RELEASEDIR}/pkgbase/CHECKSUM.${CHECKSUM} \ + ${PKGBASE_DIR}/Latest/CHECKSUM.${CHECKSUM} +. endfor +.endif + ftp-stage: remove-old-bits ${STAGE_TARGETS} diff --git a/release/packages/generate-set-ucl.lua b/release/packages/generate-set-ucl.lua index b1b70053b02a..3c8474bf8e68 100755 --- a/release/packages/generate-set-ucl.lua +++ b/release/packages/generate-set-ucl.lua @@ -1,7 +1,7 @@ #!/usr/libexec/flua --[[ usage: -generare-set-ucl.lua <template> [<variablename> <variablevalue>] +generate-set-ucl.lua <template> [<variablename> <variablevalue>] Generate the UCL for a set metapackage. The variables provided will be substituted as UCL variables. diff --git a/release/packages/generate-ucl.lua b/release/packages/generate-ucl.lua index ea3743894740..c61cbb251d8b 100755 --- a/release/packages/generate-ucl.lua +++ b/release/packages/generate-ucl.lua @@ -1,7 +1,7 @@ #!/usr/libexec/flua --[[ usage: -generare-ucl.lua [<variablename> <variablevalue>]... <sourceucl> <destucl> +generate-ucl.lua [<variablename> <variablevalue>]... <sourceucl> <destucl> Build a package's UCL configuration by loading the template UCL file <sourceucl>, replacing any $VARIABLES in the UCL based on the provided diff --git a/release/packages/ucl/ctf-all.ucl b/release/packages/ucl/ctf-all.ucl index 941990908373..25d46ab9421a 100644 --- a/release/packages/ucl/ctf-all.ucl +++ b/release/packages/ucl/ctf-all.ucl @@ -30,7 +30,7 @@ CTF is intended specifically for runtime program analyzers such as DTrace. This package provides the ctfconvert(1), ctfdump(1) and ctfmerge(1) utilities which are used to work with CTF data, and the libctf library which allows -application to access CTF debugging information programatically. +application to access CTF debugging information programmatically. EOD licenses = [ "CDDL-1.0" ] diff --git a/release/packages/ucl/fetch-all.ucl b/release/packages/ucl/fetch-all.ucl index d14f22cb74a5..5a3c0be826fa 100644 --- a/release/packages/ucl/fetch-all.ucl +++ b/release/packages/ucl/fetch-all.ucl @@ -19,13 +19,13 @@ comment = "Retrieve a file from a remote URL" desc = <<EOD -The fetch(1) utility retieves one or more files from a remote URL via +The fetch(1) utility retrieves one or more files from a remote URL via HTTP or FTP. fetch(1) includes support for TLS, HTTP proxies, .netrc files, and includes a "mirror" mode which only downloads files which are newer on the remote site. Also provided is fetch(3), a library which allows applications to use -this functionality programatically. +this functionality programmatically. EOD annotations { diff --git a/release/packages/ucl/openssl-all.ucl b/release/packages/ucl/openssl-all.ucl index 24a83ab6b9ba..4c393efe3b89 100644 --- a/release/packages/ucl/openssl-all.ucl +++ b/release/packages/ucl/openssl-all.ucl @@ -26,7 +26,7 @@ protocols such as HTTP, SMTP and DNS. OpenSSL provides openssl(1), a command-line utility used for testing TLS clients and servers, managing certificate used in TLS authentication, and -performing various miscallenous cryptographic operations. +performing various miscellaneous cryptographic operations. Also provided are two libraries, libcrypto and libssl, which can be used by applications to provide generic cryptographic functionality, and to implement diff --git a/release/packages/ucl/ufs-all.ucl b/release/packages/ucl/ufs-all.ucl index d9302bd0e3f9..b35e0f3d1dc7 100644 --- a/release/packages/ucl/ufs-all.ucl +++ b/release/packages/ucl/ufs-all.ucl @@ -32,7 +32,7 @@ utilities used to check the consistency of an existing filesystem after an unclean shutdown or panic. The libufs library is also provided, which allows applications to access -UFS filesystems programatically. +UFS filesystems programmatically. EOD annotations { diff --git a/release/packages/ucl/xz-all.ucl b/release/packages/ucl/xz-all.ucl index 16da8b76f0ac..8a7c33bcce46 100644 --- a/release/packages/ucl/xz-all.ucl +++ b/release/packages/ucl/xz-all.ucl @@ -21,7 +21,7 @@ comment = "LZMA2 data compression" desc = <<EOD xz compresses data using the LZMA2 data compression algorithm. This package provides the front-end xz(1) utility, and the liblzma library which allows -applications to use this functionality programatically. +applications to use this functionality programmatically. EOD annotations { diff --git a/release/packages/ucl/zfs-all.ucl b/release/packages/ucl/zfs-all.ucl index 70ebcdacdb57..9d166452188d 100644 --- a/release/packages/ucl/zfs-all.ucl +++ b/release/packages/ucl/zfs-all.ucl @@ -39,7 +39,7 @@ This package provides the zfs(8) and zpool(8) utilities used to manage ZFS filesystems, the zfsd(8) self-healing daemon, and several other utilities, as well as the runtime libraries used internally by ZFS itself, and the libzfs_core library providing a stable interface for -managing ZFS programatically. +managing ZFS programmatically. EOD licenses = [ "CDDL-1.0" ] diff --git a/release/scripts/make-pkg-package.sh b/release/scripts/make-pkg-package.sh index a1e006bd6964..3a1b163bd591 100755 --- a/release/scripts/make-pkg-package.sh +++ b/release/scripts/make-pkg-package.sh @@ -8,6 +8,13 @@ PKG_ABI=$(${PKG_CMD} -o ABI_FILE=${WSTAGEDIR}/bin/sh config ABI) unset PKG_VERSION unset MAKEFLAGS unset PKGBASE +# Ports interprets CROSS_TOOLCHAIN differently from src, and having this set +# breaks the package-pkg build. For now, forcibly unset this and hope ports +# can find a working compiler. +if [ -n "$CROSS_TOOLCHAIN" ]; then + printf >&2 '%s: WARNING: CROSS_TOOLCHAIN will be ignored for the pkg build.\n' "$0" + unset CROSS_TOOLCHAIN +fi export WRKDIRPREFIX=/tmp/ports.${TARGET} export DISTDIR=/tmp/distfiles export WRKDIR=$(make -C ${PORTSDIR}/ports-mgmt/pkg I_DONT_CARE_IF_MY_BUILDS_TARGET_THE_WRONG_RELEASE=YES -V WRKDIR) diff --git a/release/tools/vagrant.conf b/release/tools/vagrant.conf index 7ab0e1238693..5b0f38b740a6 100644 --- a/release/tools/vagrant.conf +++ b/release/tools/vagrant.conf @@ -14,14 +14,16 @@ export VM_EXTRA_PACKAGES="${VM_EXTRA_PACKAGES} shells/bash \ export VM_RC_LIST="firstboot_freebsd_update firstboot_pkgs growfs" vagrant_common () { - # The firstboot_pkgs rc.d script will download the repository - # catalogue and install or update pkg when the instance first - # launches, so these files would just be replaced anyway; removing - # them from the image allows it to boot faster. - env ASSUME_ALWAYS_YES=yes pkg -c ${DESTDIR} clean -y -a - env ASSUME_ALWAYS_YES=yes pkg -c ${DESTDIR} delete -f -y pkg - rm -r ${DESTDIR}/var/db/pkg/repos/FreeBSD-ports - rm -r ${DESTDIR}/var/db/pkg/repos/FreeBSD-ports-kmods + if [ -z "${NO_ROOT}" ]; then + # The firstboot_pkgs rc.d script will download the repository + # catalogue and install or update pkg when the instance first + # launches, so these files would just be replaced anyway; + # removing them from the image allows it to boot faster. + pkg -c ${DESTDIR} clean -y -a + pkg -c ${DESTDIR} delete -f -y pkg + rm -r ${DESTDIR}/var/db/pkg/repos/FreeBSD-ports + rm -r ${DESTDIR}/var/db/pkg/repos/FreeBSD-ports-kmods + fi # Vagrant instances use DHCP to get their network configuration. echo 'ifconfig_DEFAULT="SYNCDHCP"' >> ${DESTDIR}/etc/rc.conf @@ -40,8 +42,7 @@ vagrant_common () { # Create the vagrant user with a password of vagrant /usr/sbin/pw -R ${DESTDIR} \ groupadd vagrant -g 1001 - chroot ${DESTDIR} mkdir -p /home/vagrant - /usr/sbin/pw -R ${DESTDIR} \ + /usr/sbin/pw -R ${DESTDIR} -M ${DESTDIR}/METALOG \ useradd vagrant \ -m -M 0755 -w yes -n vagrant -u 1001 -g 1001 -G 0 \ -c 'Vagrant User' -d '/home/vagrant' -s '/bin/csh' @@ -58,11 +59,11 @@ vagrant_common () { echo "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key" > ${DESTDIR}/home/vagrant/.ssh/authorized_keys echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN1YdxBpNlzxDqfJyw/QKow1F+wvG9hXGoqiysfJOn5Y vagrant insecure public key" >> ${DESTDIR}/home/vagrant/.ssh/authorized_keys chmod 600 ${DESTDIR}/home/vagrant/.ssh/authorized_keys - metalog_add_data ./home/vagrant/.ssh/authorized_keys 0600 chmod 700 ${DESTDIR}/home/vagrant/.ssh chown -R 1001 ${DESTDIR}/home/vagrant/.ssh - echo "./home/vagrant/.ssh type=dir uid=1001 gid=1001 mode=0700" >> METALOG + echo "./home/vagrant/.ssh type=dir uid=1001 gid=1001 mode=0700" >> ${DESTDIR}/METALOG + echo "./home/vagrant/.ssh/authorized_keys type=file uid=1001 gid=1001 mode=0600" >> ${DESTDIR}/METALOG # Reboot quickly, Don't wait at the panic screen echo 'debug.trace_on_panic=1' >> ${DESTDIR}/etc/sysctl.conf diff --git a/share/man/man4/ice.4 b/share/man/man4/ice.4 index 3f7a9017756d..13ad304a2d5a 100644 --- a/share/man/man4/ice.4 +++ b/share/man/man4/ice.4 @@ -1,4 +1,4 @@ -.\"- +.\" .\" SPDX-License-Identifier: BSD-3-Clause .\" .\" Copyright (c) 2019-2020, Intel Corporation @@ -32,12 +32,12 @@ .\" .\" * Other names and brands may be claimed as the property of others. .\" -.Dd March 28, 2025 +.Dd October 3, 2025 .Dt ICE 4 .Os .Sh NAME .Nm ice -.Nd "Intel\(rg Ethernet 800 Series Driver" +.Nd Intel Ethernet 800 Series Driver .Sh SYNOPSIS To compile this driver into the kernel, place the following lines in your kernel configuration file: @@ -86,7 +86,7 @@ Intel\(rg Ethernet Connection E830\-XXV .El .Pp For questions related to hardware requirements, refer to the documentation -supplied with your adapter. +supplied with the adapter. .Pp Support for Jumbo Frames is provided via the interface MTU setting. Selecting an MTU larger than 1500 bytes with the @@ -134,17 +134,16 @@ See the .Dq Intel\(rg Ethernet Adapters and Devices User Guide for more details on DDP and Safe Mode. .Pp -If you encounter issues with the DDP package file, you may need to download -an updated driver or +If issues are encountered with the DDP package file, an updated driver or .Sy ice_ddp -module. +module may need to be downloaded. See the log messages for more information. .Pp -You cannot update the DDP package if any PF drivers are already loaded. +The DDP package cannot be updated if any PF drivers are already loaded. To overwrite a package, unload all PFs and then reload the driver with the new package. .Pp -You can only use one DDP package per driver, even if you have more than one +Only one DDP package can be used per driver, even if more than one device installed that uses the driver. .Pp Only the first loaded PF per device can download a package for that device. @@ -164,9 +163,9 @@ each jumbo packet. This should help to avoid buffer starvation issues when allocating receive packets. .Pp -Packet loss may have a greater impact on throughput when you use jumbo -frames. -If you observe a drop in performance after enabling jumbo frames, enabling +Packet loss may have a greater impact on throughput when jumbo frames are in +use. +If a drop in performance is observed after enabling jumbo frames, enabling flow control may mitigate the issue. .Ss Remote Direct Memory Access Remote Direct Memory Access, or RDMA, allows a network device to transfer data @@ -184,14 +183,14 @@ operating in multiport mode with more than 4 ports. For detailed installation and configuration information for RDMA, see .Xr irdma 4 . .Ss RDMA Monitoring -For debugging/testing purposes, you can use sysctl to set up a mirroring +For debugging/testing purposes, a sysctl can be used to set up a mirroring interface on a port. The interface can receive mirrored RDMA traffic for packet analysis tools like .Xr tcpdump 1 . This mirroring may impact performance. .Pp -To use RDMA monitoring, you may need to reserve more MSI\-X interrupts. +To use RDMA monitoring, more MSI\-X interrupts may need to be reserved. Before the .Nm driver loads, configure the following tunable provided by @@ -200,7 +199,7 @@ driver loads, configure the following tunable provided by dev.ice.<interface #>.iflib.use_extra_msix_vectors=4 .Ed .Pp -You may need to adjust the number of extra MSI\-X interrupt vectors. +The number of extra MSI\-X interrupt vectors may need to be adjusted. .Pp To create/delete the interface: .Bd -literal -offset indent @@ -276,7 +275,7 @@ To enable/disable priority flow control in software\-based DCBX mode: sysctl dev.ice.<interface #>.pfc=1 (or 0 to disable) .Ed .Pp -Enhanced Transmission Selection (ETS) allows you to assign bandwidth to certain +Enhanced Transmission Selection (ETS) allows bandwidth to be assigned to certain TCs, to help ensure traffic reliability. To view the assigned ETS configuration, use the following: .Bd -literal -offset indent @@ -310,7 +309,7 @@ Use the following sysctl to enable or disable L3 QoS: sysctl dev.ice.<interface #>.pfc_mode=1 (or 0 to disable) .Ed .Pp -If you disable L3 QoS mode, it returns to L2 QoS mode. +If the L3 QoS mode is disabled, it returns to L2 QoS mode. .Pp To map a DSCP value to a traffic class, separate the values by commas. For example, to map DSCPs 0\-3 and DSCP 8 to DCB TCs 0\-3 and 4, respectively: @@ -329,7 +328,7 @@ sysctl dev.ice.<interface #>.dscp2tc_map .Pp L3 QoS mode is not available when FW\-LLDP is enabled. .Pp -You also cannot enable FW\-LLDP if L3 QoS mode is active. +FW\-LLDP cannot be enabled if L3 QoS mode is active. .Pp Disable FW\-LLDP before switching to L3 QoS mode. .Pp @@ -355,11 +354,11 @@ To check the current LLDP setting: sysctl dev.ice.<interface #>.fw_lldp_agent .Ed .Pp -You must enable the UEFI HII LLDP Agent attribute for this setting +The UEFI HII LLDP Agent attribute must be enabled for this setting to take effect. If the .Dq LLDP AGENT -attribute is set to disabled, you cannot enable the FW\-LLDP Agent from the +attribute is set to disabled, the FW\-LLDP Agent cannot be enabled from the driver. .Ss Link\-Level Flow Control (LFC) Ethernet Flow Control (IEEE 802.3x) can be configured with sysctl to enable @@ -416,11 +415,11 @@ provide a stable link without FEC. .Pp For devices to benefit from this feature, link partners must have FEC enabled. .Pp -If you enable the sysctl -.Em allow_no_fec_modules_in_auto -Auto FEC negotiation will include +If the +.Va allow_no_fec_modules_in_auto +sysctl is enabled Auto FEC negotiation will include .Dq No FEC -in case your link partner does not have FEC enabled or is not FEC capable: +in case the link partner does not have FEC enabled or is not FEC capable: .Bd -literal -offset indent sysctl dev.ice.<interface #>.allow_no_fec_modules_in_auto=1 .Ed @@ -443,16 +442,16 @@ To see the valid FEC modes for the link: sysctl \-d dev.ice.<interface #>.requested_fec .Ed .Ss Speed and Duplex Configuration -You cannot set duplex or autonegotiation settings. +The speed and duplex settings cannot be hard set. .Pp -To have your device change the speeds it will use in auto-negotiation or +To have the device change the speeds it will use in auto-negotiation or force link with: .Bd -literal -offset indent sysctl dev.ice.<interface #>.advertise_speed=<mask> .Ed .Pp Supported speeds will vary by device. -Depending on the speeds your device supports, valid bits used in a speed mask +Depending on the speeds the device supports, valid bits used in a speed mask could include: .Bd -literal -offset indent 0x0 \- Auto @@ -493,13 +492,13 @@ At a high level, to capture a firmware log: .It Set the configuration for the firmware log. .It -Perform the necessary steps to generate the issue you are trying to debug. +Perform the necessary steps to reproduce the issue. .It Capture the firmware log. .It Stop capturing the firmware log. .It -Reset your firmware log settings as needed. +Reset the firmware log settings as needed. .It Work with Customer Support to debug the issue. .El @@ -583,8 +582,8 @@ PF Registration (Bit 30) Module Version (Bit 31) .El .Pp -You can change the verbosity level of the firmware logs. -You can set only one log level per module, and each level includes the +The verbosity level of the firmware logs can be modified. +It is possible to set only one log level per module, and each level includes the verbosity levels lower than it. For instance, setting the level to .Dq normal @@ -640,8 +639,8 @@ dmesg > log_output NOTE: Logging a large number of modules or too high of a verbosity level will add extraneous messages to dmesg and could hinder debug efforts. .Ss Debug Dump -Intel\(rg Ethernet 800 Series devices support debug dump, which allows you to -obtain runtime register values from the firmware for +Intel\(rg Ethernet 800 Series devices support debug dump, which allows +gathering of runtime register values from the firmware for .Dq clusters of events and then write the results to a single dump file, for debugging complicated issues in the field. @@ -654,7 +653,7 @@ stateless snapshot of the whole device. .Pp NOTE: Like with firmware logs, the contents of the debug dump are not human\-readable. -You must work with Customer Support to decode the file. +Work with Customer Support to decode the file. .Pp Debug dump is per device, not per PF. .Pp @@ -717,20 +716,19 @@ sysctl dev.ice.0.debug.dump.clusters=0 .Pp NOTE: Using 0 will skip Manageability Transactions data. .Pp -If you don't specify a cluster, the driver will dump all clusters to a +If a single cluster is not specified, the driver will dump all clusters to a single file. Issue the debug dump command, using the following: .Bd -literal -offset indent sysctl \-b dev.ice.<interface #>.debug.dump.dump=1 > dump.bin .Ed .Pp -NOTE: The driver will not receive the command if you do not write -.Dq 1 -to the sysctl. +NOTE: The driver will not receive the command if the sysctl is not set to +.Dq 1 . .Pp Replace .Dq dump.bin -above with the file name you want to use. +above with the preferred file name. .Pp To clear the .Va clusters @@ -744,7 +742,7 @@ The ice driver supports the ability to obtain the values of the PHY registers from Intel(R) Ethernet 810 Series devices in order to debug link and connection issues during runtime. .Pp -The driver allows you to obtain information about: +The driver provides information about: .Bl -bullet .It Rx and Tx Equalization parameters @@ -758,12 +756,12 @@ sysctl dev.ice.<interface #>.debug.phy_statistics .Ed .Pp NOTE: The contents of the registers are not human\-readable. -Like with firmware logs and debug dump, you must work with Customer Support +Like with firmware logs and debug dump, work with Customer Support to decode the file. .Ss Transmit Balancing -Some Intel(R) Ethernet 800 Series devices allow you to enable a transmit +Some Intel(R) Ethernet 800 Series devices allow for enabling a transmit balancing feature to improve transmit performance under certain conditions. -When the feature is enabled, you should experience more consistent transmit +When enabled, the feature should provide more consistent transmit performance across queues and/or PFs and VFs. .Pp By default, transmit balancing is disabled in the NVM. @@ -784,7 +782,7 @@ configures the device accordingly. .Pp NOTE: The user selection for transmit balancing in EPCT or HII is persistent across reboots. -You must reboot the system for the selected setting to take effect. +The system must be rebooted for the selected setting to take effect. .Pp This setting is device wide. .Pp @@ -801,7 +799,7 @@ sysctl dev.ice.<interface #>.temp may have a low number of network memory buffers (mbufs) by default. If the number of mbufs available is too low, it may cause the driver to fail to initialize and/or cause the system to become unresponsive. -You can check to see if the system is mbuf\-starved by running +Check to see if the system is mbuf\-starved by running .Ic netstat Fl m . Increase the number of mbufs by editing the lines below in .Pa /etc/sysctl.conf : @@ -813,7 +811,7 @@ kern.ipc.nmbjumbo16 kern.ipc.nmbufs .Ed .Pp -The amount of memory that you allocate is system specific, and may require some +The amount of memory that should be allocated is system specific, and may require some trial and error. Also, increasing the following in .Pa /etc/sysctl.conf @@ -908,8 +906,8 @@ link partner's switch ports. Some PCIe x8 slots are actually configured as x4 slots. These slots have insufficient bandwidth for full line rate with dual port and quad port devices. -In addition, if you put a PCIe v4.0 or v3.0\-capable adapter into a PCIe v2.x -slot, you cannot get full bandwidth. +In addition, if a PCIe v4.0 or v3.0\-capable adapter is placed into a PCIe v2.x +slot, full bandwidth will not be possible. .Pp The driver detects this situation and writes the following message in the system log: @@ -920,7 +918,7 @@ Please move the device to a different PCI\-e link with more lanes and/or higher transfer rate. .Ed .Pp -If this error occurs, moving your adapter to a true PCIe x8 or x16 slot will +If this error occurs, moving the adapter to a true PCIe x8 or x16 slot will resolve the issue. For best performance, install devices in the following PCI slots: .Bl -bullet diff --git a/share/man/man5/rc.conf.5 b/share/man/man5/rc.conf.5 index c0048f27c740..edbfa937f8df 100644 --- a/share/man/man5/rc.conf.5 +++ b/share/man/man5/rc.conf.5 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd October 2, 2025 +.Dd October 5, 2025 .Dt RC.CONF 5 .Os .Sh NAME @@ -4618,8 +4618,11 @@ Set to to enable waiting for DAD to complete. .It Va netwait_dad_timeout .Pq Vt int -Indicates the total number of seconds to wait for DAD to complete. -The default is 10. +Unset by default. +Indicates the maximum number of seconds to wait for DAD to complete. +If zero or unset, the timeout will be one more than the value of the +.Va net.inet6.ip6.dad_count +sysctl variable. .It Va rctl_enable .Pq Vt bool If set to diff --git a/share/mk/bsd.nls.mk b/share/mk/bsd.nls.mk index bd13fe56679d..5a28e1cdd026 100644 --- a/share/mk/bsd.nls.mk +++ b/share/mk/bsd.nls.mk @@ -1,6 +1,8 @@ # -# This include file <bsd.nls.mk> handles building and installing Native -# Language Support (NLS) catalogs +# Handle building and installing Native Language Support (NLS) catalogs. +# This is implemented using a <bsd.files.mk> files group called "NLS", +# so any per-group options that bsd.files.mk supports can be used here +# with the prefix "NLS". # # +++ variables +++ # @@ -17,6 +19,9 @@ # NLSMODE National Language Support files mode. [${NOBINMODE}] # # NLSOWN National Language Support files owner. [${SHAREOWN}] +# +# NLSPACKAGE Package to install the NLS files in. +# [${PACKAGE}, or "utilities" if not set] .if !target(__<bsd.init.mk>__) .error bsd.nls.mk cannot be included directly. diff --git a/share/mk/src.libnames.mk b/share/mk/src.libnames.mk index 95cd3b02d8e4..3e108591251a 100644 --- a/share/mk/src.libnames.mk +++ b/share/mk/src.libnames.mk @@ -425,7 +425,7 @@ _DP_kadm5clnt= com_err krb5 roken _DP_kadm5srv= com_err hdb krb5 roken _DP_heimntlm= crypto com_err krb5 roken _DP_hx509= asn1 com_err crypto roken wind -_DP_hdb= asn1 com_err krb5 roken sqlite3 +_DP_hdb= asn1 com_err krb5 roken sqlite3 heimbase _DP_asn1= com_err roken _DP_kdc= roken hdb hx509 krb5 heimntlm asn1 crypto _DP_wind= com_err roken diff --git a/sys/contrib/openzfs/.github/ISSUE_TEMPLATE/feature_request.md b/sys/contrib/openzfs/.github/ISSUE_TEMPLATE/feature_request.md index 9b50a4a3d96e..f3d4316f6f67 100644 --- a/sys/contrib/openzfs/.github/ISSUE_TEMPLATE/feature_request.md +++ b/sys/contrib/openzfs/.github/ISSUE_TEMPLATE/feature_request.md @@ -14,7 +14,7 @@ Please check our issue tracker before opening a new feature request. Filling out the following template will help other contributors better understand your proposed feature. --> -### Describe the feature would like to see added to OpenZFS +### Describe the feature you would like to see added to OpenZFS <!-- Provide a clear and concise description of the feature. diff --git a/sys/contrib/openzfs/.github/PULL_REQUEST_TEMPLATE.md b/sys/contrib/openzfs/.github/PULL_REQUEST_TEMPLATE.md index 79809179cf13..47edc8174603 100644 --- a/sys/contrib/openzfs/.github/PULL_REQUEST_TEMPLATE.md +++ b/sys/contrib/openzfs/.github/PULL_REQUEST_TEMPLATE.md @@ -2,11 +2,6 @@ <!--- Provide a general summary of your changes in the Title above --> -<!--- -Documentation on ZFS Buildbot options can be found at -https://openzfs.github.io/openzfs-docs/Developer%20Resources/Buildbot%20Options.html ---> - ### Motivation and Context <!--- Why is this change required? What problem does it solve? --> <!--- If it fixes an open issue, please link to the issue here. --> diff --git a/sys/contrib/openzfs/.github/workflows/scripts/qemu-2-start.sh b/sys/contrib/openzfs/.github/workflows/scripts/qemu-2-start.sh index 8439942c5a41..1c608348ffcd 100755 --- a/sys/contrib/openzfs/.github/workflows/scripts/qemu-2-start.sh +++ b/sys/contrib/openzfs/.github/workflows/scripts/qemu-2-start.sh @@ -121,7 +121,7 @@ case "$OS" in KSRC="$FREEBSD_SNAP/../amd64/$FreeBSD/src.txz" ;; freebsd15-0c) - FreeBSD="15.0-ALPHA2" + FreeBSD="15.0-ALPHA3" OSNAME="FreeBSD $FreeBSD" OSv="freebsd14.0" URLxz="$FREEBSD_SNAP/$FreeBSD/amd64/Latest/FreeBSD-$FreeBSD-amd64-BASIC-CI-ufs.raw.xz" diff --git a/sys/contrib/openzfs/.github/workflows/scripts/qemu-3-deps-vm.sh b/sys/contrib/openzfs/.github/workflows/scripts/qemu-3-deps-vm.sh index ee058b488088..f67bb2f68e94 100755 --- a/sys/contrib/openzfs/.github/workflows/scripts/qemu-3-deps-vm.sh +++ b/sys/contrib/openzfs/.github/workflows/scripts/qemu-3-deps-vm.sh @@ -20,7 +20,7 @@ function archlinux() { sudo pacman -Sy --noconfirm base-devel bc cpio cryptsetup dhclient dkms \ fakeroot fio gdb inetutils jq less linux linux-headers lsscsi nfs-utils \ parted pax perf python-packaging python-setuptools qemu-guest-agent ksh \ - samba sysstat rng-tools rsync wget xxhash + samba strace sysstat rng-tools rsync wget xxhash echo "##[endgroup]" } @@ -43,7 +43,8 @@ function debian() { lsscsi nfs-kernel-server pamtester parted python3 python3-all-dev \ python3-cffi python3-dev python3-distlib python3-packaging libtirpc-dev \ python3-setuptools python3-sphinx qemu-guest-agent rng-tools rpm2cpio \ - rsync samba sysstat uuid-dev watchdog wget xfslibs-dev xxhash zlib1g-dev + rsync samba strace sysstat uuid-dev watchdog wget xfslibs-dev xxhash \ + zlib1g-dev echo "##[endgroup]" } @@ -87,8 +88,8 @@ function rhel() { libuuid-devel lsscsi mdadm nfs-utils openssl-devel pam-devel pamtester \ parted perf python3 python3-cffi python3-devel python3-packaging \ kernel-devel python3-setuptools qemu-guest-agent rng-tools rpcgen \ - rpm-build rsync samba sysstat systemd watchdog wget xfsprogs-devel xxhash \ - zlib-devel + rpm-build rsync samba strace sysstat systemd watchdog wget xfsprogs-devel \ + xxhash zlib-devel echo "##[endgroup]" } @@ -104,7 +105,7 @@ function install_fedora_experimental_kernel { our_version="$1" sudo dnf -y copr enable @kernel-vanilla/stable sudo dnf -y copr enable @kernel-vanilla/mainline - all="$(sudo dnf list --showduplicates kernel-*)" + all="$(sudo dnf list --showduplicates kernel-* python3-perf* perf* bpftool*)" echo "Available versions:" echo "$all" diff --git a/sys/contrib/openzfs/.github/workflows/scripts/qemu-5-setup.sh b/sys/contrib/openzfs/.github/workflows/scripts/qemu-5-setup.sh index 0adcad2a99bc..4869c1003e48 100755 --- a/sys/contrib/openzfs/.github/workflows/scripts/qemu-5-setup.sh +++ b/sys/contrib/openzfs/.github/workflows/scripts/qemu-5-setup.sh @@ -108,19 +108,30 @@ echo '*/5 * * * * /root/cronjob.sh' > crontab.txt sudo crontab crontab.txt rm crontab.txt -# check if the machines are okay -echo "Waiting for vm's to come up... (${VMs}x CPU=$CPU RAM=$RAM)" -for ((i=1; i<=VMs; i++)); do - .github/workflows/scripts/qemu-wait-for-vm.sh vm$i -done -echo "All $VMs VMs are up now." - # Save the VM's serial output (ttyS0) to /var/tmp/console.txt # - ttyS0 on the VM corresponds to a local /dev/pty/N entry # - use 'virsh ttyconsole' to lookup the /dev/pty/N entry for ((i=1; i<=VMs; i++)); do mkdir -p $RESPATH/vm$i read "pty" <<< $(sudo virsh ttyconsole vm$i) + + # Create the file so we can tail it, even if there's no output. + touch $RESPATH/vm$i/console.txt + sudo nohup bash -c "cat $pty > $RESPATH/vm$i/console.txt" & + + # Write all VM boot lines to the console to aid in debugging failed boots. + # The boot lines from all the VMs will be munged together, so prepend each + # line with the vm hostname (like 'vm1:'). + (while IFS=$'\n' read -r line; do echo "vm$i: $line" ; done < <(sudo tail -f $RESPATH/vm$i/console.txt)) & + done echo "Console logging for ${VMs}x $OS started." + + +# check if the machines are okay +echo "Waiting for vm's to come up... (${VMs}x CPU=$CPU RAM=$RAM)" +for ((i=1; i<=VMs; i++)); do + .github/workflows/scripts/qemu-wait-for-vm.sh vm$i +done +echo "All $VMs VMs are up now." diff --git a/sys/contrib/openzfs/.github/workflows/scripts/qemu-6-tests.sh b/sys/contrib/openzfs/.github/workflows/scripts/qemu-6-tests.sh index 5ab822f4f076..ca6ac77f146d 100755 --- a/sys/contrib/openzfs/.github/workflows/scripts/qemu-6-tests.sh +++ b/sys/contrib/openzfs/.github/workflows/scripts/qemu-6-tests.sh @@ -111,7 +111,7 @@ fi sudo dmesg -c > dmesg-prerun.txt mount > mount.txt df -h > df-prerun.txt -$TDIR/zfs-tests.sh -vK -s 3GB -T $TAGS +$TDIR/zfs-tests.sh -vKO -s 3GB -T $TAGS RV=$? df -h > df-postrun.txt echo $RV > tests-exitcode.txt diff --git a/sys/contrib/openzfs/META b/sys/contrib/openzfs/META index 5704b5c6de8a..bdb7aee48041 100644 --- a/sys/contrib/openzfs/META +++ b/sys/contrib/openzfs/META @@ -6,5 +6,5 @@ Release: 1 Release-Tags: relext License: CDDL Author: OpenZFS -Linux-Maximum: 6.16 +Linux-Maximum: 6.17 Linux-Minimum: 4.18 diff --git a/sys/contrib/openzfs/cmd/zdb/zdb.c b/sys/contrib/openzfs/cmd/zdb/zdb.c index d655fa715e15..70a4ed46f263 100644 --- a/sys/contrib/openzfs/cmd/zdb/zdb.c +++ b/sys/contrib/openzfs/cmd/zdb/zdb.c @@ -3301,6 +3301,7 @@ zdb_derive_key(dsl_dir_t *dd, uint8_t *key_out) uint64_t keyformat, salt, iters; int i; unsigned char c; + FILE *f; VERIFY0(zap_lookup(dd->dd_pool->dp_meta_objset, dd->dd_crypto_obj, zfs_prop_to_name(ZFS_PROP_KEYFORMAT), sizeof (uint64_t), @@ -3333,6 +3334,25 @@ zdb_derive_key(dsl_dir_t *dd, uint8_t *key_out) break; + case ZFS_KEYFORMAT_RAW: + if ((f = fopen(key_material, "r")) == NULL) + return (B_FALSE); + + if (fread(key_out, 1, WRAPPING_KEY_LEN, f) != + WRAPPING_KEY_LEN) { + (void) fclose(f); + return (B_FALSE); + } + + /* Check the key length */ + if (fgetc(f) != EOF) { + (void) fclose(f); + return (B_FALSE); + } + + (void) fclose(f); + break; + default: fatal("no support for key format %u\n", (unsigned int) keyformat); diff --git a/sys/contrib/openzfs/cmd/zfs/zfs_main.c b/sys/contrib/openzfs/cmd/zfs/zfs_main.c index 484986bde719..ccdd5ffef8e6 100644 --- a/sys/contrib/openzfs/cmd/zfs/zfs_main.c +++ b/sys/contrib/openzfs/cmd/zfs/zfs_main.c @@ -914,7 +914,11 @@ zfs_do_clone(int argc, char **argv) log_history = B_FALSE; } - ret = zfs_mount_and_share(g_zfs, argv[1], ZFS_TYPE_DATASET); + /* + * Dataset cloned successfully, mount/share failures are + * non-fatal. + */ + (void) zfs_mount_and_share(g_zfs, argv[1], ZFS_TYPE_DATASET); } zfs_close(zhp); @@ -930,19 +934,15 @@ usage: } /* - * Return a default volblocksize for the pool which always uses more than - * half of the data sectors. This primarily applies to dRAID which always - * writes full stripe widths. + * Calculate the minimum allocation size based on the top-level vdevs. */ static uint64_t -default_volblocksize(zpool_handle_t *zhp, nvlist_t *props) +calculate_volblocksize(nvlist_t *config) { - uint64_t volblocksize, asize = SPA_MINBLOCKSIZE; + uint64_t asize = SPA_MINBLOCKSIZE; nvlist_t *tree, **vdevs; uint_t nvdevs; - nvlist_t *config = zpool_get_config(zhp, NULL); - if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &tree) != 0 || nvlist_lookup_nvlist_array(tree, ZPOOL_CONFIG_CHILDREN, &vdevs, &nvdevs) != 0) { @@ -973,6 +973,24 @@ default_volblocksize(zpool_handle_t *zhp, nvlist_t *props) } } + return (asize); +} + +/* + * Return a default volblocksize for the pool which always uses more than + * half of the data sectors. This primarily applies to dRAID which always + * writes full stripe widths. + */ +static uint64_t +default_volblocksize(zpool_handle_t *zhp, nvlist_t *props) +{ + uint64_t volblocksize, asize = SPA_MINBLOCKSIZE; + + nvlist_t *config = zpool_get_config(zhp, NULL); + + if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_MAX_ALLOC, &asize) != 0) + asize = calculate_volblocksize(config); + /* * Calculate the target volblocksize such that more than half * of the asize is used. The following table is for 4k sectors. @@ -1319,7 +1337,9 @@ zfs_do_create(int argc, char **argv) goto error; } - ret = zfs_mount_and_share(g_zfs, argv[0], ZFS_TYPE_DATASET); + /* Dataset created successfully, mount/share failures are non-fatal */ + ret = 0; + (void) zfs_mount_and_share(g_zfs, argv[0], ZFS_TYPE_DATASET); error: nvlist_free(props); return (ret); diff --git a/sys/contrib/openzfs/cmd/zinject/zinject.c b/sys/contrib/openzfs/cmd/zinject/zinject.c index 113797c878b9..c2f646f2567d 100644 --- a/sys/contrib/openzfs/cmd/zinject/zinject.c +++ b/sys/contrib/openzfs/cmd/zinject/zinject.c @@ -107,6 +107,8 @@ * zinject * zinject <-a | -u pool> * zinject -c <id|all> + * zinject -E <delay> [-a] [-m] [-f freq] [-l level] [-r range] + * [-T iotype] [-t type object | -b bookmark pool] * zinject [-q] <-t type> [-f freq] [-u] [-a] [-m] [-e errno] [-l level] * [-r range] <object> * zinject [-f freq] [-a] [-m] [-u] -b objset:object:level:start:end pool @@ -132,14 +134,18 @@ * The '-f' flag controls the frequency of errors injected, expressed as a * real number percentage between 0.0001 and 100. The default is 100. * - * The this form is responsible for actually injecting the handler into the + * The <object> form is responsible for actually injecting the handler into the * framework. It takes the arguments described above, translates them to the * internal tuple using libzpool, and then issues an ioctl() to register the * handler. * - * The final form can target a specific bookmark, regardless of whether a + * The '-b' option can target a specific bookmark, regardless of whether a * human-readable interface has been designed. It allows developers to specify * a particular block by number. + * + * The '-E' option injects pipeline ready stage delays for the given object or + * bookmark. The delay is specified in milliseconds, and it supports I/O type + * and range filters. */ #include <errno.h> @@ -346,6 +352,13 @@ usage(void) "\t\tsuch that the operation takes a minimum of supplied seconds\n" "\t\tto complete.\n" "\n" + "\tzinject -E <delay> [-a] [-m] [-f freq] [-l level] [-r range]\n" + "\t\t[-T iotype] [-t type object | -b bookmark pool]\n" + "\n" + "\t\tInject pipeline ready stage delays for the given object path\n" + "\t\t(data or dnode) or raw bookmark. The delay is specified in\n" + "\t\tmilliseconds.\n" + "\n" "\tzinject -I [-s <seconds> | -g <txgs>] pool\n" "\t\tCause the pool to stop writing blocks yet not\n" "\t\treport errors for a duration. Simulates buggy hardware\n" @@ -724,12 +737,15 @@ register_handler(const char *pool, int flags, zinject_record_t *record, if (quiet) { (void) printf("%llu\n", (u_longlong_t)zc.zc_guid); } else { + boolean_t show_object = B_FALSE; + boolean_t show_iotype = B_FALSE; (void) printf("Added handler %llu with the following " "properties:\n", (u_longlong_t)zc.zc_guid); (void) printf(" pool: %s\n", pool); if (record->zi_guid) { (void) printf(" vdev: %llx\n", (u_longlong_t)record->zi_guid); + show_iotype = B_TRUE; } else if (record->zi_func[0] != '\0') { (void) printf(" panic function: %s\n", record->zi_func); @@ -742,7 +758,18 @@ register_handler(const char *pool, int flags, zinject_record_t *record, } else if (record->zi_timer > 0) { (void) printf(" timer: %lld ms\n", (u_longlong_t)NSEC2MSEC(record->zi_timer)); + if (record->zi_cmd == ZINJECT_DELAY_READY) { + show_object = B_TRUE; + show_iotype = B_TRUE; + } } else { + show_object = B_TRUE; + } + if (show_iotype) { + (void) printf("iotype: %s\n", + iotype_to_str(record->zi_iotype)); + } + if (show_object) { (void) printf("objset: %llu\n", (u_longlong_t)record->zi_objset); (void) printf("object: %llu\n", @@ -910,6 +937,7 @@ main(int argc, char **argv) int ret; int flags = 0; uint32_t dvas = 0; + hrtime_t ready_delay = -1; if ((g_zfs = libzfs_init()) == NULL) { (void) fprintf(stderr, "%s\n", libzfs_error_init(errno)); @@ -940,7 +968,7 @@ main(int argc, char **argv) } while ((c = getopt(argc, argv, - ":aA:b:C:d:D:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:P:")) != -1) { + ":aA:b:C:d:D:E:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:P:")) != -1) { switch (c) { case 'a': flags |= ZINJECT_FLUSH_ARC; @@ -1113,6 +1141,18 @@ main(int argc, char **argv) case 'u': flags |= ZINJECT_UNLOAD_SPA; break; + case 'E': + ready_delay = MSEC2NSEC(strtol(optarg, &end, 10)); + if (ready_delay <= 0 || *end != '\0') { + (void) fprintf(stderr, "invalid delay '%s': " + "must be a positive duration\n", optarg); + usage(); + libzfs_fini(g_zfs); + return (1); + } + record.zi_cmd = ZINJECT_DELAY_READY; + record.zi_timer = ready_delay; + break; case 'L': if ((label = name_to_type(optarg)) == TYPE_INVAL && !LABEL_TYPE(type)) { @@ -1150,7 +1190,7 @@ main(int argc, char **argv) */ if (raw != NULL || range != NULL || type != TYPE_INVAL || level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED || - record.zi_freq > 0 || dvas != 0) { + record.zi_freq > 0 || dvas != 0 || ready_delay >= 0) { (void) fprintf(stderr, "cancel (-c) incompatible with " "any other options\n"); usage(); @@ -1186,7 +1226,7 @@ main(int argc, char **argv) */ if (raw != NULL || range != NULL || type != TYPE_INVAL || level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED || - dvas != 0) { + dvas != 0 || ready_delay >= 0) { (void) fprintf(stderr, "device (-d) incompatible with " "data error injection\n"); usage(); @@ -1276,13 +1316,23 @@ main(int argc, char **argv) return (1); } - record.zi_cmd = ZINJECT_DATA_FAULT; + if (record.zi_cmd == ZINJECT_UNINITIALIZED) { + record.zi_cmd = ZINJECT_DATA_FAULT; + if (!error) + error = EIO; + } else if (error != 0) { + (void) fprintf(stderr, "error type -e incompatible " + "with delay injection\n"); + libzfs_fini(g_zfs); + return (1); + } else { + record.zi_iotype = io_type; + } + if (translate_raw(raw, &record) != 0) { libzfs_fini(g_zfs); return (1); } - if (!error) - error = EIO; } else if (record.zi_cmd == ZINJECT_PANIC) { if (raw != NULL || range != NULL || type != TYPE_INVAL || level != 0 || device != NULL || record.zi_freq > 0 || @@ -1410,6 +1460,13 @@ main(int argc, char **argv) record.zi_dvas = dvas; } + if (record.zi_cmd != ZINJECT_UNINITIALIZED && error != 0) { + (void) fprintf(stderr, "error type -e incompatible " + "with delay injection\n"); + libzfs_fini(g_zfs); + return (1); + } + if (error == EACCES) { if (type != TYPE_DATA) { (void) fprintf(stderr, "decryption errors " @@ -1425,8 +1482,12 @@ main(int argc, char **argv) * not found. */ error = ECKSUM; - } else { + } else if (record.zi_cmd == ZINJECT_UNINITIALIZED) { record.zi_cmd = ZINJECT_DATA_FAULT; + if (!error) + error = EIO; + } else { + record.zi_iotype = io_type; } if (translate_record(type, argv[0], range, level, &record, pool, @@ -1434,8 +1495,6 @@ main(int argc, char **argv) libzfs_fini(g_zfs); return (1); } - if (!error) - error = EIO; } /* diff --git a/sys/contrib/openzfs/cmd/zpool/zpool_iter.c b/sys/contrib/openzfs/cmd/zpool/zpool_iter.c index 2eec9a95e24c..fef602736705 100644 --- a/sys/contrib/openzfs/cmd/zpool/zpool_iter.c +++ b/sys/contrib/openzfs/cmd/zpool/zpool_iter.c @@ -26,6 +26,7 @@ /* * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>. + * Copyright (c) 2025, Klara, Inc. */ #include <libintl.h> @@ -52,7 +53,7 @@ typedef struct zpool_node { zpool_handle_t *zn_handle; uu_avl_node_t zn_avlnode; - int zn_mark; + hrtime_t zn_last_refresh; } zpool_node_t; struct zpool_list { @@ -62,6 +63,7 @@ struct zpool_list { uu_avl_pool_t *zl_pool; zprop_list_t **zl_proplist; zfs_type_t zl_type; + hrtime_t zl_last_refresh; }; static int @@ -81,26 +83,30 @@ zpool_compare(const void *larg, const void *rarg, void *unused) * of known pools. */ static int -add_pool(zpool_handle_t *zhp, void *data) +add_pool(zpool_handle_t *zhp, zpool_list_t *zlp) { - zpool_list_t *zlp = data; - zpool_node_t *node = safe_malloc(sizeof (zpool_node_t)); + zpool_node_t *node, *new = safe_malloc(sizeof (zpool_node_t)); uu_avl_index_t idx; - node->zn_handle = zhp; - uu_avl_node_init(node, &node->zn_avlnode, zlp->zl_pool); - if (uu_avl_find(zlp->zl_avl, node, NULL, &idx) == NULL) { + new->zn_handle = zhp; + uu_avl_node_init(new, &new->zn_avlnode, zlp->zl_pool); + + node = uu_avl_find(zlp->zl_avl, new, NULL, &idx); + if (node == NULL) { if (zlp->zl_proplist && zpool_expand_proplist(zhp, zlp->zl_proplist, zlp->zl_type, zlp->zl_literal) != 0) { zpool_close(zhp); - free(node); + free(new); return (-1); } - uu_avl_insert(zlp->zl_avl, node, idx); + new->zn_last_refresh = zlp->zl_last_refresh; + uu_avl_insert(zlp->zl_avl, new, idx); } else { + zpool_refresh_stats_from_handle(node->zn_handle, zhp); + node->zn_last_refresh = zlp->zl_last_refresh; zpool_close(zhp); - free(node); + free(new); return (-1); } @@ -108,6 +114,18 @@ add_pool(zpool_handle_t *zhp, void *data) } /* + * add_pool(), but always returns 0. This allows zpool_iter() to continue + * even if a pool exists in the tree, or we fail to get the properties for + * a new one. + */ +static int +add_pool_cb(zpool_handle_t *zhp, void *data) +{ + (void) add_pool(zhp, data); + return (0); +} + +/* * Create a list of pools based on the given arguments. If we're given no * arguments, then iterate over all pools in the system and add them to the AVL * tree. Otherwise, add only those pool explicitly specified on the command @@ -135,9 +153,10 @@ pool_list_get(int argc, char **argv, zprop_list_t **proplist, zfs_type_t type, zlp->zl_type = type; zlp->zl_literal = literal; + zlp->zl_last_refresh = gethrtime(); if (argc == 0) { - (void) zpool_iter(g_zfs, add_pool, zlp); + (void) zpool_iter(g_zfs, add_pool_cb, zlp); zlp->zl_findall = B_TRUE; } else { int i; @@ -159,15 +178,61 @@ pool_list_get(int argc, char **argv, zprop_list_t **proplist, zfs_type_t type, } /* - * Search for any new pools, adding them to the list. We only add pools when no - * options were given on the command line. Otherwise, we keep the list fixed as - * those that were explicitly specified. + * Refresh the state of all pools on the list. Additionally, if no options were + * given on the command line, add any new pools and remove any that are no + * longer available. */ -void -pool_list_update(zpool_list_t *zlp) +int +pool_list_refresh(zpool_list_t *zlp) { - if (zlp->zl_findall) - (void) zpool_iter(g_zfs, add_pool, zlp); + zlp->zl_last_refresh = gethrtime(); + + if (!zlp->zl_findall) { + /* + * This list is a fixed list of pools, so we must not add + * or remove any. Just walk over them and refresh their + * state. + */ + int navail = 0; + for (zpool_node_t *node = uu_avl_first(zlp->zl_avl); + node != NULL; node = uu_avl_next(zlp->zl_avl, node)) { + boolean_t missing; + zpool_refresh_stats(node->zn_handle, &missing); + navail += !missing; + node->zn_last_refresh = zlp->zl_last_refresh; + } + return (navail); + } + + /* Search for any new pools and add them to the list. */ + (void) zpool_iter(g_zfs, add_pool_cb, zlp); + + /* Walk the list of existing pools, and update or remove them. */ + zpool_node_t *node, *next; + for (node = uu_avl_first(zlp->zl_avl); node != NULL; node = next) { + next = uu_avl_next(zlp->zl_avl, node); + + /* + * Skip any that were refreshed and are online; they were added + * by zpool_iter() and are already up to date. + */ + if (node->zn_last_refresh == zlp->zl_last_refresh && + zpool_get_state(node->zn_handle) != POOL_STATE_UNAVAIL) + continue; + + /* Refresh and remove if necessary. */ + boolean_t missing; + zpool_refresh_stats(node->zn_handle, &missing); + if (missing) { + uu_avl_remove(zlp->zl_avl, node); + zpool_close(node->zn_handle); + free(node); + } else { + node->zn_last_refresh = zlp->zl_last_refresh; + } + } + + return (uu_avl_numnodes(zlp->zl_avl)); } /* @@ -191,23 +256,6 @@ pool_list_iter(zpool_list_t *zlp, int unavail, zpool_iter_f func, } /* - * Remove the given pool from the list. When running iostat, we want to remove - * those pools that no longer exist. - */ -void -pool_list_remove(zpool_list_t *zlp, zpool_handle_t *zhp) -{ - zpool_node_t search, *node; - - search.zn_handle = zhp; - if ((node = uu_avl_find(zlp->zl_avl, &search, NULL, NULL)) != NULL) { - uu_avl_remove(zlp->zl_avl, node); - zpool_close(node->zn_handle); - free(node); - } -} - -/* * Free all the handles associated with this list. */ void diff --git a/sys/contrib/openzfs/cmd/zpool/zpool_main.c b/sys/contrib/openzfs/cmd/zpool/zpool_main.c index 2c46ad0df895..1feec55c0e8b 100644 --- a/sys/contrib/openzfs/cmd/zpool/zpool_main.c +++ b/sys/contrib/openzfs/cmd/zpool/zpool_main.c @@ -33,7 +33,7 @@ * Copyright (c) 2017, Intel Corporation. * Copyright (c) 2019, loli10K <ezomori.nozomu@gmail.com> * Copyright (c) 2021, Colm Buckley <colm@tuatha.org> - * Copyright (c) 2021, 2023, Klara Inc. + * Copyright (c) 2021, 2023, 2025, Klara, Inc. * Copyright (c) 2021, 2025 Hewlett Packard Enterprise Development LP. */ @@ -5761,24 +5761,6 @@ children: return (ret); } -static int -refresh_iostat(zpool_handle_t *zhp, void *data) -{ - iostat_cbdata_t *cb = data; - boolean_t missing; - - /* - * If the pool has disappeared, remove it from the list and continue. - */ - if (zpool_refresh_stats(zhp, &missing) != 0) - return (-1); - - if (missing) - pool_list_remove(cb->cb_list, zhp); - - return (0); -} - /* * Callback to print out the iostats for the given pool. */ @@ -6359,15 +6341,14 @@ get_namewidth_iostat(zpool_handle_t *zhp, void *data) * This command can be tricky because we want to be able to deal with pool * creation/destruction as well as vdev configuration changes. The bulk of this * processing is handled by the pool_list_* routines in zpool_iter.c. We rely - * on pool_list_update() to detect the addition of new pools. Configuration - * changes are all handled within libzfs. + * on pool_list_refresh() to detect the addition and removal of pools. + * Configuration changes are all handled within libzfs. */ int zpool_do_iostat(int argc, char **argv) { int c; int ret; - int npools; float interval = 0; unsigned long count = 0; zpool_list_t *list; @@ -6618,10 +6599,24 @@ zpool_do_iostat(int argc, char **argv) return (1); } + int last_npools = 0; for (;;) { - if ((npools = pool_list_count(list)) == 0) + /* + * Refresh all pools in list, adding or removing pools as + * necessary. + */ + int npools = pool_list_refresh(list); + if (npools == 0) { (void) fprintf(stderr, gettext("no pools available\n")); - else { + } else { + /* + * If the list of pools has changed since last time + * around, reset the iteration count to force the + * header to be redisplayed. + */ + if (last_npools != npools) + cb.cb_iteration = 0; + /* * If this is the first iteration and -y was supplied * we skip any printing. @@ -6630,15 +6625,6 @@ zpool_do_iostat(int argc, char **argv) cb.cb_iteration == 0); /* - * Refresh all statistics. This is done as an - * explicit step before calculating the maximum name - * width, so that any * configuration changes are - * properly accounted for. - */ - (void) pool_list_iter(list, B_FALSE, refresh_iostat, - &cb); - - /* * Iterate over all pools to determine the maximum width * for the pool / device name column across all pools. */ @@ -6691,6 +6677,7 @@ zpool_do_iostat(int argc, char **argv) if (skip) { (void) fflush(stdout); (void) fsleep(interval); + last_npools = npools; continue; } @@ -6728,6 +6715,8 @@ zpool_do_iostat(int argc, char **argv) (void) fflush(stdout); (void) fsleep(interval); + + last_npools = npools; } pool_list_free(list); diff --git a/sys/contrib/openzfs/cmd/zpool/zpool_util.h b/sys/contrib/openzfs/cmd/zpool/zpool_util.h index 5ab7cb9750f1..3af23c52bd45 100644 --- a/sys/contrib/openzfs/cmd/zpool/zpool_util.h +++ b/sys/contrib/openzfs/cmd/zpool/zpool_util.h @@ -76,11 +76,10 @@ typedef struct zpool_list zpool_list_t; zpool_list_t *pool_list_get(int, char **, zprop_list_t **, zfs_type_t, boolean_t, int *); -void pool_list_update(zpool_list_t *); +int pool_list_refresh(zpool_list_t *); int pool_list_iter(zpool_list_t *, int unavail, zpool_iter_f, void *); void pool_list_free(zpool_list_t *); int pool_list_count(zpool_list_t *); -void pool_list_remove(zpool_list_t *, zpool_handle_t *); extern libzfs_handle_t *g_zfs; diff --git a/sys/contrib/openzfs/cmd/zpool/zpool_vdev.c b/sys/contrib/openzfs/cmd/zpool/zpool_vdev.c index 684b46a2d673..088c0108e911 100644 --- a/sys/contrib/openzfs/cmd/zpool/zpool_vdev.c +++ b/sys/contrib/openzfs/cmd/zpool/zpool_vdev.c @@ -609,22 +609,28 @@ get_replication(nvlist_t *nvroot, boolean_t fatal) ZPOOL_CONFIG_PATH, &path) == 0); /* + * Skip active spares they should never cause + * the pool to be evaluated as inconsistent. + */ + if (is_spare(NULL, path)) + continue; + + /* * If we have a raidz/mirror that combines disks - * with files, report it as an error. + * with files, only report it as an error when + * fatal is set to ensure all the replication + * checks aren't skipped in check_replication(). */ - if (!dontreport && type != NULL && + if (fatal && !dontreport && type != NULL && strcmp(type, childtype) != 0) { if (ret != NULL) free(ret); ret = NULL; - if (fatal) - vdev_error(gettext( - "mismatched replication " - "level: %s contains both " - "files and devices\n"), - rep.zprl_type); - else - return (NULL); + vdev_error(gettext( + "mismatched replication " + "level: %s contains both " + "files and devices\n"), + rep.zprl_type); dontreport = B_TRUE; } diff --git a/sys/contrib/openzfs/contrib/intel_qat/readme.md b/sys/contrib/openzfs/contrib/intel_qat/readme.md index 7e45d395bb80..04c299b6404c 100644 --- a/sys/contrib/openzfs/contrib/intel_qat/readme.md +++ b/sys/contrib/openzfs/contrib/intel_qat/readme.md @@ -8,7 +8,7 @@ This contrib contains community compatibility patches to get Intel QAT working o These patches are based on the following Intel QAT version: [1.7.l.4.10.0-00014](https://01.org/sites/default/files/downloads/qat1.7.l.4.10.0-00014.tar.gz) -When using QAT with above kernels versions, the following patches needs to be applied using: +When using QAT with the above kernel versions, the following patches need to be applied using: patch -p1 < _$PATCH_ _Where $PATCH refers to the path of the patch in question_ diff --git a/sys/contrib/openzfs/contrib/pyzfs/libzfs_core/test/test_libzfs_core.py b/sys/contrib/openzfs/contrib/pyzfs/libzfs_core/test/test_libzfs_core.py index 971aa1d0d493..bad1af2d1671 100644 --- a/sys/contrib/openzfs/contrib/pyzfs/libzfs_core/test/test_libzfs_core.py +++ b/sys/contrib/openzfs/contrib/pyzfs/libzfs_core/test/test_libzfs_core.py @@ -4223,7 +4223,7 @@ class _TempPool(object): self.getRoot().reset() return - # On the Buildbot builders this may fail with "pool is busy" + # On the CI builders this may fail with "pool is busy" # Retry 5 times before raising an error retry = 0 while True: diff --git a/sys/contrib/openzfs/etc/init.d/README.md b/sys/contrib/openzfs/etc/init.d/README.md index da780fdc1222..3852dd9a6b2e 100644 --- a/sys/contrib/openzfs/etc/init.d/README.md +++ b/sys/contrib/openzfs/etc/init.d/README.md @@ -1,5 +1,5 @@ DESCRIPTION - These script were written with the primary intention of being portable and + These scripts were written with the primary intention of being portable and usable on as many systems as possible. This is, in practice, usually not possible. But the intention is there. diff --git a/sys/contrib/openzfs/include/libzfs.h b/sys/contrib/openzfs/include/libzfs.h index 3fcdc176a621..14930fb90622 100644 --- a/sys/contrib/openzfs/include/libzfs.h +++ b/sys/contrib/openzfs/include/libzfs.h @@ -479,6 +479,8 @@ _LIBZFS_H zpool_status_t zpool_import_status(nvlist_t *, const char **, _LIBZFS_H nvlist_t *zpool_get_config(zpool_handle_t *, nvlist_t **); _LIBZFS_H nvlist_t *zpool_get_features(zpool_handle_t *); _LIBZFS_H int zpool_refresh_stats(zpool_handle_t *, boolean_t *); +_LIBZFS_H void zpool_refresh_stats_from_handle(zpool_handle_t *, + zpool_handle_t *); _LIBZFS_H int zpool_get_errlog(zpool_handle_t *, nvlist_t **); _LIBZFS_H void zpool_add_propname(zpool_handle_t *, const char *); diff --git a/sys/contrib/openzfs/include/os/linux/kernel/linux/blkdev_compat.h b/sys/contrib/openzfs/include/os/linux/kernel/linux/blkdev_compat.h index 076dab8ba6dc..214f3ea0e787 100644 --- a/sys/contrib/openzfs/include/os/linux/kernel/linux/blkdev_compat.h +++ b/sys/contrib/openzfs/include/os/linux/kernel/linux/blkdev_compat.h @@ -542,24 +542,6 @@ blk_generic_alloc_queue(make_request_fn make_request, int node_id) } #endif /* !HAVE_SUBMIT_BIO_IN_BLOCK_DEVICE_OPERATIONS */ -/* - * All the io_*() helper functions below can operate on a bio, or a rq, but - * not both. The older submit_bio() codepath will pass a bio, and the - * newer blk-mq codepath will pass a rq. - */ -static inline int -io_data_dir(struct bio *bio, struct request *rq) -{ - if (rq != NULL) { - if (op_is_write(req_op(rq))) { - return (WRITE); - } else { - return (READ); - } - } - return (bio_data_dir(bio)); -} - static inline int io_is_flush(struct bio *bio, struct request *rq) { diff --git a/sys/contrib/openzfs/include/sys/fs/zfs.h b/sys/contrib/openzfs/include/sys/fs/zfs.h index 49ab9d3db795..662fd81c5ee1 100644 --- a/sys/contrib/openzfs/include/sys/fs/zfs.h +++ b/sys/contrib/openzfs/include/sys/fs/zfs.h @@ -748,6 +748,8 @@ typedef struct zpool_load_policy { #define ZPOOL_CONFIG_METASLAB_SHIFT "metaslab_shift" #define ZPOOL_CONFIG_ASHIFT "ashift" #define ZPOOL_CONFIG_ASIZE "asize" +#define ZPOOL_CONFIG_MIN_ALLOC "min_alloc" +#define ZPOOL_CONFIG_MAX_ALLOC "max_alloc" #define ZPOOL_CONFIG_DTL "DTL" #define ZPOOL_CONFIG_SCAN_STATS "scan_stats" /* not stored on disk */ #define ZPOOL_CONFIG_REMOVAL_STATS "removal_stats" /* not stored on disk */ diff --git a/sys/contrib/openzfs/include/sys/range_tree.h b/sys/contrib/openzfs/include/sys/range_tree.h index 0f6884682459..0f6def36f9f6 100644 --- a/sys/contrib/openzfs/include/sys/range_tree.h +++ b/sys/contrib/openzfs/include/sys/range_tree.h @@ -238,8 +238,7 @@ zfs_rs_set_end_raw(zfs_range_seg_t *rs, zfs_range_tree_t *rt, uint64_t end) } static inline void -zfs_zfs_rs_set_fill_raw(zfs_range_seg_t *rs, zfs_range_tree_t *rt, - uint64_t fill) +zfs_rs_set_fill_raw(zfs_range_seg_t *rs, zfs_range_tree_t *rt, uint64_t fill) { ASSERT3U(rt->rt_type, <=, ZFS_RANGE_SEG_NUM_TYPES); switch (rt->rt_type) { @@ -277,7 +276,7 @@ static inline void zfs_rs_set_fill(zfs_range_seg_t *rs, zfs_range_tree_t *rt, uint64_t fill) { ASSERT(IS_P2ALIGNED(fill, 1ULL << rt->rt_shift)); - zfs_zfs_rs_set_fill_raw(rs, rt, fill >> rt->rt_shift); + zfs_rs_set_fill_raw(rs, rt, fill >> rt->rt_shift); } typedef void zfs_range_tree_func_t(void *arg, uint64_t start, uint64_t size); diff --git a/sys/contrib/openzfs/include/sys/spa.h b/sys/contrib/openzfs/include/sys/spa.h index 66db16b33c51..f172f2af6f07 100644 --- a/sys/contrib/openzfs/include/sys/spa.h +++ b/sys/contrib/openzfs/include/sys/spa.h @@ -1030,7 +1030,7 @@ extern void spa_import_progress_set_notes_nolog(spa_t *spa, extern int spa_config_tryenter(spa_t *spa, int locks, const void *tag, krw_t rw); extern void spa_config_enter(spa_t *spa, int locks, const void *tag, krw_t rw); -extern void spa_config_enter_mmp(spa_t *spa, int locks, const void *tag, +extern void spa_config_enter_priority(spa_t *spa, int locks, const void *tag, krw_t rw); extern void spa_config_exit(spa_t *spa, int locks, const void *tag); extern int spa_config_held(spa_t *spa, int locks, krw_t rw); @@ -1084,6 +1084,7 @@ extern pool_state_t spa_state(spa_t *spa); extern spa_load_state_t spa_load_state(spa_t *spa); extern uint64_t spa_freeze_txg(spa_t *spa); extern uint64_t spa_get_worst_case_asize(spa_t *spa, uint64_t lsize); +extern void spa_get_min_alloc_range(spa_t *spa, uint64_t *min, uint64_t *max); extern uint64_t spa_get_dspace(spa_t *spa); extern uint64_t spa_get_checkpoint_space(spa_t *spa); extern uint64_t spa_get_slop_space(spa_t *spa); diff --git a/sys/contrib/openzfs/include/sys/spa_impl.h b/sys/contrib/openzfs/include/sys/spa_impl.h index 07a959db3447..62b062984d36 100644 --- a/sys/contrib/openzfs/include/sys/spa_impl.h +++ b/sys/contrib/openzfs/include/sys/spa_impl.h @@ -265,6 +265,7 @@ struct spa { uint64_t spa_min_ashift; /* of vdevs in normal class */ uint64_t spa_max_ashift; /* of vdevs in normal class */ uint64_t spa_min_alloc; /* of vdevs in normal class */ + uint64_t spa_max_alloc; /* of vdevs in normal class */ uint64_t spa_gcd_alloc; /* of vdevs in normal class */ uint64_t spa_config_guid; /* config pool guid */ uint64_t spa_load_guid; /* spa_load initialized guid */ diff --git a/sys/contrib/openzfs/include/sys/zfs_ioctl.h b/sys/contrib/openzfs/include/sys/zfs_ioctl.h index 8174242abdac..cfe11f43bb8e 100644 --- a/sys/contrib/openzfs/include/sys/zfs_ioctl.h +++ b/sys/contrib/openzfs/include/sys/zfs_ioctl.h @@ -455,6 +455,7 @@ typedef enum zinject_type { ZINJECT_DECRYPT_FAULT, ZINJECT_DELAY_IMPORT, ZINJECT_DELAY_EXPORT, + ZINJECT_DELAY_READY, } zinject_type_t; typedef enum zinject_iotype { diff --git a/sys/contrib/openzfs/include/sys/zio.h b/sys/contrib/openzfs/include/sys/zio.h index a8acb83b4c2f..acb0a03a36b2 100644 --- a/sys/contrib/openzfs/include/sys/zio.h +++ b/sys/contrib/openzfs/include/sys/zio.h @@ -718,6 +718,7 @@ extern void zio_handle_ignored_writes(zio_t *zio); extern hrtime_t zio_handle_io_delay(zio_t *zio); extern void zio_handle_import_delay(spa_t *spa, hrtime_t elapsed); extern void zio_handle_export_delay(spa_t *spa, hrtime_t elapsed); +extern hrtime_t zio_handle_ready_delay(zio_t *zio); /* * Checksum ereport functions diff --git a/sys/contrib/openzfs/lib/libuutil/libuutil.abi b/sys/contrib/openzfs/lib/libuutil/libuutil.abi index 6c736c61e4a5..2a740afa07ca 100644 --- a/sys/contrib/openzfs/lib/libuutil/libuutil.abi +++ b/sys/contrib/openzfs/lib/libuutil/libuutil.abi @@ -616,6 +616,7 @@ <array-type-def dimensions='1' type-id='de572c22' size-in-bits='1472' id='6d3c2f42'> <subrange length='23' type-id='7359adad' id='fdd0f594'/> </array-type-def> + <type-decl name='long long int' size-in-bits='64' id='1eb56b1e'/> <array-type-def dimensions='1' type-id='3a47d82b' size-in-bits='256' id='a133ec23'> <subrange length='4' type-id='7359adad' id='16fe7105'/> </array-type-def> @@ -1020,13 +1021,6 @@ <array-type-def dimensions='1' type-id='03085adc' size-in-bits='192' id='083f8d58'> <subrange length='3' type-id='7359adad' id='56f209d2'/> </array-type-def> - <array-type-def dimensions='1' type-id='d315442e' size-in-bits='16' id='811205dc'> - <subrange length='1' type-id='7359adad' id='52f813b4'/> - </array-type-def> - <array-type-def dimensions='1' type-id='d3130597' size-in-bits='768' id='f63f23b9'> - <subrange length='12' type-id='7359adad' id='84827bdc'/> - </array-type-def> - <type-decl name='long long int' size-in-bits='64' id='1eb56b1e'/> <class-decl name='mnttab' size-in-bits='256' is-struct='yes' visibility='default' id='1b055409'> <data-member access='public' layout-offset-in-bits='0'> <var-decl name='mnt_special' type-id='26a90f95' visibility='default'/> @@ -1061,93 +1055,6 @@ <var-decl name='mnt_minor' type-id='3502e3ff' visibility='default'/> </data-member> </class-decl> - <typedef-decl name='__u16' type-id='8efea9e5' id='d315442e'/> - <typedef-decl name='__s32' type-id='95e97e5e' id='3158a266'/> - <typedef-decl name='__u32' type-id='f0981eeb' id='3f1a6b60'/> - <typedef-decl name='__s64' type-id='1eb56b1e' id='49659421'/> - <typedef-decl name='__u64' type-id='3a47d82b' id='d3130597'/> - <class-decl name='statx_timestamp' size-in-bits='128' is-struct='yes' visibility='default' id='94101016'> - <data-member access='public' layout-offset-in-bits='0'> - <var-decl name='tv_sec' type-id='49659421' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='64'> - <var-decl name='tv_nsec' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='96'> - <var-decl name='__reserved' type-id='3158a266' visibility='default'/> - </data-member> - </class-decl> - <class-decl name='statx' size-in-bits='2048' is-struct='yes' visibility='default' id='720b04c5'> - <data-member access='public' layout-offset-in-bits='0'> - <var-decl name='stx_mask' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='32'> - <var-decl name='stx_blksize' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='64'> - <var-decl name='stx_attributes' type-id='d3130597' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='128'> - <var-decl name='stx_nlink' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='160'> - <var-decl name='stx_uid' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='192'> - <var-decl name='stx_gid' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='224'> - <var-decl name='stx_mode' type-id='d315442e' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='240'> - <var-decl name='__spare0' type-id='811205dc' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='256'> - <var-decl name='stx_ino' type-id='d3130597' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='320'> - <var-decl name='stx_size' type-id='d3130597' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='384'> - <var-decl name='stx_blocks' type-id='d3130597' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='448'> - <var-decl name='stx_attributes_mask' type-id='d3130597' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='512'> - <var-decl name='stx_atime' type-id='94101016' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='640'> - <var-decl name='stx_btime' type-id='94101016' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='768'> - <var-decl name='stx_ctime' type-id='94101016' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='896'> - <var-decl name='stx_mtime' type-id='94101016' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='1024'> - <var-decl name='stx_rdev_major' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='1056'> - <var-decl name='stx_rdev_minor' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='1088'> - <var-decl name='stx_dev_major' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='1120'> - <var-decl name='stx_dev_minor' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='1152'> - <var-decl name='stx_mnt_id' type-id='d3130597' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='1216'> - <var-decl name='__spare2' type-id='d3130597' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='1280'> - <var-decl name='__spare3' type-id='f63f23b9' visibility='default'/> - </data-member> - </class-decl> <class-decl name='mntent' size-in-bits='320' is-struct='yes' visibility='default' id='56fe4a37'> <data-member access='public' layout-offset-in-bits='0'> <var-decl name='mnt_fsname' type-id='26a90f95' visibility='default'/> @@ -1237,8 +1144,6 @@ <pointer-type-def type-id='1b055409' size-in-bits='64' id='9d424d31'/> <pointer-type-def type-id='0bbec9cd' size-in-bits='64' id='62f7a03d'/> <qualified-type-def type-id='62f7a03d' restrict='yes' id='f1cadedf'/> - <pointer-type-def type-id='720b04c5' size-in-bits='64' id='936b8e35'/> - <qualified-type-def type-id='936b8e35' restrict='yes' id='31d265b7'/> <function-decl name='getmntent_r' visibility='default' binding='global' size-in-bits='64'> <parameter type-id='e75a27e9'/> <parameter type-id='3cad23cd'/> @@ -1254,14 +1159,6 @@ <parameter type-id='95e97e5e'/> <return type-id='26a90f95'/> </function-decl> - <function-decl name='statx' visibility='default' binding='global' size-in-bits='64'> - <parameter type-id='95e97e5e'/> - <parameter type-id='9d26089a'/> - <parameter type-id='95e97e5e'/> - <parameter type-id='f0981eeb'/> - <parameter type-id='31d265b7'/> - <return type-id='95e97e5e'/> - </function-decl> <function-decl name='__fprintf_chk' visibility='default' binding='global' size-in-bits='64'> <parameter type-id='e75a27e9'/> <parameter type-id='95e97e5e'/> diff --git a/sys/contrib/openzfs/lib/libzfs/libzfs.abi b/sys/contrib/openzfs/lib/libzfs/libzfs.abi index 184ea4a55b43..f988d27a286a 100644 --- a/sys/contrib/openzfs/lib/libzfs/libzfs.abi +++ b/sys/contrib/openzfs/lib/libzfs/libzfs.abi @@ -571,6 +571,7 @@ <elf-symbol name='zpool_props_refresh' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_read_label' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_refresh_stats' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='zpool_refresh_stats_from_handle' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_reguid' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_reopen_one' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zpool_scan' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> @@ -641,7 +642,7 @@ <elf-symbol name='sa_protocol_names' size='16' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='spa_feature_table' size='2632' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zfeature_checks_disable' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> - <elf-symbol name='zfs_deleg_perm_tab' size='528' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='zfs_deleg_perm_tab' size='544' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zfs_history_event_names' size='328' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zfs_max_dataset_nesting' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> <elf-symbol name='zfs_userquota_prop_prefixes' size='96' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> @@ -1458,103 +1459,8 @@ </function-decl> </abi-instr> <abi-instr address-size='64' path='lib/libspl/os/linux/getmntany.c' language='LANG_C99'> - <array-type-def dimensions='1' type-id='d315442e' size-in-bits='16' id='811205dc'> - <subrange length='1' type-id='7359adad' id='52f813b4'/> - </array-type-def> - <array-type-def dimensions='1' type-id='d3130597' size-in-bits='768' id='f63f23b9'> - <subrange length='12' type-id='7359adad' id='84827bdc'/> - </array-type-def> - <typedef-decl name='__u16' type-id='8efea9e5' id='d315442e'/> - <typedef-decl name='__s32' type-id='95e97e5e' id='3158a266'/> - <typedef-decl name='__u32' type-id='f0981eeb' id='3f1a6b60'/> - <typedef-decl name='__s64' type-id='1eb56b1e' id='49659421'/> - <typedef-decl name='__u64' type-id='3a47d82b' id='d3130597'/> - <class-decl name='statx_timestamp' size-in-bits='128' is-struct='yes' visibility='default' id='94101016'> - <data-member access='public' layout-offset-in-bits='0'> - <var-decl name='tv_sec' type-id='49659421' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='64'> - <var-decl name='tv_nsec' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='96'> - <var-decl name='__reserved' type-id='3158a266' visibility='default'/> - </data-member> - </class-decl> - <class-decl name='statx' size-in-bits='2048' is-struct='yes' visibility='default' id='720b04c5'> - <data-member access='public' layout-offset-in-bits='0'> - <var-decl name='stx_mask' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='32'> - <var-decl name='stx_blksize' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='64'> - <var-decl name='stx_attributes' type-id='d3130597' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='128'> - <var-decl name='stx_nlink' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='160'> - <var-decl name='stx_uid' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='192'> - <var-decl name='stx_gid' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='224'> - <var-decl name='stx_mode' type-id='d315442e' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='240'> - <var-decl name='__spare0' type-id='811205dc' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='256'> - <var-decl name='stx_ino' type-id='d3130597' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='320'> - <var-decl name='stx_size' type-id='d3130597' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='384'> - <var-decl name='stx_blocks' type-id='d3130597' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='448'> - <var-decl name='stx_attributes_mask' type-id='d3130597' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='512'> - <var-decl name='stx_atime' type-id='94101016' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='640'> - <var-decl name='stx_btime' type-id='94101016' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='768'> - <var-decl name='stx_ctime' type-id='94101016' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='896'> - <var-decl name='stx_mtime' type-id='94101016' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='1024'> - <var-decl name='stx_rdev_major' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='1056'> - <var-decl name='stx_rdev_minor' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='1088'> - <var-decl name='stx_dev_major' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='1120'> - <var-decl name='stx_dev_minor' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='1152'> - <var-decl name='stx_mnt_id' type-id='d3130597' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='1216'> - <var-decl name='__spare2' type-id='d3130597' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='1280'> - <var-decl name='__spare3' type-id='f63f23b9' visibility='default'/> - </data-member> - </class-decl> <pointer-type-def type-id='56fe4a37' size-in-bits='64' id='b6b61d2f'/> <qualified-type-def type-id='b6b61d2f' restrict='yes' id='3cad23cd'/> - <pointer-type-def type-id='720b04c5' size-in-bits='64' id='936b8e35'/> - <qualified-type-def type-id='936b8e35' restrict='yes' id='31d265b7'/> <function-decl name='getmntent_r' visibility='default' binding='global' size-in-bits='64'> <parameter type-id='e75a27e9'/> <parameter type-id='3cad23cd'/> @@ -1566,14 +1472,6 @@ <parameter type-id='822cd80b'/> <return type-id='95e97e5e'/> </function-decl> - <function-decl name='statx' visibility='default' binding='global' size-in-bits='64'> - <parameter type-id='95e97e5e'/> - <parameter type-id='9d26089a'/> - <parameter type-id='95e97e5e'/> - <parameter type-id='f0981eeb'/> - <parameter type-id='31d265b7'/> - <return type-id='95e97e5e'/> - </function-decl> </abi-instr> <abi-instr address-size='64' path='lib/libspl/timestamp.c' language='LANG_C99'> <typedef-decl name='nl_item' type-id='95e97e5e' id='03b79a94'/> @@ -3194,6 +3092,10 @@ <parameter type-id='dace003f'/> <return type-id='80f4b756'/> </function-decl> + <function-decl name='fnvlist_dup' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='22cce67b'/> + <return type-id='5ce45b60'/> + </function-decl> <function-decl name='fnvpair_value_nvlist' visibility='default' binding='global' size-in-bits='64'> <parameter type-id='3fa542f0'/> <return type-id='5ce45b60'/> @@ -3238,6 +3140,11 @@ <parameter type-id='37e3bd22' name='missing'/> <return type-id='95e97e5e'/> </function-decl> + <function-decl name='zpool_refresh_stats_from_handle' mangled-name='zpool_refresh_stats_from_handle' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_refresh_stats_from_handle'> + <parameter type-id='4c81de99' name='dzhp'/> + <parameter type-id='4c81de99' name='szhp'/> + <return type-id='48b5725f'/> + </function-decl> <function-decl name='zpool_skip_pool' mangled-name='zpool_skip_pool' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_skip_pool'> <parameter type-id='80f4b756' name='poolname'/> <return type-id='c19b74c3'/> @@ -9398,10 +9305,6 @@ <parameter type-id='5ce45b60'/> <return type-id='48b5725f'/> </function-decl> - <function-decl name='fnvlist_dup' visibility='default' binding='global' size-in-bits='64'> - <parameter type-id='22cce67b'/> - <return type-id='5ce45b60'/> - </function-decl> <function-decl name='spl_pagesize' mangled-name='spl_pagesize' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='spl_pagesize'> <return type-id='b59d7dce'/> </function-decl> @@ -9774,8 +9677,8 @@ </function-decl> </abi-instr> <abi-instr address-size='64' path='module/zcommon/zfs_deleg.c' language='LANG_C99'> - <array-type-def dimensions='1' type-id='fa1870fd' size-in-bits='4224' id='55e705e7'> - <subrange length='33' type-id='7359adad' id='6a5934df'/> + <array-type-def dimensions='1' type-id='fa1870fd' size-in-bits='4352' id='55f84f08'> + <subrange length='34' type-id='7359adad' id='6a6a7e00'/> </array-type-def> <array-type-def dimensions='1' type-id='fa1870fd' size-in-bits='infinite' id='7c00e69d'> <subrange length='infinite' id='031f2035'/> @@ -9805,30 +9708,31 @@ <enumerator name='ZFS_DELEG_NOTE_PROMOTE' value='5'/> <enumerator name='ZFS_DELEG_NOTE_RENAME' value='6'/> <enumerator name='ZFS_DELEG_NOTE_SEND' value='7'/> - <enumerator name='ZFS_DELEG_NOTE_RECEIVE' value='8'/> - <enumerator name='ZFS_DELEG_NOTE_ALLOW' value='9'/> - <enumerator name='ZFS_DELEG_NOTE_USERPROP' value='10'/> - <enumerator name='ZFS_DELEG_NOTE_MOUNT' value='11'/> - <enumerator name='ZFS_DELEG_NOTE_SHARE' value='12'/> - <enumerator name='ZFS_DELEG_NOTE_USERQUOTA' value='13'/> - <enumerator name='ZFS_DELEG_NOTE_GROUPQUOTA' value='14'/> - <enumerator name='ZFS_DELEG_NOTE_USERUSED' value='15'/> - <enumerator name='ZFS_DELEG_NOTE_GROUPUSED' value='16'/> - <enumerator name='ZFS_DELEG_NOTE_USEROBJQUOTA' value='17'/> - <enumerator name='ZFS_DELEG_NOTE_GROUPOBJQUOTA' value='18'/> - <enumerator name='ZFS_DELEG_NOTE_USEROBJUSED' value='19'/> - <enumerator name='ZFS_DELEG_NOTE_GROUPOBJUSED' value='20'/> - <enumerator name='ZFS_DELEG_NOTE_HOLD' value='21'/> - <enumerator name='ZFS_DELEG_NOTE_RELEASE' value='22'/> - <enumerator name='ZFS_DELEG_NOTE_DIFF' value='23'/> - <enumerator name='ZFS_DELEG_NOTE_BOOKMARK' value='24'/> - <enumerator name='ZFS_DELEG_NOTE_LOAD_KEY' value='25'/> - <enumerator name='ZFS_DELEG_NOTE_CHANGE_KEY' value='26'/> - <enumerator name='ZFS_DELEG_NOTE_PROJECTUSED' value='27'/> - <enumerator name='ZFS_DELEG_NOTE_PROJECTQUOTA' value='28'/> - <enumerator name='ZFS_DELEG_NOTE_PROJECTOBJUSED' value='29'/> - <enumerator name='ZFS_DELEG_NOTE_PROJECTOBJQUOTA' value='30'/> - <enumerator name='ZFS_DELEG_NOTE_NONE' value='31'/> + <enumerator name='ZFS_DELEG_NOTE_SEND_RAW' value='8'/> + <enumerator name='ZFS_DELEG_NOTE_RECEIVE' value='9'/> + <enumerator name='ZFS_DELEG_NOTE_ALLOW' value='10'/> + <enumerator name='ZFS_DELEG_NOTE_USERPROP' value='11'/> + <enumerator name='ZFS_DELEG_NOTE_MOUNT' value='12'/> + <enumerator name='ZFS_DELEG_NOTE_SHARE' value='13'/> + <enumerator name='ZFS_DELEG_NOTE_USERQUOTA' value='14'/> + <enumerator name='ZFS_DELEG_NOTE_GROUPQUOTA' value='15'/> + <enumerator name='ZFS_DELEG_NOTE_USERUSED' value='16'/> + <enumerator name='ZFS_DELEG_NOTE_GROUPUSED' value='17'/> + <enumerator name='ZFS_DELEG_NOTE_USEROBJQUOTA' value='18'/> + <enumerator name='ZFS_DELEG_NOTE_GROUPOBJQUOTA' value='19'/> + <enumerator name='ZFS_DELEG_NOTE_USEROBJUSED' value='20'/> + <enumerator name='ZFS_DELEG_NOTE_GROUPOBJUSED' value='21'/> + <enumerator name='ZFS_DELEG_NOTE_HOLD' value='22'/> + <enumerator name='ZFS_DELEG_NOTE_RELEASE' value='23'/> + <enumerator name='ZFS_DELEG_NOTE_DIFF' value='24'/> + <enumerator name='ZFS_DELEG_NOTE_BOOKMARK' value='25'/> + <enumerator name='ZFS_DELEG_NOTE_LOAD_KEY' value='26'/> + <enumerator name='ZFS_DELEG_NOTE_CHANGE_KEY' value='27'/> + <enumerator name='ZFS_DELEG_NOTE_PROJECTUSED' value='28'/> + <enumerator name='ZFS_DELEG_NOTE_PROJECTQUOTA' value='29'/> + <enumerator name='ZFS_DELEG_NOTE_PROJECTOBJUSED' value='30'/> + <enumerator name='ZFS_DELEG_NOTE_PROJECTOBJQUOTA' value='31'/> + <enumerator name='ZFS_DELEG_NOTE_NONE' value='32'/> </enum-decl> <typedef-decl name='zfs_deleg_note_t' type-id='729d4547' id='4613c173'/> <class-decl name='zfs_deleg_perm_tab' size-in-bits='128' is-struct='yes' visibility='default' id='5aa05c1f'> diff --git a/sys/contrib/openzfs/lib/libzfs/libzfs_config.c b/sys/contrib/openzfs/lib/libzfs/libzfs_config.c index 0d2102191389..9d704e4303ff 100644 --- a/sys/contrib/openzfs/lib/libzfs/libzfs_config.c +++ b/sys/contrib/openzfs/lib/libzfs/libzfs_config.c @@ -308,6 +308,23 @@ zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing) } /* + * Copies the pool config and state from szhp to dzhp. szhp and dzhp must + * represent the same pool. Used by pool_list_refresh() to avoid another + * round-trip into the kernel to get stats already collected earlier in the + * function. + */ +void +zpool_refresh_stats_from_handle(zpool_handle_t *dzhp, zpool_handle_t *szhp) +{ + VERIFY0(strcmp(dzhp->zpool_name, szhp->zpool_name)); + nvlist_free(dzhp->zpool_old_config); + dzhp->zpool_old_config = dzhp->zpool_config; + dzhp->zpool_config = fnvlist_dup(szhp->zpool_config); + dzhp->zpool_config_size = szhp->zpool_config_size; + dzhp->zpool_state = szhp->zpool_state; +} + +/* * The following environment variables are undocumented * and should be used for testing purposes only: * diff --git a/sys/contrib/openzfs/lib/libzfs_core/libzfs_core.abi b/sys/contrib/openzfs/lib/libzfs_core/libzfs_core.abi index 7464b3adb254..263cad045f7a 100644 --- a/sys/contrib/openzfs/lib/libzfs_core/libzfs_core.abi +++ b/sys/contrib/openzfs/lib/libzfs_core/libzfs_core.abi @@ -617,6 +617,7 @@ <array-type-def dimensions='1' type-id='de572c22' size-in-bits='1472' id='6d3c2f42'> <subrange length='23' type-id='7359adad' id='fdd0f594'/> </array-type-def> + <type-decl name='long long int' size-in-bits='64' id='1eb56b1e'/> <array-type-def dimensions='1' type-id='3a47d82b' size-in-bits='256' id='a133ec23'> <subrange length='4' type-id='7359adad' id='16fe7105'/> </array-type-def> @@ -988,13 +989,6 @@ </function-decl> </abi-instr> <abi-instr address-size='64' path='lib/libspl/os/linux/getmntany.c' language='LANG_C99'> - <array-type-def dimensions='1' type-id='d315442e' size-in-bits='16' id='811205dc'> - <subrange length='1' type-id='7359adad' id='52f813b4'/> - </array-type-def> - <array-type-def dimensions='1' type-id='d3130597' size-in-bits='768' id='f63f23b9'> - <subrange length='12' type-id='7359adad' id='84827bdc'/> - </array-type-def> - <type-decl name='long long int' size-in-bits='64' id='1eb56b1e'/> <class-decl name='mnttab' size-in-bits='256' is-struct='yes' visibility='default' id='1b055409'> <data-member access='public' layout-offset-in-bits='0'> <var-decl name='mnt_special' type-id='26a90f95' visibility='default'/> @@ -1029,93 +1023,6 @@ <var-decl name='mnt_minor' type-id='3502e3ff' visibility='default'/> </data-member> </class-decl> - <typedef-decl name='__u16' type-id='8efea9e5' id='d315442e'/> - <typedef-decl name='__s32' type-id='95e97e5e' id='3158a266'/> - <typedef-decl name='__u32' type-id='f0981eeb' id='3f1a6b60'/> - <typedef-decl name='__s64' type-id='1eb56b1e' id='49659421'/> - <typedef-decl name='__u64' type-id='3a47d82b' id='d3130597'/> - <class-decl name='statx_timestamp' size-in-bits='128' is-struct='yes' visibility='default' id='94101016'> - <data-member access='public' layout-offset-in-bits='0'> - <var-decl name='tv_sec' type-id='49659421' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='64'> - <var-decl name='tv_nsec' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='96'> - <var-decl name='__reserved' type-id='3158a266' visibility='default'/> - </data-member> - </class-decl> - <class-decl name='statx' size-in-bits='2048' is-struct='yes' visibility='default' id='720b04c5'> - <data-member access='public' layout-offset-in-bits='0'> - <var-decl name='stx_mask' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='32'> - <var-decl name='stx_blksize' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='64'> - <var-decl name='stx_attributes' type-id='d3130597' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='128'> - <var-decl name='stx_nlink' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='160'> - <var-decl name='stx_uid' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='192'> - <var-decl name='stx_gid' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='224'> - <var-decl name='stx_mode' type-id='d315442e' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='240'> - <var-decl name='__spare0' type-id='811205dc' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='256'> - <var-decl name='stx_ino' type-id='d3130597' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='320'> - <var-decl name='stx_size' type-id='d3130597' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='384'> - <var-decl name='stx_blocks' type-id='d3130597' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='448'> - <var-decl name='stx_attributes_mask' type-id='d3130597' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='512'> - <var-decl name='stx_atime' type-id='94101016' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='640'> - <var-decl name='stx_btime' type-id='94101016' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='768'> - <var-decl name='stx_ctime' type-id='94101016' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='896'> - <var-decl name='stx_mtime' type-id='94101016' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='1024'> - <var-decl name='stx_rdev_major' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='1056'> - <var-decl name='stx_rdev_minor' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='1088'> - <var-decl name='stx_dev_major' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='1120'> - <var-decl name='stx_dev_minor' type-id='3f1a6b60' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='1152'> - <var-decl name='stx_mnt_id' type-id='d3130597' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='1216'> - <var-decl name='__spare2' type-id='d3130597' visibility='default'/> - </data-member> - <data-member access='public' layout-offset-in-bits='1280'> - <var-decl name='__spare3' type-id='f63f23b9' visibility='default'/> - </data-member> - </class-decl> <class-decl name='mntent' size-in-bits='320' is-struct='yes' visibility='default' id='56fe4a37'> <data-member access='public' layout-offset-in-bits='0'> <var-decl name='mnt_fsname' type-id='26a90f95' visibility='default'/> @@ -1191,8 +1098,6 @@ <pointer-type-def type-id='1b055409' size-in-bits='64' id='9d424d31'/> <pointer-type-def type-id='0bbec9cd' size-in-bits='64' id='62f7a03d'/> <qualified-type-def type-id='62f7a03d' restrict='yes' id='f1cadedf'/> - <pointer-type-def type-id='720b04c5' size-in-bits='64' id='936b8e35'/> - <qualified-type-def type-id='936b8e35' restrict='yes' id='31d265b7'/> <function-decl name='getmntent_r' visibility='default' binding='global' size-in-bits='64'> <parameter type-id='e75a27e9'/> <parameter type-id='3cad23cd'/> @@ -1208,14 +1113,6 @@ <parameter type-id='95e97e5e'/> <return type-id='26a90f95'/> </function-decl> - <function-decl name='statx' visibility='default' binding='global' size-in-bits='64'> - <parameter type-id='95e97e5e'/> - <parameter type-id='9d26089a'/> - <parameter type-id='95e97e5e'/> - <parameter type-id='f0981eeb'/> - <parameter type-id='31d265b7'/> - <return type-id='95e97e5e'/> - </function-decl> <function-decl name='stat64' visibility='default' binding='global' size-in-bits='64'> <parameter type-id='9d26089a'/> <parameter type-id='f1cadedf'/> diff --git a/sys/contrib/openzfs/man/man8/zinject.8 b/sys/contrib/openzfs/man/man8/zinject.8 index 1d9e43aed5ec..704f6a7accd8 100644 --- a/sys/contrib/openzfs/man/man8/zinject.8 +++ b/sys/contrib/openzfs/man/man8/zinject.8 @@ -138,6 +138,20 @@ This injector is automatically cleared after the import is finished. . .It Xo .Nm zinject +.Fl E Ar delay +.Op Fl a +.Op Fl m +.Op Fl f Ar freq +.Op Fl l Ar level +.Op Fl r Ar range +.Op Fl T Ar iotype +.Op Fl t Ar type Ns | Ns Fl b Ar bookmark +.Xc +Inject pipeline ready stage delays for the given object or bookmark. +The delay is specified in milliseconds. +. +.It Xo +.Nm zinject .Fl I .Op Fl s Ar seconds Ns | Ns Fl g Ar txgs .Ar pool diff --git a/sys/contrib/openzfs/man/man8/zpool-upgrade.8 b/sys/contrib/openzfs/man/man8/zpool-upgrade.8 index cf69060da5ce..adae47f82eb1 100644 --- a/sys/contrib/openzfs/man/man8/zpool-upgrade.8 +++ b/sys/contrib/openzfs/man/man8/zpool-upgrade.8 @@ -65,10 +65,10 @@ property). .Cm upgrade .Fl v .Xc -Displays legacy ZFS versions supported by the this version of ZFS. +Displays legacy ZFS versions supported by this version of ZFS. See .Xr zpool-features 7 -for a description of feature flags features supported by this version of ZFS. +for a description of features supported by this version of ZFS. .It Xo .Nm zpool .Cm upgrade diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zvol_os.c b/sys/contrib/openzfs/module/os/linux/zfs/zvol_os.c index bac166fcd89e..967a018640e1 100644 --- a/sys/contrib/openzfs/module/os/linux/zfs/zvol_os.c +++ b/sys/contrib/openzfs/module/os/linux/zfs/zvol_os.c @@ -484,7 +484,28 @@ zvol_request_impl(zvol_state_t *zv, struct bio *bio, struct request *rq, fstrans_cookie_t cookie = spl_fstrans_mark(); uint64_t offset = io_offset(bio, rq); uint64_t size = io_size(bio, rq); - int rw = io_data_dir(bio, rq); + int rw; + + if (rq != NULL) { + /* + * Flush & trim requests go down the zvol_write codepath. Or + * more specifically: + * + * If request is a write, or if it's op_is_sync() and not a + * read, or if it's a flush, or if it's a discard, then send the + * request down the write path. + */ + if (op_is_write(rq->cmd_flags) || + (op_is_sync(rq->cmd_flags) && req_op(rq) != REQ_OP_READ) || + req_op(rq) == REQ_OP_FLUSH || + op_is_discard(rq->cmd_flags)) { + rw = WRITE; + } else { + rw = READ; + } + } else { + rw = bio_data_dir(bio); + } if (unlikely(zv->zv_flags & ZVOL_REMOVING)) { zvol_end_io(bio, rq, SET_ERROR(ENXIO)); diff --git a/sys/contrib/openzfs/module/zcommon/zfs_prop.c b/sys/contrib/openzfs/module/zcommon/zfs_prop.c index 864e3898b365..9190ae0362ea 100644 --- a/sys/contrib/openzfs/module/zcommon/zfs_prop.c +++ b/sys/contrib/openzfs/module/zcommon/zfs_prop.c @@ -364,8 +364,8 @@ zfs_prop_init(void) static const zprop_index_t xattr_table[] = { { "off", ZFS_XATTR_OFF }, - { "on", ZFS_XATTR_SA }, { "sa", ZFS_XATTR_SA }, + { "on", ZFS_XATTR_SA }, { "dir", ZFS_XATTR_DIR }, { NULL } }; diff --git a/sys/contrib/openzfs/module/zfs/dnode.c b/sys/contrib/openzfs/module/zfs/dnode.c index 6c150d31c669..e88d394b5229 100644 --- a/sys/contrib/openzfs/module/zfs/dnode.c +++ b/sys/contrib/openzfs/module/zfs/dnode.c @@ -2656,6 +2656,32 @@ dnode_next_offset_level(dnode_t *dn, int flags, uint64_t *offset, } /* + * Adjust *offset to the next (or previous) block byte offset at lvl. + * Returns FALSE if *offset would overflow or underflow. + */ +static boolean_t +dnode_next_block(dnode_t *dn, int flags, uint64_t *offset, int lvl) +{ + int epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT; + int span = lvl * epbs + dn->dn_datablkshift; + uint64_t blkid, maxblkid; + + if (span >= 8 * sizeof (uint64_t)) + return (B_FALSE); + + blkid = *offset >> span; + maxblkid = 1ULL << (8 * sizeof (*offset) - span); + if (!(flags & DNODE_FIND_BACKWARDS) && blkid + 1 < maxblkid) + *offset = (blkid + 1) << span; + else if ((flags & DNODE_FIND_BACKWARDS) && blkid > 0) + *offset = (blkid << span) - 1; + else + return (B_FALSE); + + return (B_TRUE); +} + +/* * Find the next hole, data, or sparse region at or after *offset. * The value 'blkfill' tells us how many items we expect to find * in an L0 data block; this value is 1 for normal objects, @@ -2682,7 +2708,7 @@ int dnode_next_offset(dnode_t *dn, int flags, uint64_t *offset, int minlvl, uint64_t blkfill, uint64_t txg) { - uint64_t initial_offset = *offset; + uint64_t matched = *offset; int lvl, maxlvl; int error = 0; @@ -2706,16 +2732,36 @@ dnode_next_offset(dnode_t *dn, int flags, uint64_t *offset, maxlvl = dn->dn_phys->dn_nlevels; - for (lvl = minlvl; lvl <= maxlvl; lvl++) { + for (lvl = minlvl; lvl <= maxlvl; ) { error = dnode_next_offset_level(dn, flags, offset, lvl, blkfill, txg); - if (error != ESRCH) + if (error == 0 && lvl > minlvl) { + --lvl; + matched = *offset; + } else if (error == ESRCH && lvl < maxlvl && + dnode_next_block(dn, flags, &matched, lvl)) { + /* + * Continue search at next/prev offset in lvl+1 block. + * + * Usually we only search upwards at the start of the + * search as higher level blocks point at a matching + * minlvl block in most cases, but we backtrack if not. + * + * This can happen for txg > 0 searches if the block + * contains only BPs/dnodes freed at that txg. It also + * happens if we are still syncing out the tree, and + * some BP's at higher levels are not updated yet. + * + * We must adjust offset to avoid coming back to the + * same offset and getting stuck looping forever. This + * also deals with the case where offset is already at + * the beginning or end of the object. + */ + ++lvl; + *offset = matched; + } else { break; - } - - while (error == 0 && --lvl >= minlvl) { - error = dnode_next_offset_level(dn, - flags, offset, lvl, blkfill, txg); + } } /* @@ -2727,9 +2773,6 @@ dnode_next_offset(dnode_t *dn, int flags, uint64_t *offset, error = 0; } - if (error == 0 && (flags & DNODE_FIND_BACKWARDS ? - initial_offset < *offset : initial_offset > *offset)) - error = SET_ERROR(ESRCH); out: if (!(flags & DNODE_FIND_HAVELOCK)) rw_exit(&dn->dn_struct_rwlock); diff --git a/sys/contrib/openzfs/module/zfs/mmp.c b/sys/contrib/openzfs/module/zfs/mmp.c index 7db72b9b04b0..fd46127b6068 100644 --- a/sys/contrib/openzfs/module/zfs/mmp.c +++ b/sys/contrib/openzfs/module/zfs/mmp.c @@ -446,7 +446,7 @@ mmp_write_uberblock(spa_t *spa) uint64_t offset; hrtime_t lock_acquire_time = gethrtime(); - spa_config_enter_mmp(spa, SCL_STATE, mmp_tag, RW_READER); + spa_config_enter_priority(spa, SCL_STATE, mmp_tag, RW_READER); lock_acquire_time = gethrtime() - lock_acquire_time; if (lock_acquire_time > (MSEC2NSEC(MMP_MIN_INTERVAL) / 10)) zfs_dbgmsg("MMP SCL_STATE acquisition pool '%s' took %llu ns " diff --git a/sys/contrib/openzfs/module/zfs/range_tree.c b/sys/contrib/openzfs/module/zfs/range_tree.c index ea2d2c7227c8..d73195f1a21f 100644 --- a/sys/contrib/openzfs/module/zfs/range_tree.c +++ b/sys/contrib/openzfs/module/zfs/range_tree.c @@ -585,7 +585,7 @@ zfs_range_tree_remove_impl(zfs_range_tree_t *rt, uint64_t start, uint64_t size, * the size, since we do not support removing partial segments * of range trees with gaps. */ - zfs_zfs_rs_set_fill_raw(rs, rt, zfs_rs_get_end_raw(rs, rt) - + zfs_rs_set_fill_raw(rs, rt, zfs_rs_get_end_raw(rs, rt) - zfs_rs_get_start_raw(rs, rt)); zfs_range_tree_stat_incr(rt, &rs_tmp); diff --git a/sys/contrib/openzfs/module/zfs/spa_config.c b/sys/contrib/openzfs/module/zfs/spa_config.c index cf28955b0c50..f615591e826b 100644 --- a/sys/contrib/openzfs/module/zfs/spa_config.c +++ b/sys/contrib/openzfs/module/zfs/spa_config.c @@ -372,6 +372,8 @@ spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats) fnvlist_add_uint64(config, ZPOOL_CONFIG_POOL_TXG, txg); fnvlist_add_uint64(config, ZPOOL_CONFIG_POOL_GUID, spa_guid(spa)); fnvlist_add_uint64(config, ZPOOL_CONFIG_ERRATA, spa->spa_errata); + fnvlist_add_uint64(config, ZPOOL_CONFIG_MIN_ALLOC, spa->spa_min_alloc); + fnvlist_add_uint64(config, ZPOOL_CONFIG_MAX_ALLOC, spa->spa_max_alloc); if (spa->spa_comment != NULL) fnvlist_add_string(config, ZPOOL_CONFIG_COMMENT, spa->spa_comment); diff --git a/sys/contrib/openzfs/module/zfs/spa_misc.c b/sys/contrib/openzfs/module/zfs/spa_misc.c index 6f7c060f97f8..0bead6d49666 100644 --- a/sys/contrib/openzfs/module/zfs/spa_misc.c +++ b/sys/contrib/openzfs/module/zfs/spa_misc.c @@ -510,7 +510,7 @@ spa_config_tryenter(spa_t *spa, int locks, const void *tag, krw_t rw) static void spa_config_enter_impl(spa_t *spa, int locks, const void *tag, krw_t rw, - int mmp_flag) + int priority_flag) { (void) tag; int wlocks_held = 0; @@ -526,7 +526,7 @@ spa_config_enter_impl(spa_t *spa, int locks, const void *tag, krw_t rw, mutex_enter(&scl->scl_lock); if (rw == RW_READER) { while (scl->scl_writer || - (!mmp_flag && scl->scl_write_wanted)) { + (!priority_flag && scl->scl_write_wanted)) { cv_wait(&scl->scl_cv, &scl->scl_lock); } } else { @@ -551,7 +551,7 @@ spa_config_enter(spa_t *spa, int locks, const void *tag, krw_t rw) } /* - * The spa_config_enter_mmp() allows the mmp thread to cut in front of + * The spa_config_enter_priority() allows the mmp thread to cut in front of * outstanding write lock requests. This is needed since the mmp updates are * time sensitive and failure to service them promptly will result in a * suspended pool. This pool suspension has been seen in practice when there is @@ -560,7 +560,7 @@ spa_config_enter(spa_t *spa, int locks, const void *tag, krw_t rw) */ void -spa_config_enter_mmp(spa_t *spa, int locks, const void *tag, krw_t rw) +spa_config_enter_priority(spa_t *spa, int locks, const void *tag, krw_t rw) { spa_config_enter_impl(spa, locks, tag, rw, 1); } @@ -806,6 +806,7 @@ spa_add(const char *name, nvlist_t *config, const char *altroot) spa->spa_min_ashift = INT_MAX; spa->spa_max_ashift = 0; spa->spa_min_alloc = INT_MAX; + spa->spa_max_alloc = 0; spa->spa_gcd_alloc = INT_MAX; /* Reset cached value */ @@ -1865,6 +1866,19 @@ spa_get_worst_case_asize(spa_t *spa, uint64_t lsize) } /* + * Return the range of minimum allocation sizes for the normal allocation + * class. This can be used by external consumers of the DMU to estimate + * potential wasted capacity when setting the recordsize for an object. + * This is mainly for dRAID pools which always pad to a full stripe width. + */ +void +spa_get_min_alloc_range(spa_t *spa, uint64_t *min_alloc, uint64_t *max_alloc) +{ + *min_alloc = spa->spa_min_alloc; + *max_alloc = spa->spa_max_alloc; +} + +/* * Return the amount of slop space in bytes. It is typically 1/32 of the pool * (3.2%), minus the embedded log space. On very small pools, it may be * slightly larger than this. On very large pools, it will be capped to @@ -3085,6 +3099,7 @@ EXPORT_SYMBOL(spa_version); EXPORT_SYMBOL(spa_state); EXPORT_SYMBOL(spa_load_state); EXPORT_SYMBOL(spa_freeze_txg); +EXPORT_SYMBOL(spa_get_min_alloc_range); /* for Lustre */ EXPORT_SYMBOL(spa_get_dspace); EXPORT_SYMBOL(spa_update_dspace); EXPORT_SYMBOL(spa_deflate); diff --git a/sys/contrib/openzfs/module/zfs/vdev.c b/sys/contrib/openzfs/module/zfs/vdev.c index fc6d445f9785..654e034de9e1 100644 --- a/sys/contrib/openzfs/module/zfs/vdev.c +++ b/sys/contrib/openzfs/module/zfs/vdev.c @@ -1497,12 +1497,14 @@ vdev_spa_set_alloc(spa_t *spa, uint64_t min_alloc) { if (min_alloc < spa->spa_min_alloc) spa->spa_min_alloc = min_alloc; - if (spa->spa_gcd_alloc == INT_MAX) { + + if (min_alloc > spa->spa_max_alloc) + spa->spa_max_alloc = min_alloc; + + if (spa->spa_gcd_alloc == INT_MAX) spa->spa_gcd_alloc = min_alloc; - } else { - spa->spa_gcd_alloc = vdev_gcd(min_alloc, - spa->spa_gcd_alloc); - } + else + spa->spa_gcd_alloc = vdev_gcd(min_alloc, spa->spa_gcd_alloc); } void @@ -1560,8 +1562,7 @@ vdev_metaslab_group_create(vdev_t *vd) if (vd->vdev_ashift < spa->spa_min_ashift) spa->spa_min_ashift = vd->vdev_ashift; - uint64_t min_alloc = vdev_get_min_alloc(vd); - vdev_spa_set_alloc(spa, min_alloc); + vdev_spa_set_alloc(spa, vdev_get_min_alloc(vd)); } } } diff --git a/sys/contrib/openzfs/module/zfs/vdev_label.c b/sys/contrib/openzfs/module/zfs/vdev_label.c index c44f654b0261..0d4fdaa77ba0 100644 --- a/sys/contrib/openzfs/module/zfs/vdev_label.c +++ b/sys/contrib/openzfs/module/zfs/vdev_label.c @@ -511,6 +511,8 @@ vdev_config_generate(spa_t *spa, vdev_t *vd, boolean_t getstats, fnvlist_add_uint64(nv, ZPOOL_CONFIG_ASHIFT, vd->vdev_ashift); fnvlist_add_uint64(nv, ZPOOL_CONFIG_ASIZE, vd->vdev_asize); + fnvlist_add_uint64(nv, ZPOOL_CONFIG_MIN_ALLOC, + vdev_get_min_alloc(vd)); fnvlist_add_uint64(nv, ZPOOL_CONFIG_IS_LOG, vd->vdev_islog); if (vd->vdev_noalloc) { fnvlist_add_uint64(nv, ZPOOL_CONFIG_NONALLOCATING, diff --git a/sys/contrib/openzfs/module/zfs/zio.c b/sys/contrib/openzfs/module/zfs/zio.c index 4cf8912d4269..aeea58bedfe4 100644 --- a/sys/contrib/openzfs/module/zfs/zio.c +++ b/sys/contrib/openzfs/module/zfs/zio.c @@ -4574,8 +4574,29 @@ zio_vdev_io_start(zio_t *zio) ASSERT0(zio->io_child_error[ZIO_CHILD_VDEV]); if (vd == NULL) { - if (!(zio->io_flags & ZIO_FLAG_CONFIG_WRITER)) - spa_config_enter(spa, SCL_ZIO, zio, RW_READER); + if (!(zio->io_flags & ZIO_FLAG_CONFIG_WRITER)) { + /* + * A deadlock workaround. The ddt_prune_unique_entries() + * -> prune_candidates_sync() code path takes the + * SCL_ZIO reader lock and may request it again here. + * If there is another thread who wants the SCL_ZIO + * writer lock, then scl_write_wanted will be set. + * Thus, the spa_config_enter_priority() is used to + * ignore pending writer requests. + * + * The locking should be revised to remove the need + * for this workaround. If that's not workable then + * it should only be applied to the zios involved in + * the pruning process. This impacts the read/write + * I/O balance while pruning. + */ + if (spa->spa_active_ddt_prune) + spa_config_enter_priority(spa, SCL_ZIO, zio, + RW_READER); + else + spa_config_enter(spa, SCL_ZIO, zio, + RW_READER); + } /* * The mirror_ops handle multiple DVAs in a single BP. @@ -5305,6 +5326,16 @@ zio_ready(zio_t *zio) return (NULL); } + if (zio_injection_enabled) { + hrtime_t target = zio_handle_ready_delay(zio); + if (target != 0 && zio->io_target_timestamp == 0) { + zio->io_stage >>= 1; + zio->io_target_timestamp = target; + zio_delay_interrupt(zio); + return (NULL); + } + } + if (zio->io_ready) { ASSERT(IO_IS_ALLOCATING(zio)); ASSERT(BP_GET_BIRTH(bp) == zio->io_txg || diff --git a/sys/contrib/openzfs/module/zfs/zio_inject.c b/sys/contrib/openzfs/module/zfs/zio_inject.c index 981a1be4847c..287577018ed1 100644 --- a/sys/contrib/openzfs/module/zfs/zio_inject.c +++ b/sys/contrib/openzfs/module/zfs/zio_inject.c @@ -827,6 +827,44 @@ zio_handle_export_delay(spa_t *spa, hrtime_t elapsed) zio_handle_pool_delay(spa, elapsed, ZINJECT_DELAY_EXPORT); } +/* + * For testing, inject a delay before ready state. + */ +hrtime_t +zio_handle_ready_delay(zio_t *zio) +{ + inject_handler_t *handler; + hrtime_t now = gethrtime(); + hrtime_t target = 0; + + /* + * Ignore I/O not associated with any logical data. + */ + if (zio->io_logical == NULL) + return (0); + + rw_enter(&inject_lock, RW_READER); + + for (handler = list_head(&inject_handlers); handler != NULL; + handler = list_next(&inject_handlers, handler)) { + if (zio->io_spa != handler->zi_spa || + handler->zi_record.zi_cmd != ZINJECT_DELAY_READY) + continue; + + /* If this handler matches, inject the delay */ + if (zio_match_iotype(zio, handler->zi_record.zi_iotype) && + zio_match_handler(&zio->io_logical->io_bookmark, + zio->io_bp ? BP_GET_TYPE(zio->io_bp) : DMU_OT_NONE, + zio_match_dva(zio), &handler->zi_record, zio->io_error)) { + target = now + (hrtime_t)handler->zi_record.zi_timer; + break; + } + } + + rw_exit(&inject_lock); + return (target); +} + static int zio_calculate_range(const char *pool, zinject_record_t *record) { diff --git a/sys/contrib/openzfs/scripts/zfs-tests.sh b/sys/contrib/openzfs/scripts/zfs-tests.sh index 04f3b6f32cb8..5a0a1a609448 100755 --- a/sys/contrib/openzfs/scripts/zfs-tests.sh +++ b/sys/contrib/openzfs/scripts/zfs-tests.sh @@ -38,6 +38,7 @@ DEBUG="" CLEANUP="yes" CLEANUPALL="no" KMSG="" +TIMEOUT_DEBUG="" LOOPBACK="yes" STACK_TRACER="no" FILESIZE="4G" @@ -364,6 +365,7 @@ OPTIONS: -k Disable cleanup after test failure -K Log test names to /dev/kmsg -f Use files only, disables block device tests + -O Dump debugging info to /dev/kmsg on test timeout -S Enable stack tracer (negative performance impact) -c Only create and populate constrained path -R Automatically rerun failing tests @@ -402,7 +404,7 @@ $0 -x EOF } -while getopts 'hvqxkKfScRmn:d:Ds:r:?t:T:u:I:' OPTION; do +while getopts 'hvqxkKfScRmOn:d:Ds:r:?t:T:u:I:' OPTION; do case $OPTION in h) usage @@ -445,6 +447,9 @@ while getopts 'hvqxkKfScRmn:d:Ds:r:?t:T:u:I:' OPTION; do export NFS=1 . "$nfsfile" ;; + O) + TIMEOUT_DEBUG="yes" + ;; d) FILEDIR="$OPTARG" ;; @@ -773,6 +778,7 @@ msg "${TEST_RUNNER}" \ "${DEBUG:+-D}" \ "${KMEMLEAK:+-m}" \ "${KMSG:+-K}" \ + "${TIMEOUT_DEBUG:+-O}" \ "-c \"${RUNFILES}\"" \ "-T \"${TAGS}\"" \ "-i \"${STF_SUITE}\"" \ @@ -783,6 +789,7 @@ msg "${TEST_RUNNER}" \ ${DEBUG:+-D} \ ${KMEMLEAK:+-m} \ ${KMSG:+-K} \ + ${TIMEOUT_DEBUG:+-O} \ -c "${RUNFILES}" \ -T "${TAGS}" \ -i "${STF_SUITE}" \ diff --git a/sys/contrib/openzfs/tests/runfiles/common.run b/sys/contrib/openzfs/tests/runfiles/common.run index 2b002830c82f..9f531411fbe1 100644 --- a/sys/contrib/openzfs/tests/runfiles/common.run +++ b/sys/contrib/openzfs/tests/runfiles/common.run @@ -168,10 +168,10 @@ tags = ['functional', 'cli_root', 'zinject'] tests = ['zdb_002_pos', 'zdb_003_pos', 'zdb_004_pos', 'zdb_005_pos', 'zdb_006_pos', 'zdb_args_neg', 'zdb_args_pos', 'zdb_block_size_histogram', 'zdb_checksum', 'zdb_decompress', - 'zdb_display_block', 'zdb_encrypted', 'zdb_label_checksum', - 'zdb_object_range_neg', 'zdb_object_range_pos', 'zdb_objset_id', - 'zdb_decompress_zstd', 'zdb_recover', 'zdb_recover_2', 'zdb_backup', - 'zdb_tunables'] + 'zdb_display_block', 'zdb_encrypted', 'zdb_encrypted_raw', + 'zdb_label_checksum', 'zdb_object_range_neg', 'zdb_object_range_pos', + 'zdb_objset_id', 'zdb_decompress_zstd', 'zdb_recover', 'zdb_recover_2', + 'zdb_backup', 'zdb_tunables'] pre = post = tags = ['functional', 'cli_root', 'zdb'] @@ -395,8 +395,9 @@ tags = ['functional', 'cli_root', 'zpool'] [tests/functional/cli_root/zpool_add] tests = ['zpool_add_001_pos', 'zpool_add_002_pos', 'zpool_add_003_pos', 'zpool_add_004_pos', 'zpool_add_006_pos', 'zpool_add_007_neg', - 'zpool_add_008_neg', 'zpool_add_009_neg', 'zpool_add_010_pos', - 'add-o_ashift', 'add_prop_ashift', 'zpool_add_dryrun_output'] + 'zpool_add_008_neg', 'zpool_add_009_neg', 'zpool_add_warn_create', + 'zpool_add_warn_degraded', 'zpool_add_warn_removal', 'add-o_ashift', + 'add_prop_ashift', 'zpool_add_dryrun_output'] tags = ['functional', 'cli_root', 'zpool_add'] [tests/functional/cli_root/zpool_attach] @@ -490,6 +491,10 @@ tests = ['zpool_import_001_pos', 'zpool_import_002_pos', tags = ['functional', 'cli_root', 'zpool_import'] timeout = 1200 +[tests/functional/cli_root/zpool_iostat] +tests = ['zpool_iostat_interval_all', 'zpool_iostat_interval_some'] +tags = ['functional', 'cli_root', 'zpool_iostat'] + [tests/functional/cli_root/zpool_labelclear] tests = ['zpool_labelclear_active', 'zpool_labelclear_exported', 'zpool_labelclear_removed', 'zpool_labelclear_valid'] @@ -1085,7 +1090,8 @@ tags = ['functional', 'write_dirs'] [tests/functional/xattr] tests = ['xattr_001_pos', 'xattr_002_neg', 'xattr_003_neg', 'xattr_004_pos', 'xattr_005_pos', 'xattr_006_pos', 'xattr_007_neg', - 'xattr_011_pos', 'xattr_012_pos', 'xattr_013_pos', 'xattr_compat'] + 'xattr_011_pos', 'xattr_012_pos', 'xattr_013_pos', 'xattr_014_pos', + 'xattr_compat'] tags = ['functional', 'xattr'] [tests/functional/zvol/zvol_ENOSPC] diff --git a/sys/contrib/openzfs/tests/runfiles/sanity.run b/sys/contrib/openzfs/tests/runfiles/sanity.run index b56ffc3a4a2d..249b415029c4 100644 --- a/sys/contrib/openzfs/tests/runfiles/sanity.run +++ b/sys/contrib/openzfs/tests/runfiles/sanity.run @@ -622,7 +622,7 @@ tags = ['functional', 'vdev_zaps'] [tests/functional/xattr] tests = ['xattr_001_pos', 'xattr_002_neg', 'xattr_003_neg', 'xattr_004_pos', 'xattr_005_pos', 'xattr_006_pos', 'xattr_007_neg', - 'xattr_011_pos', 'xattr_013_pos', 'xattr_compat'] + 'xattr_011_pos', 'xattr_013_pos', 'xattr_014_pos', 'xattr_compat'] tags = ['functional', 'xattr'] [tests/functional/zvol/zvol_ENOSPC] diff --git a/sys/contrib/openzfs/tests/test-runner/bin/test-runner.py.in b/sys/contrib/openzfs/tests/test-runner/bin/test-runner.py.in index 2158208be6e5..d2c1185e4a94 100755 --- a/sys/contrib/openzfs/tests/test-runner/bin/test-runner.py.in +++ b/sys/contrib/openzfs/tests/test-runner/bin/test-runner.py.in @@ -34,6 +34,7 @@ from select import select from subprocess import PIPE from subprocess import Popen from subprocess import check_output +from subprocess import run from threading import Timer from time import time, CLOCK_MONOTONIC from os.path import exists @@ -187,6 +188,63 @@ User: %s ''' % (self.pathname, self.identifier, self.outputdir, self.timeout, self.user) def kill_cmd(self, proc, options, kmemleak, keyboard_interrupt=False): + + """ + We're about to kill a command due to a timeout. + If we're running with the -O option, then dump debug info about the + process with the highest CPU usage to /dev/kmsg (Linux only). This can + help debug the timeout. + + Debug info includes: + - 30 lines from 'top' + - /proc/<PID>/stack output of process with highest CPU usage + - Last lines strace-ing process with highest CPU usage + """ + if exists("/dev/kmsg"): + c = """ +TOP_OUT="$(COLUMNS=160 top -b -n 1 | head -n 30)" +read -r PID CMD <<< $(echo "$TOP_OUT" | /usr/bin/awk \ +"/COMMAND/{ + print_next=1 + next +} +{ + if (print_next == 1) { + print \\$1\\" \\"\\$12 + exit + } +}") +echo "##### ZTS timeout debug #####" +echo "----- top -----" +echo "$TOP_OUT" +echo "----- /proc/$PID/stack ($CMD)) -----" +cat /proc/$PID/stack +echo "----- strace ($CMD) -----" +TMPFILE="$(mktemp --suffix=ZTS)" +/usr/bin/strace -k --stack-traces -p $PID &> "$TMPFILE" & +sleep 0.1 +killall strace +tail -n 30 $TMPFILE +rm "$TMPFILE" +echo "##### /proc/sysrq-trigger stack #####" +""" + c = "sudo bash -c '" + c + "'" + data = run(c, capture_output=True, shell=True, text=True) + out = data.stdout + try: + kp = Popen([SUDO, "sh", "-c", + "echo '" + out + "' > /dev/kmsg"]) + kp.wait() + + """ + Trigger kernel stack traces + """ + kp = Popen([SUDO, "sh", "-c", + "echo l > /proc/sysrq-trigger"]) + kp.wait() + except Exception: + pass + """ Kill a running command due to timeout, or ^C from the keyboard. If sudo is required, this user was verified previously. @@ -1129,6 +1187,9 @@ def parse_args(): parser.add_option('-o', action='callback', callback=options_cb, default=BASEDIR, dest='outputdir', type='string', metavar='outputdir', help='Specify an output directory.') + parser.add_option('-O', action='store_true', default=False, + dest='timeout_debug', + help='Dump debugging info to /dev/kmsg on test timeout') parser.add_option('-i', action='callback', callback=options_cb, default=TESTDIR, dest='testdir', type='string', metavar='testdir', help='Specify a test directory.') diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/Makefile.am b/sys/contrib/openzfs/tests/zfs-tests/tests/Makefile.am index 1517f90e99a5..678c01b58f94 100644 --- a/sys/contrib/openzfs/tests/zfs-tests/tests/Makefile.am +++ b/sys/contrib/openzfs/tests/zfs-tests/tests/Makefile.am @@ -197,6 +197,7 @@ nobase_dist_datadir_zfs_tests_tests_DATA += \ functional/cli_root/zpool_import/blockfiles/unclean_export.dat.bz2 \ functional/cli_root/zpool_import/zpool_import.cfg \ functional/cli_root/zpool_import/zpool_import.kshlib \ + functional/cli_root/zpool_iostat/zpool_iostat.kshlib \ functional/cli_root/zpool_initialize/zpool_initialize.kshlib \ functional/cli_root/zpool_labelclear/labelclear.cfg \ functional/cli_root/zpool_remove/zpool_remove.cfg \ @@ -640,6 +641,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \ functional/cli_root/zdb/zdb_decompress_zstd.ksh \ functional/cli_root/zdb/zdb_display_block.ksh \ functional/cli_root/zdb/zdb_encrypted.ksh \ + functional/cli_root/zdb/zdb_encrypted_raw.ksh \ functional/cli_root/zdb/zdb_label_checksum.ksh \ functional/cli_root/zdb/zdb_object_range_neg.ksh \ functional/cli_root/zdb/zdb_object_range_pos.ksh \ @@ -1027,7 +1029,9 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \ functional/cli_root/zpool_add/zpool_add_007_neg.ksh \ functional/cli_root/zpool_add/zpool_add_008_neg.ksh \ functional/cli_root/zpool_add/zpool_add_009_neg.ksh \ - functional/cli_root/zpool_add/zpool_add_010_pos.ksh \ + functional/cli_root/zpool_add/zpool_add_warn_create.ksh \ + functional/cli_root/zpool_add/zpool_add_warn_degraded.ksh \ + functional/cli_root/zpool_add/zpool_add_warn_removal.ksh \ functional/cli_root/zpool_add/zpool_add_dryrun_output.ksh \ functional/cli_root/zpool_attach/attach-o_ashift.ksh \ functional/cli_root/zpool_attach/cleanup.ksh \ @@ -1178,6 +1182,10 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \ functional/cli_root/zpool_import/zpool_import_parallel_admin.ksh \ functional/cli_root/zpool_import/zpool_import_parallel_neg.ksh \ functional/cli_root/zpool_import/zpool_import_parallel_pos.ksh \ + functional/cli_root/zpool_iostat/setup.ksh \ + functional/cli_root/zpool_iostat/cleanup.ksh \ + functional/cli_root/zpool_iostat/zpool_iostat_interval_all.ksh \ + functional/cli_root/zpool_iostat/zpool_iostat_interval_some.ksh \ functional/cli_root/zpool_initialize/cleanup.ksh \ functional/cli_root/zpool_initialize/zpool_initialize_attach_detach_add_remove.ksh \ functional/cli_root/zpool_initialize/zpool_initialize_fault_export_import_online.ksh \ @@ -2226,6 +2234,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \ functional/xattr/xattr_011_pos.ksh \ functional/xattr/xattr_012_pos.ksh \ functional/xattr/xattr_013_pos.ksh \ + functional/xattr/xattr_014_pos.ksh \ functional/xattr/xattr_compat.ksh \ functional/zap_shrink/cleanup.ksh \ functional/zap_shrink/zap_shrink_001_pos.ksh \ diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_encrypted_raw.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_encrypted_raw.ksh new file mode 100755 index 000000000000..85d267d5402f --- /dev/null +++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_encrypted_raw.ksh @@ -0,0 +1,75 @@ +#!/bin/ksh -p +# SPDX-License-Identifier: CDDL-1.0 +# +# 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 (c) 2023, Klara Inc. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/cli_root/zfs_load-key/zfs_load-key_common.kshlib + +# +# DESCRIPTION: +# 'zdb -K ...' should enable reading from a raw-encrypted dataset +# +# STRATEGY: +# 1. Create an encrypted dataset +# 2. Write some data to a file +# 3. Run zdb -dddd on the file, confirm it can't be read +# 4. Run zdb -K ... -ddddd on the file, confirm it can be read +# + +verify_runnable "both" + +dataset="$TESTPOOL/$TESTFS2" +file="$TESTDIR2/somefile" +keyfile="$TEST_BASE_DIR/keyfile" + +function cleanup +{ + datasetexists "$dataset" && destroy_dataset "$dataset" -f + rm -f "$keyfile" + default_cleanup_noexit +} + +log_onexit cleanup + +log_must default_setup_noexit $DISKS + +log_assert "'zdb -K' should enable reading from a raw-encrypted dataset" + +# The key must be 32 bytes long. +echo -n "$RAWKEY" > "$keyfile" + +log_must zfs create -o mountpoint="$TESTDIR2" \ + -o encryption=on -o keyformat=raw -o keylocation="file://$keyfile" \ + "$dataset" + +echo 'my great encrypted text' > "$file" + +typeset -i obj=$(ls -i "$file" | cut -d' ' -f1) +typeset -i size=$(wc -c < "$file") + +log_note "test file $file is objid $obj, size $size" + +sync_pool "$TESTPOOL" true + +log_must eval "zdb -dddd $dataset $obj | grep -q 'object encrypted'" + +log_must eval "zdb -K $keyfile -dddd $dataset $obj | grep -q 'size\s$size$'" + +log_pass "'zdb -K' enables reading from a raw-encrypted dataset" diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add.kshlib b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add.kshlib index 091d65bb4f33..74780bb02141 100644 --- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add.kshlib +++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add.kshlib @@ -27,6 +27,7 @@ # # Copyright (c) 2012, 2016 by Delphix. All rights reserved. +# Copyright 2025 by Lawrence Livermore National Security, LLC. # . $STF_SUITE/include/libtest.shlib @@ -89,3 +90,44 @@ function save_dump_dev fi echo $dumpdev } + +function zpool_create_add_setup +{ + typeset -i i=0 + + while ((i < 10)); do + log_must truncate -s $MINVDEVSIZE $TEST_BASE_DIR/vdev$i + + eval vdev$i=$TEST_BASE_DIR/vdev$i + ((i += 1)) + done + + if is_linux; then + vdev_lo="$(losetup -f "$vdev4" --show)" + elif is_freebsd; then + vdev_lo=/dev/"$(mdconfig -a -t vnode -f "$vdev4")" + else + vdev_lo="$(lofiadm -a "$vdev4")" + fi +} + +function zpool_create_add_cleanup +{ + datasetexists $TESTPOOL1 && destroy_pool $TESTPOOL1 + + if [[ -e $vdev_lo ]]; then + if is_linux; then + log_must losetup -d "$vdev_lo" + elif is_freebsd; then + log_must mdconfig -d -u "$vdev_lo" + else + log_must lofiadm -d "$vdev_lo" + fi + fi + + typeset -i i=0 + while ((i < 10)); do + rm -f $TEST_BASE_DIR/vdev$i + ((i += 1)) + done +} diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_010_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_warn_create.ksh index df085a2ec746..661e55998d8d 100755 --- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_010_pos.ksh +++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_warn_create.ksh @@ -23,67 +23,51 @@ # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# - -# -# Copyright (c) 2012, 2016 by Delphix. All rights reserved. +# Copyright 2012, 2016 by Delphix. All rights reserved. +# Copyright 2025 by Lawrence Livermore National Security, LLC. # . $STF_SUITE/include/libtest.shlib -. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib +. $STF_SUITE/tests/functional/cli_root/zpool_add/zpool_add.kshlib # # DESCRIPTION: -# Verify zpool add succeed when adding vdevs with matching redundancy. +# Verify zpool add succeeds when adding vdevs with matching redundancy +# and warns with differing redundancy for a healthy pool. # # STRATEGY: # 1. Create several files == $MINVDEVSIZE. # 2. Verify 'zpool add' succeeds with matching redundancy. # 3. Verify 'zpool add' warns with differing redundancy. -# 4. Verify 'zpool add' warns with differing redundancy after removal. # verify_runnable "global" -function cleanup -{ - datasetexists $TESTPOOL1 && destroy_pool $TESTPOOL1 - - typeset -i i=0 - while ((i < 10)); do - rm -f $TEST_BASE_DIR/vdev$i - ((i += 1)) - done -} - +log_assert "Verify 'zpool add' warns for differing redundancy." +log_onexit zpool_create_add_cleanup -log_assert "Verify 'zpool add' succeed with keywords combination." -log_onexit cleanup +zpool_create_add_setup -# 1. Create several files == $MINVDEVSIZE. typeset -i i=0 -while ((i < 10)); do - log_must truncate -s $MINVDEVSIZE $TEST_BASE_DIR/vdev$i - - eval vdev$i=$TEST_BASE_DIR/vdev$i - ((i += 1)) -done +typeset -i j=0 set -A redundancy0_create_args \ "$vdev0" set -A redundancy1_create_args \ "mirror $vdev0 $vdev1" \ - "raidz1 $vdev0 $vdev1" + "raidz1 $vdev0 $vdev1" \ + "draid1:1s $vdev0 $vdev1 $vdev9" set -A redundancy2_create_args \ "mirror $vdev0 $vdev1 $vdev2" \ - "raidz2 $vdev0 $vdev1 $vdev2" + "raidz2 $vdev0 $vdev1 $vdev2" \ + "draid2:1s $vdev0 $vdev1 $vdev2 $vdev9" set -A redundancy3_create_args \ "mirror $vdev0 $vdev1 $vdev2 $vdev3" \ - "raidz3 $vdev0 $vdev1 $vdev2 $vdev3" + "raidz3 $vdev0 $vdev1 $vdev2 $vdev3" \ + "draid3:1s $vdev0 $vdev1 $vdev2 $vdev3 $vdev9" set -A redundancy0_add_args \ "$vdev5" \ @@ -93,21 +77,19 @@ set -A redundancy1_add_args \ "mirror $vdev5 $vdev6" \ "raidz1 $vdev5 $vdev6" \ "raidz1 $vdev5 $vdev6 mirror $vdev7 $vdev8" \ - "mirror $vdev5 $vdev6 raidz1 $vdev7 $vdev8" + "mirror $vdev5 $vdev6 raidz1 $vdev7 $vdev8" \ + "draid1 $vdev5 $vdev6 mirror $vdev7 $vdev8" \ + "mirror $vdev5 $vdev6 draid1 $vdev7 $vdev8" set -A redundancy2_add_args \ "mirror $vdev5 $vdev6 $vdev7" \ - "raidz2 $vdev5 $vdev6 $vdev7" + "raidz2 $vdev5 $vdev6 $vdev7" \ + "draid2 $vdev5 $vdev6 $vdev7" set -A redundancy3_add_args \ "mirror $vdev5 $vdev6 $vdev7 $vdev8" \ - "raidz3 $vdev5 $vdev6 $vdev7 $vdev8" - -set -A log_args "log" "$vdev4" -set -A cache_args "cache" "$vdev4" -set -A spare_args "spare" "$vdev4" - -typeset -i j=0 + "raidz3 $vdev5 $vdev6 $vdev7 $vdev8" \ + "draid3 $vdev5 $vdev6 $vdev7 $vdev8" function zpool_create_add { @@ -148,30 +130,6 @@ function zpool_create_forced_add done } -function zpool_create_rm_add -{ - typeset -n create_args=$1 - typeset -n add_args=$2 - typeset -n rm_args=$3 - - i=0 - while ((i < ${#create_args[@]})); do - j=0 - while ((j < ${#add_args[@]})); do - log_must zpool create $TESTPOOL1 ${create_args[$i]} - log_must zpool add $TESTPOOL1 ${rm_args[0]} ${rm_args[1]} - log_must zpool add $TESTPOOL1 ${add_args[$j]} - log_must zpool remove $TESTPOOL1 ${rm_args[1]} - log_mustnot zpool add $TESTPOOL1 ${rm_args[1]} - log_must zpool add $TESTPOOL1 ${rm_args[0]} ${rm_args[1]} - log_must zpool destroy -f $TESTPOOL1 - - ((j += 1)) - done - ((i += 1)) - done -} - # 2. Verify 'zpool add' succeeds with matching redundancy. zpool_create_add redundancy0_create_args redundancy0_add_args zpool_create_add redundancy1_create_args redundancy1_add_args @@ -195,17 +153,4 @@ zpool_create_forced_add redundancy3_create_args redundancy0_add_args zpool_create_forced_add redundancy3_create_args redundancy1_add_args zpool_create_forced_add redundancy3_create_args redundancy2_add_args -# 4. Verify 'zpool add' warns with differing redundancy after removal. -zpool_create_rm_add redundancy1_create_args redundancy1_add_args log_args -zpool_create_rm_add redundancy2_create_args redundancy2_add_args log_args -zpool_create_rm_add redundancy3_create_args redundancy3_add_args log_args - -zpool_create_rm_add redundancy1_create_args redundancy1_add_args cache_args -zpool_create_rm_add redundancy2_create_args redundancy2_add_args cache_args -zpool_create_rm_add redundancy3_create_args redundancy3_add_args cache_args - -zpool_create_rm_add redundancy1_create_args redundancy1_add_args spare_args -zpool_create_rm_add redundancy2_create_args redundancy2_add_args spare_args -zpool_create_rm_add redundancy3_create_args redundancy3_add_args spare_args - -log_pass "'zpool add' succeed with keywords combination." +log_pass "Verify 'zpool add' warns for differing redundancy." diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_warn_degraded.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_warn_degraded.ksh new file mode 100755 index 000000000000..313eb3666f27 --- /dev/null +++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_warn_degraded.ksh @@ -0,0 +1,204 @@ +#!/bin/ksh -p +# SPDX-License-Identifier: CDDL-1.0 +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or https://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Copyright 2012, 2016 by Delphix. All rights reserved. +# Copyright 2025 by Lawrence Livermore National Security, LLC. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/cli_root/zpool_add/zpool_add.kshlib + +# +# DESCRIPTION: +# Verify zpool add succeeds when adding vdevs with matching redundancy +# and warns with differing redundancy for a degraded pool. +# +# STRATEGY: +# 1. Create several files == $MINVDEVSIZE. +# 2. Verify 'zpool add' succeeds with matching redundancy +# 3. Verify 'zpool add' warns with differing redundancy when +# a. Degraded pool with replaced mismatch vdev (file vs disk) +# b. Degraded pool dRAID distributed spare active +# c. Degraded pool hot spare active +# + +verify_runnable "global" + +log_assert "Verify 'zpool add' warns for differing redundancy." +log_onexit zpool_create_add_cleanup + +zpool_create_add_setup + +set -A redundancy1_create_args \ + "mirror $vdev0 $vdev1" \ + "raidz1 $vdev0 $vdev1" \ + "draid1:1s $vdev0 $vdev1 $vdev9" + +set -A redundancy2_create_args \ + "mirror $vdev0 $vdev1 $vdev2" \ + "raidz2 $vdev0 $vdev1 $vdev2" \ + "draid2:1s $vdev0 $vdev1 $vdev2 $vdev9" + +set -A redundancy3_create_args \ + "mirror $vdev0 $vdev1 $vdev2 $vdev3" \ + "raidz3 $vdev0 $vdev1 $vdev2 $vdev3" \ + "draid3:1s $vdev0 $vdev1 $vdev2 $vdev3 $vdev9" + +set -A redundancy1_add_args \ + "mirror $vdev5 $vdev6" \ + "raidz1 $vdev5 $vdev6" \ + "raidz1 $vdev5 $vdev6 mirror $vdev7 $vdev8" \ + "mirror $vdev5 $vdev6 raidz1 $vdev7 $vdev8" \ + "draid1 $vdev5 $vdev6 mirror $vdev7 $vdev8" \ + "mirror $vdev5 $vdev6 draid1 $vdev7 $vdev8" + +set -A redundancy2_add_args \ + "mirror $vdev5 $vdev6 $vdev7" \ + "raidz2 $vdev5 $vdev6 $vdev7" \ + "draid2 $vdev5 $vdev6 $vdev7" + +set -A redundancy3_add_args \ + "mirror $vdev5 $vdev6 $vdev7 $vdev8" \ + "raidz3 $vdev5 $vdev6 $vdev7 $vdev8" \ + "draid3 $vdev5 $vdev6 $vdev7 $vdev8" + +set -A redundancy1_create_draid_args \ + "draid1:1s $vdev0 $vdev1 $vdev2" + +set -A redundancy2_create_draid_args \ + "draid2:1s $vdev0 $vdev1 $vdev2 $vdev3" + +set -A redundancy3_create_draid_args \ + "draid3:1s $vdev0 $vdev1 $vdev2 $vdev3 $vdev9" + +set -A redundancy1_create_spare_args \ + "mirror $vdev0 $vdev1 spare $vdev_lo" \ + "raidz1 $vdev0 $vdev1 spare $vdev_lo" \ + "draid1 $vdev0 $vdev1 spare $vdev_lo" + +set -A redundancy2_create_spare_args \ + "mirror $vdev0 $vdev1 $vdev2 spare $vdev_lo" \ + "raidz2 $vdev0 $vdev1 $vdev2 spare $vdev_lo" \ + "draid2 $vdev0 $vdev1 $vdev2 spare $vdev_lo" + +set -A redundancy3_create_spare_args \ + "mirror $vdev0 $vdev1 $vdev2 $vdev3 spare $vdev_lo" \ + "raidz3 $vdev0 $vdev1 $vdev2 $vdev3 spare $vdev_lo" \ + "draid3 $vdev0 $vdev1 $vdev2 $vdev3 spare $vdev_lo" + +set -A replace_args "$vdev1" "$vdev_lo" +set -A draid1_args "$vdev1" "draid1-0-0" +set -A draid2_args "$vdev1" "draid2-0-0" +set -A draid3_args "$vdev1" "draid3-0-0" + +typeset -i i=0 +typeset -i j=0 + +function zpool_create_degraded_add +{ + typeset -n create_args=$1 + typeset -n add_args=$2 + typeset -n rm_args=$3 + + i=0 + while ((i < ${#create_args[@]})); do + j=0 + while ((j < ${#add_args[@]})); do + log_must zpool create $TESTPOOL1 ${create_args[$i]} + log_must zpool offline -f $TESTPOOL1 ${rm_args[0]} + log_must zpool replace -w $TESTPOOL1 ${rm_args[0]} ${rm_args[1]} + log_must zpool add $TESTPOOL1 ${add_args[$j]} + log_must zpool destroy -f $TESTPOOL1 + log_must zpool labelclear -f ${rm_args[0]} + + ((j += 1)) + done + ((i += 1)) + done +} + +function zpool_create_forced_degraded_add +{ + typeset -n create_args=$1 + typeset -n add_args=$2 + typeset -n rm_args=$3 + + i=0 + while ((i < ${#create_args[@]})); do + j=0 + while ((j < ${#add_args[@]})); do + log_must zpool create $TESTPOOL1 ${create_args[$i]} + log_must zpool offline -f $TESTPOOL1 ${rm_args[0]} + log_must zpool replace -w $TESTPOOL1 ${rm_args[0]} ${rm_args[1]} + log_mustnot zpool add $TESTPOOL1 ${add_args[$j]} + log_must zpool add --allow-replication-mismatch $TESTPOOL1 ${add_args[$j]} + log_must zpool destroy -f $TESTPOOL1 + log_must zpool labelclear -f ${rm_args[0]} + + ((j += 1)) + done + ((i += 1)) + done +} + +# 2. Verify 'zpool add' succeeds with matching redundancy and a degraded pool. +zpool_create_degraded_add redundancy1_create_args redundancy1_add_args replace_args +zpool_create_degraded_add redundancy2_create_args redundancy2_add_args replace_args +zpool_create_degraded_add redundancy3_create_args redundancy3_add_args replace_args + +# 3. Verify 'zpool add' warns with differing redundancy and a degraded pool. +# +# a. Degraded pool with replaced mismatch vdev (file vs disk) +zpool_create_forced_degraded_add redundancy1_create_args redundancy2_add_args replace_args +zpool_create_forced_degraded_add redundancy1_create_args redundancy3_add_args replace_args + +zpool_create_forced_degraded_add redundancy2_create_args redundancy1_add_args replace_args +zpool_create_forced_degraded_add redundancy2_create_args redundancy3_add_args replace_args + +zpool_create_forced_degraded_add redundancy3_create_args redundancy1_add_args replace_args +zpool_create_forced_degraded_add redundancy3_create_args redundancy2_add_args replace_args + +# b. Degraded pool dRAID distributed spare active + +zpool_create_forced_degraded_add redundancy1_create_draid_args redundancy2_add_args draid1_args +zpool_create_forced_degraded_add redundancy1_create_draid_args redundancy3_add_args draid1_args + +zpool_create_forced_degraded_add redundancy2_create_draid_args redundancy1_add_args draid2_args +zpool_create_forced_degraded_add redundancy2_create_draid_args redundancy3_add_args draid2_args + +zpool_create_forced_degraded_add redundancy3_create_draid_args redundancy1_add_args draid3_args +zpool_create_forced_degraded_add redundancy3_create_draid_args redundancy2_add_args draid3_args + +# c. Degraded pool hot spare active +zpool_create_forced_degraded_add redundancy1_create_spare_args redundancy2_add_args replace_args +zpool_create_forced_degraded_add redundancy1_create_spare_args redundancy3_add_args replace_args + +zpool_create_forced_degraded_add redundancy2_create_spare_args redundancy1_add_args replace_args +zpool_create_forced_degraded_add redundancy2_create_spare_args redundancy3_add_args replace_args + +zpool_create_forced_degraded_add redundancy3_create_spare_args redundancy1_add_args replace_args +zpool_create_forced_degraded_add redundancy3_create_spare_args redundancy2_add_args replace_args + +log_pass "Verify 'zpool add' warns for differing redundancy." diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_warn_removal.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_warn_removal.ksh new file mode 100755 index 000000000000..782858e301ac --- /dev/null +++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_warn_removal.ksh @@ -0,0 +1,126 @@ +#!/bin/ksh -p +# SPDX-License-Identifier: CDDL-1.0 +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or https://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Copyright 2012, 2016 by Delphix. All rights reserved. +# Copyright 2025 by Lawrence Livermore National Security, LLC. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/cli_root/zpool_add/zpool_add.kshlib + +# +# DESCRIPTION: +# Verify zpool add succeeds when adding vdevs with matching redundancy +# and warns with differing redundancy after removal. +# +# STRATEGY: +# 1. Create several files == $MINVDEVSIZE. +# 2. Verify 'zpool add' warns with differing redundancy after removal. +# + +verify_runnable "global" + +log_assert "Verify 'zpool add' warns for differing redundancy." +log_onexit zpool_create_add_cleanup + +zpool_create_add_setup + +typeset -i i=0 +typeset -i j=0 + +set -A redundancy1_create_args \ + "mirror $vdev0 $vdev1" \ + "raidz1 $vdev0 $vdev1" \ + "draid1:1s $vdev0 $vdev1 $vdev9" + +set -A redundancy2_create_args \ + "mirror $vdev0 $vdev1 $vdev2" \ + "raidz2 $vdev0 $vdev1 $vdev2" \ + "draid2:1s $vdev0 $vdev1 $vdev2 $vdev9" + +set -A redundancy3_create_args \ + "mirror $vdev0 $vdev1 $vdev2 $vdev3" \ + "raidz3 $vdev0 $vdev1 $vdev2 $vdev3" \ + "draid3:1s $vdev0 $vdev1 $vdev2 $vdev3 $vdev9" + +set -A redundancy1_add_args \ + "mirror $vdev5 $vdev6" \ + "raidz1 $vdev5 $vdev6" \ + "raidz1 $vdev5 $vdev6 mirror $vdev7 $vdev8" \ + "mirror $vdev5 $vdev6 raidz1 $vdev7 $vdev8" \ + "draid1 $vdev5 $vdev6 mirror $vdev7 $vdev8" \ + "mirror $vdev5 $vdev6 draid1 $vdev7 $vdev8" + +set -A redundancy2_add_args \ + "mirror $vdev5 $vdev6 $vdev7" \ + "raidz2 $vdev5 $vdev6 $vdev7" \ + "draid2 $vdev5 $vdev6 $vdev7" + +set -A redundancy3_add_args \ + "mirror $vdev5 $vdev6 $vdev7 $vdev8" \ + "raidz3 $vdev5 $vdev6 $vdev7 $vdev8" \ + "draid3 $vdev5 $vdev6 $vdev7 $vdev8" + +set -A log_args "log" "$vdev_lo" +set -A cache_args "cache" "$vdev_lo" +set -A spare_args "spare" "$vdev_lo" + + +function zpool_create_rm_add +{ + typeset -n create_args=$1 + typeset -n add_args=$2 + typeset -n rm_args=$3 + + i=0 + while ((i < ${#create_args[@]})); do + j=0 + while ((j < ${#add_args[@]})); do + log_must zpool create $TESTPOOL1 ${create_args[$i]} + log_must zpool add $TESTPOOL1 ${rm_args[0]} ${rm_args[1]} + log_must zpool add $TESTPOOL1 ${add_args[$j]} + log_must zpool remove $TESTPOOL1 ${rm_args[1]} + log_mustnot zpool add $TESTPOOL1 ${rm_args[1]} + log_must zpool add $TESTPOOL1 ${rm_args[0]} ${rm_args[1]} + log_must zpool destroy -f $TESTPOOL1 + + ((j += 1)) + done + ((i += 1)) + done +} + +# 2. Verify 'zpool add' warns with differing redundancy after removal. +zpool_create_rm_add redundancy1_create_args redundancy1_add_args log_args +zpool_create_rm_add redundancy2_create_args redundancy2_add_args log_args +zpool_create_rm_add redundancy3_create_args redundancy3_add_args log_args + +zpool_create_rm_add redundancy1_create_args redundancy1_add_args cache_args +zpool_create_rm_add redundancy2_create_args redundancy2_add_args cache_args +zpool_create_rm_add redundancy3_create_args redundancy3_add_args cache_args + +zpool_create_rm_add redundancy1_create_args redundancy1_add_args spare_args +zpool_create_rm_add redundancy2_create_args redundancy2_add_args spare_args +zpool_create_rm_add redundancy3_create_args redundancy3_add_args spare_args diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/cleanup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/cleanup.ksh new file mode 100755 index 000000000000..099b5426031d --- /dev/null +++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/cleanup.ksh @@ -0,0 +1,30 @@ +#!/bin/ksh -p +# SPDX-License-Identifier: CDDL-1.0 +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or https://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2025, Klara, Inc. +# +# +. $STF_SUITE/include/libtest.shlib + +log_pass diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/setup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/setup.ksh new file mode 100755 index 000000000000..3529a0ccc015 --- /dev/null +++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/setup.ksh @@ -0,0 +1,32 @@ +#!/bin/ksh -p +# SPDX-License-Identifier: CDDL-1.0 +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or https://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2025, Klara, Inc. +# +# +. $STF_SUITE/include/libtest.shlib + +verify_runnable "global" + +log_pass diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/zpool_iostat.kshlib b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/zpool_iostat.kshlib new file mode 100644 index 000000000000..ea4b0bd2756d --- /dev/null +++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/zpool_iostat.kshlib @@ -0,0 +1,235 @@ +# SPDX-License-Identifier: CDDL-1.0 +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or https://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2025, Klara, Inc. +# + +# Since we want to make sure that iostat responds correctly as pools appear and +# disappear, we run it in the background and capture its output to a file. +# Once we're done, we parse the output and ensure it matches what we'd expect +# from the operations we performed. +# +# Because iostat is producing output every interval, it may produce the "same" +# output for each step of the change; in fact, we want that to make sure we +# don't miss anything. So, we describe what we expect as a series of "chunks". +# Each chunk is a particular kind of output, which may repeat. Current known +# chunk types are: +# +# NOPOOL: the text "no pools available" +# HEADER: three lines, starting with "capacity", "pool" and "----" respectively. +# (the rough shape of the normal iostat header). +# POOL1: a line starting with "pool1" (stats line for a pool of that name) +# POOL2: a line starting with "pool2" +# POOLBOTH: three lines, starting with "pool1", "pool2" (either order) and +# "-----" respectively. (the pool stat output for multiple pools) +# +# (the parser may produce other chunks in a failed parse to assist with +# debugging, but they should never be part of the "wanted" output See the +# parser commentary below). +# +# To help recognise the start of a new interval output, we run iostat with the +# -T u option, which will output a numeric timestamp before each header or +# second-or-later pool stat after the header. +# +# To keep the test run shorter, we use a subsecond interval, but to make sure +# nothing is missed, we sleep for three intervals after each change. + +typeset _iostat_out=$(mktemp) +typeset _iostat_pid="" + +function cleanup_iostat { + if [[ -n $_iostat_pid ]] ; then + kill -KILL $_iostat_pid || true + fi + rm -f $_iostat_out +} + +function start_iostat { + zpool iostat -T u $@ 0.1 > $_iostat_out 2>&1 & + _iostat_pid=$! +} + +function stop_iostat { + kill -TERM $_iostat_pid + wait $_iostat_pid + _iostat_pid="" +} + +function delay_iostat { + sleep 0.3 +} + +typeset -a _iostat_expect +function expect_iostat { + typeset chunk=$1 + _iostat_expect+=($chunk) +} + +# Parse the output The `state` var is used to track state across +# multiple lines. The `last` var and the `_got_iostat` function are used +# to record the completed chunks, and to collapse repetitions. +typeset -a _iostat_got +typeset _iostat_last="" +typeset _iostat_state="" + +function _got_iostat { + typeset chunk=$1 + if [[ -n $chunk && $_iostat_last != $chunk ]] ; then + _iostat_last=$chunk + _iostat_got+=($chunk) + fi + _iostat_state="" +} + +function verify_iostat { + + cat $_iostat_out | while read line ; do + + # The "no pools available" text has no timestamp or other + # header, and should never appear in the middle of multiline + # chunk, so we can close any in-flight state. + if [[ $line = "no pools available" ]] ; then + _got_iostat $_iostat_state + _got_iostat "NOPOOL" + continue + fi + + # A run of digits alone on the line is a timestamp (the `-T u` + # switch to `iostat`). It closes any in-flight state as a + # complete chunk, and indicates the start of a new chunk. + if [[ -z ${line/#+([0-9])/} ]] ; then + _got_iostat $_iostat_state + _iostat_state="TIMESTAMP" + continue + fi + + # For this test, the first word of each line should be unique, + # so we extract it and use it for simplicity. + typeset first=${line%% *} + + # Header is emitted whenever the pool list changes. It has + # three lines: + # + # capacity operations bandwidth + # pool alloc free read write read write + # ---------- ----- ----- ----- ----- ----- ----- + # + # Each line moves the state; when we get to a run of dashes, we + # commit. Note that we check for one-or-more dashes, because + # the width can vary depending on the length of pool name. + # + if [[ $_iostat_state = "TIMESTAMP" && + $first = "capacity" ]] ; then + _iostat_state="INHEADER1" + continue + fi + if [[ $_iostat_state = "INHEADER1" && + $first = "pool" ]] ; then + _iostat_state="INHEADER2" + continue + fi + if [[ $_iostat_state = "INHEADER2" && + -z ${first/#+(-)/} ]] ; then + # Headers never repeat, so if the last committed chunk + # was a header, we commit this one as EXTRAHEADER so we + # can see it in the error output. + if [[ $_iostat_last = "HEADER" ]] ; then + _got_iostat "EXTRAHEADER" + elif [[ $_iostat_last != "EXTRAHEADER" ]] ; then + _got_iostat "HEADER" + fi + _iostat_state="HEADER" + continue + fi + + # A pool stat line looks like: + # + # pool1 147K 240M 0 0 0 0 + # + # If there are multiple pools, iostat follows them with a + # separator of dashed lines: + # + # pool1 147K 240M 0 0 0 0 + # pool2 147K 240M 0 0 0 0 + # ---------- ----- ----- ----- ----- ----- ----- + # + # Stats rows always start after a timestamp or a header. If the + # header was emitted, we won't see a timestamp here (it goes + # before the header). + # + # Because our test exercises both pools on their own and + # together, we allow pools in either order. In practice they + # are sorted, but that's a side-effect of the implementation + # (see zpool_compare()), so we're not going to rely on it here. + if [[ $first = "pool1" ]] || [[ $first = "pool2" ]] ; then + + # First line, track which one we saw. If it's a + # standalone line, it will be committed by the next + # NOPOOL or TIMESTAMP above (or the `_got_iostat` after + # the loop if this is the last line). + if [[ $_iostat_state == "TIMESTAMP" || + $_iostat_state == "HEADER" ]] ; then + if [[ $first = "pool1" ]] ; then + _iostat_state="POOL1" + elif [[ $first = "pool2" ]] ; then + _iostat_state="POOL2" + fi + continue + fi + + # If this is the second pool, we're in a multi-pool + # block, and need to look for the separator to close it + # out. + if [[ $_iostat_state = "POOL1" && $first = "pool2" ]] || + [[ $_iostat_state = "POOL2" && $first = "pool1" ]] ; + then + _iostat_state="INPOOLBOTH" + continue + fi + fi + + # Separator after the stats block. + if [[ $_iostat_state = "INPOOLBOTH" && + -z ${first/#+(-)/} ]] ; then + _got_iostat "POOLBOTH" + continue + fi + + # Anything else will fall through to here. We commit any + # in-flight state, then "UNKNOWN", all to help with debugging.. + if [[ $_iostat_state != "UNKNOWN" ]] ; then + _got_iostat $_iostat_state + _got_iostat "UNKNOWN" + fi + done + + # Close out any remaining state. + _got_iostat $_iostat_state + + # Compare what we wanted with what we got, and pass/fail the test! + if [[ "${_iostat_expect[*]}" != "${_iostat_got[*]}" ]] ; then + log_note "expected: ${_iostat_expect[*]}" + log_note " got: ${_iostat_got[*]}" + log_fail "zpool iostat did not produce expected output" + fi +} diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/zpool_iostat_interval_all.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/zpool_iostat_interval_all.ksh new file mode 100755 index 000000000000..8e040058ec3e --- /dev/null +++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/zpool_iostat_interval_all.ksh @@ -0,0 +1,90 @@ +#!/bin/ksh -p +# SPDX-License-Identifier: CDDL-1.0 +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or https://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2025, Klara, Inc. +# + +# `zpool iostat <N>` should keep running and update the pools it displays as +# pools are created/destroyed/imported/export. + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/cli_root/zpool_iostat/zpool_iostat.kshlib + +typeset vdev1=$(mktemp) +typeset vdev2=$(mktemp) + +function cleanup { + cleanup_iostat + + poolexists pool1 && destroy_pool pool1 + poolexists pool2 && destroy_pool pool2 + rm -f $vdev1 $vdev2 +} + +log_must mkfile $MINVDEVSIZE $vdev1 $vdev2 + +expect_iostat "NOPOOL" + +start_iostat + +delay_iostat + +expect_iostat "HEADER" +expect_iostat "POOL1" +log_must zpool create pool1 $vdev1 +delay_iostat + +expect_iostat "HEADER" +expect_iostat "POOLBOTH" +log_must zpool create pool2 $vdev2 +delay_iostat + +expect_iostat "NOPOOL" +log_must zpool export -a +delay_iostat + +expect_iostat "HEADER" +expect_iostat "POOL2" +log_must zpool import -d $vdev2 pool2 +delay_iostat + +expect_iostat "HEADER" +expect_iostat "POOLBOTH" +log_must zpool import -d $vdev1 pool1 +delay_iostat + +expect_iostat "HEADER" +expect_iostat "POOL2" +log_must zpool destroy pool1 +delay_iostat + +expect_iostat "NOPOOL" +log_must zpool destroy pool2 +delay_iostat + +stop_iostat + +verify_iostat + +log_pass "zpool iostat in interval mode follows pool updates" diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/zpool_iostat_interval_some.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/zpool_iostat_interval_some.ksh new file mode 100755 index 000000000000..ab1f258aa1cd --- /dev/null +++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/zpool_iostat_interval_some.ksh @@ -0,0 +1,80 @@ +#!/bin/ksh -p +# SPDX-License-Identifier: CDDL-1.0 +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or https://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2025, Klara, Inc. +# + +# `zpool iostat <pools> <N>` should keep running and only show the listed pools. + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/cli_root/zpool_iostat/zpool_iostat.kshlib + +typeset vdev1=$(mktemp) +typeset vdev2=$(mktemp) + +function cleanup { + cleanup_iostat + + poolexists pool1 && destroy_pool pool1 + poolexists pool2 && destroy_pool pool2 + rm -f $vdev1 $vdev2 +} + +log_must mkfile $MINVDEVSIZE $vdev1 $vdev2 + +log_must zpool create pool1 $vdev1 +delay_iostat + +expect_iostat "HEADER" +expect_iostat "POOL1" +start_iostat pool1 +delay_iostat + +log_must zpool create pool2 $vdev2 +delay_iostat + +expect_iostat "NOPOOL" +log_must zpool export -a +delay_iostat + +log_must zpool import -d $vdev2 pool2 +delay_iostat + +expect_iostat "HEADER" +expect_iostat "POOL1" +log_must zpool import -d $vdev1 pool1 +delay_iostat + +expect_iostat "NOPOOL" +log_must zpool destroy pool1 +delay_iostat + +log_must zpool destroy pool2 +delay_iostat + +stop_iostat + +verify_iostat + +log_pass "zpool iostat in interval mode with pools follows listed pool updates" diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/delegate/delegate_common.kshlib b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/delegate/delegate_common.kshlib index 0a402e71ee68..345239b88680 100644 --- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/delegate/delegate_common.kshlib +++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/delegate/delegate_common.kshlib @@ -1234,10 +1234,10 @@ function verify_fs_aedsx typeset oldval set -A modes "on" "off" oldval=$(get_prop $perm $fs) - if [[ $oldval == "on" ]]; then - n=1 - elif [[ $oldval == "off" ]]; then + if [[ $oldval == "off" ]]; then n=0 + else + n=1 fi log_note "$user zfs set $perm=${modes[$n]} $fs" user_run $user zfs set $perm=${modes[$n]} $fs diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/upgrade/setup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/upgrade/setup.ksh index 26153aafbc02..0e79e9b8b70c 100755 --- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/upgrade/setup.ksh +++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/upgrade/setup.ksh @@ -39,6 +39,6 @@ verify_runnable "global" # create a pool without any features -log_must mkfile 128m $TMPDEV +log_must truncate -s $MINVDEVSIZE $TMPDEV log_pass diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/upgrade/upgrade_readonly_pool.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/upgrade/upgrade_readonly_pool.ksh index d6bd69b7e134..e81d07794689 100755 --- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/upgrade/upgrade_readonly_pool.ksh +++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/upgrade/upgrade_readonly_pool.ksh @@ -35,17 +35,19 @@ verify_runnable "global" -TESTFILE="$TESTDIR/file.bin" - log_assert "User accounting upgrade should not be executed on readonly pool" log_onexit cleanup_upgrade # 1. Create a pool with the feature@userobj_accounting disabled to simulate # a legacy pool from a previous ZFS version. -log_must zpool create -d -m $TESTDIR $TESTPOOL $TMPDEV +log_must zpool create -d $TESTPOOL $TMPDEV +log_must zfs create $TESTPOOL/$TESTFS + +MNTPNT=$(get_prop mountpoint $TESTPOOL/$TESTFS) +TESTFILE="$MNTPNT/file.bin" # 2. Create a file on the "legecy" dataset -log_must touch $TESTDIR/file.bin +log_must touch $TESTFILE # 3. Enable feature@userobj_accounting on the pool and verify it is only # "enabled" and not "active": upgrading starts when the filesystem is mounted @@ -54,12 +56,12 @@ log_must test "enabled" == "$(get_pool_prop 'feature@userobj_accounting' $TESTPO # 4. Export the pool and re-import is readonly, without mounting any filesystem log_must zpool export $TESTPOOL -log_must zpool import -o readonly=on -N -d "$(dirname $TMPDEV)" $TESTPOOL +log_must zpool import -o readonly=on -N -d $TEST_BASE_DIR $TESTPOOL # 5. Try to mount the root dataset manually without the "ro" option, then verify # filesystem status and the pool feature status (not "active") to ensure the # pool "readonly" status is enforced. -log_must mount -t zfs -o zfsutil $TESTPOOL $TESTDIR +log_must zfs mount -R $TESTPOOL log_must stat "$TESTFILE" log_mustnot touch "$TESTFILE" log_must test "enabled" == "$(get_pool_prop 'feature@userobj_accounting' $TESTPOOL)" diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/xattr/xattr_014_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/xattr/xattr_014_pos.ksh new file mode 100755 index 000000000000..d4c9a0a41816 --- /dev/null +++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/xattr/xattr_014_pos.ksh @@ -0,0 +1,53 @@ +#!/bin/ksh -p +# SPDX-License-Identifier: CDDL-1.0 +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or https://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2025 by Klara, Inc. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/xattr/xattr_common.kshlib + +# +# DESCRIPTION: +# The default xattr should be shown as 'sa', not 'on', for clarity. +# +# STRATEGY: +# 1. Create a filesystem. +# 2. Verify that the xattra is shown as 'sa'. +# 3. Manually set the value to 'dir', 'sa', 'on', and 'off'. +# 4. Verify that it is shown as 'dir', 'sa', 'sa', and 'off. +# + +log_assert "The default and specific xattr values are displayed correctly." + +set -A args "dir" "sa" "on" "off" +set -A display "dir" "sa" "sa" "off" + +log_must eval "[[ 'sa' == '$(zfs get -Hpo value xattr $TESTPOOL)' ]]" + +for i in `seq 0 3`; do + log_must zfs set xattr="${args[$i]}" $TESTPOOL + log_must eval "[[ '${display[$i]}' == '$(zfs get -Hpo value xattr $TESTPOOL)' ]]" +done +log_pass "The default and specific xattr values are displayed correctly." diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_fua.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_fua.ksh index 571a698eb63a..502ebada22dc 100755 --- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_fua.ksh +++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_fua.ksh @@ -50,17 +50,53 @@ fi typeset datafile1="$(mktemp -t zvol_misc_fua1.XXXXXX)" typeset datafile2="$(mktemp -t zvol_misc_fua2.XXXXXX)" +typeset datafile3="$(mktemp -t zvol_misc_fua3_log.XXXXXX)" typeset zvolpath=${ZVOL_DEVDIR}/$TESTPOOL/$TESTVOL +typeset DISK1=${DISKS%% *} function cleanup { - rm "$datafile1" "$datafile2" + log_must zpool remove $TESTPOOL $datafile3 + rm "$datafile1" "$datafile2" "$datafile2" +} + +# Prints the total number of sync writes for a vdev +# $1: vdev +function get_sync +{ + zpool iostat -p -H -v -r $TESTPOOL $1 | \ + awk '/[0-9]+$/{s+=$4+$5} END{print s}' } function do_test { # Wait for udev to create symlinks to our zvol block_device_wait $zvolpath + # Write using sync (creates FLUSH calls after writes, but not FUA) + old_vdev_writes=$(get_sync $DISK1) + old_log_writes=$(get_sync $datafile3) + + log_must fio --name=write_iops --size=5M \ + --ioengine=libaio --verify=0 --bs=4K \ + --iodepth=1 --rw=randwrite --group_reporting=1 \ + --filename=$zvolpath --sync=1 + + vdev_writes=$(( $(get_sync $DISK1) - $old_vdev_writes)) + log_writes=$(( $(get_sync $datafile3) - $old_log_writes)) + + # When we're doing sync writes, we should see many more writes go to + # the log vs the first vdev. Experiments show anywhere from a 160-320x + # ratio of writes to the log vs the first vdev (due to some straggler + # writes to the first vdev). + # + # Check that we have a large ratio (100x) of sync writes going to the + # log device + ratio=$(($log_writes / $vdev_writes)) + log_note "Got $log_writes log writes, $vdev_writes vdev writes." + if [ $ratio -lt 100 ] ; then + log_fail "Expected > 100x more log writes than vdev writes. " + fi + # Create a data file log_must dd if=/dev/urandom of="$datafile1" bs=1M count=5 @@ -81,6 +117,8 @@ log_assert "Verify that a ZFS volume can do Force Unit Access (FUA)" log_onexit cleanup log_must zfs set compression=off $TESTPOOL/$TESTVOL +log_must truncate -s 100M $datafile3 +log_must zpool add $TESTPOOL log $datafile3 log_note "Testing without blk-mq" diff --git a/sys/dev/acpica/acpi_apei.c b/sys/dev/acpica/acpi_apei.c index 9cfd46c97430..624c81ad1b4f 100644 --- a/sys/dev/acpica/acpi_apei.c +++ b/sys/dev/acpica/acpi_apei.c @@ -754,7 +754,7 @@ apei_detach(device_t dev) apei_nmi = NULL; apei_nmi_nges = NULL; if (sc->nges.swi_ih != NULL) { - swi_remove(&sc->nges.swi_ih); + swi_remove(sc->nges.swi_ih); sc->nges.swi_ih = NULL; } if (acpi_get_handle(dev) != NULL) { diff --git a/sys/dev/iwx/if_iwx.c b/sys/dev/iwx/if_iwx.c index 8422fcb787c3..04ed09f04604 100644 --- a/sys/dev/iwx/if_iwx.c +++ b/sys/dev/iwx/if_iwx.c @@ -4805,6 +4805,8 @@ iwx_rx_tx_cmd(struct iwx_softc *sc, struct iwx_rx_packet *pkt, static void iwx_clear_oactive(struct iwx_softc *sc, struct iwx_tx_ring *ring) { + IWX_ASSERT_LOCKED(sc); + if (ring->queued < iwx_lomark) { sc->qfullmsk &= ~(1 << ring->qid); if (sc->qfullmsk == 0 /* && ifq_is_oactive(&ifp->if_snd) */) { @@ -4890,11 +4892,19 @@ iwx_rx_bmiss(struct iwx_softc *sc, struct iwx_rx_packet *pkt, bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); + IWX_DPRINTF(sc, IWX_DEBUG_BEACON, + "%s: mac_id=%u, cmslrx=%u, cmb=%u, neb=%d, nrb=%u\n", + __func__, + le32toh(mbn->mac_id), + le32toh(mbn->consec_missed_beacons_since_last_rx), + le32toh(mbn->consec_missed_beacons), + le32toh(mbn->num_expected_beacons), + le32toh(mbn->num_recvd_beacons)); + missed = le32toh(mbn->consec_missed_beacons_since_last_rx); if (missed > vap->iv_bmissthreshold) { ieee80211_beacon_miss(ic); } - } static int @@ -5491,6 +5501,9 @@ iwx_tx_fill_cmd(struct iwx_softc *sc, struct iwx_node *in, /* for non-data, use the lowest supported rate */ ridx = min_ridx; *flags |= IWX_TX_FLAGS_CMD_RATE; + } else if (ni->ni_flags & IEEE80211_NODE_VHT) { + /* TODO: VHT - the ridx / rate array doesn't have VHT rates yet */ + ridx = iwx_min_basic_rate(ic); } else if (ni->ni_flags & IEEE80211_NODE_HT) { ridx = iwx_mcs2ridx[ieee80211_node_get_txrate_dot11rate(ni) & ~IEEE80211_RATE_MCS]; @@ -5622,6 +5635,8 @@ iwx_tx(struct iwx_softc *sc, struct mbuf *m, struct ieee80211_node *ni) struct mbuf *m1; size_t txcmd_size; + IWX_ASSERT_LOCKED(sc); + wh = mtod(m, struct ieee80211_frame *); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; @@ -7308,97 +7323,107 @@ iwx_rs_init(struct iwx_softc *sc, struct iwx_node *in) return iwx_rs_init_v3(sc, in); } -static void -iwx_rs_update(struct iwx_softc *sc, struct iwx_tlc_update_notif *notif) + +/** + * @brief Turn the given TX rate control notification into an ieee80211_node_txrate + * + * This populates the given txrate node with the TX rate control notification. + * + * @param sc driver softc + * @param notif firmware notification + * @param ni ieee80211_node update + * @returns true if updated, false if not + */ +static bool +iwx_rs_update_node_txrate(struct iwx_softc *sc, + const struct iwx_tlc_update_notif *notif, struct ieee80211_node *ni) { struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - struct ieee80211_node *ni = (void *)vap->iv_bss; + /* XXX TODO: create an inline function in if_iwxreg.h? */ + static int cck_idx_to_rate[] = { 2, 4, 11, 22, 2, 2, 2, 2 }; + static int ofdm_idx_to_rate[] = { 12, 18, 24, 36, 48, 72, 96, 108 }; - struct ieee80211_rateset *rs = &ni->ni_rates; uint32_t rate_n_flags; - uint8_t plcp, rval; - int i, cmd_ver, rate_n_flags_ver2 = 0; - - if (notif->sta_id != IWX_STATION_ID || - (le32toh(notif->flags) & IWX_TLC_NOTIF_FLAG_RATE) == 0) - return; + uint32_t type; + /* Extract the rate and command version */ rate_n_flags = le32toh(notif->rate); + if (sc->sc_rate_n_flags_version != 2) { + net80211_ic_printf(ic, + "%s: unsupported rate_n_flags version (%d)\n", + __func__, + sc->sc_rate_n_flags_version); + return (false); + } + if (sc->sc_debug & IWX_DEBUG_TXRATE) print_ratenflags(__func__, __LINE__, rate_n_flags, sc->sc_rate_n_flags_version); - cmd_ver = iwx_lookup_notif_ver(sc, IWX_DATA_PATH_GROUP, - IWX_TLC_MNG_UPDATE_NOTIF); - if (cmd_ver != IWX_FW_CMD_VER_UNKNOWN && cmd_ver >= 3) - rate_n_flags_ver2 = 1; - - if (rate_n_flags_ver2) { - uint32_t mod_type = (rate_n_flags & IWX_RATE_MCS_MOD_TYPE_MSK); - if (mod_type == IWX_RATE_MCS_HT_MSK) { - - ieee80211_node_set_txrate_dot11rate(ni, - IWX_RATE_HT_MCS_INDEX(rate_n_flags) | - IEEE80211_RATE_MCS); - IWX_DPRINTF(sc, IWX_DEBUG_TXRATE, - "%s:%d new MCS: %d rate_n_flags: %x\n", - __func__, __LINE__, - ieee80211_node_get_txrate_dot11rate(ni) & ~IEEE80211_RATE_MCS, - rate_n_flags); - return; - } - } else { - if (rate_n_flags & IWX_RATE_MCS_HT_MSK_V1) { - ieee80211_node_set_txrate_dot11rate(ni, - rate_n_flags & (IWX_RATE_HT_MCS_RATE_CODE_MSK_V1 | - IWX_RATE_HT_MCS_NSS_MSK_V1)); - - IWX_DPRINTF(sc, IWX_DEBUG_TXRATE, - "%s:%d new MCS idx: %d rate_n_flags: %x\n", - __func__, __LINE__, - ieee80211_node_get_txrate_dot11rate(ni), rate_n_flags); - return; - } + type = (rate_n_flags & IWX_RATE_MCS_MOD_TYPE_MSK); + switch (type) { + case IWX_RATE_MCS_CCK_MSK: + ieee80211_node_set_txrate_dot11rate(ni, + cck_idx_to_rate[rate_n_flags & IWX_RATE_LEGACY_RATE_MSK]); + return (true); + case IWX_RATE_MCS_LEGACY_OFDM_MSK: + ieee80211_node_set_txrate_dot11rate(ni, + ofdm_idx_to_rate[rate_n_flags & IWX_RATE_LEGACY_RATE_MSK]); + return (true); + case IWX_RATE_MCS_HT_MSK: + /* + * TODO: the current API doesn't include channel width + * and other flags, so we can't accurately store them yet! + * + * channel width: (flags & IWX_RATE_MCS_CHAN_WIDTH_MSK) + * >> IWX_RATE_MCS_CHAN_WIDTH_POS) + * LDPC: (flags & (1 << 16)) + */ + ieee80211_node_set_txrate_ht_mcsrate(ni, + IWX_RATE_HT_MCS_INDEX(rate_n_flags)); + return (true); + case IWX_RATE_MCS_VHT_MSK: + /* TODO: same comment on channel width, etc above */ + ieee80211_node_set_txrate_vht_rate(ni, + IWX_RATE_VHT_MCS_CODE(rate_n_flags), + IWX_RATE_VHT_MCS_NSS(rate_n_flags)); + return (true); + default: + net80211_ic_printf(ic, + "%s: unsupported chosen rate type in " + "IWX_RATE_MCS_MOD_TYPE (%d)\n", __func__, + type >> IWX_RATE_MCS_MOD_TYPE_POS); + return (false); } - if (rate_n_flags_ver2) { - const struct ieee80211_rateset *rs; - uint32_t ridx = (rate_n_flags & IWX_RATE_LEGACY_RATE_MSK); - if (rate_n_flags & IWX_RATE_MCS_LEGACY_OFDM_MSK) - rs = &ieee80211_std_rateset_11a; - else - rs = &ieee80211_std_rateset_11b; - if (ridx < rs->rs_nrates) - rval = (rs->rs_rates[ridx] & IEEE80211_RATE_VAL); - else - rval = 0; - } else { - plcp = (rate_n_flags & IWX_RATE_LEGACY_RATE_MSK_V1); + /* Default: if we get here, we didn't successfully update anything */ + return (false); +} - rval = 0; - for (i = IWX_RATE_1M_INDEX; i < nitems(iwx_rates); i++) { - if (iwx_rates[i].plcp == plcp) { - rval = iwx_rates[i].rate; - break; - } - } - } +/** + * @brief Process a firmware rate control update and update net80211. + * + * Since firmware is doing rate control, this just needs to update + * the txrate in the ieee80211_node entry. + */ +static void +iwx_rs_update(struct iwx_softc *sc, struct iwx_tlc_update_notif *notif) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + /* XXX TODO: get a node ref! */ + struct ieee80211_node *ni = (void *)vap->iv_bss; - if (rval) { - uint8_t rv; - for (i = 0; i < rs->rs_nrates; i++) { - rv = rs->rs_rates[i] & IEEE80211_RATE_VAL; - if (rv == rval) { - ieee80211_node_set_txrate_dot11rate(ni, i); - break; - } - } - IWX_DPRINTF(sc, IWX_DEBUG_TXRATE, - "%s:%d new rate %d\n", __func__, __LINE__, - ieee80211_node_get_txrate_dot11rate(ni)); - } + /* + * For now the iwx driver only supports a single vdev with a single + * node; it doesn't yet support ibss/hostap/multiple vdevs. + */ + if (notif->sta_id != IWX_STATION_ID || + (le32toh(notif->flags) & IWX_TLC_NOTIF_FLAG_RATE) == 0) + return; + + iwx_rs_update_node_txrate(sc, notif, ni); } static int @@ -8526,6 +8551,8 @@ iwx_start(struct iwx_softc *sc) struct ieee80211_node *ni; struct mbuf *m; + IWX_ASSERT_LOCKED(sc); + while (sc->qfullmsk == 0 && (m = mbufq_dequeue(&sc->sc_snd)) != NULL) { ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; if (iwx_tx(sc, m, ni) != 0) { @@ -8985,10 +9012,10 @@ iwx_rx_pkt(struct iwx_softc *sc, struct iwx_rx_data *data, struct mbuf *ml) break; case IWX_MISSED_BEACONS_NOTIFICATION: + IWX_DPRINTF(sc, IWX_DEBUG_BEACON, + "%s: IWX_MISSED_BEACONS_NOTIFICATION\n", + __func__); iwx_rx_bmiss(sc, pkt, data); - DPRINTF(("%s: IWX_MISSED_BEACONS_NOTIFICATION\n", - __func__)); - ieee80211_beacon_miss(ic); break; case IWX_MFUART_LOAD_NOTIFICATION: diff --git a/sys/dev/iwx/if_iwxreg.h b/sys/dev/iwx/if_iwxreg.h index 6755b93fa0ba..f3d1f078b48e 100644 --- a/sys/dev/iwx/if_iwxreg.h +++ b/sys/dev/iwx/if_iwxreg.h @@ -5176,6 +5176,10 @@ enum { #define IWX_RATE_HT_MCS_INDEX(r) ((((r) & IWX_RATE_MCS_NSS_MSK) >> 1) | \ ((r) & IWX_RATE_HT_MCS_CODE_MSK)) +#define IWX_RATE_VHT_MCS_CODE(r) ((r) & IWX_RATE_HT_MCS_CODE_MSK) +#define IWX_RATE_VHT_MCS_NSS(r) \ + ((((r) & IWX_RATE_MCS_NSS_MSK) == 0) >> IWX_RATE_MCS_NSS_POS) + /* Bits 7-5: reserved */ /* diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 9e43a4c1909f..cde98cb62cef 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -240,6 +240,7 @@ struct pci_quirk { #define PCI_QUIRK_DISABLE_MSIX 5 /* MSI-X doesn't work */ #define PCI_QUIRK_MSI_INTX_BUG 6 /* PCIM_CMD_INTxDIS disables MSI */ #define PCI_QUIRK_REALLOC_BAR 7 /* Can't allocate memory at the default address */ +#define PCI_QUIRK_DISABLE_FLR 8 /* Function-Level Reset (FLR) not working. */ int arg1; int arg2; }; @@ -319,6 +320,13 @@ static const struct pci_quirk pci_quirks[] = { * expected place. */ { 0x98741002, PCI_QUIRK_REALLOC_BAR, 0, 0 }, + + /* + * With some MediaTek mt76 WiFi FLR does not work despite advertised. + */ + { 0x061614c3, PCI_QUIRK_DISABLE_FLR, 0, 0 }, /* mt76 7922 */ + + /* end of table */ { 0 } }; @@ -6740,6 +6748,8 @@ pcie_flr(device_t dev, u_int max_delay, bool force) if (!(pci_read_config(dev, cap + PCIER_DEVICE_CAP, 4) & PCIEM_CAP_FLR)) return (false); + if (pci_has_quirk(pci_get_devid(dev), PCI_QUIRK_DISABLE_FLR)) + return (false); /* * Disable busmastering to prevent generation of new diff --git a/sys/dev/vmware/vmxnet3/if_vmx.c b/sys/dev/vmware/vmxnet3/if_vmx.c index 62b5f313a137..1a314ca6660e 100644 --- a/sys/dev/vmware/vmxnet3/if_vmx.c +++ b/sys/dev/vmware/vmxnet3/if_vmx.c @@ -2056,7 +2056,12 @@ vmxnet3_update_admin_status(if_ctx_t ctx) struct vmxnet3_softc *sc; sc = iflib_get_softc(ctx); - if (sc->vmx_ds->event != 0) + /* + * iflib may invoke this routine before vmxnet3_attach_post() has + * run, which is before the top level shared data area is + * initialized and the device made aware of it. + */ + if (sc->vmx_ds != NULL && sc->vmx_ds->event != 0) vmxnet3_evintr(sc); vmxnet3_refresh_host_stats(sc); diff --git a/sys/kern/kern_mutex.c b/sys/kern/kern_mutex.c index 8b5908f5219a..d67c70984528 100644 --- a/sys/kern/kern_mutex.c +++ b/sys/kern/kern_mutex.c @@ -503,8 +503,8 @@ _mtx_trylock_flags_(volatile uintptr_t *c, int opts, const char *file, int line) /* * __mtx_lock_sleep: the tougher part of acquiring an MTX_DEF lock. * - * We call this if the lock is either contested (i.e. we need to go to - * sleep waiting for it), or if we need to recurse on it. + * We get here if lock profiling is enabled, the lock is already held by + * someone else or we are recursing on it. */ #if LOCK_DEBUG > 0 void @@ -660,13 +660,8 @@ retry_turnstile: } #endif - /* - * If the mutex isn't already contested and a failure occurs - * setting the contested bit, the mutex was either released - * or the state of the MTX_RECURSED bit changed. - */ - if ((v & MTX_CONTESTED) == 0 && - !atomic_fcmpset_ptr(&m->mtx_lock, &v, v | MTX_CONTESTED)) { + if ((v & MTX_WAITERS) == 0 && + !atomic_fcmpset_ptr(&m->mtx_lock, &v, v | MTX_WAITERS)) { goto retry_turnstile; } @@ -869,7 +864,7 @@ _thread_lock(struct thread *td) WITNESS_LOCK(&m->lock_object, LOP_EXCLUSIVE, file, line); return; } - _mtx_release_lock_quick(m); + atomic_store_rel_ptr(&m->mtx_lock, MTX_UNOWNED); slowpath_unlocked: spinlock_exit(); slowpath_noirq: @@ -959,7 +954,7 @@ retry: } if (m == td->td_lock) break; - _mtx_release_lock_quick(m); + atomic_store_rel_ptr(&m->mtx_lock, MTX_UNOWNED); } LOCK_LOG_LOCK("LOCK", &m->lock_object, opts, m->mtx_recurse, file, line); @@ -1029,8 +1024,8 @@ thread_lock_set(struct thread *td, struct mtx *new) /* * __mtx_unlock_sleep: the tougher part of releasing an MTX_DEF lock. * - * We are only called here if the lock is recursed, contested (i.e. we - * need to wake up a blocked thread) or lockstat probe is active. + * We get here if lock profiling is enabled, the lock is already held by + * someone else or we are recursing on it. */ #if LOCK_DEBUG > 0 void @@ -1071,7 +1066,7 @@ __mtx_unlock_sleep(volatile uintptr_t *c, uintptr_t v) * can be removed from the hash list if it is empty. */ turnstile_chain_lock(&m->lock_object); - _mtx_release_lock_quick(m); + atomic_store_rel_ptr(&m->mtx_lock, MTX_UNOWNED); ts = turnstile_lookup(&m->lock_object); MPASS(ts != NULL); if (LOCK_LOG_TEST(&m->lock_object, opts)) @@ -1207,7 +1202,7 @@ _mtx_destroy(volatile uintptr_t *c) if (!mtx_owned(m)) MPASS(mtx_unowned(m)); else { - MPASS((m->mtx_lock & (MTX_RECURSED|MTX_CONTESTED)) == 0); + MPASS((m->mtx_lock & (MTX_RECURSED|MTX_WAITERS)) == 0); /* Perform the non-mtx related part of mtx_unlock_spin(). */ if (LOCK_CLASS(&m->lock_object) == &lock_class_mtx_spin) { @@ -1359,8 +1354,8 @@ db_show_mtx(const struct lock_object *lock) db_printf("DESTROYED"); else { db_printf("OWNED"); - if (m->mtx_lock & MTX_CONTESTED) - db_printf(", CONTESTED"); + if (m->mtx_lock & MTX_WAITERS) + db_printf(", WAITERS"); if (m->mtx_lock & MTX_RECURSED) db_printf(", RECURSED"); } diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c index 30527fdd4fd0..57ebe8dc85f0 100644 --- a/sys/kern/sys_pipe.c +++ b/sys/kern/sys_pipe.c @@ -567,7 +567,7 @@ pipespace_new(struct pipe *cpipe, int size) static int curfail = 0; static struct timeval lastfail; - KASSERT(!mtx_owned(PIPE_MTX(cpipe)), ("pipespace: pipe mutex locked")); + PIPE_LOCK_ASSERT(cpipe, MA_NOTOWNED); KASSERT(!(cpipe->pipe_state & PIPE_DIRECTW), ("pipespace: resize of direct writes not allowed")); retry: @@ -1679,8 +1679,7 @@ static void pipe_free_kmem(struct pipe *cpipe) { - KASSERT(!mtx_owned(PIPE_MTX(cpipe)), - ("pipe_free_kmem: pipe mutex locked")); + PIPE_LOCK_ASSERT(cpipe, MA_NOTOWNED); if (cpipe->pipe_buffer.buffer != NULL) { atomic_subtract_long(&amountpipekva, cpipe->pipe_buffer.size); diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 3d4567b6ab1e..a53df50c06bd 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -806,9 +806,12 @@ file_v_lock(struct file *fp, short lock_bit, short lock_wait_bit) flagsp = &fp->f_vflags; state = atomic_load_16(flagsp); - if ((state & lock_bit) == 0 && - atomic_cmpset_acq_16(flagsp, state, state | lock_bit)) - return; + for (;;) { + if ((state & lock_bit) != 0) + break; + if (atomic_fcmpset_acq_16(flagsp, &state, state | lock_bit)) + return; + } sleepq_lock(flagsp); state = atomic_load_16(flagsp); @@ -842,9 +845,12 @@ file_v_unlock(struct file *fp, short lock_bit, short lock_wait_bit) flagsp = &fp->f_vflags; state = atomic_load_16(flagsp); - if ((state & lock_wait_bit) == 0 && - atomic_cmpset_rel_16(flagsp, state, state & ~lock_bit)) - return; + for (;;) { + if ((state & lock_wait_bit) != 0) + break; + if (atomic_fcmpset_rel_16(flagsp, &state, state & ~lock_bit)) + return; + } sleepq_lock(flagsp); MPASS((*flagsp & lock_bit) != 0); @@ -864,10 +870,6 @@ foffset_lock(struct file *fp, int flags) FILE_V_FOFFSET_LOCK_WAITING); } - /* - * According to McKusick the vn lock was protecting f_offset here. - * It is now protected by the FOFFSET_LOCKED flag. - */ return (atomic_load_long(&fp->f_offset)); } diff --git a/sys/modules/zfs/zfs_config.h b/sys/modules/zfs/zfs_config.h index c595030ed4a0..db1b6f33a8ef 100644 --- a/sys/modules/zfs/zfs_config.h +++ b/sys/modules/zfs/zfs_config.h @@ -843,7 +843,7 @@ /* #undef ZFS_DEVICE_MINOR */ /* Define the project alias string. */ -#define ZFS_META_ALIAS "zfs-2.4.99-72-FreeBSD_gb2196fbed" +#define ZFS_META_ALIAS "zfs-2.4.99-95-FreeBSD_g5605a6d79" /* Define the project author. */ #define ZFS_META_AUTHOR "OpenZFS" @@ -852,7 +852,7 @@ /* #undef ZFS_META_DATA */ /* Define the maximum compatible kernel version. */ -#define ZFS_META_KVER_MAX "6.16" +#define ZFS_META_KVER_MAX "6.17" /* Define the minimum compatible kernel version. */ #define ZFS_META_KVER_MIN "4.18" @@ -873,7 +873,7 @@ #define ZFS_META_NAME "zfs" /* Define the project release. */ -#define ZFS_META_RELEASE "72-FreeBSD_gb2196fbed" +#define ZFS_META_RELEASE "95-FreeBSD_g5605a6d79" /* Define the project version. */ #define ZFS_META_VERSION "2.4.99" diff --git a/sys/modules/zfs/zfs_gitrev.h b/sys/modules/zfs/zfs_gitrev.h index 9eae1e8573c0..8a1802f5480b 100644 --- a/sys/modules/zfs/zfs_gitrev.h +++ b/sys/modules/zfs/zfs_gitrev.h @@ -1 +1 @@ -#define ZFS_META_GITREV "zfs-2.4.99-72-gb2196fbed" +#define ZFS_META_GITREV "zfs-2.4.99-95-g5605a6d79" diff --git a/sys/netgraph/netflow/netflow.c b/sys/netgraph/netflow/netflow.c index 978d6fd0b54d..05c6062463be 100644 --- a/sys/netgraph/netflow/netflow.c +++ b/sys/netgraph/netflow/netflow.c @@ -960,7 +960,7 @@ struct ngnf_show_header *resp) list_id = 0; TAILQ_FOREACH(fle, &hsh->head, fle_hash) { - if (hsh->mtx.mtx_lock & MTX_CONTESTED) { + if (hsh->mtx.mtx_lock & MTX_WAITERS) { resp->hash_id = i; resp->list_id = list_id; mtx_unlock(&hsh->mtx); @@ -1111,7 +1111,7 @@ ng_netflow_expire(void *arg) * Interrupt thread wants this entry! * Quick! Quick! Bail out! */ - if (hsh->mtx.mtx_lock & MTX_CONTESTED) + if (hsh->mtx.mtx_lock & MTX_WAITERS) break; /* @@ -1150,7 +1150,7 @@ ng_netflow_expire(void *arg) * Interrupt thread wants this entry! * Quick! Quick! Bail out! */ - if (hsh->mtx.mtx_lock & MTX_CONTESTED) + if (hsh->mtx.mtx_lock & MTX_WAITERS) break; /* diff --git a/sys/netinet/sctp_lock_bsd.h b/sys/netinet/sctp_lock_bsd.h index ec66be0cf371..a60983cb30e3 100644 --- a/sys/netinet/sctp_lock_bsd.h +++ b/sys/netinet/sctp_lock_bsd.h @@ -263,10 +263,10 @@ } while (0) #define SCTP_INP_LOCK_CONTENDED(_inp) \ - ((_inp)->inp_mtx.mtx_lock & MTX_CONTESTED) + ((_inp)->inp_mtx.mtx_lock & MTX_WAITERS) #define SCTP_INP_READ_CONTENDED(_inp) \ - ((_inp)->inp_rdata_mtx.mtx_lock & MTX_CONTESTED) + ((_inp)->inp_rdata_mtx.mtx_lock & MTX_WAITERS) #ifdef SCTP_LOCK_LOGGING #define SCTP_INP_RLOCK(_inp) do { \ @@ -337,7 +337,7 @@ } while (0) #define SCTP_ASOC_CREATE_LOCK_CONTENDED(_inp) \ - ((_inp)->inp_create_mtx.mtx_lock & MTX_CONTESTED) + ((_inp)->inp_create_mtx.mtx_lock & MTX_WAITERS) /* * For the majority of things (once we have found the association) we will diff --git a/sys/sys/mutex.h b/sys/sys/mutex.h index 08d4e2d28b33..4f6b45d78a88 100644 --- a/sys/sys/mutex.h +++ b/sys/sys/mutex.h @@ -68,9 +68,9 @@ */ #define MTX_UNOWNED 0x00000000 /* Cookie for free mutex */ #define MTX_RECURSED 0x00000001 /* lock recursed (for MTX_DEF only) */ -#define MTX_CONTESTED 0x00000002 /* lock contested (for MTX_DEF only) */ +#define MTX_WAITERS 0x00000002 /* lock has waiters (for MTX_DEF only) */ #define MTX_DESTROYED 0x00000004 /* lock destroyed */ -#define MTX_FLAGMASK (MTX_RECURSED | MTX_CONTESTED | MTX_DESTROYED) +#define MTX_FLAGMASK (MTX_RECURSED | MTX_WAITERS | MTX_DESTROYED) /* * Prototypes @@ -217,14 +217,10 @@ void _thread_lock(struct thread *); #define _mtx_obtain_lock_fetch(mp, vp, tid) \ atomic_fcmpset_acq_ptr(&(mp)->mtx_lock, vp, (tid)) -/* Try to release mtx_lock if it is unrecursed and uncontested. */ +/* Try to release mtx_lock if it is unrecursed and without waiters. */ #define _mtx_release_lock(mp, tid) \ atomic_cmpset_rel_ptr(&(mp)->mtx_lock, (tid), MTX_UNOWNED) -/* Release mtx_lock quickly, assuming we own it. */ -#define _mtx_release_lock_quick(mp) \ - atomic_store_rel_ptr(&(mp)->mtx_lock, MTX_UNOWNED) - #define _mtx_release_lock_fetch(mp, vp) \ atomic_fcmpset_rel_ptr(&(mp)->mtx_lock, (vp), MTX_UNOWNED) @@ -246,10 +242,10 @@ void _thread_lock(struct thread *); }) /* - * Lock a spin mutex. For spinlocks, we handle recursion inline (it - * turns out that function calls can be significantly expensive on - * some architectures). Since spin locks are not _too_ common, - * inlining this code is not too big a deal. + * Lock a spin mutex. + * + * FIXME: spinlock_enter is a function call, defeating the point of inlining in + * this. */ #ifdef SMP #define __mtx_lock_spin(mp, tid, opts, file, line) __extension__ ({ \ @@ -317,10 +313,10 @@ void _thread_lock(struct thread *); }) /* - * Unlock a spin mutex. For spinlocks, we can handle everything - * inline, as it's pretty simple and a function call would be too - * expensive (at least on some architectures). Since spin locks are - * not _too_ common, inlining this code is not too big a deal. + * Unlock a spin mutex. + * + * FIXME: spinlock_exit is a function call, defeating the point of inlining in + * this. * * Since we always perform a spinlock_enter() when attempting to acquire a * spin lock, we need to always perform a matching spinlock_exit() when @@ -332,7 +328,7 @@ void _thread_lock(struct thread *); (mp)->mtx_recurse--; \ else { \ LOCKSTAT_PROFILE_RELEASE_SPIN_LOCK(spin__release, mp); \ - _mtx_release_lock_quick((mp)); \ + atomic_store_rel_ptr(&(mp)->mtx_lock, MTX_UNOWNED); \ } \ spinlock_exit(); \ }) diff --git a/tools/test/stress2/misc/all.exclude b/tools/test/stress2/misc/all.exclude index f9b32db95799..0658bfdc0c1b 100644 --- a/tools/test/stress2/misc/all.exclude +++ b/tools/test/stress2/misc/all.exclude @@ -25,6 +25,7 @@ gnop13.sh https://people.freebsd.org/~pho/stress/log/log0386.txt 20221113 gnop7.sh Waiting for patch commit 20190820 gnop8.sh Waiting for patch commit 20201214 gnop9.sh Waiting for patch commit 20201214 +graid1_3.sh Hang seen 20250915 graid1_8.sh Known issue 20170909 graid1_9.sh panic: Bad effnlink 20180212 lockf5.sh Spinning threads seen 20160718 @@ -74,10 +75,13 @@ syzkaller67.sh panic: ASan: Invalid access, 8-byte read at ... 20230621 syzkaller80.sh panic 20250711 syzkaller81.sh panic 20250711 syzkaller82.sh panic: m_apply, length > size of mbuf chain 20250724 +syzkaller84.sh panic: Assertion !(sb->sb_state & SBS_CANTRCVMORE) 20250810 +syzkaller85.sh panic: Assertion uio->uio_resid < 0 failed 20250928 +syzkaller86.sh Fatal trap 12: page fault while in kernel mode 20251001 +write2.sh panic: sndbuf_acquire: count 255 > free 0 20251003 quota3.sh https://people.freebsd.org/~pho/stress/log/log0604.txt 20250728 quota6.sh https://people.freebsd.org/~pho/stress/log/log0456.txt 20240707 truss3.sh WiP 20200915 -zfs18.sh https://people.freebsd.org/~pho/stress/log/log0560.txt 20241118 zfs9.sh panic: sacked_bytes < 0 20250711 # Test not to run for other reasons: diff --git a/tools/test/stress2/misc/fuzz.sh b/tools/test/stress2/misc/fuzz.sh index 189cdbfebd01..add3d0d19a21 100755 --- a/tools/test/stress2/misc/fuzz.sh +++ b/tools/test/stress2/misc/fuzz.sh @@ -49,6 +49,7 @@ . ../default.cfg D=$diskimage +backup=/tmp/fuzz.sh.diskimage.`date +%Y%m%dT%H%M%S`.gz tst() { rm -f $D @@ -62,6 +63,7 @@ tst() { for i in `jot 50`; do ./fuzz -n 50 $D + gzip < $D > $backup if fsck -f -y /dev/md$mdstart 2>&1 | egrep "^[A-Z]" > /dev/null; then if fsck -f -y /dev/md$mdstart 2>&1 | egrep "^[A-Z]" > /dev/null; then if fsck -f -y /dev/md$mdstart 2>&1 | egrep "^[A-Z]" > /dev/null; then @@ -73,7 +75,7 @@ tst() { sync;sync;sync if mount /dev/md$mdstart $mntpoint; then ls -l $mntpoint > /dev/null - find $mntpoint -exec dd if={} of=/dev/null bs=1m count=3 \; > /dev/null 2>&1 + find $mntpoint -type f -exec dd if={} of=/dev/null bs=1m count=3 \; > /dev/null 2>&1 umount $mntpoint else echo "Giving up at loop $i" @@ -96,7 +98,7 @@ for j in `jot 10`; do date '+%T' tst done -rm -f fuzz +rm -f fuzz $backup exit diff --git a/tools/test/stress2/misc/syzkaller84.sh b/tools/test/stress2/misc/syzkaller84.sh new file mode 100755 index 000000000000..a7976be2eeb6 --- /dev/null +++ b/tools/test/stress2/misc/syzkaller84.sh @@ -0,0 +1,402 @@ +#!/bin/sh + +# panic: Assertion !(sb->sb_state & SBS_CANTRCVMORE) failed at ../../../kern/uipc_usrreq.c:1549 +# cpuid = 6 +# time = 1754809105 +# KDB: stack backtrace: +# db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame 0xfffffe0176ef6a80 +# vpanic() at vpanic+0x136/frame 0xfffffe0176ef6bb0 +# panic() at panic+0x43/frame 0xfffffe0176ef6c10 +# uipc_soreceive_stream_or_seqpacket() at uipc_soreceive_stream_or_seqpacket+0x968/frame 0xfffffe0176ef6cd0 +# soreceive() at soreceive+0x45/frame 0xfffffe0176ef6cf0 +# kern_recvit() at kern_recvit+0x181/frame 0xfffffe0176ef6da0 +# sys_recvmsg() at sys_recvmsg+0x67/frame 0xfffffe0176ef6e00 +# amd64_syscall() at amd64_syscall+0x169/frame 0xfffffe0176ef6f30 +# fast_syscall_common() at fast_syscall_common+0xf8/frame 0xfffffe0176ef6f30 +# --- syscall (0, FreeBSD ELF64, syscall), rip = 0x821d3da8a, rsp = 0x824440f68, rbp = 0x824440f90 --- +# KDB: enter: panic +# [ thread pid 17448 tid 292963 ] +# Stopped at kdb_enter+0x33: movq $0,0x12304a2(%rip) +# db> x/s version +# version: FreeBSD 15.0-PRERELEASE #0 main-n279510-db7c0e32a05d-dirty: Sat Aug 9 17:21:54 CEST 2025 +# pho@mercat1.netperf.freebsd.org:/usr/src/sys/amd64/compile/PHO +# db> + +[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 + +. ../default.cfg +set -u +prog=$(basename "$0" .sh) +cat > /tmp/$prog.c <<EOF +// https://syzkaller.appspot.com/bug?id=79d6de939eb5c7de69e8e4993b6239aa0ae67335 +// autogenerated by syzkaller (https://github.com/google/syzkaller) +// syzbot+ffcc3612ea266e36604e@syzkaller.appspotmail.com + +#define _GNU_SOURCE + +#include <sys/types.h> + +#include <errno.h> +#include <pthread.h> +#include <pwd.h> +#include <signal.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/endian.h> +#include <sys/resource.h> +#include <sys/syscall.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> + +static unsigned long long procid; + +static void kill_and_wait(int pid, int* status) +{ + kill(pid, SIGKILL); + while (waitpid(-1, status, 0) != pid) { + } +} + +static void sleep_ms(uint64_t ms) +{ + usleep(ms * 1000); +} + +static uint64_t current_time_ms(void) +{ + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts)) + exit(1); + return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; +} + +static void thread_start(void* (*fn)(void*), void* arg) +{ + pthread_t th; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, 128 << 10); + int i = 0; + for (; i < 100; i++) { + if (pthread_create(&th, &attr, fn, arg) == 0) { + pthread_attr_destroy(&attr); + return; + } + if (errno == EAGAIN) { + usleep(50); + continue; + } + break; + } + exit(1); +} + +typedef struct { + pthread_mutex_t mu; + pthread_cond_t cv; + int state; +} event_t; + +static void event_init(event_t* ev) +{ + if (pthread_mutex_init(&ev->mu, 0)) + exit(1); + if (pthread_cond_init(&ev->cv, 0)) + exit(1); + ev->state = 0; +} + +static void event_reset(event_t* ev) +{ + ev->state = 0; +} + +static void event_set(event_t* ev) +{ + pthread_mutex_lock(&ev->mu); + if (ev->state) + exit(1); + ev->state = 1; + pthread_mutex_unlock(&ev->mu); + pthread_cond_broadcast(&ev->cv); +} + +static void event_wait(event_t* ev) +{ + pthread_mutex_lock(&ev->mu); + while (!ev->state) + pthread_cond_wait(&ev->cv, &ev->mu); + pthread_mutex_unlock(&ev->mu); +} + +static int event_isset(event_t* ev) +{ + pthread_mutex_lock(&ev->mu); + int res = ev->state; + pthread_mutex_unlock(&ev->mu); + return res; +} + +static int event_timedwait(event_t* ev, uint64_t timeout) +{ + uint64_t start = current_time_ms(); + uint64_t now = start; + pthread_mutex_lock(&ev->mu); + for (;;) { + if (ev->state) + break; + uint64_t remain = timeout - (now - start); + struct timespec ts; + ts.tv_sec = remain / 1000; + ts.tv_nsec = (remain % 1000) * 1000 * 1000; + pthread_cond_timedwait(&ev->cv, &ev->mu, &ts); + now = current_time_ms(); + if (now - start > timeout) + break; + } + int res = ev->state; + pthread_mutex_unlock(&ev->mu); + return res; +} + +static void sandbox_common() +{ + struct rlimit rlim; + rlim.rlim_cur = rlim.rlim_max = 128 << 20; + setrlimit(RLIMIT_AS, &rlim); + rlim.rlim_cur = rlim.rlim_max = 8 << 20; + setrlimit(RLIMIT_MEMLOCK, &rlim); + rlim.rlim_cur = rlim.rlim_max = 1 << 20; + setrlimit(RLIMIT_FSIZE, &rlim); + rlim.rlim_cur = rlim.rlim_max = 1 << 20; + setrlimit(RLIMIT_STACK, &rlim); + rlim.rlim_cur = rlim.rlim_max = 0; + setrlimit(RLIMIT_CORE, &rlim); + rlim.rlim_cur = rlim.rlim_max = 256; + setrlimit(RLIMIT_NOFILE, &rlim); +} + +static void loop(); + +static int do_sandbox_none(void) +{ + sandbox_common(); + loop(); + return 0; +} + +struct thread_t { + int created, call; + event_t ready, done; +}; + +static struct thread_t threads[16]; +static void execute_call(int call); +static int running; + +static void* thr(void* arg) +{ + struct thread_t* th = (struct thread_t*)arg; + for (;;) { + event_wait(&th->ready); + event_reset(&th->ready); + execute_call(th->call); + __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED); + event_set(&th->done); + } + return 0; +} + +static void execute_one(void) +{ + if (write(1, "executing program\n", sizeof("executing program\n") - 1)) { + } + int i, call, thread; + for (call = 0; call < 4; call++) { + for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0])); + thread++) { + struct thread_t* th = &threads[thread]; + if (!th->created) { + th->created = 1; + event_init(&th->ready); + event_init(&th->done); + event_set(&th->done); + thread_start(thr, th); + } + if (!event_isset(&th->done)) + continue; + event_reset(&th->done); + th->call = call; + __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED); + event_set(&th->ready); + event_timedwait(&th->done, 50); + break; + } + } + for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++) + sleep_ms(1); +} + +static void execute_one(void); + +#define WAIT_FLAGS 0 + +static void loop(void) +{ +// int iter = 0; + for (;; /*iter++*/) { + int pid = fork(); + if (pid < 0) + exit(1); + if (pid == 0) { + execute_one(); + exit(0); + } + int status = 0; + uint64_t start = current_time_ms(); + for (;;) { + sleep_ms(10); + if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid) + break; + if (current_time_ms() - start < 5000) + continue; + kill_and_wait(pid, &status); + break; + } + } +} + +uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff}; + +void execute_call(int call) +{ + intptr_t res = 0; + switch (call) { + case 0: + // socketpair\$unix arguments: [ + // domain: const = 0x1 (8 bytes) + // type: unix_socket_type = 0x5 (8 bytes) + // proto: const = 0x0 (1 bytes) + // fds: ptr[out, unix_pair] { + // unix_pair { + // fd0: sock_unix (resource) + // fd1: sock_unix (resource) + // } + // } + // ] + res = syscall(SYS_socketpair, /*domain=*/1ul, /*type=SOCK_SEQPACKET*/ 5ul, + /*proto=*/0, /*fds=*/0x200000000440ul); + if (res != -1) { + r[0] = *(uint32_t*)0x200000000440; + r[1] = *(uint32_t*)0x200000000444; + } + break; + case 1: + // sendmsg arguments: [ + // fd: sock (resource) + // msg: ptr[in, send_msghdr] { + // send_msghdr { + // msg_name: nil + // msg_namelen: len = 0x0 (4 bytes) + // pad = 0x0 (4 bytes) + // msg_iov: nil + // msg_iovlen: len = 0x0 (8 bytes) + // msg_control: ptr[inout, array[ANYUNION]] { + // array[ANYUNION] { + // union ANYUNION { + // ANYBLOB: buffer: {04 01 00 00 ff ff 00 00 01} (length 0x9) + // } + // } + // } + // msg_controllen: bytesize = 0x104 (8 bytes) + // msg_flags: const = 0x0 (4 bytes) + // pad = 0x0 (4 bytes) + // } + // } + // f: send_flags = 0x0 (8 bytes) + // ] + *(uint64_t*)0x200000000000 = 0; + *(uint32_t*)0x200000000008 = 0; + *(uint64_t*)0x200000000010 = 0; + *(uint64_t*)0x200000000018 = 0; + *(uint64_t*)0x200000000020 = 0x2000000007c0; + memcpy((void*)0x2000000007c0, "\x04\x01\x00\x00\xff\xff\x00\x00\x01", 9); + *(uint64_t*)0x200000000028 = 0x104; + *(uint32_t*)0x200000000030 = 0; + syscall(SYS_sendmsg, /*fd=*/r[1], /*msg=*/0x200000000000ul, /*f=*/0ul); + for (int i = 0; i < 32; i++) { + syscall(SYS_sendmsg, /*fd=*/r[1], /*msg=*/0x200000000000ul, /*f=*/0ul); + } + break; + case 2: + // close arguments: [ + // fd: fd (resource) + // ] + syscall(SYS_close, /*fd=*/r[1]); + break; + case 3: + // recvmsg arguments: [ + // fd: sock (resource) + // msg: ptr[inout, recv_msghdr] { + // recv_msghdr { + // msg_name: nil + // msg_namelen: len = 0x0 (4 bytes) + // pad = 0x0 (4 bytes) + // msg_iov: nil + // msg_iovlen: len = 0x0 (8 bytes) + // msg_control: ptr[out, buffer] { + // buffer: (DirOut) + // } + // msg_controllen: len = 0x19 (8 bytes) + // msg_flags: const = 0x0 (4 bytes) + // pad = 0x0 (4 bytes) + // } + // } + // f: recv_flags = 0x80 (8 bytes) + // ] + *(uint64_t*)0x2000000005c0 = 0; + *(uint32_t*)0x2000000005c8 = 0; + *(uint64_t*)0x2000000005d0 = 0; + *(uint64_t*)0x2000000005d8 = 0; + *(uint64_t*)0x2000000005e0 = 0x200000000580; + *(uint64_t*)0x2000000005e8 = 0x19; + *(uint32_t*)0x2000000005f0 = 0; + syscall(SYS_recvmsg, /*fd=*/r[0], /*msg=*/0x2000000005c0ul, + /*f=MSG_DONTWAIT*/ 0x80ul); + break; + } +} +int main(void) +{ + syscall(SYS_mmap, /*addr=*/0x200000000000ul, /*len=*/0x1000000ul, + /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/ 7ul, + /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x1012ul, + /*fd=*/(intptr_t)-1, /*offset=*/0ul); + const char* reason; + (void)reason; + for (procid = 0; procid < 4; procid++) { + if (fork() == 0) { + do_sandbox_none(); + } + } + sleep(1000000); + return 0; +} +EOF +mycc -o /tmp/$prog -Wall -Wextra -O0 /tmp/$prog.c -pthread || exit 1 + +work=/tmp/$prog.dir +rm -rf $work +mkdir $work +cd /tmp/$prog.dir +kldstat | grep -q sctp || { kldload sctp.ko && loaded=1; } +timeout 3m /tmp/$prog > /dev/null 2>&1 + +rm -rf /tmp/$prog /tmp/$prog.c /tmp/$prog.core $work +[ $loaded ] && kldunload sctp.ko +exit 0 diff --git a/tools/test/stress2/misc/syzkaller85.sh b/tools/test/stress2/misc/syzkaller85.sh new file mode 100755 index 000000000000..1772c0dc58b8 --- /dev/null +++ b/tools/test/stress2/misc/syzkaller85.sh @@ -0,0 +1,499 @@ +#!/bin/sh + +# panic: Assertion uio->uio_resid < 0 failed at ../../../netlink/netlink_domain.c:808 +# cpuid = 8 +# time = 1759044376 +# KDB: stack backtrace: +# db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame 0xfffffe0184d17a70 +# vpanic() at vpanic+0x136/frame 0xfffffe0184d17ba0 +# panic() at panic+0x43/frame 0xfffffe0184d17c00 +# nl_soreceive() at nl_soreceive+0x433/frame 0xfffffe0184d17ca0 +# soreceive() at soreceive+0x45/frame 0xfffffe0184d17cc0 +# kern_recvit() at kern_recvit+0x181/frame 0xfffffe0184d17d70 +# sys_recvfrom() at sys_recvfrom+0xa2/frame 0xfffffe0184d17e00 +# amd64_syscall() at amd64_syscall+0x169/frame 0xfffffe0184d17f30 +# fast_syscall_common() at fast_syscall_common+0xf8/frame 0xfffffe0184d17f30 +# --- syscall (0, FreeBSD ELF64, syscall), rip = 0x822882cca, rsp = 0x823572e88, rbp = 0x823572f90 --- +# KDB: enter: panic +# [ thread pid 11012 tid 138112 ] +# Stopped at $0,0x121a722(%rip) +# db> x/s version +# version: FreeBSD 16.0-CURRENT #0 main-n280667-52eb7e394a7e-dirty: Sun Sep 28 08:56:14 CEST 2025 +# pho@mercat1.netperf.freebsd.org:/usr/src/sys/amd64/compile/PHO +# db> + +[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 + +. ../default.cfg +set -u +prog=$(basename "$0" .sh) +cat > /tmp/$prog.c <<EOF +// https://syzkaller.appspot.com/bug?id=e33cdff88b17af77553159c4b372cac4e4bcd652 +// autogenerated by syzkaller (https://github.com/google/syzkaller) +// syzbot+194f95f2c5fdffef1ef5@syzkaller.appspotmail.com + +#define _GNU_SOURCE + +#include <sys/types.h> + +#include <dirent.h> +#include <errno.h> +#include <pthread.h> +#include <pwd.h> +#include <setjmp.h> +#include <signal.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/endian.h> +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/syscall.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> + +static unsigned long long procid; + +static __thread int clone_ongoing; +static __thread int skip_segv; +static __thread jmp_buf segv_env; + +static void segv_handler(int sig, siginfo_t* info, void* ctx __unused) +{ + if (__atomic_load_n(&clone_ongoing, __ATOMIC_RELAXED) != 0) { + exit(sig); + } + uintptr_t addr = (uintptr_t)info->si_addr; + const uintptr_t prog_start = 1 << 20; + const uintptr_t prog_end = 100 << 20; + int skip = __atomic_load_n(&skip_segv, __ATOMIC_RELAXED) != 0; + int valid = addr < prog_start || addr > prog_end; + if (sig == SIGBUS) + valid = 1; + if (skip && valid) { + _longjmp(segv_env, 1); + } + exit(sig); +} + +static void install_segv_handler(void) +{ + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = segv_handler; + sa.sa_flags = SA_NODEFER | SA_SIGINFO; + sigaction(SIGSEGV, &sa, NULL); + sigaction(SIGBUS, &sa, NULL); +} + +#define NONFAILING(...) \ + ({ \ + int ok = 1; \ + __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \ + if (_setjmp(segv_env) == 0) { \ + __VA_ARGS__; \ + } else \ + ok = 0; \ + __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \ + ok; \ + }) + +static void kill_and_wait(int pid, int* status) +{ + kill(pid, SIGKILL); + while (waitpid(-1, status, 0) != pid) { + } +} + +static void sleep_ms(uint64_t ms) +{ + usleep(ms * 1000); +} + +static uint64_t current_time_ms(void) +{ + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts)) + exit(1); + return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; +} + +static void use_temporary_dir(void) +{ + char tmpdir_template[] = "./syzkaller.XXXXXX"; + char* tmpdir = mkdtemp(tmpdir_template); + if (!tmpdir) + exit(1); + if (chmod(tmpdir, 0777)) + exit(1); + if (chdir(tmpdir)) + exit(1); +} + +static void reset_flags(const char* filename) +{ + struct stat st; + if (lstat(filename, &st)) + exit(1); + st.st_flags &= ~(SF_NOUNLINK | UF_NOUNLINK | SF_IMMUTABLE | UF_IMMUTABLE | + SF_APPEND | UF_APPEND); + if (lchflags(filename, st.st_flags)) + exit(1); +} +static void __attribute__((noinline)) remove_dir(const char* dir) +{ + DIR* dp = opendir(dir); + if (dp == NULL) { + if (errno == EACCES) { + if (rmdir(dir)) + exit(1); + return; + } + exit(1); + } + struct dirent* ep = 0; + while ((ep = readdir(dp))) { + if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0) + continue; + char filename[FILENAME_MAX]; + snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name); + struct stat st; + if (lstat(filename, &st)) + exit(1); + if (S_ISDIR(st.st_mode)) { + remove_dir(filename); + continue; + } + if (unlink(filename)) { + if (errno == EPERM) { + reset_flags(filename); + reset_flags(dir); + if (unlink(filename) == 0) + continue; + } + exit(1); + } + } + closedir(dp); + while (rmdir(dir)) { + if (errno == EPERM) { + reset_flags(dir); + if (rmdir(dir) == 0) + break; + } + exit(1); + } +} + +static void thread_start(void* (*fn)(void*), void* arg) +{ + pthread_t th; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, 128 << 10); + int i = 0; + for (; i < 100; i++) { + if (pthread_create(&th, &attr, fn, arg) == 0) { + pthread_attr_destroy(&attr); + return; + } + if (errno == EAGAIN) { + usleep(50); + continue; + } + break; + } + exit(1); +} + +typedef struct { + pthread_mutex_t mu; + pthread_cond_t cv; + int state; +} event_t; + +static void event_init(event_t* ev) +{ + if (pthread_mutex_init(&ev->mu, 0)) + exit(1); + if (pthread_cond_init(&ev->cv, 0)) + exit(1); + ev->state = 0; +} + +static void event_reset(event_t* ev) +{ + ev->state = 0; +} + +static void event_set(event_t* ev) +{ + pthread_mutex_lock(&ev->mu); + if (ev->state) + exit(1); + ev->state = 1; + pthread_mutex_unlock(&ev->mu); + pthread_cond_broadcast(&ev->cv); +} + +static void event_wait(event_t* ev) +{ + pthread_mutex_lock(&ev->mu); + while (!ev->state) + pthread_cond_wait(&ev->cv, &ev->mu); + pthread_mutex_unlock(&ev->mu); +} + +static int event_isset(event_t* ev) +{ + pthread_mutex_lock(&ev->mu); + int res = ev->state; + pthread_mutex_unlock(&ev->mu); + return res; +} + +static int event_timedwait(event_t* ev, uint64_t timeout) +{ + uint64_t start = current_time_ms(); + uint64_t now = start; + pthread_mutex_lock(&ev->mu); + for (;;) { + if (ev->state) + break; + uint64_t remain = timeout - (now - start); + struct timespec ts; + ts.tv_sec = remain / 1000; + ts.tv_nsec = (remain % 1000) * 1000 * 1000; + pthread_cond_timedwait(&ev->cv, &ev->mu, &ts); + now = current_time_ms(); + if (now - start > timeout) + break; + } + int res = ev->state; + pthread_mutex_unlock(&ev->mu); + return res; +} + +static void sandbox_common() +{ + struct rlimit rlim; + rlim.rlim_cur = rlim.rlim_max = 128 << 20; + setrlimit(RLIMIT_AS, &rlim); + rlim.rlim_cur = rlim.rlim_max = 8 << 20; + setrlimit(RLIMIT_MEMLOCK, &rlim); + rlim.rlim_cur = rlim.rlim_max = 1 << 20; + setrlimit(RLIMIT_FSIZE, &rlim); + rlim.rlim_cur = rlim.rlim_max = 1 << 20; + setrlimit(RLIMIT_STACK, &rlim); + rlim.rlim_cur = rlim.rlim_max = 0; + setrlimit(RLIMIT_CORE, &rlim); + rlim.rlim_cur = rlim.rlim_max = 256; + setrlimit(RLIMIT_NOFILE, &rlim); +} + +static void loop(); + +static int do_sandbox_none(void) +{ + sandbox_common(); + loop(); + return 0; +} + +struct thread_t { + int created, call; + event_t ready, done; +}; + +static struct thread_t threads[16]; +static void execute_call(int call); +static int running; + +static void* thr(void* arg) +{ + struct thread_t* th = (struct thread_t*)arg; + for (;;) { + event_wait(&th->ready); + event_reset(&th->ready); + execute_call(th->call); + __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED); + event_set(&th->done); + } + return 0; +} + +static void execute_one(void) +{ + if (write(1, "executing program\n", sizeof("executing program\n") - 1)) { + } + int i, call, thread; + for (call = 0; call < 3; call++) { + for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0])); + thread++) { + struct thread_t* th = &threads[thread]; + if (!th->created) { + th->created = 1; + event_init(&th->ready); + event_init(&th->done); + event_set(&th->done); + thread_start(thr, th); + } + if (!event_isset(&th->done)) + continue; + event_reset(&th->done); + th->call = call; + __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED); + event_set(&th->ready); + event_timedwait(&th->done, 50); + break; + } + } + for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++) + sleep_ms(1); +} + +static void execute_one(void); + +#define WAIT_FLAGS 0 + +static void loop(void) +{ + int iter = 0; + for (;; iter++) { + char cwdbuf[32]; + sprintf(cwdbuf, "./%d", iter); + if (mkdir(cwdbuf, 0777)) + exit(1); + int pid = fork(); + if (pid < 0) + exit(1); + if (pid == 0) { + if (chdir(cwdbuf)) + exit(1); + execute_one(); + exit(0); + } + int status = 0; + uint64_t start = current_time_ms(); + for (;;) { + sleep_ms(10); + if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid) + break; + if (current_time_ms() - start < 5000) + continue; + kill_and_wait(pid, &status); + break; + } + remove_dir(cwdbuf); + } +} + +uint64_t r[1] = {0xffffffffffffffff}; + +void execute_call(int call) +{ + intptr_t res = 0; + switch (call) { + case 0: + // socket arguments: [ + // domain: socket_domain = 0x26 (8 bytes) + // type: socket_type = 0x2 (8 bytes) + // proto: int8 = 0x0 (1 bytes) + // ] + // returns sock + res = syscall(SYS_socket, /*domain=AF_INET|0x24*/ 0x26ul, + /*type=SOCK_DGRAM*/ 2ul, /*proto=*/0); + if (res != -1) + r[0] = res; + break; + case 1: + // bind arguments: [ + // fd: sock (resource) + // addr: ptr[in, sockaddr_storage] { + // union sockaddr_storage { + // in6: sockaddr_in6 { + // len: len = 0x22 (1 bytes) + // family: const = 0x1c (1 bytes) + // port: proc = 0x3 (2 bytes) + // flow: int32 = 0x0 (4 bytes) + // addr: union ipv6_addr { + // mcast1: ipv6_addr_multicast1 { + // a0: const = 0xff (1 bytes) + // a1: const = 0x1 (1 bytes) + // a2: buffer: {00 00 00 00 00 00 00 00 00 00 00 00 00} (length + // 0xd) a3: const = 0x1 (1 bytes) + // } + // } + // scope: int32 = 0x0 (4 bytes) + // } + // } + // } + // addrlen: len = 0xc (8 bytes) + // ] + NONFAILING(*(uint8_t*)0x200000000040 = 0x22); + NONFAILING(*(uint8_t*)0x200000000041 = 0x1c); + NONFAILING(*(uint16_t*)0x200000000042 = htobe16(0x4e23 + procid * 4)); + NONFAILING(*(uint32_t*)0x200000000044 = 0); + NONFAILING(*(uint8_t*)0x200000000048 = -1); + NONFAILING(*(uint8_t*)0x200000000049 = 1); + NONFAILING(memset((void*)0x20000000004a, 0, 13)); + NONFAILING(*(uint8_t*)0x200000000057 = 1); + NONFAILING(*(uint32_t*)0x200000000058 = 0); + syscall(SYS_bind, /*fd=*/r[0], /*addr=*/0x200000000040ul, + /*addrlen=*/0xcul); + break; + case 2: + // recvfrom\$inet arguments: [ + // fd: sock_in (resource) + // buf: nil + // len: len = 0x51 (8 bytes) + // f: recv_flags = 0x401313ab1a02f21f (8 bytes) + // addr: nil + // addrlen: len = 0x0 (8 bytes) + // ] + syscall(SYS_recvfrom, /*fd=*/r[0], /*buf=*/0ul, /*len=*/0x51ul, + /*f=MSG_PEEK|MSG_OOB|0x401313ab1a02f21c*/ 0x401313ab1a02f21ful, + /*addr=*/0ul, /*addrlen=*/0ul); + break; + } +} +int main(void) +{ + syscall(SYS_mmap, /*addr=*/0x200000000000ul, /*len=*/0x1000000ul, + /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/ 7ul, + /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x1012ul, + /*fd=*/(intptr_t)-1, /*offset=*/0ul); + const char* reason; + (void)reason; + install_segv_handler(); + for (procid = 0; procid < 4; procid++) { + if (fork() == 0) { + use_temporary_dir(); + do_sandbox_none(); + } + } + sleep(1000000); + return 0; +} +EOF +mycc -o /tmp/$prog -Wall -Wextra -O0 /tmp/$prog.c -pthread || exit 1 + +(cd ../testcases/swap; ./swap -t 5m -i 20 -l 100 > /dev/null 2>&1) & +sleep 5 + +work=/tmp/$prog.dir +rm -rf $work +mkdir $work +cd /tmp/$prog.dir + +timeout 5m /tmp/$prog > /dev/null 2>&1 + +while pkill swap; do :; done +wait + +rm -rf /tmp/$prog /tmp/$prog.c /tmp/$prog.core /tmp/syzkaller.?????? $work +exit 0 diff --git a/tools/test/stress2/misc/syzkaller86.sh b/tools/test/stress2/misc/syzkaller86.sh new file mode 100755 index 000000000000..12922a2d05fa --- /dev/null +++ b/tools/test/stress2/misc/syzkaller86.sh @@ -0,0 +1,555 @@ +#!/bin/sh + +# Fatal trap 12: page fault while in kernel mode +# cpuid = 1; apic id = 01 +# fault virtual address = 0x18 +# fault code = supervisor read data, page not present +# instruction pointer = 0x20:0xffffffff80b69835 +# stack pointer = 0x28:0xfffffe00ff8e7d90 +# frame pointer = 0x28:0xfffffe00ff8e7d90 +# code segment = base 0x0, limit 0xfffff, type 0x1b +# = DPL 0, pres 1, long 1, def32 0, gran 1 +# processor eflags = interrupt enabled, resume, IOPL = 0 +# current process = 0 (thread taskq) +# rdi: 0000000000000018 rsi: 0000000000000004 rdx: ffffffff812b3f65 +# rcx: 00000000000008ba r8: fffff800044b8780 r9: fffff80003397000 +# rax: 0000000000000001 rbx: fffff8004221fa00 rbp: fffffe00ff8e7d90 +# r10: 0000000000000001 r11: fffffe00dc47b000 r12: fffffe0177ed0000 +# r13: fffff800044b8780 r14: fffff8004221f800 r15: fffff8004221f800 +# trap number = 12 +# panic: page fault +# cpuid = 1 +# time = 1759322830 +# KDB: stack backtrace: +# db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame 0xfffffe00ff8e7ac0 +# vpanic() at vpanic+0x136/frame 0xfffffe00ff8e7bf0 +# panic() at panic+0x43/frame 0xfffffe00ff8e7c50 +# trap_pfault() at trap_pfault+0x47c/frame 0xfffffe00ff8e7cc0 +# calltrap() at calltrap+0x8/frame 0xfffffe00ff8e7cc0 +# --- trap 0xc, rip = 0xffffffff80b69835, rsp = 0xfffffe00ff8e7d90, rbp = 0xfffffe00ff8e7d90 --- +# __mtx_assert() at __mtx_assert+0x35/frame 0xfffffe00ff8e7d90 +# ktls_check_rx() at ktls_check_rx+0x2f/frame 0xfffffe00ff8e7dd0 +# socantrcvmore() at socantrcvmore+0x5e/frame 0xfffffe00ff8e7df0 +# unp_gc() at unp_gc+0x5df/frame 0xfffffe00ff8e7e40 +# taskqueue_run_locked() at taskqueue_run_locked+0x1c2/frame 0xfffffe00ff8e7ec0 +# taskqueue_thread_loop() at taskqueue_thread_loop+0xd3/frame 0xfffffe00ff8e7ef0 +# fork_exit() at fork_exit+0x82/frame 0xfffffe00ff8e7f30 +# fork_trampoline() at fork_trampoline+0xe/frame 0xfffffe00ff8e7f30 +# --- trap 0, rip = 0, rsp = 0, rbp = 0 --- +# KDB: enter: panic +# [ thread pid 0 tid 100045 ] +# Stopped at kdb_enter+0x33: movq $0,0x121a9e2(%rip) +# db> x/s version +# version: FreeBSD 16.0-CURRENT #0 vmfqe-n280784-b7f165e45d6d: Wed Oct 1 13:48:43 CEST 2025 +# pho@mercat1.netperf.freebsd.org:/var/tmp/deviant3/sys/amd64/compile/PHO +# db> + +[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 + +. ../default.cfg +set -u +prog=$(basename "$0" .sh) +cat > /tmp/$prog.c <<EOF +// https://syzkaller.appspot.com/bug?id=ec40fe3e3e2b41218d1d417bc10d0be2517bf751 +// autogenerated by syzkaller (https://github.com/google/syzkaller) +// syzbot+a62883292a5c257703be@syzkaller.appspotmail.com + +#define _GNU_SOURCE + +#include <sys/types.h> + +#include <dirent.h> +#include <errno.h> +#include <pthread.h> +#include <pwd.h> +#include <signal.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/endian.h> +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/syscall.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> + +static unsigned long long procid; + +static void kill_and_wait(int pid, int* status) +{ + kill(pid, SIGKILL); + while (waitpid(-1, status, 0) != pid) { + } +} + +static void sleep_ms(uint64_t ms) +{ + usleep(ms * 1000); +} + +static uint64_t current_time_ms(void) +{ + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts)) + exit(1); + return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; +} + +static void use_temporary_dir(void) +{ + char tmpdir_template[] = "./syzkaller.XXXXXX"; + char* tmpdir = mkdtemp(tmpdir_template); + if (!tmpdir) + exit(1); + if (chmod(tmpdir, 0777)) + exit(1); + if (chdir(tmpdir)) + exit(1); +} + +static void reset_flags(const char* filename) +{ + struct stat st; + if (lstat(filename, &st)) + exit(1); + st.st_flags &= ~(SF_NOUNLINK | UF_NOUNLINK | SF_IMMUTABLE | UF_IMMUTABLE | + SF_APPEND | UF_APPEND); + if (lchflags(filename, st.st_flags)) + exit(1); +} +static void __attribute__((noinline)) remove_dir(const char* dir) +{ + DIR* dp = opendir(dir); + if (dp == NULL) { + if (errno == EACCES) { + if (rmdir(dir)) + exit(1); + return; + } + exit(1); + } + struct dirent* ep = 0; + while ((ep = readdir(dp))) { + if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0) + continue; + char filename[FILENAME_MAX]; + snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name); + struct stat st; + if (lstat(filename, &st)) + exit(1); + if (S_ISDIR(st.st_mode)) { + remove_dir(filename); + continue; + } + if (unlink(filename)) { + if (errno == EPERM) { + reset_flags(filename); + reset_flags(dir); + if (unlink(filename) == 0) + continue; + } + exit(1); + } + } + closedir(dp); + while (rmdir(dir)) { + if (errno == EPERM) { + reset_flags(dir); + if (rmdir(dir) == 0) + break; + } + exit(1); + } +} + +static void thread_start(void* (*fn)(void*), void* arg) +{ + pthread_t th; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, 128 << 10); + int i = 0; + for (; i < 100; i++) { + if (pthread_create(&th, &attr, fn, arg) == 0) { + pthread_attr_destroy(&attr); + return; + } + if (errno == EAGAIN) { + usleep(50); + continue; + } + break; + } + exit(1); +} + +typedef struct { + pthread_mutex_t mu; + pthread_cond_t cv; + int state; +} event_t; + +static void event_init(event_t* ev) +{ + if (pthread_mutex_init(&ev->mu, 0)) + exit(1); + if (pthread_cond_init(&ev->cv, 0)) + exit(1); + ev->state = 0; +} + +static void event_reset(event_t* ev) +{ + ev->state = 0; +} + +static void event_set(event_t* ev) +{ + pthread_mutex_lock(&ev->mu); + if (ev->state) + exit(1); + ev->state = 1; + pthread_mutex_unlock(&ev->mu); + pthread_cond_broadcast(&ev->cv); +} + +static void event_wait(event_t* ev) +{ + pthread_mutex_lock(&ev->mu); + while (!ev->state) + pthread_cond_wait(&ev->cv, &ev->mu); + pthread_mutex_unlock(&ev->mu); +} + +static int event_isset(event_t* ev) +{ + pthread_mutex_lock(&ev->mu); + int res = ev->state; + pthread_mutex_unlock(&ev->mu); + return res; +} + +static int event_timedwait(event_t* ev, uint64_t timeout) +{ + uint64_t start = current_time_ms(); + uint64_t now = start; + pthread_mutex_lock(&ev->mu); + for (;;) { + if (ev->state) + break; + uint64_t remain = timeout - (now - start); + struct timespec ts; + ts.tv_sec = remain / 1000; + ts.tv_nsec = (remain % 1000) * 1000 * 1000; + pthread_cond_timedwait(&ev->cv, &ev->mu, &ts); + now = current_time_ms(); + if (now - start > timeout) + break; + } + int res = ev->state; + pthread_mutex_unlock(&ev->mu); + return res; +} + +static void sandbox_common() +{ + struct rlimit rlim; + rlim.rlim_cur = rlim.rlim_max = 128 << 20; + setrlimit(RLIMIT_AS, &rlim); + rlim.rlim_cur = rlim.rlim_max = 8 << 20; + setrlimit(RLIMIT_MEMLOCK, &rlim); + rlim.rlim_cur = rlim.rlim_max = 1 << 20; + setrlimit(RLIMIT_FSIZE, &rlim); + rlim.rlim_cur = rlim.rlim_max = 1 << 20; + setrlimit(RLIMIT_STACK, &rlim); + rlim.rlim_cur = rlim.rlim_max = 0; + setrlimit(RLIMIT_CORE, &rlim); + rlim.rlim_cur = rlim.rlim_max = 256; + setrlimit(RLIMIT_NOFILE, &rlim); +} + +static void loop(); + +static int do_sandbox_none(void) +{ + sandbox_common(); + loop(); + return 0; +} + +struct thread_t { + int created, call; + event_t ready, done; +}; + +static struct thread_t threads[16]; +static void execute_call(int call); +static int running; + +static void* thr(void* arg) +{ + struct thread_t* th = (struct thread_t*)arg; + for (;;) { + event_wait(&th->ready); + event_reset(&th->ready); + execute_call(th->call); + __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED); + event_set(&th->done); + } + return 0; +} + +static void execute_one(void) +{ + if (write(1, "executing program\n", sizeof("executing program\n") - 1)) { + } + int i, call, thread; + for (call = 0; call < 8; call++) { + for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0])); + thread++) { + struct thread_t* th = &threads[thread]; + if (!th->created) { + th->created = 1; + event_init(&th->ready); + event_init(&th->done); + event_set(&th->done); + thread_start(thr, th); + } + if (!event_isset(&th->done)) + continue; + event_reset(&th->done); + th->call = call; + __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED); + event_set(&th->ready); + event_timedwait(&th->done, 50); + break; + } + } + for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++) + sleep_ms(1); +} + +static void execute_one(void); + +#define WAIT_FLAGS 0 + +static void loop(void) +{ + int iter = 0; + for (;; iter++) { + char cwdbuf[32]; + sprintf(cwdbuf, "./%d", iter); + if (mkdir(cwdbuf, 0777)) + exit(1); + int pid = fork(); + if (pid < 0) + exit(1); + if (pid == 0) { + if (chdir(cwdbuf)) + exit(1); + execute_one(); + exit(0); + } + int status = 0; + uint64_t start = current_time_ms(); + for (;;) { + sleep_ms(10); + if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid) + break; + if (current_time_ms() - start < 5000) + continue; + kill_and_wait(pid, &status); + break; + } + remove_dir(cwdbuf); + } +} + +uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff}; + +void execute_call(int call) +{ + intptr_t res = 0; + switch (call) { + case 0: + // freebsd10_pipe arguments: [ + // pipefd: ptr[out, pipefd] { + // pipefd { + // rfd: fd (resource) + // wfd: fd (resource) + // } + // } + // ] + res = syscall(SYS_freebsd10_pipe, /*pipefd=*/0x2000000001c0ul); + if (res != -1) + r[0] = *(uint32_t*)0x2000000001c4; + break; + case 1: + // close arguments: [ + // fd: fd (resource) + // ] + syscall(SYS_close, /*fd=*/r[0]); + break; + case 2: + // socket\$unix arguments: [ + // domain: const = 0x1 (8 bytes) + // type: unix_socket_type = 0x5 (8 bytes) + // proto: const = 0x0 (1 bytes) + // ] + // returns sock_unix + res = syscall(SYS_socket, /*domain=*/1ul, /*type=SOCK_SEQPACKET*/ 5ul, + /*proto=*/0); + if (res != -1) + r[1] = res; + break; + case 3: + // bind\$unix arguments: [ + // fd: sock_unix (resource) + // addr: ptr[in, sockaddr_un] { + // union sockaddr_un { + // file: sockaddr_un_file { + // len: len = 0xa (1 bytes) + // family: unix_socket_family = 0x1 (1 bytes) + // path: buffer: {2e 2f 66 69 6c 65 31 00} (length 0x8) + // } + // } + // } + // addrlen: len = 0xa (8 bytes) + // ] + *(uint8_t*)0x2000000002c0 = 0xa; + *(uint8_t*)0x2000000002c1 = 1; + memcpy((void*)0x2000000002c2, "./file1\000", 8); + syscall(SYS_bind, /*fd=*/r[1], /*addr=*/0x2000000002c0ul, + /*addrlen=*/0xaul); + break; + case 4: + // listen arguments: [ + // fd: sock (resource) + // backlog: int32 = 0xfffffffe (4 bytes) + // ] + syscall(SYS_listen, /*fd=*/r[1], /*backlog=*/0xfffffffe); + break; + case 5: + // sendmsg\$unix arguments: [ + // fd: sock_unix (resource) + // msg: ptr[in, msghdr_un] { + // msghdr_un { + // addr: nil + // addrlen: len = 0x0 (4 bytes) + // pad = 0x0 (4 bytes) + // vec: nil + // vlen: len = 0x0 (8 bytes) + // ctrl: ptr[inout, array[ANYUNION]] { + // array[ANYUNION] { + // union ANYUNION { + // ANYBLOB: buffer: {89 00 00 00 ff ff 00 00 01} (length 0x9) + // } + // } + // } + // ctrllen: bytesize = 0x9 (8 bytes) + // f: send_flags = 0x0 (4 bytes) + // pad = 0x0 (4 bytes) + // } + // } + // f: send_flags = 0x0 (8 bytes) + // ] + *(uint64_t*)0x200000000080 = 0; + *(uint32_t*)0x200000000088 = 0; + *(uint64_t*)0x200000000090 = 0; + *(uint64_t*)0x200000000098 = 0; + *(uint64_t*)0x2000000000a0 = 0x200000000000; + memcpy((void*)0x200000000000, "\x89\x00\x00\x00\xff\xff\x00\x00\x01", 9); + *(uint64_t*)0x2000000000a8 = 9; + *(uint32_t*)0x2000000000b0 = 0; + syscall(SYS_sendmsg, /*fd=*/(intptr_t)-1, /*msg=*/0x200000000080ul, + /*f=*/0ul); + break; + case 6: + // socketpair\$unix arguments: [ + // domain: const = 0x1 (8 bytes) + // type: unix_socket_type = 0x2 (8 bytes) + // proto: const = 0x0 (1 bytes) + // fds: ptr[out, unix_pair] { + // unix_pair { + // fd0: sock_unix (resource) + // fd1: sock_unix (resource) + // } + // } + // ] + res = syscall(SYS_socketpair, /*domain=*/1ul, /*type=SOCK_DGRAM*/ 2ul, + /*proto=*/0, /*fds=*/0x200000000040ul); + if (res != -1) + r[2] = *(uint32_t*)0x200000000040; + break; + case 7: + // sendmsg arguments: [ + // fd: sock (resource) + // msg: ptr[in, send_msghdr] { + // send_msghdr { + // msg_name: nil + // msg_namelen: len = 0x32c (4 bytes) + // pad = 0x0 (4 bytes) + // msg_iov: nil + // msg_iovlen: len = 0x0 (8 bytes) + // msg_control: ptr[in, array[cmsghdr]] { + // array[cmsghdr] { + // } + // } + // msg_controllen: bytesize = 0x90 (8 bytes) + // msg_flags: const = 0x0 (4 bytes) + // pad = 0x0 (4 bytes) + // } + // } + // f: send_flags = 0x0 (8 bytes) + // ] + *(uint64_t*)0x200000000380 = 0; + *(uint32_t*)0x200000000388 = 0x32c; + *(uint64_t*)0x200000000390 = 0; + *(uint64_t*)0x200000000398 = 0; + *(uint64_t*)0x2000000003a0 = 0x200000000000; + *(uint64_t*)0x2000000003a8 = 0x90; + *(uint32_t*)0x2000000003b0 = 0; + syscall(SYS_sendmsg, /*fd=*/r[2], /*msg=*/0x200000000380ul, /*f=*/0ul); + break; + } +} +int main(void) +{ + syscall(SYS_mmap, /*addr=*/0x200000000000ul, /*len=*/0x1000000ul, + /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/ 7ul, + /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x1012ul, + /*fd=*/(intptr_t)-1, /*offset=*/0ul); + const char* reason; + (void)reason; + for (procid = 0; procid < 4; procid++) { + if (fork() == 0) { + use_temporary_dir(); + do_sandbox_none(); + } + } + sleep(1000000); + return 0; +} +EOF +mycc -o /tmp/$prog -Wall -Wextra -O0 /tmp/$prog.c -pthread || exit 1 + +work=/tmp/$prog.dir +rm -rf $work +mkdir $work +cd /tmp/$prog.dir +for i in `jot 30`; do + ( + mkdir d$i + cd d$i + timeout 3m /tmp/$prog > /dev/null 2>&1 & + ) +done +while pgrep -q $prog; do sleep 2; done +wait + +rm -rf /tmp/$prog /tmp/$prog.c /tmp/$prog.core $work +exit 0 diff --git a/usr.sbin/acpi/acpidump/acpi.c b/usr.sbin/acpi/acpidump/acpi.c index a8a3c953d72d..63613d5a4707 100644 --- a/usr.sbin/acpi/acpidump/acpi.c +++ b/usr.sbin/acpi/acpidump/acpi.c @@ -1764,7 +1764,7 @@ acpi_handle_ivrs_ivhd_devs(ACPI_IVRS_DE_HEADER *d, char *de) d8b = (ACPI_IVRS_DEVICE8B *)db; len = sizeof(*d8b); printf("\t\tDev Type=%#x Id=%#06x", - d8a->Header.Type, d8a->Header.Id); + d8b->Header.Type, d8b->Header.Id); acpi_handle_ivrs_ivhd_dte(d8b->Header.DataSetting); printf("\t\t"); acpi_handle_ivrs_ivhd_edte(d8b->ExtendedData); @@ -1774,7 +1774,7 @@ acpi_handle_ivrs_ivhd_devs(ACPI_IVRS_DE_HEADER *d, char *de) d4 = (ACPI_IVRS_DEVICE4 *)(db + sizeof(*d8b)); len = sizeof(*d8b) + sizeof(*d4); printf("\t\tDev Type=%#x Id=%#06x-%#06x", - d8a->Header.Type, d8a->Header.Id, d4->Header.Id); + d8b->Header.Type, d8b->Header.Id, d4->Header.Id); acpi_handle_ivrs_ivhd_dte(d8b->Header.DataSetting); acpi_handle_ivrs_ivhd_edte(d8b->ExtendedData); } else if (d->Type == ACPI_IVRS_TYPE_SPECIAL) { diff --git a/usr.sbin/bsdinstall/bsdinstall.8 b/usr.sbin/bsdinstall/bsdinstall.8 index 5ccbaef87835..6175d26b4fd3 100644 --- a/usr.sbin/bsdinstall/bsdinstall.8 +++ b/usr.sbin/bsdinstall/bsdinstall.8 @@ -1,4 +1,6 @@ -.\"- +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" .\" Copyright (c) 2011-2013 Nathan Whitehorn <nwhitehorn@FreeBSD.org> All rights reserved. .\" Copyright (c) 2018 Roberto Fernandez Cueto <roberfern@gmail.com> .\" Copyright (c) 2024 The FreeBSD Foundation @@ -27,7 +29,7 @@ .\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd November 4, 2024 +.Dd October 3, 2025 .Dt BSDINSTALL 8 .Os .Sh NAME @@ -40,9 +42,10 @@ .Op Ar ... .Sh DESCRIPTION .Nm -is used for installation of new systems, both for system setup from -installation media, e.g., CD-ROMs, and for use on live systems to prepare -VM images and jails. +is used for installation of new systems, +both for system setup from installation media, +such as discs, USBs, or network boot environments, +and for use on live systems to prepare jails and virtual machine images. .Pp Much like .Xr make 1 , Nm @@ -56,7 +59,7 @@ these subtargets can be invoked separately by an installation script. .Sh OPTIONS .Nm supports the following options, global to all targets: -.Bl -tag -width indent+ +.Bl -tag -width "-D file" .It Fl D Ar file Provide a path for the installation log file .Pq overrides Ev BSDINSTALL_LOG . @@ -73,7 +76,7 @@ For interactive use, most users will be interested only in the and .Cm script targets. -.Bl -tag -width "jail destination" +.Bl -tag -width "-D file" .It Cm auto Run the standard interactive installation, including disk partitioning. .It Cm jail Ar destination @@ -244,7 +247,7 @@ Extracts the distributions listed in .Ev DISTRIBUTIONS into .Ev BSDINSTALL_CHROOT . -.It Cm pkgbase Op Fl --no-kernel +.It Cm pkgbase Op Fl --jail Fetch and install base system packages to .Ev BSDINSTALL_CHROOT . Packages are fetched according to repository configuration in @@ -253,8 +256,10 @@ if set, or .Lk pkg.freebsd.org otherwise. If the -.Fl --no-kernel -option is passed, no kernel is installed. +.Fl --jail +option is passed, no kernel is installed, and the +.Dq jail +variant of each package set will be selected where applicable. .It Cm firmware executes .Xr fwget 8 @@ -293,7 +298,7 @@ Many are used internally during installation and have reasonable default values for most installation scenarios. Others are set by various interactive user prompts, and can be usefully overridden when making scripted or customized installers. -.Bl -tag -width "BSDINSTALL_DISTSITE" +.Bl -tag -width "-D file" .It Ev TMPDIR The directory to use for temporary files. Default: diff --git a/usr.sbin/bsdinstall/scripts/jail b/usr.sbin/bsdinstall/scripts/jail index 0c3c7e125fdd..f2c7ef2b37de 100755 --- a/usr.sbin/bsdinstall/scripts/jail +++ b/usr.sbin/bsdinstall/scripts/jail @@ -183,7 +183,7 @@ if [ ! "$nonInteractive" == "YES" ]; then fi if [ "$PKGBASE" == yes ]; then - bsdinstall pkgbase --no-kernel || error "Installation of base system packages failed" + bsdinstall pkgbase --jail || error "Installation of base system packages failed" else distbase fi diff --git a/usr.sbin/bsdinstall/scripts/pkgbase.in b/usr.sbin/bsdinstall/scripts/pkgbase.in index 14ef67723d59..5299d34fcb71 100755 --- a/usr.sbin/bsdinstall/scripts/pkgbase.in +++ b/usr.sbin/bsdinstall/scripts/pkgbase.in @@ -80,7 +80,9 @@ local function select_components(components, options) ["kernel-dbg"] = "Debug symbols for the kernel", ["devel"] = "C/C++ compilers and related utilities", ["optional"] = "Optional software (excluding compilers)", + ["optional-jail"] = "Optional software (excluding compilers)", ["base"] = "The complete base system (includes devel and optional)", + ["base-jail"] = "The complete base system (includes devel and optional)", ["src"] = "System source tree", ["tests"] = "Test suite", ["lib32"] = "32-bit compatibility libraries", @@ -91,6 +93,7 @@ local function select_components(components, options) -- by default. local defaults = { ["base"] = "on", + ["base-jail"] = "on", ["kernel-dbg"] = "on", } -- Enable compat sets by default. @@ -101,40 +104,66 @@ local function select_components(components, options) -- Sorting the components is necessary to ensure that the ordering is -- consistent in the UI. local sorted_components = {} + + -- Determine which components we want to offer the user. + local show_component = function (component) + -- "pkg" is always installed if present. + if component == "pkg" then return false end + + -- Don't include individual "-dbg" components, because those + -- are handled via the "debug" component, except for kernel-dbg + -- which is always shown for non-jail installations. + if component == "kernel-dbg" then + return (not options.jail) + end + if component:match("%-dbg$") then return false end + + -- Some sets have "-jail" variants which are jail-specific + -- variants of the base set. + + if options.jail and components[component.."-jail"] then + -- If we're installing in a jail, and this component + -- has a jail variant, hide it. + return false + end + + if not options.jail and component:match("%-jail$") then + -- Otherwise if we're not installing in a jail, and + -- this is a jail variant, hide it. + return false + end + + -- "minimal(-jail)" is always installed if present. + if component == "minimal" or component == "minimal-jail" then + return false + end + + -- "kernel" (the generic kernel) and "kernels" (the set) are + -- never offered; we always install the kernel for a non-jail + -- installation. + if component == "kernel" or component == "kernels" then + return false + end + + -- If we didn't find a reason to hide this component, show it. + return true + end + for component, _ in pairs(components) do - -- Decide which sets we want to offer to the user: - -- - -- "minimal" is not offered since it's always included, as is - -- "pkg" if it's present. - -- - -- "-dbg" sets are never offered, because those are handled - -- via the "debug" component. - -- - -- "kernels" is never offered because we only want one kernel, - -- which is handled separately. - -- - -- Sets whose name ends in "-jail" are intended for jails, and - -- are only offered if no_kernel is set. - if component ~= "pkg" and - not component:match("^minimal") and - not (component:match("%-dbg$") and component ~= "kernel-dbg") and - not (component == "kernels") and - not (not options.no_kernel and component:match("%-jail$")) then + if show_component(component) then table.insert(sorted_components, component) end end + table.sort(sorted_components) local checklist_items = {} for _, component in ipairs(sorted_components) do - if component ~= "kernel" and not - (component == "kernel-dbg" and options.no_kernel) then - local description = descriptions[component] or "" - local default = defaults[component] or "off" - table.insert(checklist_items, component) - table.insert(checklist_items, description) - table.insert(checklist_items, default) - end + local description = descriptions[component] or "" + local default = defaults[component] or "off" + table.insert(checklist_items, component) + table.insert(checklist_items, description) + table.insert(checklist_items, default) end local bsddialog_args = { @@ -162,7 +191,12 @@ local function select_components(components, options) -- to work. The base set depends on minimal, but it's fine to install -- both, and this way the user can remove the base set without pkg -- autoremove then trying to remove minimal. - local selected = {"minimal"} + local selected = {} + if options.jail then + table.insert(selected, "minimal-jail") + else + table.insert(selected, "minimal") + end -- If pkg is available, always install it so the user can manage the -- installed system. This is optional, because a repository built @@ -171,7 +205,7 @@ local function select_components(components, options) table.insert(selected, "pkg") end - if not options.no_kernel then + if not options.jail then table.insert(selected, "kernel") end @@ -264,8 +298,8 @@ end local function parse_options() local options = {} for _, a in ipairs(arg) do - if a == "--no-kernel" then - options.no_kernel = true + if a == "--jail" then + options.jail = true else io.stderr:write("Error: unknown option " .. a .. "\n") os.exit(1) |