diff options
281 files changed, 7640 insertions, 2161 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index a282ddf789ed..b5c96820c192 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -4,13 +4,13 @@ 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 env: - PKG_FORMAT: tar + PKG_LEVEL: 1 task: matrix: @@ -219,6 +219,8 @@ META_TGT_WHITELIST+= build${libcompat} .ORDER: buildworld distribute .ORDER: buildworld distributeworld .ORDER: buildworld buildkernel +.ORDER: buildworld packages +.ORDER: buildworld update-packages .ORDER: distrib-dirs distribute .ORDER: distrib-dirs distributeworld .ORDER: distrib-dirs installworld @@ -232,6 +234,8 @@ META_TGT_WHITELIST+= build${libcompat} .ORDER: buildkernel installkernel.debug .ORDER: buildkernel reinstallkernel .ORDER: buildkernel reinstallkernel.debug +.ORDER: buildkernel packages +.ORDER: buildkernel update-packages .ORDER: kernel-toolchain buildkernel # Only sanitize PATH on FreeBSD. 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/ObsoleteFiles.inc b/ObsoleteFiles.inc index 539ab7d54460..36e8c048661e 100644 --- a/ObsoleteFiles.inc +++ b/ObsoleteFiles.inc @@ -51,6 +51,10 @@ # xargs -n1 | sort | uniq -d; # done +# 20251003: kgdb python scripts moved +OLD_FILES+=usr/libexec/kgdb/acttrace.py +OLD_DIRS+=usr/libexec/kgdb + # 20251001: test helper sendto-IP_MULTICAST_IF renamed OLD_FILES+=usr/tests/sys/netinet/sendto-IP_MULTICAST_IF diff --git a/contrib/libucl/lua/lua_ucl.c b/contrib/libucl/lua/lua_ucl.c index d6be69e42a71..1b3f9dfd111c 100644 --- a/contrib/libucl/lua/lua_ucl.c +++ b/contrib/libucl/lua/lua_ucl.c @@ -30,6 +30,8 @@ #include "lua_ucl.h" #include <strings.h> +#include "bootstrap.h" + /*** * @module ucl * This lua module allows to parse objects from strings and to store data into @@ -1571,3 +1573,5 @@ ucl_object_toclosure (const ucl_object_t *obj) return (struct ucl_lua_funcdata*)obj->value.ud; } + +FLUA_MODULE(ucl); diff --git a/contrib/lyaml/ext/yaml/yaml.c b/contrib/lyaml/ext/yaml/yaml.c index 54478610134f..6a5ddc605e0f 100644 --- a/contrib/lyaml/ext/yaml/yaml.c +++ b/contrib/lyaml/ext/yaml/yaml.c @@ -35,6 +35,8 @@ #include "lyaml.h" +#include "bootstrap.h" + #define MYNAME "yaml" #define MYVERSION MYNAME " library for " LUA_VERSION " / " VERSION @@ -64,3 +66,5 @@ luaopen_yaml (lua_State *L) return 1; } + +FLUA_MODULE(yaml); 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/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/etc/mtree/BSD.usr.dist b/etc/mtree/BSD.usr.dist index 1945c26ebc5f..d7d839b94b96 100644 --- a/etc/mtree/BSD.usr.dist +++ b/etc/mtree/BSD.usr.dist @@ -181,8 +181,6 @@ .. hyperv .. - kgdb - .. lpr ru .. 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/include/stdlib.h b/include/stdlib.h index ba0cf4b5e88e..784cb63bfc5b 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -314,6 +314,8 @@ int radixsort(const unsigned char **, int, const unsigned char *, unsigned); void *reallocarray(void *, size_t, size_t) __result_use_check __alloc_size2(2, 3); +void *recallocarray(void *, size_t, size_t, size_t) __result_use_check + __alloc_size2(3, 4); void *reallocf(void *, size_t) __result_use_check __alloc_size(2); int rpmatch(const char *); char *secure_getenv(const 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/Versions.def b/lib/libc/Versions.def index 184e107d225a..1c7b34bef35b 100644 --- a/lib/libc/Versions.def +++ b/lib/libc/Versions.def @@ -42,6 +42,10 @@ FBSD_1.7 { FBSD_1.8 { } FBSD_1.7; +# This version was first added to 16.0-current. +FBSD_1.9 { +} FBSD_1.8; + # This is our private namespace. Any global interfaces that are # strictly for use only by other FreeBSD applications and libraries # are listed here. We use a separate namespace so we can write @@ -49,4 +53,4 @@ FBSD_1.8 { # # Please do NOT increment the version of this namespace. FBSDprivate_1.0 { -} FBSD_1.8; +} FBSD_1.9; 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/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc index ca199a669be1..e7b9955b9646 100644 --- a/lib/libc/stdlib/Makefile.inc +++ b/lib/libc/stdlib/Makefile.inc @@ -10,7 +10,7 @@ MISRCS+=C99_Exit.c a64l.c abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \ insque.c l64a.c labs.c ldiv.c llabs.c lldiv.c lsearch.c \ merge.c mergesort_b.c ptsname.c qsort.c qsort_r.c qsort_r_compat.c \ qsort_s.c quick_exit.c radixsort.c rand.c \ - random.c reallocarray.c reallocf.c realpath.c remque.c \ + random.c reallocarray.c reallocf.c realpath.c recallocarray.c remque.c \ set_constraint_handler_s.c strfmon.c strtoimax.c \ strtol.c strtold.c strtoll.c strtoq.c strtoul.c strtonum.c strtoull.c \ strtoumax.c strtouq.c system.c tdelete.c tfind.c tsearch.c twalk.c @@ -76,6 +76,7 @@ MLINKS+=random.3 initstate.3 \ random.3 srandom.3 \ random.3 srandomdev.3 MLINKS+=radixsort.3 sradixsort.3 +MLINKS+=reallocarray.3 recallocarray.3 MLINKS+=set_constraint_handler_s.3 abort_handler_s.3 MLINKS+=set_constraint_handler_s.3 ignore_handler_s.3 MLINKS+=strfmon.3 strfmon_l.3 diff --git a/lib/libc/stdlib/Symbol.map b/lib/libc/stdlib/Symbol.map index 2b79ca2ece8b..53d71bcafb7d 100644 --- a/lib/libc/stdlib/Symbol.map +++ b/lib/libc/stdlib/Symbol.map @@ -131,6 +131,10 @@ FBSD_1.8 { getenv_r; }; +FBSD_1.9 { + recallocarray; +}; + FBSDprivate_1.0 { __system; _system; diff --git a/lib/libc/stdlib/reallocarray.3 b/lib/libc/stdlib/reallocarray.3 index 80035c67a497..9a2ab5c7a840 100644 --- a/lib/libc/stdlib/reallocarray.3 +++ b/lib/libc/stdlib/reallocarray.3 @@ -26,7 +26,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd May 1, 2015 +.Dd October 2, 2025 .Dt REALLOCARRAY 3 .Os .Sh NAME @@ -38,6 +38,8 @@ .In stdlib.h .Ft void * .Fn reallocarray "void *ptr" "size_t nmemb" "size_t size" +.Ft void * +.Fn recallocarray "void *ptr" "size_t oldnmeb" "size_t nmemb" size_t size" .Sh DESCRIPTION The .Fn reallocarray @@ -52,6 +54,33 @@ and checks for integer overflow in the calculation .Fa nmemb * .Fa size . +.Pp +The +.Fn recallocarray +function is similar to the +.Fn reallocarray +function +except it ensures newly allocated memory is cleared similar to +.Fn calloc . +If +.Fa ptr +is +.Dv NULL , +.Fa oldnmemb +is ignored and the call is equivalent to +.Fn calloc . +If +.Fa ptr +is not +.Dv NULL , +.Fa oldnmemb +must be a value such that +.Fa oldnmemb +* +.Fa size +is the size of the earlier allocation that returned +.Fa ptr , +otherwise the behaviour is undefined. .Sh RETURN VALUES The .Fn reallocarray @@ -142,3 +171,9 @@ function first appeared in .Ox 5.6 and .Fx 11.0 . +The +.Fn recallocarray +function first appeared in +.Ox 6.1 +and +.Fx 16.0 . diff --git a/lib/libc/stdlib/reallocarray.c b/lib/libc/stdlib/reallocarray.c index 0868804486cc..3632734c84de 100644 --- a/lib/libc/stdlib/reallocarray.c +++ b/lib/libc/stdlib/reallocarray.c @@ -17,23 +17,19 @@ #include <sys/types.h> #include <errno.h> +#include <stdckdint.h> #include <stdint.h> #include <stdlib.h> -/* - * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX - * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW - */ -#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) - void * reallocarray(void *optr, size_t nmemb, size_t size) { + size_t nbytes; - if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && - nmemb > 0 && SIZE_MAX / nmemb < size) { + if (ckd_mul(&nbytes, nmemb, size)) { errno = ENOMEM; return (NULL); } - return (realloc(optr, size * nmemb)); + + return (realloc(optr, nbytes)); } diff --git a/lib/libopenbsd/recallocarray.c b/lib/libc/stdlib/recallocarray.c index 11e1fda744c7..cbf1fb2470cf 100644 --- a/lib/libopenbsd/recallocarray.c +++ b/lib/libc/stdlib/recallocarray.c @@ -16,17 +16,12 @@ */ #include <errno.h> +#include <stdckdint.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <unistd.h> -/* - * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX - * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW - */ -#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) - void *recallocarray(void *, size_t, size_t, size_t); void * @@ -38,19 +33,15 @@ recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size) if (ptr == NULL) return calloc(newnmemb, size); - if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && - newnmemb > 0 && SIZE_MAX / newnmemb < size) { + if (ckd_mul(&newsize, newnmemb, size)) { errno = ENOMEM; return NULL; } - newsize = newnmemb * size; - if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && - oldnmemb > 0 && SIZE_MAX / oldnmemb < size) { + if (ckd_mul(&oldsize, oldnmemb, size)) { errno = EINVAL; return NULL; } - oldsize = oldnmemb * size; /* * Don't bother too much if we're shrinking just a bit, diff --git a/lib/libdiff/Makefile b/lib/libdiff/Makefile index 8541ff424de2..25f849a69e05 100644 --- a/lib/libdiff/Makefile +++ b/lib/libdiff/Makefile @@ -8,7 +8,7 @@ INTERNALLIB= # API not published or supported. SRCS= diff_atomize_text.c diff_main.c diff_myers.c \ diff_patience.c diff_output.c diff_output_plain.c \ - diff_output_unidiff.c diff_output_edscript.c recallocarray.c + diff_output_unidiff.c diff_output_edscript.c WARNS= CFLAGS+= -I${SRCTOP}/contrib/libdiff/compat/include diff --git a/lib/libfido2/Makefile b/lib/libfido2/Makefile index 10c008967e3d..021a32dd514b 100644 --- a/lib/libfido2/Makefile +++ b/lib/libfido2/Makefile @@ -43,7 +43,6 @@ SRCS+= u2f.c SRCS+= util.c SRCS+= openbsd-compat/freezero.c -SRCS+= openbsd-compat/recallocarray.c CFLAGS+= -I ${DIST}/src -I${SRCTOP}/contrib/libcbor/src -I${.CURDIR}/../libcbor CFLAGS+= -D_FIDO_INTERNAL diff --git a/lib/libopenbsd/Makefile b/lib/libopenbsd/Makefile index 53bd0200934f..80ae0f90621a 100644 --- a/lib/libopenbsd/Makefile +++ b/lib/libopenbsd/Makefile @@ -1,8 +1,12 @@ LIB= openbsd SRCS= imsg-buffer.c \ imsg.c \ - ohash.c \ - recallocarray.c + ohash.c +.if defined(BOOTSTRAPPING) +.PATH: ${SRCTOP}/lib/libc/stdlib +SRCS+= recallocarray.c +.endif + .if !defined(BOOTSTRAPPING) # Skip getdtablecount.c when bootstrapping since it doesn't compile for Linux # and is not used by any of the bootstrap tools diff --git a/libexec/Makefile b/libexec/Makefile index 7ce78321f08e..e87b48b153a8 100644 --- a/libexec/Makefile +++ b/libexec/Makefile @@ -10,7 +10,6 @@ SUBDIR= ${_atf} \ flua \ getty \ ${_hyperv} \ - kgdb \ ${_mail.local} \ ${_makewhatis.local} \ ${_mknetid} \ diff --git a/libexec/flua/Makefile b/libexec/flua/Makefile index 86d27c0653d4..23de404710d0 100644 --- a/libexec/flua/Makefile +++ b/libexec/flua/Makefile @@ -1,10 +1,42 @@ .include <src.lua.mk> -SUBDIR+= libfreebsd -SUBDIR+= libhash -SUBDIR+= libjail -SUBDIR+= libucl -SUBDIR+= liblyaml +# New flua modules should be added here rather than to SUBDIR so that we can do +# the right thing for both bootstrap flua and target flua. The former does not +# do any shared libs, so we just build them all straight into flua itself rather +# than mucking about with the infrastructure to make them linkable -- thus, why +# these are all structured to have a Makefile that describes what we want +# *installed*, and a Makefile.inc that describes what we need to *build*. +FLUA_MODULES+= lfbsd +FLUA_MODULES+= lfs +FLUA_MODULES+= libhash +.ifndef BOOTSTRAPPING +# Bootstrap flua can't usefully do anything with libjail anyways, because it +# can't assume it's being run on a system that even supports jails. +FLUA_MODULES+= libjail +.endif +FLUA_MODULES+= libucl +FLUA_MODULES+= liblyaml + +.ifdef BOOTSTRAPPING +# 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 +FLUA_PATH= ${SHAREDIR}/?.lua;${SHAREDIR}/?/init.lua +CFLAGS+= -DBOOTSTRAP_FLUA_PATH=\"${FLUA_PATH:Q}\" + +.for mod in ${FLUA_MODULES} +.include "${mod}/Makefile.inc" +.endfor + +.else + +FLUA_MODULES+= libfreebsd +SUBDIR+= ${FLUA_MODULES} + +.endif LUASRC?= ${SRCTOP}/contrib/lua/src .PATH: ${LUASRC} @@ -14,7 +46,7 @@ WARNS?= 3 CWARNFLAGS.gcc+= -Wno-format-nonliteral -LIBADD= lua +LIBADD+= lua # Entry point SRCS+= lua.c @@ -22,7 +54,7 @@ SRCS+= lua.c # FreeBSD Extensions .PATH: ${.CURDIR}/modules SRCS+= linit_flua.c -SRCS+= lfs.c lposix.c lfbsd.c +SRCS+= lposix.c CFLAGS+= -I${SRCTOP}/lib/liblua -I${.CURDIR}/modules -I${LUASRC} CFLAGS+= -DLUA_PROGNAME="\"${PROG}\"" diff --git a/libexec/flua/Makefile.inc b/libexec/flua/Makefile.inc index 34505d54d7df..37a49e258ecb 100644 --- a/libexec/flua/Makefile.inc +++ b/libexec/flua/Makefile.inc @@ -2,4 +2,9 @@ SHLIBDIR?= ${LIBDIR}/flua CFLAGS+= \ -I${SRCTOP}/contrib/lua/src \ - -I${SRCTOP}/lib/liblua + -I${SRCTOP}/lib/liblua \ + -I${SRCTOP}/libexec/flua + +.ifdef BOOTSTRAPPING +CFLAGS+= -DBOOTSTRAPPING +.endif diff --git a/libexec/flua/bootstrap.h b/libexec/flua/bootstrap.h new file mode 100644 index 000000000000..caf00518c1e0 --- /dev/null +++ b/libexec/flua/bootstrap.h @@ -0,0 +1,32 @@ +/*- + * Copyright (c) 2025 Kyle Evans <kevans@FreeBSD.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef FLUA_BOOTSTRAP_H +#define FLUA_BOOTSTRAP_H + +#ifdef BOOTSTRAPPING +#include <sys/linker_set.h> + +#include <lauxlib.h> + +#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_SETNAME, ident) + +#define FLUA_MODULE_NAMED(mod, name) \ + FLUA_MODULE_DEF(module_ ## mod, name, luaopen_ ## mod) +#define FLUA_MODULE(mod) \ + FLUA_MODULE_DEF(module_ ## mod, #mod, luaopen_ ## mod) +#else /* !BOOTSTRAPPING */ +#define FLUA_MODULE_DEF(ident, modname, openfn) +#define FLUA_MODULE_NAMED(mod, name) +#define FLUA_MODULE(modname) +#endif /* BOOTSTRAPPING */ + +#endif /* FLUA_BOOTSTRAP_H */ diff --git a/libexec/flua/lfbsd/Makefile b/libexec/flua/lfbsd/Makefile new file mode 100644 index 000000000000..e2a4aae14bcd --- /dev/null +++ b/libexec/flua/lfbsd/Makefile @@ -0,0 +1,5 @@ +SHLIB_NAME= fbsd.so +WARNS?= 3 + +.include "Makefile.inc" +.include <bsd.lib.mk> diff --git a/libexec/flua/lfbsd/Makefile.inc b/libexec/flua/lfbsd/Makefile.inc new file mode 100644 index 000000000000..7a78ef82e0fc --- /dev/null +++ b/libexec/flua/lfbsd/Makefile.inc @@ -0,0 +1,2 @@ +.PATH: ${.PARSEDIR} +SRCS+= lfbsd.c diff --git a/libexec/flua/modules/lfbsd.c b/libexec/flua/lfbsd/lfbsd.c index ef660ba9fd77..541b6c9611df 100644 --- a/libexec/flua/modules/lfbsd.c +++ b/libexec/flua/lfbsd/lfbsd.c @@ -40,6 +40,8 @@ #include "lauxlib.h" #include "lfbsd.h" +#include "bootstrap.h" + #define FBSD_PROCESSHANDLE "fbsd_process_t*" struct fbsd_process { @@ -283,3 +285,5 @@ luaopen_fbsd(lua_State *L) return (1); } + +FLUA_MODULE(fbsd); diff --git a/libexec/flua/modules/lfbsd.h b/libexec/flua/lfbsd/lfbsd.h index 01034a3ad7cd..01034a3ad7cd 100644 --- a/libexec/flua/modules/lfbsd.h +++ b/libexec/flua/lfbsd/lfbsd.h diff --git a/libexec/flua/lfs/Makefile b/libexec/flua/lfs/Makefile new file mode 100644 index 000000000000..3df83d6d2fc1 --- /dev/null +++ b/libexec/flua/lfs/Makefile @@ -0,0 +1,5 @@ +SHLIB_NAME= lfs.so +WARNS?= 3 + +.include "Makefile.inc" +.include <bsd.lib.mk> diff --git a/libexec/flua/lfs/Makefile.inc b/libexec/flua/lfs/Makefile.inc new file mode 100644 index 000000000000..9d40c42dc0e6 --- /dev/null +++ b/libexec/flua/lfs/Makefile.inc @@ -0,0 +1,2 @@ +.PATH: ${.PARSEDIR} +SRCS+= lfs.c diff --git a/libexec/flua/modules/lfs.c b/libexec/flua/lfs/lfs.c index 8cb8d6fc9fed..517e16ae65c8 100644 --- a/libexec/flua/modules/lfs.c +++ b/libexec/flua/lfs/lfs.c @@ -66,9 +66,10 @@ #ifdef _STANDALONE #include "lstd.h" #include "lutils.h" -#include "bootstrap.h" #endif +#include "bootstrap.h" + #ifndef nitems #define nitems(x) (sizeof((x)) / sizeof((x)[0])) #endif @@ -446,3 +447,7 @@ luaopen_lfs(lua_State *L) #endif return 1; } + +#ifndef _STANDALONE +FLUA_MODULE(lfs); +#endif diff --git a/libexec/flua/modules/lfs.h b/libexec/flua/lfs/lfs.h index a99e66d7f601..a99e66d7f601 100644 --- a/libexec/flua/modules/lfs.h +++ b/libexec/flua/lfs/lfs.h diff --git a/libexec/flua/libfreebsd/kenv/Makefile b/libexec/flua/libfreebsd/kenv/Makefile index 1726c892c515..a1b388bb3612 100644 --- a/libexec/flua/libfreebsd/kenv/Makefile +++ b/libexec/flua/libfreebsd/kenv/Makefile @@ -1,5 +1,5 @@ SHLIB_NAME= kenv.so -SRCS+= kenv.c MAN= freebsd.kenv.3lua +.include "Makefile.inc" .include <bsd.lib.mk> diff --git a/libexec/flua/libfreebsd/kenv/Makefile.inc b/libexec/flua/libfreebsd/kenv/Makefile.inc new file mode 100644 index 000000000000..05819c5280d9 --- /dev/null +++ b/libexec/flua/libfreebsd/kenv/Makefile.inc @@ -0,0 +1,2 @@ +.PATH: ${.PARSEDIR} +SRCS+= kenv.c diff --git a/libexec/flua/libfreebsd/kenv/kenv.c b/libexec/flua/libfreebsd/kenv/kenv.c index 954baa00facb..56b24c72904a 100644 --- a/libexec/flua/libfreebsd/kenv/kenv.c +++ b/libexec/flua/libfreebsd/kenv/kenv.c @@ -14,6 +14,8 @@ #include <lualib.h> #include <lauxlib.h> +#include "bootstrap.h" + int luaopen_freebsd_kenv(lua_State *L); static int @@ -94,3 +96,5 @@ luaopen_freebsd_kenv(lua_State *L) return (1); } + +FLUA_MODULE_NAMED(freebsd_kenv, "freebsd.kenv"); diff --git a/libexec/flua/libfreebsd/sys/linker/Makefile b/libexec/flua/libfreebsd/sys/linker/Makefile index 1adf547b503c..f1f65ad5f6c1 100644 --- a/libexec/flua/libfreebsd/sys/linker/Makefile +++ b/libexec/flua/libfreebsd/sys/linker/Makefile @@ -1,7 +1,6 @@ SHLIB_NAME= linker.so -SRCS+= linker.c - MAN= freebsd.sys.linker.3lua +.include "Makefile.inc" .include <bsd.lib.mk> diff --git a/libexec/flua/libfreebsd/sys/linker/Makefile.inc b/libexec/flua/libfreebsd/sys/linker/Makefile.inc new file mode 100644 index 000000000000..da65c0070170 --- /dev/null +++ b/libexec/flua/libfreebsd/sys/linker/Makefile.inc @@ -0,0 +1,2 @@ +.PATH: ${.PARSEDIR} +SRCS+= linker.c diff --git a/libexec/flua/libfreebsd/sys/linker/linker.c b/libexec/flua/libfreebsd/sys/linker/linker.c index 87eccfb651f0..c78fbb2b39d2 100644 --- a/libexec/flua/libfreebsd/sys/linker/linker.c +++ b/libexec/flua/libfreebsd/sys/linker/linker.c @@ -15,6 +15,8 @@ #include <lualib.h> #include <lauxlib.h> +#include "bootstrap.h" + int luaopen_freebsd_sys_linker(lua_State *L); static int @@ -80,3 +82,5 @@ luaopen_freebsd_sys_linker(lua_State *L) return (1); } + +FLUA_MODULE_NAMED(freebsd_sys_linker, "freebsd.sys.linker"); diff --git a/libexec/flua/libhash/Makefile b/libexec/flua/libhash/Makefile index b7c8d7ee9948..9cbd6f15acae 100644 --- a/libexec/flua/libhash/Makefile +++ b/libexec/flua/libhash/Makefile @@ -1,9 +1,6 @@ SHLIB_NAME= hash.so -SRCS+= lhash.c - -LIBADD+= md - MAN= hash.3lua +.include "Makefile.inc" .include <bsd.lib.mk> diff --git a/libexec/flua/libhash/Makefile.inc b/libexec/flua/libhash/Makefile.inc new file mode 100644 index 000000000000..d112dfe7df33 --- /dev/null +++ b/libexec/flua/libhash/Makefile.inc @@ -0,0 +1,3 @@ +.PATH: ${.PARSEDIR} +SRCS+= lhash.c +LIBADD+= md diff --git a/libexec/flua/libhash/lhash.c b/libexec/flua/libhash/lhash.c index 4587961fe8a0..f455f006bf27 100644 --- a/libexec/flua/libhash/lhash.c +++ b/libexec/flua/libhash/lhash.c @@ -11,6 +11,8 @@ #include <sha256.h> #include <string.h> +#include "bootstrap.h" + #define SHA256_META "SHA256 meta table" #define SHA256_DIGEST_LEN 32 @@ -175,3 +177,7 @@ luaopen_hash(lua_State *L) return 1; } + +#ifndef _STANDALONE +FLUA_MODULE(hash); +#endif diff --git a/libexec/flua/libjail/Makefile b/libexec/flua/libjail/Makefile index 20cd9f5f1429..b9c8bdc39095 100644 --- a/libexec/flua/libjail/Makefile +++ b/libexec/flua/libjail/Makefile @@ -1,9 +1,6 @@ SHLIB_NAME= jail.so -SRCS+= lua_jail.c - -LIBADD+= jail - MAN= jail.3lua +.include "Makefile.inc" .include <bsd.lib.mk> diff --git a/libexec/flua/libjail/Makefile.inc b/libexec/flua/libjail/Makefile.inc new file mode 100644 index 000000000000..a896bf38c65b --- /dev/null +++ b/libexec/flua/libjail/Makefile.inc @@ -0,0 +1,3 @@ +.PATH: ${.PARSEDIR} +SRCS+= lua_jail.c +LIBADD+= jail diff --git a/libexec/flua/libjail/lua_jail.c b/libexec/flua/libjail/lua_jail.c index 9632db795775..8c3ec6c1d500 100644 --- a/libexec/flua/libjail/lua_jail.c +++ b/libexec/flua/libjail/lua_jail.c @@ -38,6 +38,8 @@ #include <lauxlib.h> #include <lualib.h> +#include "bootstrap.h" + #define JAIL_METATABLE "jail iterator metatable" /* @@ -716,3 +718,5 @@ luaopen_jail(lua_State *L) return (1); } + +FLUA_MODULE(jail); diff --git a/libexec/flua/liblyaml/Makefile b/libexec/flua/liblyaml/Makefile index e7a89d09bb9e..8d1432acd325 100644 --- a/libexec/flua/liblyaml/Makefile +++ b/libexec/flua/liblyaml/Makefile @@ -1,22 +1,4 @@ SHLIB_NAME= yaml.so -WARNS= 1 -LYAMLSRC?= ${SRCTOP}/contrib/lyaml -.PATH: ${LYAMLSRC}/ext/yaml ${LYAMLSRC}/lib/lyaml -SRCS= emitter.c \ - parser.c \ - scanner.c \ - yaml.c -CFLAGS+= \ - -I${LYAMLSRC}/ext/yaml \ - -I${SRCTOP}/contrib/libyaml/include \ - -DVERSION=\"6.2.8\" -LIBADD+= yaml - -FILES= explicit.lua \ - functional.lua \ - implicit.lua \ - init.lua -FILESDIR= ${SHAREDIR}/flua/lyaml - +.include "Makefile.inc" .include <bsd.lib.mk> diff --git a/libexec/flua/liblyaml/Makefile.inc b/libexec/flua/liblyaml/Makefile.inc new file mode 100644 index 000000000000..caa1f37b57eb --- /dev/null +++ b/libexec/flua/liblyaml/Makefile.inc @@ -0,0 +1,20 @@ +WARNS= 1 + +LYAMLSRC?= ${SRCTOP}/contrib/lyaml +.PATH: ${LYAMLSRC}/ext/yaml ${LYAMLSRC}/lib/lyaml +SRCS+= emitter.c \ + parser.c \ + scanner.c \ + yaml.c +CFLAGS+= \ + -I${LYAMLSRC}/ext/yaml \ + -I${SRCTOP}/contrib/libyaml/include \ + -DVERSION=\"6.2.8\" +LIBADD+= yaml + +FILESGROUPS+= YAML +YAML= explicit.lua \ + functional.lua \ + implicit.lua \ + init.lua +YAMLDIR= ${SHAREDIR}/flua/lyaml diff --git a/libexec/flua/libucl/Makefile b/libexec/flua/libucl/Makefile index a88c8bda6bfc..32d76d1ea1ad 100644 --- a/libexec/flua/libucl/Makefile +++ b/libexec/flua/libucl/Makefile @@ -1,14 +1,4 @@ SHLIB_NAME= ucl.so -WARNS= 2 - -UCLSRC?= ${SRCTOP}/contrib/libucl -.PATH: ${UCLSRC}/lua -SRCS+= lua_ucl.c -CFLAGS+= \ - -I${UCLSRC}/include \ - -I${UCLSRC}/src \ - -I${UCLSRC}/uthash -LIBADD+= ucl - +.include "Makefile.inc" .include <bsd.lib.mk> diff --git a/libexec/flua/libucl/Makefile.inc b/libexec/flua/libucl/Makefile.inc new file mode 100644 index 000000000000..70fb0f265635 --- /dev/null +++ b/libexec/flua/libucl/Makefile.inc @@ -0,0 +1,12 @@ +.if ${WARNS:U6} > 2 +WARNS= 2 +.endif + +UCLSRC?= ${SRCTOP}/contrib/libucl +.PATH: ${UCLSRC}/lua +SRCS+= lua_ucl.c +CFLAGS+= \ + -I${UCLSRC}/include \ + -I${UCLSRC}/src \ + -I${UCLSRC}/uthash +LIBADD+= ucl diff --git a/libexec/flua/linit_flua.c b/libexec/flua/linit_flua.c index b466b7872158..65356c938671 100644 --- a/libexec/flua/linit_flua.c +++ b/libexec/flua/linit_flua.c @@ -26,16 +26,16 @@ #include "lprefix.h" - #include <stddef.h> +#include <stdlib.h> #include "lua.h" #include "lualib.h" #include "lauxlib.h" -#include "lfs.h" #include "lposix.h" -#include "lfbsd.h" + +#include "bootstrap.h" /* ** these libs are loaded by lua.c and are readily available to any Lua @@ -56,12 +56,32 @@ static const luaL_Reg loadedlibs[] = { {LUA_BITLIBNAME, luaopen_bit32}, #endif /* FreeBSD Extensions */ - {"lfs", luaopen_lfs}, {"posix", luaopen_posix}, - {"fbsd", luaopen_fbsd}, {NULL, NULL} }; +#ifdef BOOTSTRAPPING +static void __attribute__((constructor)) flua_init_env(void) { + /* + * This happens in the middle of luaopen_package(). We could move it into + * flua_setup_mods(), but it seems better to avoid its timing being so + * important that it would break some of our bootstrap modules if someone + * were to reorder things. + */ + if (getenv("LUA_PATH") == NULL) + setenv("LUA_PATH", BOOTSTRAP_FLUA_PATH, 1); +} + +static void flua_setup_mods (lua_State *L) { + const luaL_Reg **flib; + + SET_FOREACH(flib, FLUA_MODULE_SETNAME) { + luaL_requiref(L, (*flib)->name, (*flib)->func, 1); + lua_pop(L, 1); /* remove lib */ + } +}; +#endif + LUALIB_API void luaL_openlibs (lua_State *L) { const luaL_Reg *lib; /* "require" functions from 'loadedlibs' and set results to global table */ @@ -69,4 +89,7 @@ LUALIB_API void luaL_openlibs (lua_State *L) { luaL_requiref(L, lib->name, lib->func, 1); lua_pop(L, 1); /* remove lib */ } +#ifdef BOOTSTRAPPING + flua_setup_mods(L); +#endif } diff --git a/libexec/kgdb/Makefile b/libexec/kgdb/Makefile deleted file mode 100644 index f6b255ab4f60..000000000000 --- a/libexec/kgdb/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -FILESDIR?= /usr/libexec/kgdb - -FILES= acttrace.py - -.include <bsd.prog.mk> 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/release/Makefile b/release/Makefile index f907bf985893..12f5114f8b22 100644 --- a/release/Makefile +++ b/release/Makefile @@ -75,11 +75,19 @@ VOLUME_LABEL= ${REVISION:C/[.-]/_/g}_${BRANCH:C/[.-]/_/g}_${TARGET_ARCH} .endfor .endif +.if !defined(NOPKGBASE) || empty(NOPKGBASE) +PKGBASE_REPO_DIR= pkgbase-repo-dir +WSTAGEDIR!= ${IMAKE} -f Makefile.inc1 -C ${WORLDDIR} -V WSTAGEDIR +PKG_ABI_FILE= ${WSTAGEDIR}/usr/bin/uname +PKG_ABI= $$(${PKG_CMD} -o ABI_FILE=${PKG_ABI_FILE} config ABI) +.endif + .if ${.MAKE.OS} == "FreeBSD" # For installing packages into the release media. PKG_ENV+= INSTALL_AS_USER=yes PKG_ENV+= ASSUME_ALWAYS_YES=yes PKG_ARGS+= -o METALOG=METALOG +PKG_ARGS+= -o ABI=${PKG_ABI} PKG_ARGS+= -r ${.TARGET} PKG_REPO_ARGS= -o REPOS_DIR=${.CURDIR}/pkg_repos PKGBASE_REPO_ARGS=-o REPOS_DIR=${.OBJDIR}/pkgbase-repo-dir @@ -108,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 @@ -124,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) @@ -134,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> @@ -188,17 +202,15 @@ 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 .endif - .if !defined(NOPKGBASE) || empty(NOPKGBASE) -PKGBASE_REPO_DIR= pkgbase-repo-dir -WSTAGEDIR!= ${IMAKE} -f Makefile.inc1 -C ${WORLDDIR} -V WSTAGEDIR -PKG_ABI_FILE= ${WSTAGEDIR}/usr/bin/uname -PKG_ABI= $$(${PKG_CMD} -o ABI_FILE=${PKG_ABI_FILE} config ABI) +disc1: pkgbase-repo-dir +bootonly: pkgbase-repo-dir +dvd: pkgbase-repo-dir .endif pkgbase-repo: @@ -207,13 +219,16 @@ 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 }" \ ${.OBJDIR}/pkgbase-repo/${PKG_ABI}/latest \ > pkgbase-repo-dir/FreeBSD-base.conf -disc1: ${PKGBASE_REPO_DIR} +disc1: # Install system mkdir -p ${.TARGET} ( cd ${WORLDDIR} && ${IMAKE} installworld installkernel distribution \ @@ -236,7 +251,7 @@ disc1: ${PKGBASE_REPO_DIR} 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 @@ -278,7 +293,7 @@ disc1: ${PKGBASE_REPO_DIR} echo "./etc/rc.local type=file uname=root gname=wheel mode=0644" >> ${.TARGET}/METALOG touch ${.TARGET} -bootonly: ${PKGBASE_REPO_DIR} +bootonly: # Install system mkdir -p ${.TARGET} ( cd ${WORLDDIR} && ${IMAKE} installworld installkernel distribution \ @@ -289,7 +304,7 @@ bootonly: ${PKGBASE_REPO_DIR} 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 @@ -322,7 +337,7 @@ bootonly: ${PKGBASE_REPO_DIR} echo "./boot/loader.conf type=file uname=root gname=wheel mode=0644" >> ${.TARGET}/METALOG echo "./etc/rc.local type=file uname=root gname=wheel mode=0644" >> ${.TARGET}/METALOG -dvd: ${PKGBASE_REPO_DIR} +dvd: # Install system mkdir -p ${.TARGET} ( cd ${WORLDDIR} && ${IMAKE} installworld installkernel distribution \ @@ -341,7 +356,7 @@ dvd: ${PKGBASE_REPO_DIR} 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 @@ -443,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} @@ -454,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/Makefile.vm b/release/Makefile.vm index eafd1d6abf71..336e8fc82299 100644 --- a/release/Makefile.vm +++ b/release/Makefile.vm @@ -134,6 +134,7 @@ cw-${_CW:tl}-${_FS}-${_FMT}: ${QEMUTGT} ${PKGBASE_REPO_DIR} ${WITHOUT_QEMU:DWITHOUT_QEMU=true} \ ${NO_ROOT:DNO_ROOT=true} \ PKG_CMD=${PKG_CMD:Upkg} \ + PKG_ABI=${PKG_ABI} \ PKG_REPOS_DIR=${PKG_REPOS_DIR:U${.OBJDIR}/${.TARGET}/etc/pkg} \ PKG_REPO_NAME=${PKG_REPO_NAME:UFreeBSD-ports} \ PKG_INSTALL_EPOCH=${PKG_INSTALL_EPOCH:U${GITEPOCH}} \ @@ -192,6 +193,7 @@ vm-image: ${QEMUTGT} ${PKGBASE_REPO_DIR} ${WITHOUT_QEMU:DWITHOUT_QEMU=true} \ ${NO_ROOT:DNO_ROOT=true} \ PKG_CMD=${PKG_CMD:Upkg} \ + PKG_ABI=${PKG_ABI} \ PKG_REPOS_DIR=${PKG_REPOS_DIR:U${.OBJDIR}/${.TARGET}-${FORMAT}-${FS}/etc/pkg} \ PKG_REPO_NAME=${PKG_REPO_NAME:UFreeBSD-ports} \ PKG_INSTALL_EPOCH=${PKG_INSTALL_EPOCH:U${GITEPOCH}} \ diff --git a/release/packages/create-sets.sh b/release/packages/create-sets.sh index 09567657c161..3780e8ee46c6 100755 --- a/release/packages/create-sets.sh +++ b/release/packages/create-sets.sh @@ -1,4 +1,20 @@ #! /bin/sh +# +# SPDX-License-Identifier: ISC +# +# Copyright (c) 2025 Lexi Winter <ivy@FreeBSD.org> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # Generate metapackage sets. We do this by examining the annotations field # of the packages we previously built. 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/release/tools/vmimage.subr b/release/tools/vmimage.subr index 577abaac73cf..3b0519c21dbc 100644 --- a/release/tools/vmimage.subr +++ b/release/tools/vmimage.subr @@ -94,7 +94,10 @@ vm_install_base() { local pkg_cmd pkg_cmd="pkg --rootdir ${DESTDIR} --repo-conf-dir ${PKGBASE_REPO_DIR} -o ASSUME_ALWAYS_YES=yes -o IGNORE_OSVERSION=yes - -o INSTALL_AS_USER=yes " + -o ABI=${PKG_ABI} -o INSTALL_AS_USER=yes " + if [ -n "${NO_ROOT}" ]; then + pkg_cmd="$pkg_cmd -o METALOG=METALOG" + fi $pkg_cmd update selected=$($pkg_cmd rquery -U -r FreeBSD-base %n | \ vm_filter_base_packages | vm_extra_filter_base_packages) @@ -198,6 +201,7 @@ vm_extra_install_packages() { for pkg in ${VM_EXTRA_PACKAGES}; do INSTALL_AS_USER=yes \ ${PKG_CMD} \ + -o ABI=${PKG_ABI} \ -o METALOG=${DESTDIR}/METALOG.pkg \ -o REPOS_DIR=${PKG_REPOS_DIR} \ -o PKG_DBDIR=${DESTDIR}/var/db/pkg \ @@ -249,9 +253,16 @@ vm_emulation_cleanup() { } vm_extra_pkg_rmcache() { - if [ -e ${DESTDIR}/usr/local/sbin/pkg ]; then - chroot ${DESTDIR} ${EMULATOR} env ASSUME_ALWAYS_YES=yes \ - /usr/local/sbin/pkg clean -y -a + if [ -n "${NO_ROOT}" ]; then + ${PKG_CMD} \ + -o ASSUME_ALWAYS_YES=yes \ + -r ${DESTDIR} \ + clean -y -a + else + if [ -e ${DESTDIR}/usr/local/sbin/pkg ]; then + chroot ${DESTDIR} ${EMULATOR} env ASSUME_ALWAYS_YES=yes \ + /usr/local/sbin/pkg clean -y -a + fi fi return 0 diff --git a/sbin/ipf/libipf/printdstl_live.c b/sbin/ipf/libipf/printdstl_live.c index 088448e6656d..72cb75a832c9 100644 --- a/sbin/ipf/libipf/printdstl_live.c +++ b/sbin/ipf/libipf/printdstl_live.c @@ -40,6 +40,9 @@ printdstl_live( ippool_dst_t *d, int fd, char *name, int opts, if ((d->ipld_flags & IPHASH_DELETE) != 0) PRINTF("# "); + if (opts & OPT_SAVEOUT) + PRINTF("{\n"); + if ((opts & OPT_DEBUG) == 0) PRINTF("\t{"); diff --git a/sbin/ipf/libipf/printdstlist.c b/sbin/ipf/libipf/printdstlist.c index 2cf41ffe414c..497d7004c94c 100644 --- a/sbin/ipf/libipf/printdstlist.c +++ b/sbin/ipf/libipf/printdstlist.c @@ -42,6 +42,8 @@ printdstlist( ippool_dst_t *pp, copyfunc_t copyfunc, char *name, int opts, return (NULL); } + if (opts & OPT_SAVEOUT) + PRINTF("\t"); node = printdstlistnode(n, bcopywrap, opts, fields); free(n); diff --git a/sbin/ipf/libipf/printdstlistdata.c b/sbin/ipf/libipf/printdstlistdata.c index 7940d2ae021b..546bf35cabf6 100644 --- a/sbin/ipf/libipf/printdstlistdata.c +++ b/sbin/ipf/libipf/printdstlistdata.c @@ -11,8 +11,7 @@ void printdstlistdata( ippool_dst_t *pool, int opts) { - - if ((opts & OPT_DEBUG) == 0) { + if ((opts & OPT_DEBUG) == 0 || opts & OPT_SAVEOUT) { if ((pool->ipld_flags & IPDST_DELETE) != 0) PRINTF("# "); PRINTF("pool "); @@ -24,7 +23,7 @@ printdstlistdata( ippool_dst_t *pool, int opts) printunit(pool->ipld_unit); - if ((opts & OPT_DEBUG) == 0) { + if ((opts & OPT_DEBUG) == 0 || opts & OPT_SAVEOUT) { PRINTF("/dstlist (name %s;", pool->ipld_name); if (pool->ipld_policy != IPLDP_NONE) { PRINTF(" policy "); diff --git a/sbin/ipf/libipf/printhash_live.c b/sbin/ipf/libipf/printhash_live.c index b8ee31b27597..427daa18316b 100644 --- a/sbin/ipf/libipf/printhash_live.c +++ b/sbin/ipf/libipf/printhash_live.c @@ -26,7 +26,9 @@ printhash_live(iphtable_t *hp, int fd, char *name, int opts, wordtab_t *fields) if ((hp->iph_flags & IPHASH_DELETE) != 0) PRINTF("# "); - if ((opts & OPT_DEBUG) == 0) + if (opts & OPT_SAVEOUT) + PRINTF("{\n"); + else if ((opts & OPT_DEBUG) == 0) PRINTF("\t{"); obj.ipfo_rev = IPFILTER_VERSION; @@ -50,6 +52,8 @@ printhash_live(iphtable_t *hp, int fd, char *name, int opts, wordtab_t *fields) last = 1; if (bcmp(&zero, &entry, sizeof(zero)) == 0) break; + if (opts & OPT_SAVEOUT) + PRINTF("\t"); (void) printhashnode(hp, &entry, bcopywrap, opts, fields); printed++; } @@ -59,7 +63,7 @@ printhash_live(iphtable_t *hp, int fd, char *name, int opts, wordtab_t *fields) if (printed == 0) putchar(';'); - if ((opts & OPT_DEBUG) == 0) + if ((opts & OPT_DEBUG) == 0 || (opts & OPT_SAVEOUT)) PRINTF(" };\n"); (void) ioctl(fd,SIOCIPFDELTOK, &iter.ili_key); diff --git a/sbin/ipf/libipf/printhashdata.c b/sbin/ipf/libipf/printhashdata.c index 690243d63f1e..6fa62e67556d 100644 --- a/sbin/ipf/libipf/printhashdata.c +++ b/sbin/ipf/libipf/printhashdata.c @@ -12,7 +12,11 @@ void printhashdata(iphtable_t *hp, int opts) { - if ((opts & OPT_DEBUG) == 0) { + if (opts & OPT_SAVEOUT) { + if ((hp->iph_flags & IPHASH_DELETE) == IPHASH_DELETE) + PRINTF("# "); + PRINTF("pool "); + } else if ((opts & OPT_DEBUG) == 0) { if ((hp->iph_type & IPHASH_ANON) == IPHASH_ANON) PRINTF("# 'anonymous' table refs %d\n", hp->iph_ref); if ((hp->iph_flags & IPHASH_DELETE) == IPHASH_DELETE) @@ -37,6 +41,8 @@ printhashdata(iphtable_t *hp, int opts) } PRINTF(" role="); } else { + if ((hp->iph_flags & IPHASH_DELETE) == IPHASH_DELETE) + PRINTF("# "); PRINTF("Hash Table %s: %s", ISDIGIT(*hp->iph_name) ? "Number" : "Name", hp->iph_name); @@ -48,7 +54,16 @@ printhashdata(iphtable_t *hp, int opts) printunit(hp->iph_unit); - if ((opts & OPT_DEBUG) == 0) { + if ((opts & OPT_SAVEOUT)) { + if ((hp->iph_type & ~IPHASH_ANON) == IPHASH_LOOKUP) + PRINTF("/hash"); + PRINTF("(%s \"%s\"; size %lu;", + ISDIGIT(*hp->iph_name) ? "number" : "name", + hp->iph_name, (u_long)hp->iph_size); + if (hp->iph_seed != 0) + PRINTF(" seed %lu;", hp->iph_seed); + PRINTF(")\n", hp->iph_seed); + } else if ((opts & OPT_DEBUG) == 0) { if ((hp->iph_type & ~IPHASH_ANON) == IPHASH_LOOKUP) PRINTF(" type=hash"); PRINTF(" %s=%s size=%lu", diff --git a/sbin/ipf/libipf/printpooldata.c b/sbin/ipf/libipf/printpooldata.c index bd5af316eb19..b203522734be 100644 --- a/sbin/ipf/libipf/printpooldata.c +++ b/sbin/ipf/libipf/printpooldata.c @@ -13,6 +13,8 @@ printpooldata(ip_pool_t *pool, int opts) { if (opts & OPT_SAVEOUT) { + if ((pool->ipo_flags & IPOOL_DELETE) != 0) + PRINTF("# "); PRINTF("pool "); } else if ((opts & OPT_DEBUG) == 0) { if ((pool->ipo_flags & IPOOL_ANON) != 0) diff --git a/sbin/ipfw/tests/test_add_rule.py b/sbin/ipfw/tests/test_add_rule.py index 60c8cebaceaa..c2c4bf0b360c 100755 --- a/sbin/ipfw/tests/test_add_rule.py +++ b/sbin/ipfw/tests/test_add_rule.py @@ -36,6 +36,7 @@ from atf_python.sys.netpfil.ipfw.insns import InsnProb from atf_python.sys.netpfil.ipfw.insns import InsnProto from atf_python.sys.netpfil.ipfw.insns import InsnReject from atf_python.sys.netpfil.ipfw.insns import InsnTable +from atf_python.sys.netpfil.ipfw.insns import InsnU32 from atf_python.sys.netpfil.ipfw.insns import IpFwOpcode from atf_python.sys.netpfil.ipfw.ioctl import CTlv from atf_python.sys.netpfil.ipfw.ioctl import CTlvRule @@ -152,8 +153,8 @@ class TestAddRule(BaseTest): NTlv(IpFwTlvType.IPFW_TLV_TBL_NAME, idx=2, name="BBB"), ], "insns": [ - InsnTable(IpFwOpcode.O_IP_SRC_LOOKUP, arg1=1), - InsnTable(IpFwOpcode.O_IP_DST_LOOKUP, arg1=2), + InsnU32(IpFwOpcode.O_IP_SRC_LOOKUP, u32=1), + InsnU32(IpFwOpcode.O_IP_DST_LOOKUP, u32=2), InsnEmpty(IpFwOpcode.O_ACCEPT), ], }, @@ -182,7 +183,7 @@ class TestAddRule(BaseTest): ], "insns": [ InsnIp(IpFwOpcode.O_IP_DST, ip="1.2.3.4"), - Insn(IpFwOpcode.O_EXTERNAL_ACTION, arg1=1), + InsnU32(IpFwOpcode.O_EXTERNAL_ACTION, u32=1), Insn(IpFwOpcode.O_EXTERNAL_DATA, arg1=123), ], }, @@ -199,8 +200,8 @@ class TestAddRule(BaseTest): ], "insns": [ InsnIp(IpFwOpcode.O_IP_DST, ip="1.2.3.4"), - Insn(IpFwOpcode.O_EXTERNAL_ACTION, arg1=1), - Insn(IpFwOpcode.O_EXTERNAL_INSTANCE, arg1=2), + InsnU32(IpFwOpcode.O_EXTERNAL_ACTION, u32=1), + InsnU32(IpFwOpcode.O_EXTERNAL_INSTANCE, u32=2), ], }, }, @@ -227,7 +228,7 @@ class TestAddRule(BaseTest): ], "insns": [ InsnComment(comment="test comment"), - Insn(IpFwOpcode.O_CHECK_STATE, arg1=1), + InsnU32(IpFwOpcode.O_CHECK_STATE, u32=1), ], }, }, @@ -241,9 +242,9 @@ class TestAddRule(BaseTest): NTlv(IpFwTlvType.IPFW_TLV_STATE_NAME, idx=1, name="OUT"), ], "insns": [ - Insn(IpFwOpcode.O_PROBE_STATE, arg1=1), + InsnU32(IpFwOpcode.O_PROBE_STATE, u32=1), Insn(IpFwOpcode.O_PROTO, arg1=6), - Insn(IpFwOpcode.O_KEEP_STATE, arg1=1), + InsnU32(IpFwOpcode.O_KEEP_STATE, u32=1), InsnEmpty(IpFwOpcode.O_ACCEPT), ], }, @@ -259,7 +260,7 @@ class TestAddRule(BaseTest): ], "insns": [ Insn(IpFwOpcode.O_PROTO, arg1=6), - Insn(IpFwOpcode.O_KEEP_STATE, arg1=1), + InsnU32(IpFwOpcode.O_KEEP_STATE, u32=1), InsnEmpty(IpFwOpcode.O_ACCEPT), ], }, @@ -370,7 +371,7 @@ class TestAddRule(BaseTest): ), pytest.param(("pipe 42", Insn(IpFwOpcode.O_PIPE, arg1=42)), id="pipe_42"), pytest.param( - ("skipto 42", Insn(IpFwOpcode.O_SKIPTO, arg1=42)), id="skipto_42" + ("skipto 42", InsnU32(IpFwOpcode.O_SKIPTO, u32=42)), id="skipto_42" ), pytest.param( ("netgraph 42", Insn(IpFwOpcode.O_NETGRAPH, arg1=42)), id="netgraph_42" @@ -386,7 +387,7 @@ class TestAddRule(BaseTest): ), pytest.param(("tee 42", Insn(IpFwOpcode.O_TEE, arg1=42)), id="tee_42"), pytest.param( - ("call 420", Insn(IpFwOpcode.O_CALLRETURN, arg1=420)), id="call_420" + ("call 420", InsnU32(IpFwOpcode.O_CALLRETURN, u32=420)), id="call_420" ), # TOK_FORWARD pytest.param( @@ -400,7 +401,7 @@ class TestAddRule(BaseTest): ), pytest.param(("reass", InsnEmpty(IpFwOpcode.O_REASS)), id="reass"), pytest.param( - ("return", InsnEmpty(IpFwOpcode.O_CALLRETURN, is_not=True)), id="return" + ("return", InsnU32(IpFwOpcode.O_CALLRETURN, is_not=True)), id="return" ), ], ) diff --git a/share/man/man3/snl.3 b/share/man/man3/snl.3 index 9a6eceb66a32..f678d6cb2cea 100644 --- a/share/man/man3/snl.3 +++ b/share/man/man3/snl.3 @@ -288,7 +288,7 @@ main(int ac, char *argv[]) struct nl_parsed_link link = {}; if (!snl_parse_nlmsg(&ss, hdr, &link_parser, &link)) continue; - printf("Link#%u %s mtu %u\n", link.ifi_index, link.ifla_ifname, link.ifla_mtu); + printf("Link#%u %s mtu %u\\n", link.ifi_index, link.ifla_ifname, link.ifla_mtu); } return (0); 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/man4/nda.4 b/share/man/man4/nda.4 index c4fa157af851..e45b2905462e 100644 --- a/share/man/man4/nda.4 +++ b/share/man/man4/nda.4 @@ -1,4 +1,6 @@ .\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" .\" Copyright (c) 2017 Netflix, Inc. .\" .\" Redistribution and use in source and binary forms, with or without @@ -23,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd June 6, 2020 +.Dd October 2, 2025 .Dt NDA 4 .Os .Sh NAME @@ -39,6 +41,14 @@ driver provides support for direct access devices, implementing the .Tn NVMe command protocol, that are attached to the system through a host adapter supported by the CAM subsystem. +.Sh HARDWARE +The +.Nm +driver supports NVMe +.Pq Non-Volatile Memory Express +storage devices connected via PCIe or over NVMF +.Pq NVMe over Fabric +via the CAM subsystem. .Sh SYSCTL VARIABLES The following variables are available as both .Xr sysctl 8 diff --git a/share/man/man4/sdhci.4 b/share/man/man4/sdhci.4 index 4a4e02539acd..1608d9c2fe1a 100644 --- a/share/man/man4/sdhci.4 +++ b/share/man/man4/sdhci.4 @@ -1,4 +1,6 @@ .\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" .\" Copyright (c) 2008 Alexander Motin <mav@FreeBSD.org> .\" All rights reserved. .\" @@ -22,7 +24,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd August 25, 2020 +.Dd October 3, 2025 .Dt SDHCI 4 .Os .Sh NAME @@ -56,21 +58,28 @@ detaches it on card removing. .Sh HARDWARE The .Nm -driver supports different specification compatible chips. -The following chips have been verified to work: +driver supports the SD Host Controller Specification. +When attaching via the PCI bus, +the controller is automatically configured. +Many SoC chips provide a SDHCI controller directly mapped to I/O memory. +For those, the controller may be configured using +.Xr fdt 4 +or +.Xr acpi 4 +methods, supplied by your board's vendor. .Pp -.Bl -bullet -compact -.It -ENE CB712 -.It -ENE CB714 -.It -RICOH R5C822 -.It -RICOH R5CE823 -.It -TI PCIXX21/XX11/XX12 -.El +Unlike most other drivers that support a generic standard, +.Nm +requires a large number of quirks to cope with hardware bugs, +proprietary registers and poorly specified power management. +While many chipsets from +Intel, Xilinx, Rockchip, Frescale, Ricoh, and TI have these entries, +suboptimal performance may result when using some controllers. +Quirks and custom configuration are most often required +when the device is configured via +.Xr fdt 4 +or +.Xr acpi 4 . .Sh SEE ALSO .Xr mmc 4 , .Xr mmcsd 4 @@ -79,8 +88,3 @@ TI PCIXX21/XX11/XX12 .Re .Sh AUTHORS .An Alexander Motin Aq Mt mav@FreeBSD.org -.Sh BUGS -Many of existing SD controller chips have some nonstandard requirements, -proprietary registers and hardware bugs, requiring additional handling. -ENE chips are handled to work fine, while some revisions of RICOH and TI -controllers still do not see cards without some additional initialization. diff --git a/share/man/man4/umass.4 b/share/man/man4/umass.4 index 03e8b6ff6ef1..db4e6f0890f2 100644 --- a/share/man/man4/umass.4 +++ b/share/man/man4/umass.4 @@ -1,3 +1,6 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" .\" Copyright (c) 1999 .\" Nick Hibma <n_hibma@FreeBSD.org>. All rights reserved. .\" @@ -22,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd January 27, 2020 +.Dd October 2, 2025 .Dt UMASS 4 .Os .Sh NAME @@ -71,6 +74,19 @@ requires and .Xr scbus 4 to be included in the kernel. +.Sh HARDWARE +The +.Nm +driver supports USB Mass Storage devices such as: +.Pp +.Bl -bullet -compact +.It +USB thumb drives +.It +USB hard disk drives +.It +USB floppy drives +.El .Sh EXAMPLES .Bd -literal -offset indent device umass @@ -92,7 +108,8 @@ camcontrol rescan 0:0:3 Rescan all slots on a multi-slot flash reader, where the slots map to separate LUNs on a single SCSI ID. Typically only the first slot will be enabled at boot time. -This assumes that the flash reader is the first SCSI bus in the system and has 4 slots. +This assumes that +the flash reader is the first SCSI bus in the system and has 4 slots. .Sh SEE ALSO .Xr cfumass 4 , .Xr ehci 4 , @@ -101,7 +118,11 @@ This assumes that the flash reader is the first SCSI bus in the system and has 4 .Xr usb 4 , .Xr xhci 4 , .Xr camcontrol 8 -.\".Sh HISTORY +.Sh HISTORY +The +.Nm +driver appeared in +.Fx 4.3 . .Sh AUTHORS .An -nosplit The diff --git a/share/man/man4/usbhid.4 b/share/man/man4/usbhid.4 index 4c7f254bdace..0b2e7230e3f4 100644 --- a/share/man/man4/usbhid.4 +++ b/share/man/man4/usbhid.4 @@ -67,6 +67,8 @@ Default is 1. Debug output level, where 0 is debugging disabled and larger values increase debug message verbosity. Default is 0. +Debug messages are printed on the system console and can be viewed using +.Xr dmesg 8 . .El .Sh SEE ALSO .Xr ehci 4 , diff --git a/share/man/man5/Makefile b/share/man/man5/Makefile index 0f6559b236c6..c13a8b7afde2 100644 --- a/share/man/man5/Makefile +++ b/share/man/man5/Makefile @@ -73,9 +73,11 @@ MANGROUPS+= BOOTLOADER BOOTLOADER= device.hints.5 BOOTLOADERPACKAGE=bootloader -MANGROUPS+= CLANG -CLANG= ar.5 -CLANGPACKAGE= clang +.if ${MK_TOOLCHAIN} != "no" +MANGROUPS+= TOOLCHAIN +TOOLCHAIN= ar.5 +TOOLCHAINPACKAGE=toolchain +.endif MANGROUPS+= LP LP= hosts.lpd.5 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/stand/liblua/Makefile b/stand/liblua/Makefile index ce7eb89fe494..b1c34ec0a466 100644 --- a/stand/liblua/Makefile +++ b/stand/liblua/Makefile @@ -24,7 +24,7 @@ SRCS+= lauxlib.c lbaselib.c lstrlib.c loadlib.c SRCS+= lerrno.c lpager.c lstd.c lutils.c SRCS+= gfx_utils.c -.PATH: ${FLUASRC}/modules +.PATH: ${FLUASRC}/lfs SRCS+= lfs.c .PATH: ${FLUALIB}/libhash SRCS+= lhash.c diff --git a/stand/loader.mk b/stand/loader.mk index 4073e523e552..e26ba1401912 100644 --- a/stand/loader.mk +++ b/stand/loader.mk @@ -89,7 +89,7 @@ SRCS+= interp_lua.c .include "${BOOTSRC}/lua.mk" LDR_INTERP= ${LIBLUA} LDR_INTERP32= ${LIBLUA32} -CFLAGS.interp_lua.c= -DLUA_PATH=\"${LUAPATH}\" -I${FLUASRC}/modules +CFLAGS.interp_lua.c= -DLUA_PATH=\"${LUAPATH}\" -I${FLUASRC}/lfs .elif ${LOADER_INTERP} == "4th" SRCS+= interp_forth.c .include "${BOOTSRC}/ficl.mk" diff --git a/sys/conf/kern.post.mk b/sys/conf/kern.post.mk index bb3c7af82a4d..7cdfd17778db 100644 --- a/sys/conf/kern.post.mk +++ b/sys/conf/kern.post.mk @@ -398,6 +398,14 @@ CFLAGS+= -fdebug-prefix-map=./${_link}=${PREFIX_SYSDIR}/${_link}/include .endif .endfor +# Install GDB plugins that are useful for kernel debugging. See the +# README in sys/tools/gdb for more information. +GDB_FILES= acttrace.py \ + freebsd.py \ + pcpu.py \ + selftest.py \ + vnet.py + ${_ILINKS}: @case ${.TARGET} in \ machine) \ @@ -447,6 +455,13 @@ kernel-install: .PHONY .if defined(DEBUG) && !defined(INSTALL_NODEBUG) && ${MK_KERNEL_SYMBOLS} != "no" mkdir -p ${DESTDIR}${KERN_DEBUGDIR}${KODIR} ${INSTALL} -p -m ${KMODMODE} -o ${KMODOWN} -g ${KMODGRP} ${KERNEL_KO}.debug ${DESTDIR}${KERN_DEBUGDIR}${KODIR}/ + ${INSTALL} -m ${KMODMODE} -o ${KMODOWN} -g ${KMODGRP} \ + $S/tools/kernel-gdb.py ${DESTDIR}${KERN_DEBUGDIR}${KODIR}/${KERNEL_KO}-gdb.py + mkdir -p ${DESTDIR}${KERN_DEBUGDIR}${KODIR}/gdb +.for file in ${GDB_FILES} + ${INSTALL} -m ${KMODMODE} -o ${KMODOWN} -g ${KMODGRP} \ + $S/tools/gdb/${file} ${DESTDIR}${KERN_DEBUGDIR}${KODIR}/gdb/${file} +.endfor .endif .if defined(KERNEL_EXTRA_INSTALL) ${INSTALL} -p -m ${KMODMODE} -o ${KMODOWN} -g ${KMODGRP} ${KERNEL_EXTRA_INSTALL} ${DESTDIR}${KODIR}/ 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/fs/nullfs/null.h b/sys/fs/nullfs/null.h index 0a93878c859f..aa7a689bec34 100644 --- a/sys/fs/nullfs/null.h +++ b/sys/fs/nullfs/null.h @@ -37,6 +37,9 @@ #define NULLM_CACHE 0x0001 +#include <sys/ck.h> +#include <vm/uma.h> + struct null_mount { struct mount *nullm_vfs; struct vnode *nullm_lowerrootvp; /* Ref to lower root vnode */ @@ -50,7 +53,7 @@ struct null_mount { * A cache of vnode references */ struct null_node { - LIST_ENTRY(null_node) null_hash; /* Hash list */ + CK_LIST_ENTRY(null_node) null_hash; /* Hash list */ struct vnode *null_lowervp; /* VREFed once */ struct vnode *null_vnode; /* Back pointer */ u_int null_flags; @@ -61,6 +64,7 @@ struct null_node { #define MOUNTTONULLMOUNT(mp) ((struct null_mount *)((mp)->mnt_data)) #define VTONULL(vp) ((struct null_node *)(vp)->v_data) +#define VTONULL_SMR(vp) ((struct null_node *)vn_load_v_data_smr(vp)) #define NULLTOV(xp) ((xp)->null_vnode) int nullfs_init(struct vfsconf *vfsp); @@ -79,9 +83,7 @@ struct vnode *null_checkvp(struct vnode *vp, char *fil, int lno); extern struct vop_vector null_vnodeops; -#ifdef MALLOC_DECLARE -MALLOC_DECLARE(M_NULLFSNODE); -#endif +extern uma_zone_t null_node_zone; #ifdef NULLFS_DEBUG #define NULLFSDEBUG(format, args...) printf(format ,## args) diff --git a/sys/fs/nullfs/null_subr.c b/sys/fs/nullfs/null_subr.c index 053614b6910d..146d3bbdaedd 100644 --- a/sys/fs/nullfs/null_subr.c +++ b/sys/fs/nullfs/null_subr.c @@ -41,9 +41,14 @@ #include <sys/mount.h> #include <sys/proc.h> #include <sys/vnode.h> +#include <sys/smr.h> #include <fs/nullfs/null.h> +#include <vm/uma.h> + +VFS_SMR_DECLARE; + /* * Null layer cache: * Each cache entry holds a reference to the lower vnode @@ -54,12 +59,12 @@ #define NULL_NHASH(vp) (&null_node_hashtbl[vfs_hash_index(vp) & null_hash_mask]) -static LIST_HEAD(null_node_hashhead, null_node) *null_node_hashtbl; +static CK_LIST_HEAD(null_node_hashhead, null_node) *null_node_hashtbl; static struct rwlock null_hash_lock; static u_long null_hash_mask; static MALLOC_DEFINE(M_NULLFSHASH, "nullfs_hash", "NULLFS hash table"); -MALLOC_DEFINE(M_NULLFSNODE, "nullfs_node", "NULLFS vnode private part"); +uma_zone_t __read_mostly null_node_zone; static void null_hashins(struct mount *, struct null_node *); @@ -73,6 +78,10 @@ nullfs_init(struct vfsconf *vfsp) null_node_hashtbl = hashinit(desiredvnodes, M_NULLFSHASH, &null_hash_mask); rw_init(&null_hash_lock, "nullhs"); + null_node_zone = uma_zcreate("nullfs node", sizeof(struct null_node), + NULL, NULL, NULL, NULL, 0, UMA_ZONE_ZINIT); + VFS_SMR_ZONE_SET(null_node_zone); + return (0); } @@ -80,6 +89,7 @@ int nullfs_uninit(struct vfsconf *vfsp) { + uma_zdestroy(null_node_zone); rw_destroy(&null_hash_lock); hashdestroy(null_node_hashtbl, M_NULLFSHASH, null_hash_mask); return (0); @@ -96,7 +106,7 @@ null_hashget_locked(struct mount *mp, struct vnode *lowervp) struct null_node *a; struct vnode *vp; - ASSERT_VOP_LOCKED(lowervp, "null_hashget"); + ASSERT_VOP_LOCKED(lowervp, __func__); rw_assert(&null_hash_lock, RA_LOCKED); /* @@ -106,18 +116,21 @@ null_hashget_locked(struct mount *mp, struct vnode *lowervp) * reference count (but NOT the lower vnode's VREF counter). */ hd = NULL_NHASH(lowervp); - LIST_FOREACH(a, hd, null_hash) { - if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) { - /* - * Since we have the lower node locked the nullfs - * node can not be in the process of recycling. If - * it had been recycled before we grabed the lower - * lock it would not have been found on the hash. - */ - vp = NULLTOV(a); - vref(vp); - return (vp); - } + CK_LIST_FOREACH(a, hd, null_hash) { + if (a->null_lowervp != lowervp) + continue; + /* + * Since we have the lower node locked the nullfs + * node can not be in the process of recycling. If + * it had been recycled before we grabed the lower + * lock it would not have been found on the hash. + */ + vp = NULLTOV(a); + VNPASS(!VN_IS_DOOMED(vp), vp); + if (vp->v_mount != mp) + continue; + vref(vp); + return (vp); } return (NULL); } @@ -126,17 +139,34 @@ struct vnode * null_hashget(struct mount *mp, struct vnode *lowervp) { struct null_node_hashhead *hd; + struct null_node *a; struct vnode *vp; + enum vgetstate vs; - hd = NULL_NHASH(lowervp); - if (LIST_EMPTY(hd)) - return (NULL); - - rw_rlock(&null_hash_lock); - vp = null_hashget_locked(mp, lowervp); - rw_runlock(&null_hash_lock); + ASSERT_VOP_LOCKED(lowervp, "null_hashget"); + rw_assert(&null_hash_lock, RA_UNLOCKED); - return (vp); + vfs_smr_enter(); + hd = NULL_NHASH(lowervp); + CK_LIST_FOREACH(a, hd, null_hash) { + if (a->null_lowervp != lowervp) + continue; + /* + * See null_hashget_locked as to why the nullfs vnode can't be + * doomed here. + */ + vp = NULLTOV(a); + VNPASS(!VN_IS_DOOMED(vp), vp); + if (vp->v_mount != mp) + continue; + vs = vget_prep_smr(vp); + vfs_smr_exit(); + VNPASS(vs != VGET_NONE, vp); + vget_finish_ref(vp, vs); + return (vp); + } + vfs_smr_exit(); + return (NULL); } static void @@ -151,7 +181,7 @@ null_hashins(struct mount *mp, struct null_node *xp) hd = NULL_NHASH(xp->null_lowervp); #ifdef INVARIANTS - LIST_FOREACH(oxp, hd, null_hash) { + CK_LIST_FOREACH(oxp, hd, null_hash) { if (oxp->null_lowervp == xp->null_lowervp && NULLTOV(oxp)->v_mount == mp) { VNASSERT(0, NULLTOV(oxp), @@ -159,7 +189,7 @@ null_hashins(struct mount *mp, struct null_node *xp) } } #endif - LIST_INSERT_HEAD(hd, xp, null_hash); + CK_LIST_INSERT_HEAD(hd, xp, null_hash); } static void @@ -174,7 +204,7 @@ null_destroy_proto(struct vnode *vp, void *xp) VI_UNLOCK(vp); vgone(vp); vput(vp); - free(xp, M_NULLFSNODE); + uma_zfree_smr(null_node_zone, xp); } /* @@ -208,12 +238,12 @@ null_nodeget(struct mount *mp, struct vnode *lowervp, struct vnode **vpp) * Note that duplicate can only appear in hash if the lowervp is * locked LK_SHARED. */ - xp = malloc(sizeof(struct null_node), M_NULLFSNODE, M_WAITOK); + xp = uma_zalloc_smr(null_node_zone, M_WAITOK); error = getnewvnode("nullfs", mp, &null_vnodeops, &vp); if (error) { vput(lowervp); - free(xp, M_NULLFSNODE); + uma_zfree_smr(null_node_zone, xp); return (error); } @@ -261,8 +291,8 @@ null_nodeget(struct mount *mp, struct vnode *lowervp, struct vnode **vpp) return (error); } - null_hashins(mp, xp); vn_set_state(vp, VSTATE_CONSTRUCTED); + null_hashins(mp, xp); rw_wunlock(&null_hash_lock); *vpp = vp; @@ -277,7 +307,7 @@ null_hashrem(struct null_node *xp) { rw_wlock(&null_hash_lock); - LIST_REMOVE(xp, null_hash); + CK_LIST_REMOVE(xp, null_hash); rw_wunlock(&null_hash_lock); } diff --git a/sys/fs/nullfs/null_vnops.c b/sys/fs/nullfs/null_vnops.c index e9d598014a2f..375b6aa27531 100644 --- a/sys/fs/nullfs/null_vnops.c +++ b/sys/fs/nullfs/null_vnops.c @@ -174,6 +174,8 @@ #include <sys/mount.h> #include <sys/mutex.h> #include <sys/namei.h> +#include <sys/proc.h> +#include <sys/smr.h> #include <sys/sysctl.h> #include <sys/vnode.h> #include <sys/stat.h> @@ -185,6 +187,8 @@ #include <vm/vm_object.h> #include <vm/vnode_pager.h> +VFS_SMR_DECLARE; + static int null_bug_bypass = 0; /* for debugging: enables bypass printf'ing */ SYSCTL_INT(_debug, OID_AUTO, nullfs_bug_bypass, CTLFLAG_RW, &null_bug_bypass, 0, ""); @@ -768,83 +772,110 @@ null_rmdir(struct vop_rmdir_args *ap) } /* - * We need to process our own vnode lock and then clear the - * interlock flag as it applies only to our vnode, not the - * vnodes below us on the stack. + * We need to process our own vnode lock and then clear the interlock flag as + * it applies only to our vnode, not the vnodes below us on the stack. + * + * We have to hold the vnode here to solve a potential reclaim race. If we're + * forcibly vgone'd while we still have refs, a thread could be sleeping inside + * the lowervp's vop_lock routine. When we vgone we will drop our last ref to + * the lowervp, which would allow it to be reclaimed. The lowervp could then + * be recycled, in which case it is not legal to be sleeping in its VOP. We + * prevent it from being recycled by holding the vnode here. */ +static struct vnode * +null_lock_prep_with_smr(struct vop_lock1_args *ap) +{ + struct null_node *nn; + struct vnode *lvp; + + vfs_smr_enter(); + + lvp = NULL; + + nn = VTONULL_SMR(ap->a_vp); + if (__predict_true(nn != NULL)) { + lvp = nn->null_lowervp; + if (lvp != NULL && !vhold_smr(lvp)) + lvp = NULL; + } + + vfs_smr_exit(); + return (lvp); +} + +static struct vnode * +null_lock_prep_with_interlock(struct vop_lock1_args *ap) +{ + struct null_node *nn; + struct vnode *lvp; + + ASSERT_VI_LOCKED(ap->a_vp, __func__); + + ap->a_flags &= ~LK_INTERLOCK; + + lvp = NULL; + + nn = VTONULL(ap->a_vp); + if (__predict_true(nn != NULL)) { + lvp = nn->null_lowervp; + if (lvp != NULL) + vholdnz(lvp); + } + VI_UNLOCK(ap->a_vp); + return (lvp); +} + static int null_lock(struct vop_lock1_args *ap) { - struct vnode *vp = ap->a_vp; - int flags; - struct null_node *nn; struct vnode *lvp; - int error; + int error, flags; - if ((ap->a_flags & LK_INTERLOCK) == 0) - VI_LOCK(vp); - else - ap->a_flags &= ~LK_INTERLOCK; - flags = ap->a_flags; - nn = VTONULL(vp); + if (__predict_true((ap->a_flags & LK_INTERLOCK) == 0)) { + lvp = null_lock_prep_with_smr(ap); + if (__predict_false(lvp == NULL)) { + VI_LOCK(ap->a_vp); + lvp = null_lock_prep_with_interlock(ap); + } + } else { + lvp = null_lock_prep_with_interlock(ap); + } + + ASSERT_VI_UNLOCKED(ap->a_vp, __func__); + + if (__predict_false(lvp == NULL)) + return (vop_stdlock(ap)); + + VNPASS(lvp->v_holdcnt > 0, lvp); + error = VOP_LOCK(lvp, ap->a_flags); /* - * If we're still active we must ask the lower layer to - * lock as ffs has special lock considerations in its - * vop lock. + * We might have slept to get the lock and someone might have + * clean our vnode already, switching vnode lock from one in + * lowervp to v_lock in our own vnode structure. Handle this + * case by reacquiring correct lock in requested mode. */ - if (nn != NULL && (lvp = NULLVPTOLOWERVP(vp)) != NULL) { - /* - * We have to hold the vnode here to solve a potential - * reclaim race. If we're forcibly vgone'd while we - * still have refs, a thread could be sleeping inside - * the lowervp's vop_lock routine. When we vgone we will - * drop our last ref to the lowervp, which would allow it - * to be reclaimed. The lowervp could then be recycled, - * in which case it is not legal to be sleeping in its VOP. - * We prevent it from being recycled by holding the vnode - * here. - */ - vholdnz(lvp); - VI_UNLOCK(vp); - error = VOP_LOCK(lvp, flags); - - /* - * We might have slept to get the lock and someone might have - * clean our vnode already, switching vnode lock from one in - * lowervp to v_lock in our own vnode structure. Handle this - * case by reacquiring correct lock in requested mode. - */ - if (VTONULL(vp) == NULL && error == 0) { - ap->a_flags &= ~LK_TYPE_MASK; - switch (flags & LK_TYPE_MASK) { - case LK_SHARED: - ap->a_flags |= LK_SHARED; - break; - case LK_UPGRADE: - case LK_EXCLUSIVE: - ap->a_flags |= LK_EXCLUSIVE; - break; - default: - panic("Unsupported lock request %d\n", - ap->a_flags); - } - VOP_UNLOCK(lvp); - error = vop_stdlock(ap); + if (VTONULL(ap->a_vp) == NULL && error == 0) { + flags = ap->a_flags; + ap->a_flags &= ~LK_TYPE_MASK; + switch (flags & LK_TYPE_MASK) { + case LK_SHARED: + ap->a_flags |= LK_SHARED; + break; + case LK_UPGRADE: + case LK_EXCLUSIVE: + ap->a_flags |= LK_EXCLUSIVE; + break; + default: + panic("Unsupported lock request %d\n", + flags); } - vdrop(lvp); - } else { - VI_UNLOCK(vp); + VOP_UNLOCK(lvp); error = vop_stdlock(ap); } - + vdrop(lvp); return (error); } -/* - * We need to process our own vnode unlock and then clear the - * interlock flag as it applies only to our vnode, not the - * vnodes below us on the stack. - */ static int null_unlock(struct vop_unlock_args *ap) { @@ -853,11 +884,20 @@ null_unlock(struct vop_unlock_args *ap) struct vnode *lvp; int error; + /* + * Contrary to null_lock, we don't need to hold the vnode around + * unlock. + * + * We hold the lock, which means we can't be racing against vgone. + * + * At the same time VOP_UNLOCK promises to not touch anything after + * it finishes unlock, just like we don't. + * + * vop_stdunlock for a doomed vnode matches doomed locking in null_lock. + */ nn = VTONULL(vp); if (nn != NULL && (lvp = NULLVPTOLOWERVP(vp)) != NULL) { - vholdnz(lvp); error = VOP_UNLOCK(lvp); - vdrop(lvp); } else { error = vop_stdunlock(ap); } @@ -961,7 +1001,7 @@ null_reclaim(struct vop_reclaim_args *ap) vunref(lowervp); else vput(lowervp); - free(xp, M_NULLFSNODE); + uma_zfree_smr(null_node_zone, xp); return (0); } diff --git a/sys/isa/isa_common.c b/sys/isa/isa_common.c index 8e4064af1455..1a6df7bf6046 100644 --- a/sys/isa/isa_common.c +++ b/sys/isa/isa_common.c @@ -1114,7 +1114,7 @@ isab_attach(device_t dev) { device_t child; - child = device_add_child(dev, "isa", 0); + child = device_add_child(dev, "isa", DEVICE_UNIT_ANY); if (child == NULL) return (ENXIO); bus_attach_children(dev); diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c index 31bff6d2c1aa..76f68677e292 100644 --- a/sys/kern/kern_lock.c +++ b/sys/kern/kern_lock.c @@ -1780,9 +1780,11 @@ lockmgr_chain(struct thread *td, struct thread **ownerp) lk = td->td_wchan; - if (LOCK_CLASS(&lk->lock_object) != &lock_class_lockmgr) + if (!TD_ON_SLEEPQ(td) || sleepq_type(td->td_wchan) != SLEEPQ_LK || + LOCK_CLASS(&lk->lock_object) != &lock_class_lockmgr) return (0); - db_printf("blocked on lockmgr %s", lk->lock_object.lo_name); + db_printf("blocked on lock %p (%s) \"%s\" ", &lk->lock_object, + lock_class_lockmgr.lc_name, lk->lock_object.lo_name); if (lk->lk_lock & LK_SHARE) db_printf("SHARED (count %ju)\n", (uintmax_t)LK_SHARERS(lk->lk_lock)); diff --git a/sys/kern/kern_mutex.c b/sys/kern/kern_mutex.c index 8b5908f5219a..b7316ea5f387 100644 --- a/sys/kern/kern_mutex.c +++ b/sys/kern/kern_mutex.c @@ -869,7 +869,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 +959,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); @@ -1071,7 +1071,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)) diff --git a/sys/kern/kern_sx.c b/sys/kern/kern_sx.c index c005e112d3b9..249faf5b1ec4 100644 --- a/sys/kern/kern_sx.c +++ b/sys/kern/kern_sx.c @@ -1539,16 +1539,19 @@ sx_chain(struct thread *td, struct thread **ownerp) /* * Check to see if this thread is blocked on an sx lock. - * First, we check the lock class. If that is ok, then we - * compare the lock name against the wait message. + * The thread should be on a sleep queue with type SLEEPQ_SX, the + * purported lock should have the lock class index of sx, and the lock + * name should match the wait message. */ sx = td->td_wchan; - if (LOCK_CLASS(&sx->lock_object) != &lock_class_sx || + if (!TD_ON_SLEEPQ(td) || sleepq_type(td->td_wchan) != SLEEPQ_SX || + LOCK_CLASS(&sx->lock_object) != &lock_class_sx || sx->lock_object.lo_name != td->td_wmesg) return (0); /* We think we have an sx lock, so output some details. */ - db_printf("blocked on sx \"%s\" ", td->td_wmesg); + db_printf("blocked on lock %p (%s) \"%s\" ", &sx->lock_object, + lock_class_sx.lc_name, td->td_wmesg); *ownerp = sx_xholder(sx); if (sx->sx_lock & SX_LOCK_SHARED) db_printf("SLOCK (count %ju)\n", diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c index bbebadc4c395..ebd203858b66 100644 --- a/sys/kern/link_elf.c +++ b/sys/kern/link_elf.c @@ -518,9 +518,15 @@ link_elf_init(void* arg) (void)link_elf_link_common_finish(linker_kernel_file); linker_kernel_file->flags |= LINKER_FILE_LINKED; TAILQ_INIT(&set_pcpu_list); + ef->pcpu_start = DPCPU_START; + ef->pcpu_stop = DPCPU_STOP; + ef->pcpu_base = DPCPU_START; #ifdef VIMAGE TAILQ_INIT(&set_vnet_list); vnet_save_init((void *)VNET_START, VNET_STOP - VNET_START); + ef->vnet_start = VNET_START; + ef->vnet_stop = VNET_STOP; + ef->vnet_base = VNET_START; #endif } diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c index 151aab96f9be..a3a53a39bfd6 100644 --- a/sys/kern/link_elf_obj.c +++ b/sys/kern/link_elf_obj.c @@ -70,6 +70,7 @@ typedef struct { void *addr; + void *origaddr; /* Used by debuggers. */ Elf_Off size; int flags; /* Section flags. */ int sec; /* Original section number. */ @@ -492,7 +493,8 @@ link_elf_link_preload(linker_class_t cls, const char *filename, case SHT_FINI_ARRAY: if (shdr[i].sh_addr == 0) break; - ef->progtab[pb].addr = (void *)shdr[i].sh_addr; + ef->progtab[pb].addr = ef->progtab[pb].origaddr = + (void *)shdr[i].sh_addr; if (shdr[i].sh_type == SHT_PROGBITS) ef->progtab[pb].name = "<<PROGBITS>>"; #ifdef __amd64__ @@ -1088,6 +1090,8 @@ link_elf_load_file(linker_class_t cls, const char *filename, ef->progtab[pb].name = "<<NOBITS>>"; if (ef->progtab[pb].name != NULL && !strcmp(ef->progtab[pb].name, DPCPU_SETNAME)) { + ef->progtab[pb].origaddr = + (void *)(uintptr_t)mapbase; ef->progtab[pb].addr = dpcpu_alloc(shdr[i].sh_size); if (ef->progtab[pb].addr == NULL) { @@ -1101,6 +1105,8 @@ link_elf_load_file(linker_class_t cls, const char *filename, #ifdef VIMAGE else if (ef->progtab[pb].name != NULL && !strcmp(ef->progtab[pb].name, VNET_SETNAME)) { + ef->progtab[pb].origaddr = + (void *)(uintptr_t)mapbase; ef->progtab[pb].addr = vnet_data_alloc(shdr[i].sh_size); if (ef->progtab[pb].addr == NULL) { diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index 5606b36f772f..7d666da9f88b 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -729,7 +729,7 @@ kern_ioctl(struct thread *td, int fd, u_long com, caddr_t data) { struct file *fp; struct filedesc *fdp; - int error, tmp, locked; + int error, f_flag, tmp, locked; AUDIT_ARG_FD(fd); AUDIT_ARG_CMD(com); @@ -782,30 +782,36 @@ kern_ioctl(struct thread *td, int fd, u_long com, caddr_t data) goto out; } + f_flag = 0; switch (com) { case FIONCLEX: fdp->fd_ofiles[fd].fde_flags &= ~UF_EXCLOSE; - goto out; + break; case FIOCLEX: fdp->fd_ofiles[fd].fde_flags |= UF_EXCLOSE; - goto out; - case FIONBIO: - if ((tmp = *(int *)data)) - atomic_set_int(&fp->f_flag, FNONBLOCK); - else - atomic_clear_int(&fp->f_flag, FNONBLOCK); - data = (void *)&tmp; break; + case FIONBIO: case FIOASYNC: - if ((tmp = *(int *)data)) - atomic_set_int(&fp->f_flag, FASYNC); - else - atomic_clear_int(&fp->f_flag, FASYNC); - data = (void *)&tmp; + f_flag = com == FIONBIO ? FNONBLOCK : FASYNC; + tmp = *(int *)data; + fsetfl_lock(fp); + if (((fp->f_flag & f_flag) != 0) != (tmp != 0)) { + error = fo_ioctl(fp, com, (void *)&tmp, td->td_ucred, + td); + if (error == 0) { + if (tmp != 0) + atomic_set_int(&fp->f_flag, f_flag); + else + atomic_clear_int(&fp->f_flag, f_flag); + } + } + fsetfl_unlock(fp); + break; + default: + error = fo_ioctl(fp, com, data, td->td_ucred, td); break; } - error = fo_ioctl(fp, com, data, td->td_ucred, td); out: switch (locked) { case LA_XLOCKED: 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/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/netinet/ip_carp.c b/sys/netinet/ip_carp.c index d3d7957cf087..4f553b9aac5e 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -1640,18 +1640,31 @@ carp_iamatch(struct ifaddr *ifa, uint8_t **enaddr) static void carp_send_na(struct carp_softc *sc) { - static struct in6_addr mcast = IN6ADDR_LINKLOCAL_ALLNODES_INIT; struct ifaddr *ifa; - struct in6_addr *in6; + int flags; + /* + * Sending Unsolicited Neighbor Advertisements + * + * If the node is a router, we MUST set the Router flag to one. + * We set Override flag to one and send link-layer address option, + * thus neighboring nodes will install the new link-layer address. + */ + flags = ND_NA_FLAG_OVERRIDE; + if (V_ip6_forwarding) + flags |= ND_NA_FLAG_ROUTER; CARP_FOREACH_IFA(sc, ifa) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; - - in6 = IFA_IN6(ifa); - nd6_na_output(sc->sc_carpdev, &mcast, in6, - ND_NA_FLAG_OVERRIDE, 1, NULL); - DELAY(1000); /* XXX */ + /* + * We use unspecified address as destination here to avoid + * scope initialization for each call. + * nd6_na_output() will use all nodes multicast address if + * destinaion address is unspecified. + */ + nd6_na_output(sc->sc_carpdev, &in6addr_any, IFA_IN6(ifa), + flags, ND6_NA_OPT_LLA | ND6_NA_CARP_MASTER, NULL); + DELAY(1000); /* RetransTimer */ } } diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c index 7f842512858d..def6bc886617 100644 --- a/sys/netinet/tcp_syncache.c +++ b/sys/netinet/tcp_syncache.c @@ -1201,7 +1201,6 @@ syncache_expand(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, */ if (sc->sc_flags & SCF_TIMESTAMP && to->to_flags & TOF_TS && TSTMP_LT(to->to_tsval, sc->sc_tsreflect)) { - SCH_UNLOCK(sch); if ((s = tcp_log_addrs(inc, th, NULL, NULL))) { log(LOG_DEBUG, "%s; %s: SEG.TSval %u < TS.Recent %u, " @@ -1209,6 +1208,7 @@ syncache_expand(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, to->to_tsval, sc->sc_tsreflect); free(s, M_TCPLOG); } + SCH_UNLOCK(sch); return (-1); /* Do not send RST */ } @@ -1280,11 +1280,11 @@ syncache_expand(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, * SEG.ACK must match our initial send sequence number + 1. */ if (th->th_ack != sc->sc_iss + 1) { - SCH_UNLOCK(sch); if ((s = tcp_log_addrs(inc, th, NULL, NULL))) log(LOG_DEBUG, "%s; %s: ACK %u != ISS+1 %u, " "segment rejected\n", s, __func__, th->th_ack, sc->sc_iss + 1); + SCH_UNLOCK(sch); goto failed; } diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index 8ef755e2dc0a..4f756a75fac7 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -2604,8 +2604,6 @@ in6_domifattach(struct ifnet *ifp) COUNTER_ARRAY_ALLOC(ext->icmp6_ifstat, sizeof(struct icmp6_ifstat) / sizeof(uint64_t), M_WAITOK); - ext->dad_failures = counter_u64_alloc(M_WAITOK); - ext->nd_ifinfo = nd6_ifattach(ifp); ext->scope6_id = scope6_ifattach(ifp); ext->lltable = in6_lltattach(ifp); @@ -2641,7 +2639,6 @@ in6_domifdetach(struct ifnet *ifp, void *aux) COUNTER_ARRAY_FREE(ext->icmp6_ifstat, sizeof(struct icmp6_ifstat) / sizeof(uint64_t)); free(ext->icmp6_ifstat, M_IFADDR); - counter_u64_free(ext->dad_failures); free(ext, M_IFADDR); } diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c index 4fde346fb691..090ba610460b 100644 --- a/sys/netinet6/in6_ifattach.c +++ b/sys/netinet6/in6_ifattach.c @@ -44,7 +44,6 @@ #include <sys/rmlock.h> #include <sys/syslog.h> #include <sys/md5.h> -#include <crypto/sha2/sha256.h> #include <net/if.h> #include <net/if_var.h> @@ -72,6 +71,9 @@ #include <netinet6/mld6_var.h> #include <netinet6/scope6_var.h> +#include <crypto/sha2/sha256.h> +#include <machine/atomic.h> + #ifdef IP6_AUTO_LINKLOCAL VNET_DEFINE(int, ip6_auto_linklocal) = IP6_AUTO_LINKLOCAL; #else @@ -377,7 +379,7 @@ in6_get_stableifid(struct ifnet *ifp, struct in6_addr *in6, int prefixlen) } hostuuid_len = strlen(hostuuid); - dad_failures = counter_u64_fetch(DAD_FAILURES(ifp)); + dad_failures = atomic_load_int(&DAD_FAILURES(ifp)); /* * RFC 7217 section 7 diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c index 6669a2ba56ce..f567b42b42ca 100644 --- a/sys/netinet6/in6_proto.c +++ b/sys/netinet6/in6_proto.c @@ -167,7 +167,7 @@ VNET_DEFINE(int, ip6_rr_prune) = 5; /* router renumbering prefix * walk list every 5 sec. */ VNET_DEFINE(int, ip6_mcast_pmtu) = 0; /* enable pMTU discovery for multicast? */ VNET_DEFINE(int, ip6_v6only) = 1; -VNET_DEFINE(int, ip6_stableaddr_maxretries) = IP6_IDGEN_RETRIES; +VNET_DEFINE(u_int, ip6_stableaddr_maxretries) = IP6_IDGEN_RETRIES; #ifdef IPSTEALTH VNET_DEFINE(int, ip6stealth) = 0; @@ -317,7 +317,7 @@ SYSCTL_INT(_net_inet6_ip6, IPV6CTL_USETEMPADDR, use_tempaddr, SYSCTL_BOOL(_net_inet6_ip6, IPV6CTL_USESTABLEADDR, use_stableaddr, CTLFLAG_VNET | CTLFLAG_RWTUN, &VNET_NAME(ip6_use_stableaddr), 0, "Create RFC7217 semantically opaque address for autoconfigured addresses (default for new interfaces)"); -SYSCTL_INT(_net_inet6_ip6, IPV6CTL_STABLEADDR_MAXRETRIES, stableaddr_maxretries, +SYSCTL_UINT(_net_inet6_ip6, IPV6CTL_STABLEADDR_MAXRETRIES, stableaddr_maxretries, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_stableaddr_maxretries), IP6_IDGEN_RETRIES, "RFC7217 semantically opaque address DAD max retries"); SYSCTL_INT(_net_inet6_ip6, IPV6CTL_STABLEADDR_NETIFSRC, stableaddr_netifsource, diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c index dd6864482b3c..3e55c6e5fc05 100644 --- a/sys/netinet6/in6_src.c +++ b/sys/netinet6/in6_src.c @@ -132,8 +132,8 @@ static int in6_selectif(struct sockaddr_in6 *, struct ip6_pktopts *, struct ip6_moptions *, struct ifnet **, struct ifnet *, u_int); static int in6_selectsrc(uint32_t, struct sockaddr_in6 *, - struct ip6_pktopts *, struct inpcb *, struct ucred *, - struct ifnet **, struct in6_addr *); + struct ip6_pktopts *, struct ip6_moptions *, struct inpcb *, + struct ucred *, struct ifnet **, struct in6_addr *); static struct in6_addrpolicy *lookup_addrsel_policy(struct sockaddr_in6 *); @@ -173,8 +173,8 @@ static struct in6_addrpolicy *match_addrsel_policy(struct sockaddr_in6 *); static int in6_selectsrc(uint32_t fibnum, struct sockaddr_in6 *dstsock, - struct ip6_pktopts *opts, struct inpcb *inp, struct ucred *cred, - struct ifnet **ifpp, struct in6_addr *srcp) + struct ip6_pktopts *opts, struct ip6_moptions *mopts, struct inpcb *inp, + struct ucred *cred, struct ifnet **ifpp, struct in6_addr *srcp) { struct rm_priotracker in6_ifa_tracker; struct in6_addr dst, tmp; @@ -186,7 +186,6 @@ in6_selectsrc(uint32_t fibnum, struct sockaddr_in6 *dstsock, u_int32_t odstzone; int prefer_tempaddr; int error; - struct ip6_moptions *mopts; NET_EPOCH_ASSERT(); KASSERT(srcp != NULL, ("%s: srcp is NULL", __func__)); @@ -205,13 +204,6 @@ in6_selectsrc(uint32_t fibnum, struct sockaddr_in6 *dstsock, *ifpp = NULL; } - if (inp != NULL) { - INP_LOCK_ASSERT(inp); - mopts = inp->in6p_moptions; - } else { - mopts = NULL; - } - /* * If the source address is explicitly specified by the caller, * check if the requested source address is indeed a unicast address @@ -552,10 +544,13 @@ in6_selectsrc_socket(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, uint32_t fibnum; int error; + INP_LOCK_ASSERT(inp); + fibnum = inp->inp_inc.inc_fibnum; retifp = NULL; - error = in6_selectsrc(fibnum, dstsock, opts, inp, cred, &retifp, srcp); + error = in6_selectsrc(fibnum, dstsock, opts, inp->in6p_moptions, + inp, cred, &retifp, srcp); if (error != 0) return (error); @@ -583,7 +578,7 @@ in6_selectsrc_socket(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, * Stores selected address to @srcp. * Returns 0 on success. * - * Used by non-socket based consumers (ND code mostly) + * Used by non-socket based consumers */ int in6_selectsrc_addr(uint32_t fibnum, const struct in6_addr *dst, @@ -602,13 +597,42 @@ in6_selectsrc_addr(uint32_t fibnum, const struct in6_addr *dst, dst_sa.sin6_scope_id = scopeid; sa6_embedscope(&dst_sa, 0); - error = in6_selectsrc(fibnum, &dst_sa, NULL, NULL, NULL, &retifp, srcp); + error = in6_selectsrc(fibnum, &dst_sa, NULL, NULL, + NULL, NULL, &retifp, srcp); if (hlim != NULL) *hlim = in6_selecthlim(NULL, retifp); return (error); } +/* + * Select source address based on @fibnum, @dst and @mopts. + * Stores selected address to @srcp. + * Returns 0 on success. + * + * Used by non-socket based consumers (ND code mostly) + */ +int +in6_selectsrc_nbr(uint32_t fibnum, const struct in6_addr *dst, + struct ip6_moptions *mopts, struct ifnet *ifp, struct in6_addr *srcp) +{ + struct sockaddr_in6 dst_sa; + struct ifnet *retifp; + int error; + + retifp = ifp; + bzero(&dst_sa, sizeof(dst_sa)); + dst_sa.sin6_family = AF_INET6; + dst_sa.sin6_len = sizeof(dst_sa); + dst_sa.sin6_addr = *dst; + dst_sa.sin6_scope_id = ntohs(in6_getscope(dst)); + sa6_embedscope(&dst_sa, 0); + + error = in6_selectsrc(fibnum, &dst_sa, NULL, mopts, + NULL, NULL, &retifp, srcp); + return (error); +} + static struct nhop_object * cache_route(uint32_t fibnum, const struct sockaddr_in6 *dst, struct route_in6 *ro, uint32_t flowid) diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index e511ead24f08..1414cc71388d 100644 --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -106,7 +106,7 @@ struct in6_ifextra { struct scope6_id *scope6_id; struct lltable *lltable; struct mld_ifsoftc *mld_ifinfo; - counter_u64_t dad_failures; /* DAD failures when using RFC 7217 stable addresses */ + u_int dad_failures; /* DAD failures when using RFC 7217 stable addresses */ }; #define LLTABLE6(ifp) (((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->lltable) diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index e1a4e8678ebb..db1631736c4a 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -344,7 +344,7 @@ VNET_DECLARE(bool, ip6_use_stableaddr); /* Whether to use stable address generat #define V_ip6_use_stableaddr VNET(ip6_use_stableaddr) #define IP6_IDGEN_RETRIES 3 /* RFC 7217 section 7 default max retries */ -VNET_DECLARE(int, ip6_stableaddr_maxretries); +VNET_DECLARE(u_int, ip6_stableaddr_maxretries); #define V_ip6_stableaddr_maxretries VNET(ip6_stableaddr_maxretries) #define IP6_STABLEADDR_NETIFSRC_NAME 0 @@ -440,6 +440,8 @@ int in6_selectsrc_socket(struct sockaddr_in6 *, struct ip6_pktopts *, struct inpcb *, struct ucred *, int, struct in6_addr *, int *); int in6_selectsrc_addr(uint32_t, const struct in6_addr *, uint32_t, struct ifnet *, struct in6_addr *, int *); +int in6_selectsrc_nbr(uint32_t, const struct in6_addr *, + struct ip6_moptions *, struct ifnet *, struct in6_addr *); int in6_selectroute(struct sockaddr_in6 *, struct ip6_pktopts *, struct ip6_moptions *, struct route_in6 *, struct ifnet **, struct nhop_object **, u_int, uint32_t); diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h index 5fe027ac5e7c..e484c709e29a 100644 --- a/sys/netinet6/nd6.h +++ b/sys/netinet6/nd6.h @@ -171,6 +171,10 @@ struct in6_ndifreq { #define NDPRF_ONLINK 0x1 #define NDPRF_DETACHED 0x2 +/* ND6 NA output flags */ +#define ND6_NA_OPT_LLA 0x01 +#define ND6_NA_CARP_MASTER 0x02 + /* protocol constants */ #define MAX_RTR_SOLICITATION_DELAY 1 /* 1sec */ #define RTR_SOLICITATION_INTERVAL 4 /* 4sec */ diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index cc17b4e1a402..29151b29a071 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -77,6 +77,8 @@ #include <netinet/ip_carp.h> #include <netinet6/send.h> +#include <machine/atomic.h> + #define SDL(s) ((struct sockaddr_dl *)s) struct dadq; @@ -245,10 +247,9 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) * In implementation, we add target link-layer address by default. * We do not add one in MUST NOT cases. */ - if (!IN6_IS_ADDR_MULTICAST(&daddr6)) - tlladdr = 0; - else - tlladdr = 1; + tlladdr = 0; + if (IN6_IS_ADDR_MULTICAST(&daddr6)) + tlladdr |= ND6_NA_OPT_LLA; /* * Target address (taddr6) must be either: @@ -257,9 +258,11 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) * (3) "tentative" address on which DAD is being performed. */ /* (1) and (3) check. */ - if (ifp->if_carp) + if (ifp->if_carp) { ifa = (*carp_iamatch6_p)(ifp, &taddr6); - else + if (ifa != NULL) + tlladdr |= ND6_NA_CARP_MASTER; + } else ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6); /* (2) check. */ @@ -323,32 +326,28 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) } /* + * If the Target Address is either an anycast address or a unicast + * address for which the node is providing proxy service, or the Target + * Link-Layer Address option is not included, the Override flag SHOULD + * be set to zero. Otherwise, the Override flag SHOULD be set to one. + */ + if (anycast == 0 && proxy == 0 && (tlladdr & ND6_NA_OPT_LLA) != 0) + rflag |= ND_NA_FLAG_OVERRIDE; + /* * If the source address is unspecified address, entries must not * be created or updated. - * It looks that sender is performing DAD. Output NA toward - * all-node multicast address, to tell the sender that I'm using - * the address. + * It looks that sender is performing DAD. nd6_na_output() will + * send NA toward all-node multicast address, to tell the sender + * that I'm using the address. * S bit ("solicited") must be zero. */ - if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { - struct in6_addr in6_all; - - in6_all = in6addr_linklocal_allnodes; - if (in6_setscope(&in6_all, ifp, NULL) != 0) - goto bad; - nd6_na_output_fib(ifp, &in6_all, &taddr6, - ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) | - rflag, tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL, - M_GETFIB(m)); - goto freeit; + if (!IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { + nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, + ND_NEIGHBOR_SOLICIT, 0); + rflag |= ND_NA_FLAG_SOLICITED; } - nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, - ND_NEIGHBOR_SOLICIT, 0); - - nd6_na_output_fib(ifp, &saddr6, &taddr6, - ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) | - rflag | ND_NA_FLAG_SOLICITED, tlladdr, + nd6_na_output_fib(ifp, &saddr6, &taddr6, rflag, tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m)); freeit: if (ifa != NULL) @@ -440,13 +439,6 @@ nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *saddr6, return; M_SETFIB(m, fibnum); - if (daddr6 == NULL || IN6_IS_ADDR_MULTICAST(daddr6)) { - m->m_flags |= M_MCAST; - im6o.im6o_multicast_ifp = ifp; - im6o.im6o_multicast_hlim = 255; - im6o.im6o_multicast_loop = 0; - } - icmp6len = sizeof(*nd_ns); m->m_pkthdr.len = m->m_len = sizeof(*ip6) + icmp6len; m->m_data += max_linkhdr; /* or M_ALIGN() equivalent? */ @@ -471,6 +463,12 @@ nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *saddr6, if (in6_setscope(&ip6->ip6_dst, ifp, NULL) != 0) goto bad; } + if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { + m->m_flags |= M_MCAST; + im6o.im6o_multicast_ifp = ifp; + im6o.im6o_multicast_hlim = 255; + im6o.im6o_multicast_loop = 0; + } if (nonce == NULL) { char ip6buf[INET6_ADDRSTRLEN]; struct ifaddr *ifa = NULL; @@ -492,20 +490,16 @@ nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *saddr6, ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, saddr6); if (ifa == NULL) { int error; - struct in6_addr dst6, src6; - uint32_t scopeid; - in6_splitscope(&ip6->ip6_dst, &dst6, &scopeid); - error = in6_selectsrc_addr(fibnum, &dst6, - scopeid, ifp, &src6, NULL); + error = in6_selectsrc_nbr(fibnum, &ip6->ip6_dst, &im6o, + ifp, &ip6->ip6_src); if (error) { nd6log((LOG_DEBUG, "%s: source can't be " "determined: dst=%s, error=%d\n", __func__, - ip6_sprintf(ip6buf, &dst6), + ip6_sprintf(ip6buf, &ip6->ip6_dst), error)); goto bad; } - ip6->ip6_src = src6; } else ip6->ip6_src = *saddr6; @@ -968,7 +962,9 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD) * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD) * - * tlladdr - 1 if include target link-layer address + * tlladdr: + * - 0x01 if include target link-layer address + * - 0x02 if target address is CARP MASTER * sdl0 - sockaddr_dl (= proxy NA) or NULL */ static void @@ -981,8 +977,7 @@ nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0, struct ip6_hdr *ip6; struct nd_neighbor_advert *nd_na; struct ip6_moptions im6o; - struct in6_addr daddr6, dst6, src6; - uint32_t scopeid; + struct in6_addr daddr6; NET_EPOCH_ASSERT(); @@ -1006,13 +1001,6 @@ nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0, return; M_SETFIB(m, fibnum); - if (IN6_IS_ADDR_MULTICAST(&daddr6)) { - m->m_flags |= M_MCAST; - im6o.im6o_multicast_ifp = ifp; - im6o.im6o_multicast_hlim = 255; - im6o.im6o_multicast_loop = 0; - } - icmp6len = sizeof(*nd_na); m->m_pkthdr.len = m->m_len = sizeof(struct ip6_hdr) + icmp6len; m->m_data += max_linkhdr; /* or M_ALIGN() equivalent? */ @@ -1024,26 +1012,24 @@ nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0, ip6->ip6_vfc |= IPV6_VERSION; ip6->ip6_nxt = IPPROTO_ICMPV6; ip6->ip6_hlim = 255; + if (IN6_IS_ADDR_UNSPECIFIED(&daddr6)) { /* reply to DAD */ - daddr6.s6_addr16[0] = IPV6_ADDR_INT16_MLL; - daddr6.s6_addr16[1] = 0; - daddr6.s6_addr32[1] = 0; - daddr6.s6_addr32[2] = 0; - daddr6.s6_addr32[3] = IPV6_ADDR_INT32_ONE; + daddr6 = in6addr_linklocal_allnodes; if (in6_setscope(&daddr6, ifp, NULL)) goto bad; flags &= ~ND_NA_FLAG_SOLICITED; } - ip6->ip6_dst = daddr6; + if (IN6_IS_ADDR_MULTICAST(&daddr6)) { + m->m_flags |= M_MCAST; + im6o.im6o_multicast_ifp = ifp; + im6o.im6o_multicast_hlim = 255; + im6o.im6o_multicast_loop = 0; + } - /* - * Select a source whose scope is the same as that of the dest. - */ - in6_splitscope(&daddr6, &dst6, &scopeid); - error = in6_selectsrc_addr(fibnum, &dst6, - scopeid, ifp, &src6, NULL); + ip6->ip6_dst = daddr6; + error = in6_selectsrc_nbr(fibnum, &daddr6, &im6o, ifp, &ip6->ip6_src); if (error) { char ip6buf[INET6_ADDRSTRLEN]; nd6log((LOG_DEBUG, "nd6_na_output: source can't be " @@ -1051,7 +1037,6 @@ nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0, ip6_sprintf(ip6buf, &daddr6), error)); goto bad; } - ip6->ip6_src = src6; nd_na = (struct nd_neighbor_advert *)(ip6 + 1); nd_na->nd_na_type = ND_NEIGHBOR_ADVERT; nd_na->nd_na_code = 0; @@ -1059,20 +1044,24 @@ nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0, in6_clearscope(&nd_na->nd_na_target); /* XXX */ /* + * If we respond from CARP address, we need to prepare mac address + * for carp_output(). + */ + if (ifp->if_carp && (tlladdr & ND6_NA_CARP_MASTER)) + mac = (*carp_macmatch6_p)(ifp, m, taddr6); + /* * "tlladdr" indicates NS's condition for adding tlladdr or not. * see nd6_ns_input() for details. * Basically, if NS packet is sent to unicast/anycast addr, * target lladdr option SHOULD NOT be included. */ - if (tlladdr) { + if (tlladdr & ND6_NA_OPT_LLA) { /* * sdl0 != NULL indicates proxy NA. If we do proxy, use * lladdr in sdl0. If we are not proxying (sending NA for * my address) use lladdr configured for the interface. */ if (sdl0 == NULL) { - if (ifp->if_carp) - mac = (*carp_macmatch6_p)(ifp, m, taddr6); if (mac == NULL) mac = nd6_ifptomac(ifp); } else if (sdl0->sa_family == AF_LINK) { @@ -1082,7 +1071,7 @@ nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0, mac = LLADDR(sdl); } } - if (tlladdr && mac) { + if ((tlladdr & ND6_NA_OPT_LLA) && mac != NULL) { int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen; struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_na + 1); @@ -1473,7 +1462,7 @@ nd6_dad_timer(void *arg) if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) == 0) { ia->ia6_flags &= ~IN6_IFF_TENTATIVE; if ((ND_IFINFO(ifp)->flags & ND6_IFF_STABLEADDR) && !(ia->ia6_flags & IN6_IFF_TEMPORARY)) - counter_u64_zero(DAD_FAILURES(ifp)); + atomic_store_int(&DAD_FAILURES(ifp), 0); } nd6log((LOG_DEBUG, @@ -1522,10 +1511,10 @@ nd6_dad_duplicated(struct ifaddr *ifa, struct dadq *dp) * More addresses will be generated as long as retries are not exhausted. */ if ((ND_IFINFO(ifp)->flags & ND6_IFF_STABLEADDR) && !(ia->ia6_flags & IN6_IFF_TEMPORARY)) { - uint64_t dad_failures = counter_u64_fetch(DAD_FAILURES(ifp)); + u_int dad_failures = atomic_load_int(&DAD_FAILURES(ifp)); if (dad_failures <= V_ip6_stableaddr_maxretries) { - counter_u64_add(DAD_FAILURES(ifp), 1); + atomic_add_int(&DAD_FAILURES(ifp), 1); /* if retries exhausted, output an informative error message */ if (dad_failures == V_ip6_stableaddr_maxretries) log(LOG_ERR, "%s: manual intervention required, consider disabling \"stableaddr\" on the interface" diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index f9684b085767..10f0342f2bc4 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -74,6 +74,8 @@ #include <netinet/icmp6.h> #include <netinet6/scope6_var.h> +#include <machine/atomic.h> + static struct nd_defrouter *defrtrlist_update(struct nd_defrouter *); static int prelist_update(struct nd_prefixctl *, struct nd_defrouter *, struct mbuf *, int); @@ -1756,7 +1758,7 @@ prelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr, * to fail and no further retries should happen. */ if (ND_IFINFO(ifp)->flags & ND6_IFF_STABLEADDR && - counter_u64_fetch(DAD_FAILURES(ifp)) <= V_ip6_stableaddr_maxretries && + atomic_load_int(&DAD_FAILURES(ifp)) <= V_ip6_stableaddr_maxretries && ifa6->ia6_flags & (IN6_IFF_DUPLICATED | IN6_IFF_TEMPORARY)) continue; diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 2c6d62078e6a..d6fc24a23fe9 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -3364,7 +3364,7 @@ pf_change_ap(struct pf_pdesc *pd, struct pf_addr *a, u_int16_t *p, u_int16_t po; uint8_t u = pd->virtual_proto == IPPROTO_UDP; - MPASS(pd->pcksum); + MPASS(pd->pcksum != NULL); if (pd->af == AF_INET) { MPASS(pd->ip_sum); } @@ -5965,37 +5965,42 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm, ctx.nat_pool = &(ctx.nr->rdr); } - ruleset = &pf_main_ruleset; - rv = pf_match_rule(&ctx, ruleset, match_rules); - if (rv == PF_TEST_FAIL) { - /* - * Reason has been set in pf_match_rule() already. - */ - goto cleanup; - } - - r = *ctx.rm; /* matching rule */ - ctx.a = *ctx.am; /* rule that defines an anchor containing 'r' */ - ruleset = *ctx.rsm; /* ruleset of the anchor defined by the rule 'a' */ - ctx.aruleset = ctx.arsm; /* ruleset of the 'a' rule itself */ + if (ctx.nr && ctx.nr->natpass) { + r = ctx.nr; + ruleset = *ctx.rsm; + } else { + ruleset = &pf_main_ruleset; + rv = pf_match_rule(&ctx, ruleset, match_rules); + if (rv == PF_TEST_FAIL) { + /* + * Reason has been set in pf_match_rule() already. + */ + goto cleanup; + } - REASON_SET(&ctx.reason, PFRES_MATCH); + r = *ctx.rm; /* matching rule */ + ctx.a = *ctx.am; /* rule that defines an anchor containing 'r' */ + ruleset = *ctx.rsm; /* ruleset of the anchor defined by the rule 'a' */ + ctx.aruleset = ctx.arsm; /* ruleset of the 'a' rule itself */ - /* apply actions for last matching pass/block rule */ - pf_rule_to_actions(r, &pd->act); - transerror = pf_rule_apply_nat(&ctx, r); - switch (transerror) { - case PFRES_MATCH: - /* Translation action found in rule and applied successfully */ - case PFRES_MAX: - /* No translation action found in rule */ - break; - default: - /* Translation action found in rule but failed to apply */ - REASON_SET(&ctx.reason, transerror); - goto cleanup; + /* apply actions for last matching pass/block rule */ + pf_rule_to_actions(r, &pd->act); + transerror = pf_rule_apply_nat(&ctx, r); + switch (transerror) { + case PFRES_MATCH: + /* Translation action found in rule and applied successfully */ + case PFRES_MAX: + /* No translation action found in rule */ + break; + default: + /* Translation action found in rule but failed to apply */ + REASON_SET(&ctx.reason, transerror); + goto cleanup; + } } + REASON_SET(&ctx.reason, PFRES_MATCH); + if (r->log) { if (ctx.rewrite) m_copyback(pd->m, pd->off, pd->hdrlen, pd->hdr.any); @@ -7634,6 +7639,7 @@ again: nj->pd.m = j->pd.m; nj->op = j->op; + MPASS(nj->pd.pcksum); TAILQ_INSERT_TAIL(&pd->sctp_multihome_jobs, nj, next); } PF_SCTP_ENDPOINTS_UNLOCK(); @@ -7753,6 +7759,7 @@ pf_multihome_scan(int start, int len, struct pf_pdesc *pd, int op) job->pd.m = pd->m; job->op = op; + MPASS(job->pd.pcksum); TAILQ_INSERT_TAIL(&pd->sctp_multihome_jobs, job, next); break; } @@ -7786,6 +7793,7 @@ pf_multihome_scan(int start, int len, struct pf_pdesc *pd, int op) job->pd.m = pd->m; job->op = op; + MPASS(job->pd.pcksum); TAILQ_INSERT_TAIL(&pd->sctp_multihome_jobs, job, next); break; } @@ -10443,28 +10451,28 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0, __func__); *action = PF_DROP; REASON_SET(reason, PFRES_SHORT); - return (-1); + return (PF_DROP); } h = mtod(pd->m, struct ip *); if (pd->m->m_pkthdr.len < ntohs(h->ip_len)) { *action = PF_DROP; REASON_SET(reason, PFRES_SHORT); - return (-1); + return (PF_DROP); } if (pf_normalize_ip(reason, pd) != PF_PASS) { /* We do IP header normalization and packet reassembly here */ *m0 = pd->m; *action = PF_DROP; - return (-1); + return (PF_DROP); } *m0 = pd->m; h = mtod(pd->m, struct ip *); if (pf_walk_header(pd, h, reason) != PF_PASS) { *action = PF_DROP; - return (-1); + return (PF_DROP); } pd->src = (struct pf_addr *)&h->ip_src; @@ -10494,7 +10502,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0, ", pullup failed", __func__); *action = PF_DROP; REASON_SET(reason, PFRES_SHORT); - return (-1); + return (PF_DROP); } h = mtod(pd->m, struct ip6_hdr *); @@ -10502,7 +10510,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0, sizeof(struct ip6_hdr) + ntohs(h->ip6_plen)) { *action = PF_DROP; REASON_SET(reason, PFRES_SHORT); - return (-1); + return (PF_DROP); } /* @@ -10511,12 +10519,12 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0, */ if (htons(h->ip6_plen) == 0) { *action = PF_DROP; - return (-1); + return (PF_DROP); } if (pf_walk_header6(pd, h, reason) != PF_PASS) { *action = PF_DROP; - return (-1); + return (PF_DROP); } h = mtod(pd->m, struct ip6_hdr *); @@ -10538,13 +10546,13 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0, PF_PASS) { *m0 = pd->m; *action = PF_DROP; - return (-1); + return (PF_DROP); } *m0 = pd->m; if (pd->m == NULL) { /* packet sits in reassembly queue, no error */ *action = PF_PASS; - return (-1); + return (PF_DROP); } /* Update pointers into the packet. */ @@ -10556,7 +10564,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0, if (pf_walk_header6(pd, h, reason) != PF_PASS) { *action = PF_DROP; - return (-1); + return (PF_DROP); } if (m_tag_find(pd->m, PACKET_TAG_PF_REASSEMBLED, NULL) != NULL) { @@ -10586,7 +10594,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0, reason, af)) { *action = PF_DROP; REASON_SET(reason, PFRES_SHORT); - return (-1); + return (PF_DROP); } pd->hdrlen = sizeof(*th); pd->p_len = pd->tot_len - pd->off - (th->th_off << 2); @@ -10602,7 +10610,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0, reason, af)) { *action = PF_DROP; REASON_SET(reason, PFRES_SHORT); - return (-1); + return (PF_DROP); } pd->hdrlen = sizeof(*uh); if (uh->uh_dport == 0 || @@ -10610,7 +10618,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0, ntohs(uh->uh_ulen) < sizeof(struct udphdr)) { *action = PF_DROP; REASON_SET(reason, PFRES_SHORT); - return (-1); + return (PF_DROP); } pd->sport = &uh->uh_sport; pd->dport = &uh->uh_dport; @@ -10622,7 +10630,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0, reason, af)) { *action = PF_DROP; REASON_SET(reason, PFRES_SHORT); - return (-1); + return (PF_DROP); } pd->hdrlen = sizeof(pd->hdr.sctp); pd->p_len = pd->tot_len - pd->off; @@ -10632,19 +10640,23 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0, if (pd->hdr.sctp.src_port == 0 || pd->hdr.sctp.dest_port == 0) { *action = PF_DROP; REASON_SET(reason, PFRES_SHORT); - return (-1); - } - if (pf_scan_sctp(pd) != PF_PASS) { - *action = PF_DROP; - REASON_SET(reason, PFRES_SHORT); - return (-1); + return (PF_DROP); } + /* * Placeholder. The SCTP checksum is 32-bits, but * pf_test_state() expects to update a 16-bit checksum. * Provide a dummy value which we'll subsequently ignore. + * Do this before pf_scan_sctp() so any jobs we enqueue + * have a pcksum set. */ pd->pcksum = &pd->sctp_dummy_sum; + + if (pf_scan_sctp(pd) != PF_PASS) { + *action = PF_DROP; + REASON_SET(reason, PFRES_SHORT); + return (PF_DROP); + } break; } case IPPROTO_ICMP: { @@ -10652,7 +10664,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0, reason, af)) { *action = PF_DROP; REASON_SET(reason, PFRES_SHORT); - return (-1); + return (PF_DROP); } pd->pcksum = &pd->hdr.icmp.icmp_cksum; pd->hdrlen = ICMP_MINLEN; @@ -10666,7 +10678,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0, reason, af)) { *action = PF_DROP; REASON_SET(reason, PFRES_SHORT); - return (-1); + return (PF_DROP); } /* ICMP headers we look further into to match state */ switch (pd->hdr.icmp6.icmp6_type) { @@ -10692,7 +10704,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0, reason, af)) { *action = PF_DROP; REASON_SET(reason, PFRES_SHORT); - return (-1); + return (PF_DROP); } pd->hdrlen = icmp_hlen; pd->pcksum = &pd->hdr.icmp6.icmp6_cksum; @@ -10715,7 +10727,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0, MPASS(pd->pcksum != NULL); - return (0); + return (PF_PASS); } static __inline void @@ -10977,7 +10989,7 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0 PF_RULES_RLOCK(); if (pf_setup_pdesc(af, dir, &pd, m0, &action, &reason, - kif, default_actions) == -1) { + kif, default_actions) != PF_PASS) { if (action != PF_PASS) pd.act.log |= PF_LOG_FORCE; goto done; diff --git a/sys/sys/mutex.h b/sys/sys/mutex.h index 08d4e2d28b33..83300d4eb593 100644 --- a/sys/sys/mutex.h +++ b/sys/sys/mutex.h @@ -221,10 +221,6 @@ void _thread_lock(struct thread *); #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/sys/tools/gdb/README.txt b/sys/tools/gdb/README.txt new file mode 100644 index 000000000000..8c31565ddc42 --- /dev/null +++ b/sys/tools/gdb/README.txt @@ -0,0 +1,21 @@ +This directory contains Python scripts that can be loaded by GDB to help debug +FreeBSD kernel crashes. + +Add new commands and functions in their own files. Functions with general +utility should be added to freebsd.py. sys/tools/kernel-gdb.py is installed +into the kernel debug directory (typically /usr/lib/debug/boot/kernel). It will +be automatically loaded by kgdb when opening a vmcore, so if you add new GDB +commands or functions, that script should be updated to import them, and you +should document them here. + +To provide some rudimentary testing, selftest.py tries to exercise all of the +commands and functions defined here. To use it, run selftest.sh to panic the +system. Then, create a kernel dump or attach to the panicked kernel, and invoke +the script with "python import selftest" in (k)gdb. + +Commands: +acttrace Display a backtrace for all on-CPU threads + +Functions: +$PCPU(<field>[, <cpuid>]) Display the value of a PCPU/DPCPU field +$V(<variable>[, <vnet>]) Display the value of a VNET variable diff --git a/libexec/kgdb/acttrace.py b/sys/tools/gdb/acttrace.py index 3229ff708de1..147effbbddf1 100644 --- a/libexec/kgdb/acttrace.py +++ b/sys/tools/gdb/acttrace.py @@ -1,38 +1,23 @@ -#- +# # Copyright (c) 2022 The FreeBSD Foundation # # This software was developed by Mark Johnston under sponsorship from the # FreeBSD Foundation. # +# SPDX-License-Identifier: BSD-2-Clause +# import gdb - - -def symval(name): - return gdb.lookup_global_symbol(name).value() - - -def tid_to_gdb_thread(tid): - for thread in gdb.inferiors()[0].threads(): - if thread.ptid[2] == tid: - return thread - else: - return None - - -def all_pcpus(): - mp_maxid = symval("mp_maxid") - cpuid_to_pcpu = symval("cpuid_to_pcpu") - - cpu = 0 - while cpu <= mp_maxid: - pcpu = cpuid_to_pcpu[cpu] - if pcpu: - yield pcpu - cpu = cpu + 1 - +from freebsd import * +from pcpu import * class acttrace(gdb.Command): + """ + Register an acttrace command with gdb. + + When run, acttrace prints the stack trace of all threads that were on-CPU + at the time of the panic. + """ def __init__(self): super(acttrace, self).__init__("acttrace", gdb.COMMAND_USER) @@ -40,13 +25,13 @@ class acttrace(gdb.Command): # Save the current thread so that we can switch back after. curthread = gdb.selected_thread() - for pcpu in all_pcpus(): + for pcpu in pcpu_foreach(): td = pcpu['pc_curthread'] tid = td['td_tid'] gdb_thread = tid_to_gdb_thread(tid) if gdb_thread is None: - print("failed to find GDB thread with TID {}".format(tid)) + raise gdb.error(f"failed to find GDB thread with TID {tid}") else: gdb_thread.switch() diff --git a/sys/tools/gdb/freebsd.py b/sys/tools/gdb/freebsd.py new file mode 100644 index 000000000000..81ea60373348 --- /dev/null +++ b/sys/tools/gdb/freebsd.py @@ -0,0 +1,75 @@ +# +# Copyright (c) 2025 Mark Johnston <markj@FreeBSD.org> +# +# SPDX-License-Identifier: BSD-2-Clause +# + +import gdb + +def symval(name): + sym = gdb.lookup_global_symbol(name) + if sym is None: + sym = gdb.lookup_static_symbol(name) + if sym is None: + raise gdb.GdbError(f"Symbol '{name}' not found") + return sym.value() + + +def _queue_foreach(head, field, headf, nextf): + elm = head[headf] + while elm != 0: + yield elm + elm = elm[field][nextf] + + +def list_foreach(head, field): + """sys/queue.h-style iterator.""" + return _queue_foreach(head, field, "lh_first", "le_next") + + +def tailq_foreach(head, field): + """sys/queue.h-style iterator.""" + return _queue_foreach(head, field, "tqh_first", "tqe_next") + + +def linker_file_foreach(): + """Iterate over loaded linker files.""" + return tailq_foreach(symval("linker_files"), "link") + + +def pcpu_foreach(): + mp_maxid = symval("mp_maxid") + cpuid_to_pcpu = symval("cpuid_to_pcpu") + + cpu = 0 + while cpu <= mp_maxid: + pcpu = cpuid_to_pcpu[cpu] + if pcpu: + yield pcpu + cpu = cpu + 1 + + +def tid_to_gdb_thread(tid): + """Convert a FreeBSD kernel thread ID to a gdb inferior thread.""" + for thread in gdb.inferiors()[0].threads(): + if thread.ptid[2] == tid: + return thread + else: + return None + + +def tdfind(tid, pid=-1): + """Convert a FreeBSD kernel thread ID to a struct thread pointer.""" + td = tdfind.cached_threads.get(int(tid)) + if td: + return td + + for p in list_foreach(symval("allproc"), "p_list"): + if pid != -1 and pid != p['p_pid']: + continue + for td in tailq_foreach(p['p_threads'], "td_plist"): + ntid = td['td_tid'] + tdfind.cached_threads[int(ntid)] = td + if ntid == tid: + return td +tdfind.cached_threads = dict() diff --git a/sys/tools/gdb/pcpu.py b/sys/tools/gdb/pcpu.py new file mode 100644 index 000000000000..aadc4b2d42df --- /dev/null +++ b/sys/tools/gdb/pcpu.py @@ -0,0 +1,77 @@ +# +# Copyright (c) 2025 Mark Johnston <markj@FreeBSD.org> +# +# SPDX-License-Identifier: BSD-2-Clause +# + +import gdb +from freebsd import * + +class pcpu(gdb.Function): + """ + Register a function to lookup PCPU and DPCPU variables by name. + + To look up the value of the PCPU field foo on CPU n, use + $PCPU("foo", n). This works for DPCPU fields too. If the CPU ID is + omitted, and the currently selected thread is on-CPU, that CPU is + used, otherwise an error is raised. + """ + def __init__(self): + super(pcpu, self).__init__("PCPU") + + def invoke(self, field, cpuid=-1): + if cpuid == -1: + cpuid = tdfind(gdb.selected_thread().ptid[2])['td_oncpu'] + if cpuid == -1: + raise gdb.error("Currently selected thread is off-CPU") + if cpuid < 0 or cpuid > symval("mp_maxid"): + raise gdb.error(f"Currently selected on invalid CPU {cpuid}") + pcpu = symval("cpuid_to_pcpu")[cpuid] + + # Are we dealing with a PCPU or DPCPU field? + field = field.string() + for f in gdb.lookup_type("struct pcpu").fields(): + if f.name == "pc_" + field: + return pcpu["pc_" + field] + + def uintptr_t(val): + return val.cast(gdb.lookup_type("uintptr_t")) + + # We're dealing with a DPCPU field. This is handled similarly + # to VNET symbols, see vnet.py for comments. + pcpu_base = pcpu['pc_dynamic'] + pcpu_entry = symval("pcpu_entry_" + field) + pcpu_entry_addr = uintptr_t(pcpu_entry.address) + + for lf in linker_file_foreach(): + block = gdb.block_for_pc(lf['ops']['cls']['methods'][0]['func']) + elf_file_t = gdb.lookup_type("elf_file_t", block).target() + ef = lf.cast(elf_file_t) + + file_type = lf['ops']['cls']['name'].string() + if file_type == "elf64": + start = uintptr_t(ef['pcpu_start']) + if start == 0: + continue + end = uintptr_t(ef['pcpu_stop']) + base = uintptr_t(ef['pcpu_base']) + elif file_type == "elf64_obj": + for i in range(ef['nprogtab']): + pe = ef['progtab'][i] + if pe['name'].string() == "set_pcpu": + start = uintptr_t(pe['origaddr']) + end = start + uintptr_t(pe['size']) + base = uintptr_t(pe['addr']) + break + else: + continue + else: + path = lf['pathname'].string() + raise gdb.error(f"{path} has unexpected linker file type {file_type}") + + if pcpu_entry_addr >= start and pcpu_entry_addr < end: + obj = gdb.Value(pcpu_base + pcpu_entry_addr - start + base) + return obj.cast(pcpu_entry.type.pointer()).dereference() + +# Register with gdb. +pcpu() diff --git a/sys/tools/gdb/selftest.py b/sys/tools/gdb/selftest.py new file mode 100644 index 000000000000..41e9211c4bb3 --- /dev/null +++ b/sys/tools/gdb/selftest.py @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025 Mark Johnston <markj@FreeBSD.org> +# +# SPDX-License-Identifier: BSD-2-Clause +# + +import gdb + +cmds = ["acttrace", + "p $V(\"tcbinfo\")", + "p $V(\"tcbinfo\", vnet0)", + "p $V(\"pf_status\")", + "p $V(\"pf_status\", \"gdbselftest\")", + "p $PCPU(\"curthread\")", + "p $PCPU(\"curthread\", 0)", + "p/x $PCPU(\"hardclocktime\", 1)", + "p $PCPU(\"pqbatch\")[0][0]", + "p $PCPU(\"ss\", 1)", + ] + +for cmd in cmds: + try: + print(f"Running command: '{cmd}'") + gdb.execute(cmd) + except gdb.error as e: + print(f"Command '{cmd}' failed: {e}") + break + +# We didn't hit any unexpected errors. This isn't as good as actually +# verifying the output, but it's better than nothing. +print("Everything seems OK") diff --git a/sys/tools/gdb/selftest.sh b/sys/tools/gdb/selftest.sh new file mode 100644 index 000000000000..252fae14af17 --- /dev/null +++ b/sys/tools/gdb/selftest.sh @@ -0,0 +1,23 @@ +# +# Copyright (c) 2025 Mark Johnston <markj@FreeBSD.org> +# +# SPDX-License-Identifier: BSD-2-Clause +# + +set -e + +n=$(sysctl -n hw.ncpu) +if [ $n -lt 2 ]; then + echo "This test requires at least 2 CPUs" + exit 1 +fi + +# Set up some things expected by selftest.py. +kldload -n pf siftr +pfctl -e || true +jail -c name=gdbselftest vnet persist + +echo "I'm about to panic your system, ctrl-C now if that's not what you want." +sleep 10 +sysctl debug.debugger_on_panic=0 +sysctl debug.kdb.panic=1 diff --git a/sys/tools/gdb/vnet.py b/sys/tools/gdb/vnet.py new file mode 100644 index 000000000000..36b4d512a3eb --- /dev/null +++ b/sys/tools/gdb/vnet.py @@ -0,0 +1,100 @@ +# +# Copyright (c) 2025 Mark Johnston <markj@FreeBSD.org> +# +# SPDX-License-Identifier: BSD-2-Clause +# + +import gdb +import traceback +from freebsd import * + +class vnet(gdb.Function): + """ + Register a function to look up VNET variables by name. + + To look at the value of a VNET variable V_foo, print $V("foo"). The + currently selected thread's VNET is used by default, but can be optionally + specified as a second parameter, e.g., $V("foo", <vnet>), where <vnet> is a + pointer to a struct vnet (e.g., vnet0 or allprison.tqh_first->pr_vnet) or a + string naming a jail. + """ + def __init__(self): + super(vnet, self).__init__("V") + + def invoke(self, sym, vnet=None): + sym = sym.string() + if sym.startswith("V_"): + sym = sym[len("V_"):] + if gdb.lookup_symbol("sysctl___kern_features_vimage")[0] is None: + return symval(sym) + + # Look up the VNET's base address. + if vnet is None: + vnet = tdfind(gdb.selected_thread().ptid[2])['td_vnet'] + if not vnet: + # If curthread->td_vnet == NULL, vnet0 is the current vnet. + vnet = symval("vnet0") + elif vnet.type.is_string_like: + vnet = vnet.string() + for prison in tailq_foreach(symval("allprison"), "pr_list"): + if prison['pr_name'].string() == vnet: + vnet = prison['pr_vnet'] + break + else: + raise gdb.error(f"No prison named {vnet}") + + def uintptr_t(val): + return val.cast(gdb.lookup_type("uintptr_t")) + + # Now the tricky part: compute the address of the symbol relative + # to the selected VNET. In the compiled kernel this is done at + # load time by applying a magic transformation to relocations + # against symbols in the vnet linker set. Here we have to apply + # the transformation manually. + vnet_data_base = vnet['vnet_data_base'] + vnet_entry = symval("vnet_entry_" + sym) + vnet_entry_addr = uintptr_t(vnet_entry.address) + + # First, which kernel module does the symbol belong to? + for lf in linker_file_foreach(): + # Find the bounds of this linker file's VNET linker set. The + # struct containing the bounds depends on the type of the linker + # file, and unfortunately both are called elf_file_t. So we use a + # PC value from the compilation unit (either link_elf.c or + # link_elf_obj.c) to disambiguate. + block = gdb.block_for_pc(lf['ops']['cls']['methods'][0]['func']) + elf_file_t = gdb.lookup_type("elf_file_t", block).target() + ef = lf.cast(elf_file_t) + + file_type = lf['ops']['cls']['name'].string() + if file_type == "elf64": + start = uintptr_t(ef['vnet_start']) + if start == 0: + # This linker file doesn't have a VNET linker set. + continue + end = uintptr_t(ef['vnet_stop']) + base = uintptr_t(ef['vnet_base']) + elif file_type == "elf64_obj": + for i in range(ef['nprogtab']): + pe = ef['progtab'][i] + if pe['name'].string() == "set_vnet": + start = uintptr_t(pe['origaddr']) + end = start + uintptr_t(pe['size']) + base = uintptr_t(pe['addr']) + break + else: + # This linker file doesn't have a VNET linker set. + continue + else: + path = lf['pathname'].string() + raise gdb.error(f"{path} has unexpected linker file type {file_type}") + + if vnet_entry_addr >= start and vnet_entry_addr < end: + # The symbol belongs to this linker file, so compute the final + # address. + obj = gdb.Value(vnet_data_base + vnet_entry_addr - start + base) + return obj.cast(vnet_entry.type.pointer()).dereference() + + +# Register with gdb. +vnet() diff --git a/sys/tools/kernel-gdb.py b/sys/tools/kernel-gdb.py new file mode 100644 index 000000000000..8a41ef6efab1 --- /dev/null +++ b/sys/tools/kernel-gdb.py @@ -0,0 +1,15 @@ +# +# Copyright (c) 2025 Mark Johnston <markj@FreeBSD.org> +# +# SPDX-License-Identifier: BSD-2-Clause +# + +import os +import sys + +sys.path.append(os.path.join(os.path.dirname(__file__), "gdb")) + +# Import FreeBSD kernel debugging commands and modules below. +import acttrace +import pcpu +import vnet diff --git a/sys/x86/include/mca.h b/sys/x86/include/mca.h index 183480625f6d..553b5d765f17 100644 --- a/sys/x86/include/mca.h +++ b/sys/x86/include/mca.h @@ -44,6 +44,31 @@ struct mca_record { int mr_cpu; }; +enum mca_stat_types { + MCA_T_NONE = 0, + MCA_T_UNCLASSIFIED, + MCA_T_UCODE_ROM_PARITY, + MCA_T_EXTERNAL, + MCA_T_FRC, + MCA_T_INTERNAL_PARITY, + MCA_T_SMM_HANDLER, + MCA_T_INTERNAL_TIMER, + MCA_T_GENERIC_IO, + MCA_T_INTERNAL, + MCA_T_MEMORY, + MCA_T_TLB, + MCA_T_MEMCONTROLLER_GEN, + MCA_T_MEMCONTROLLER_RD, + MCA_T_MEMCONTROLLER_WR, + MCA_T_MEMCONTROLLER_AC, + MCA_T_MEMCONTROLLER_MS, + MCA_T_MEMCONTROLLER_OTHER, + MCA_T_CACHE, + MCA_T_BUS, + MCA_T_UNKNOWN, + MCA_T_COUNT /* Must stay last */ +}; + #ifdef _KERNEL void cmc_intr(void); diff --git a/sys/x86/x86/mca.c b/sys/x86/x86/mca.c index 4ba49469d3a2..1851df8d00a0 100644 --- a/sys/x86/x86/mca.c +++ b/sys/x86/x86/mca.c @@ -134,6 +134,12 @@ static struct task mca_resize_task; static struct timeout_task mca_scan_task; static struct mtx mca_lock; +/* Statistics on number of MCA events by type, updated atomically. */ +static uint64_t mca_stats[MCA_T_COUNT]; +SYSCTL_OPAQUE(_hw_mca, OID_AUTO, stats, CTLFLAG_RD | CTLFLAG_SKIP, + mca_stats, MCA_T_COUNT * sizeof(mca_stats[0]), + "S", "Array of MCA events by type"); + static unsigned int mca_ia32_ctl_reg(int bank) { @@ -356,21 +362,27 @@ mca_error_request(uint16_t mca_error) } static const char * -mca_error_mmtype(uint16_t mca_error) +mca_error_mmtype(uint16_t mca_error, enum mca_stat_types *event_type) { switch ((mca_error & 0x70) >> 4) { case 0x0: + *event_type = MCA_T_MEMCONTROLLER_GEN; return ("GEN"); case 0x1: + *event_type = MCA_T_MEMCONTROLLER_RD; return ("RD"); case 0x2: + *event_type = MCA_T_MEMCONTROLLER_WR; return ("WR"); case 0x3: + *event_type = MCA_T_MEMCONTROLLER_AC; return ("AC"); case 0x4: + *event_type = MCA_T_MEMCONTROLLER_MS; return ("MS"); } + *event_type = MCA_T_MEMCONTROLLER_OTHER; return ("???"); } @@ -426,6 +438,7 @@ static void mca_log(const struct mca_record *rec) { uint16_t mca_error; + enum mca_stat_types event_type; if (mca_mute(rec)) return; @@ -473,34 +486,44 @@ mca_log(const struct mca_record *rec) if (rec->mr_status & MC_STATUS_OVER) printf("OVER "); mca_error = rec->mr_status & MC_STATUS_MCA_ERROR; + event_type = MCA_T_COUNT; switch (mca_error) { /* Simple error codes. */ case 0x0000: printf("no error"); + event_type = MCA_T_NONE; break; case 0x0001: printf("unclassified error"); + event_type = MCA_T_UNCLASSIFIED; break; case 0x0002: printf("ucode ROM parity error"); + event_type = MCA_T_UCODE_ROM_PARITY; break; case 0x0003: printf("external error"); + event_type = MCA_T_EXTERNAL; break; case 0x0004: printf("FRC error"); + event_type = MCA_T_FRC; break; case 0x0005: printf("internal parity error"); + event_type = MCA_T_INTERNAL_PARITY; break; case 0x0006: printf("SMM handler code access violation"); + event_type = MCA_T_SMM_HANDLER; break; case 0x0400: printf("internal timer error"); + event_type = MCA_T_INTERNAL_TIMER; break; case 0x0e0b: printf("generic I/O error"); + event_type = MCA_T_GENERIC_IO; if (rec->mr_cpu_vendor_id == CPU_VENDOR_INTEL && (rec->mr_status & MC_STATUS_MISCV)) { printf(" (pci%d:%d:%d:%d)", @@ -513,6 +536,7 @@ mca_log(const struct mca_record *rec) default: if ((mca_error & 0xfc00) == 0x0400) { printf("internal error %x", mca_error & 0x03ff); + event_type = MCA_T_INTERNAL; break; } @@ -521,6 +545,7 @@ mca_log(const struct mca_record *rec) /* Memory hierarchy error. */ if ((mca_error & 0xeffc) == 0x000c) { printf("%s memory error", mca_error_level(mca_error)); + event_type = MCA_T_MEMORY; break; } @@ -528,12 +553,14 @@ mca_log(const struct mca_record *rec) if ((mca_error & 0xeff0) == 0x0010) { printf("%sTLB %s error", mca_error_ttype(mca_error), mca_error_level(mca_error)); + event_type = MCA_T_TLB; break; } /* Memory controller error. */ if ((mca_error & 0xef80) == 0x0080) { - printf("%s channel ", mca_error_mmtype(mca_error)); + printf("%s channel ", mca_error_mmtype(mca_error, + &event_type)); if ((mca_error & 0x000f) != 0x000f) printf("%d", mca_error & 0x000f); else @@ -548,12 +575,14 @@ mca_log(const struct mca_record *rec) mca_error_ttype(mca_error), mca_error_level(mca_error), mca_error_request(mca_error)); + event_type = MCA_T_CACHE; break; } /* Extended memory error. */ if ((mca_error & 0xef80) == 0x0280) { - printf("%s channel ", mca_error_mmtype(mca_error)); + printf("%s channel ", mca_error_mmtype(mca_error, + &event_type)); if ((mca_error & 0x000f) != 0x000f) printf("%d", mca_error & 0x000f); else @@ -565,6 +594,7 @@ mca_log(const struct mca_record *rec) /* Bus and/or Interconnect error. */ if ((mca_error & 0xe800) == 0x0800) { printf("BUS%s ", mca_error_level(mca_error)); + event_type = MCA_T_BUS; switch ((mca_error & 0x0600) >> 9) { case 0: printf("Source"); @@ -600,6 +630,7 @@ mca_log(const struct mca_record *rec) } printf("unknown error %x", mca_error); + event_type = MCA_T_UNKNOWN; break; } printf("\n"); @@ -615,6 +646,12 @@ mca_log(const struct mca_record *rec) } if (rec->mr_status & MC_STATUS_MISCV) printf("MCA: Misc 0x%llx\n", (long long)rec->mr_misc); + if (event_type < 0 || event_type >= MCA_T_COUNT) { + KASSERT(0, ("%s: invalid event type (%d)", __func__, + event_type)); + event_type = MCA_T_UNKNOWN; + } + atomic_add_64(&mca_stats[event_type], 1); } static bool diff --git a/tests/atf_python/sys/netpfil/ipfw/insns.py b/tests/atf_python/sys/netpfil/ipfw/insns.py index 12f145f49393..f8a56de901ae 100644 --- a/tests/atf_python/sys/netpfil/ipfw/insns.py +++ b/tests/atf_python/sys/netpfil/ipfw/insns.py @@ -510,7 +510,7 @@ class InsnIp6(Insn): insn_attrs = prepare_attrs_map( [ - AttrDescr(IpFwOpcode.O_CHECK_STATE, Insn), + AttrDescr(IpFwOpcode.O_CHECK_STATE, InsnU32), AttrDescr(IpFwOpcode.O_ACCEPT, InsnEmpty), AttrDescr(IpFwOpcode.O_COUNT, InsnEmpty), @@ -521,16 +521,19 @@ insn_attrs = prepare_attrs_map( AttrDescr(IpFwOpcode.O_COUNT, InsnEmpty), AttrDescr(IpFwOpcode.O_QUEUE, Insn), AttrDescr(IpFwOpcode.O_PIPE, Insn), - AttrDescr(IpFwOpcode.O_SKIPTO, Insn), + AttrDescr(IpFwOpcode.O_SKIPTO, InsnU32), AttrDescr(IpFwOpcode.O_NETGRAPH, Insn), AttrDescr(IpFwOpcode.O_NGTEE, Insn), AttrDescr(IpFwOpcode.O_DIVERT, Insn), AttrDescr(IpFwOpcode.O_TEE, Insn), - AttrDescr(IpFwOpcode.O_CALLRETURN, Insn), + AttrDescr(IpFwOpcode.O_CALLRETURN, InsnU32), AttrDescr(IpFwOpcode.O_SETFIB, Insn), AttrDescr(IpFwOpcode.O_SETDSCP, Insn), AttrDescr(IpFwOpcode.O_REASS, InsnEmpty), - AttrDescr(IpFwOpcode.O_SETMARK, Insn), + AttrDescr(IpFwOpcode.O_SETMARK, InsnU32), + + AttrDescr(IpFwOpcode.O_EXTERNAL_ACTION, InsnU32), + AttrDescr(IpFwOpcode.O_EXTERNAL_INSTANCE, InsnU32), @@ -545,11 +548,11 @@ insn_attrs = prepare_attrs_map( AttrDescr(IpFwOpcode.O_IP_DST, InsnIp), AttrDescr(IpFwOpcode.O_IP6_DST, InsnIp6), AttrDescr(IpFwOpcode.O_IP6_SRC, InsnIp6), - AttrDescr(IpFwOpcode.O_IP_SRC_LOOKUP, InsnTable), - AttrDescr(IpFwOpcode.O_IP_DST_LOOKUP, InsnTable), + AttrDescr(IpFwOpcode.O_IP_SRC_LOOKUP, InsnU32), + AttrDescr(IpFwOpcode.O_IP_DST_LOOKUP, InsnU32), AttrDescr(IpFwOpcode.O_IP_SRCPORT, InsnPorts), AttrDescr(IpFwOpcode.O_IP_DSTPORT, InsnPorts), - AttrDescr(IpFwOpcode.O_PROBE_STATE, Insn), - AttrDescr(IpFwOpcode.O_KEEP_STATE, Insn), + AttrDescr(IpFwOpcode.O_PROBE_STATE, InsnU32), + AttrDescr(IpFwOpcode.O_KEEP_STATE, InsnU32), ] ) diff --git a/tests/oclo/Makefile b/tests/oclo/Makefile index 350c9f857c85..6f73aec0ff7c 100644 --- a/tests/oclo/Makefile +++ b/tests/oclo/Makefile @@ -5,7 +5,6 @@ TESTSDIR= ${TESTSBASE}/cddl/oclo PLAIN_TESTS_C= oclo oclo_errors ocloexec_verify SRCS.oclo= oclo.c -LIBADD.oclo+= openbsd LIBADD.ocloexec_verify+= util .include <bsd.test.mk> diff --git a/tests/sys/file/Makefile b/tests/sys/file/Makefile index f80d1b271b85..beb4452359b7 100644 --- a/tests/sys/file/Makefile +++ b/tests/sys/file/Makefile @@ -5,7 +5,7 @@ BINDIR= ${TESTSDIR} ATF_TESTS_C+= path_test TAP_TESTS_C+= closefrom_test TAP_TESTS_C+= dup_test -TAP_TESTS_C+= fcntlflags_test +ATF_TESTS_C+= fcntlflags_test TAP_TESTS_SH+= flock_test PLAIN_TESTS_C+= ftruncate_test PLAIN_TESTS_C+= newfileops_on_fork_test diff --git a/tests/sys/file/fcntlflags_test.c b/tests/sys/file/fcntlflags_test.c index c5026e38c48b..15a18c113c4a 100644 --- a/tests/sys/file/fcntlflags_test.c +++ b/tests/sys/file/fcntlflags_test.c @@ -24,85 +24,110 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> - +#include <sys/filio.h> +#include <errno.h> #include <fcntl.h> #include <stdio.h> #include <unistd.h> +#include <atf-c.h> + /* * O_ACCMODE is currently defined incorrectly. This is what it should be. * Various code depends on the incorrect value. */ #define CORRECT_O_ACCMODE (O_ACCMODE | O_EXEC) -static int testnum; - static void -subtests(const char *path, int omode, const char *omodetext) +basic_tests(const char *path, int omode, const char *omodetext) { int fd, flags1, flags2, flags3; fd = open(path, omode); - if (fd == -1) - printf("not ok %d - open(\"%s\", %s) failed\n", - testnum++, path, omodetext); - else - printf("ok %d - open(\"%s\", %s) succeeded\n", - testnum++, path, omodetext); + ATF_REQUIRE_MSG(fd != -1, "open(\"%s\", %s) failed: %s", path, + omodetext, strerror(errno)); + flags1 = fcntl(fd, F_GETFL); - if (flags1 == -1) - printf("not ok %d - fcntl(F_GETFL) failed\n", testnum++); - else if ((flags1 & CORRECT_O_ACCMODE) == omode) - printf("ok %d - fcntl(F_GETFL) gave correct result\n", - testnum++); - else - printf("not ok %d - fcntl(F_GETFL) gave incorrect result " - "(%#x & %#x != %#x)\n", - testnum++, flags1, CORRECT_O_ACCMODE, omode); - if (fcntl(fd, F_SETFL, flags1) == -1) - printf("not ok %d - fcntl(F_SETFL) same flags failed\n", - testnum++); - else - printf("ok %d - fcntl(F_SETFL) same flags succeeded\n", - testnum++); + ATF_REQUIRE_MSG(flags1 != -1, "fcntl(F_GETFL) (1) failed: %s", + strerror(errno)); + ATF_REQUIRE_INTEQ(omode, flags1 & CORRECT_O_ACCMODE); + ATF_REQUIRE((flags1 & O_NONBLOCK) == 0); + + ATF_REQUIRE_MSG(fcntl(fd, F_SETFL, flags1) != -1, + "fcntl(F_SETFL) same flags failed: %s", strerror(errno)); + flags2 = fcntl(fd, F_GETFL); - if (flags2 == -1) - printf("not ok %d - fcntl(F_GETFL) failed\n", testnum++); - else if (flags2 == flags1) - printf("ok %d - fcntl(F_GETFL) gave same result\n", - testnum++); - else - printf("not ok %d - fcntl(F_SETFL) caused fcntl(F_GETFL) to " - "change from %#x to %#x\n", - testnum++, flags1, flags2); - if (fcntl(fd, F_SETFL, flags2 | O_NONBLOCK) == -1) - printf("not ok %d - fcntl(F_SETFL) O_NONBLOCK failed\n", - testnum++); - else - printf("ok %d - fcntl(F_SETFL) O_NONBLOCK succeeded\n", - testnum++); + ATF_REQUIRE_MSG(flags2 != -1, "fcntl(F_GETFL) (2) failed: %s", + strerror(errno)); + ATF_REQUIRE_INTEQ(flags1, flags2); + + ATF_REQUIRE_MSG(fcntl(fd, F_SETFL, flags2 | O_NONBLOCK) != -1, + "fcntl(F_SETFL) O_NONBLOCK failed: %s", strerror(errno)); + flags3 = fcntl(fd, F_GETFL); - if (flags3 == -1) - printf("not ok %d - fcntl(F_GETFL) failed\n", testnum++); - else if (flags3 == (flags2 | O_NONBLOCK)) - printf("ok %d - fcntl(F_GETFL) gave expected result\n", - testnum++); - else - printf("not ok %d - fcntl(F_SETFL) gave unexpected result " - "(%#x != %#x)\n", - testnum++, flags3, flags2 | O_NONBLOCK); + ATF_REQUIRE_MSG(flags3 != -1, "fcntl(F_GETFL) (3) failed: %s", + strerror(errno)); + ATF_REQUIRE_INTEQ(flags2 | O_NONBLOCK, flags3); + (void)close(fd); } -int -main(int argc __unused, char **argv __unused) +ATF_TC_WITHOUT_HEAD(read_only_null); +ATF_TC_BODY(read_only_null, tc) { - printf("1..24\n"); - testnum = 1; - subtests("/dev/null", O_RDONLY, "O_RDONLY"); - subtests("/dev/null", O_WRONLY, "O_WRONLY"); - subtests("/dev/null", O_RDWR, "O_RDWR"); - subtests("/bin/sh", O_EXEC, "O_EXEC"); - return (0); + basic_tests("/dev/null", O_RDONLY, "O_RDONLY"); +} + +ATF_TC_WITHOUT_HEAD(write_only_null); +ATF_TC_BODY(write_only_null, tc) +{ + basic_tests("/dev/null", O_WRONLY, "O_WRONLY"); +} + +ATF_TC_WITHOUT_HEAD(read_write_null); +ATF_TC_BODY(read_write_null, tc) +{ + basic_tests("/dev/null", O_RDWR, "O_RDWR"); +} + +ATF_TC_WITHOUT_HEAD(exec_only_sh); +ATF_TC_BODY(exec_only_sh, tc) +{ + basic_tests("/bin/sh", O_EXEC, "O_EXEC"); +} + +ATF_TC_WITHOUT_HEAD(fioasync_dev_null); +ATF_TC_BODY(fioasync_dev_null, tc) +{ + int fd, flags1, flags2, val; + + fd = open("/dev/null", O_RDONLY); + ATF_REQUIRE_MSG(fd != -1, "open(\"/dev/null\") failed: %s", + strerror(errno)); + + flags1 = fcntl(fd, F_GETFL); + ATF_REQUIRE_MSG(flags1 != -1, "fcntl(F_GETFL) (1) failed: %s", + strerror(errno)); + ATF_REQUIRE((flags1 & O_ASYNC) == 0); + + val = 1; + ATF_REQUIRE_ERRNO(EINVAL, ioctl(fd, FIOASYNC, &val) == -1); + + flags2 = fcntl(fd, F_GETFL); + ATF_REQUIRE_MSG(flags2 != -1, "fcntl(F_GETFL) (2) failed: %s", + strerror(errno)); + ATF_REQUIRE_INTEQ(flags1, flags2); + + (void)close(fd); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, read_only_null); + ATF_TP_ADD_TC(tp, write_only_null); + ATF_TP_ADD_TC(tp, read_write_null); + ATF_TP_ADD_TC(tp, exec_only_sh); + ATF_TP_ADD_TC(tp, fioasync_dev_null); + + return (atf_no_error()); } diff --git a/tests/sys/netpfil/pf/nat.sh b/tests/sys/netpfil/pf/nat.sh index 170d813d57fe..e55f46418221 100644 --- a/tests/sys/netpfil/pf/nat.sh +++ b/tests/sys/netpfil/pf/nat.sh @@ -838,7 +838,7 @@ dummynet_mask_body() jexec gw dnctl pipe 1 config delay 100 mask src-ip 0xffffff00 jexec gw pfctl -e pft_set_rules gw \ - "nat pass on ${epair_srv}b inet from 192.0.2.0/24 to any -> (${epair_srv}b)" \ + "nat on ${epair_srv}b inet from 192.0.2.0/24 to any -> (${epair_srv}b)" \ "pass out dnpipe 1" atf_check -s exit:0 -o ignore \ diff --git a/tests/sys/netpfil/pf/rdr.sh b/tests/sys/netpfil/pf/rdr.sh index f7c920bbfa8f..24b95b2047f4 100644 --- a/tests/sys/netpfil/pf/rdr.sh +++ b/tests/sys/netpfil/pf/rdr.sh @@ -281,8 +281,66 @@ srcport_pass_cleanup() pft_cleanup } +atf_test_case "natpass" "cleanup" +natpass_head() +{ + atf_set descr 'Test rdr pass' + atf_set require.user root +} + +natpass_body() +{ + pft_init + + epair=$(vnet_mkepair) + epair_link=$(vnet_mkepair) + + ifconfig ${epair}a 192.0.2.2/24 up + + vnet_mkjail alcatraz ${epair}b ${epair_link}a + jexec alcatraz ifconfig lo0 inet 127.0.0.1/8 up + jexec alcatraz ifconfig ${epair}b inet 192.0.2.1/24 up + jexec alcatraz ifconfig ${epair_link}a 198.51.100.1/24 up + jexec alcatraz sysctl net.inet.ip.forwarding=1 + + vnet_mkjail srv ${epair_link}b + jexec srv ifconfig ${epair_link}b inet 198.51.100.2/24 up + jexec srv route add default 198.51.100.1 + + # Sanity check + atf_check -s exit:0 -o ignore \ + ping -c 1 192.0.2.1 + atf_check -s exit:0 -o ignore \ + jexec alcatraz ping -c 1 198.51.100.2 + + jexec alcatraz pfctl -e + pft_set_rules alcatraz \ + "rdr pass on ${epair}b proto udp from any to 192.0.2.1 port 80 -> 198.51.100.2" \ + "nat on ${epair}b inet from 198.51.100.0/24 to any -> 192.0.2.1" \ + "block in proto udp from any to any port 80" \ + "pass in proto icmp" + + echo "foo" | jexec srv nc -u -l 80 & + sleep 1 # Give the above a moment to start + + out=$(echo 1 | nc -u -w 1 192.0.2.1 80) + echo "out ${out}" + if [ "${out}" != "foo" ]; + then + jexec alcatraz pfctl -sn -vv + jexec alcatraz pfctl -ss -vv + atf_fail "rdr failed" + fi +} + +natpass_cleanup() +{ + pft_cleanup +} + atf_init_test_cases() { + atf_add_test_case "natpass" atf_add_test_case "tcp_v6_compat" atf_add_test_case "tcp_v6_pass" atf_add_test_case "srcport_compat" diff --git a/tools/build/Makefile b/tools/build/Makefile index 3c4e07e3cfc2..09351900599a 100644 --- a/tools/build/Makefile +++ b/tools/build/Makefile @@ -497,6 +497,7 @@ INSTALLDIR_LIST= \ usr/include/casper \ usr/include/openssl \ usr/include/private/ucl \ + usr/include/private/yaml \ usr/include/private/zstd \ usr/lib \ usr/libdata/pkgconfig \ 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.bin/calendar/calendars/calendar.freebsd b/usr.bin/calendar/calendars/calendar.freebsd index a664f5d1145c..b6e18083e24b 100644 --- a/usr.bin/calendar/calendars/calendar.freebsd +++ b/usr.bin/calendar/calendars/calendar.freebsd @@ -480,6 +480,7 @@ 12/05 Ivan Voras <ivoras@FreeBSD.org> born in Slavonski Brod, Croatia, 1981 12/06 Stefan Farfeleder <stefanf@FreeBSD.org> born in Wien, Austria, 1980 12/08 Michael Tuexen <tuexen@FreeBSD.org> born in Oldenburg, Germany, 1966 +12/09 Tiago Gasiba <tiga@FreeBSD.org> born in Porto, Portugal, 1978 12/10 Hiroki Tagato <tagattie@FreeBSD.org> born in Shiga, Japan, 1971 12/11 Ganael Laplanche <martymac@FreeBSD.org> born in Reims, France, 1980 12/11 Koichiro Iwao <meta@FreeBSD.org> born in Oita, Japan, 1987 diff --git a/usr.bin/getconf/sysconf.gperf b/usr.bin/getconf/sysconf.gperf index baf341c8962b..2bd75dd47851 100644 --- a/usr.bin/getconf/sysconf.gperf +++ b/usr.bin/getconf/sysconf.gperf @@ -47,6 +47,7 @@ OPEN_MAX, _SC_OPEN_MAX PAGESIZE, _SC_PAGESIZE PAGE_SIZE, _SC_PAGESIZE PASS_MAX, _SC_PASS_MAX +PHYS_PAGES, _SC_PHYS_PAGES PTHREAD_DESTRUCTOR_ITERATIONS, _SC_THREAD_DESTRUCTOR_ITERATIONS PTHREAD_KEYS_MAX, _SC_THREAD_KEYS_MAX PTHREAD_STACK_MIN, _SC_THREAD_STACK_MIN diff --git a/usr.bin/mandoc/Makefile b/usr.bin/mandoc/Makefile index 2c7c3ed85040..181d4e16c8ee 100644 --- a/usr.bin/mandoc/Makefile +++ b/usr.bin/mandoc/Makefile @@ -60,8 +60,7 @@ LIB_SRCS= ${LIBMAN_SRCS} \ mandoc_xr.c \ msec.c \ preconv.c \ - read.c \ - compat_recallocarray.c \ + read.c HTML_SRCS= eqn_html.c \ html.c \ diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c index 622141e4ff69..7ee03eb3689b 100644 --- a/usr.bin/netstat/if.c +++ b/usr.bin/netstat/if.c @@ -282,7 +282,8 @@ next_ifma(struct ifmaddrs *ifma, const char *name, const sa_family_t family) sdl = (struct sockaddr_dl *)ifma->ifma_name; if (ifma->ifma_addr->sa_family == family && - strcmp(sdl->sdl_data, name) == 0) + sdl->sdl_nlen == strlen(name) && + strncmp(sdl->sdl_data, name, sdl->sdl_nlen) == 0) break; } 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) diff --git a/usr.sbin/crashinfo/crashinfo.sh b/usr.sbin/crashinfo/crashinfo.sh index 3bb1e1456462..68115f09f9d4 100755 --- a/usr.sbin/crashinfo/crashinfo.sh +++ b/usr.sbin/crashinfo/crashinfo.sh @@ -217,10 +217,7 @@ echo file=`mktemp /tmp/crashinfo.XXXXXX` if [ $? -eq 0 ]; then - scriptdir=/usr/libexec/kgdb - echo "bt -full" >> $file - echo "source ${scriptdir}/acttrace.py" >> $file echo "acttrace" >> $file echo "quit" >> $file ${GDB%gdb}kgdb -q $KERNEL $VMCORE < $file |