From: Rafael Sadowski Subject: slowcgi: preserve PARAMS order in the CGI environment To: tech@openbsd.org Date: Mon, 13 Jul 2026 16:50:32 +0200 I fixed the order in httpd ("tail insert during read from conf" followed by "tail insert" during copying) but still had an incorrect order because of slowcgi. env vars were stored on an SLIST via SLIST_INSERT_HEAD and later walked with SLIST_FOREACH when populating envp[]. Prepending on insert and iterating head-to-tail reverses the list, so FastCGI PARAMS delivered as curl -s http://127.0.0.1:8089/env.cgi FCGI_TEST_BB=BB FCGI_TEST_E=E FCGI_TEST_D=D FCGI_TEST_C=C FCGI_TEST_B=B FCGI_TEST_A=A even httpd provided them in the correct order: ... fcgi_add_param: HTTP_HOST[9] => 127.0.0.1:8089[14], total_len: 164 fcgi_add_param: HTTP_USER_AGENT[15] => curl/8.21.0[11], total_len: 189 fcgi_add_param: FCGI_TEST_A[11] => A[1], total_len: 217 fcgi_add_param: FCGI_TEST_B[11] => B[1], total_len: 231 fcgi_add_param: FCGI_TEST_C[11] => C[1], total_len: 245 fcgi_add_param: FCGI_TEST_D[11] => D[1], total_len: 259 fcgi_add_param: FCGI_TEST_E[11] => E[1], total_len: 273 fcgi_add_param: FCGI_TEST_BB[12] => BB[2], total_len: 287 fcgi_add_param: REMOTE_ADDR[11] => 127.0.0.1[9], total_len: 303 fcgi_add_param: REMOTE_PORT[11] => 24112[5], total_len: 325 ... Switch the list to STAILQ and insert at the tail so envp[] follows the order in which parameters arrived. OK? diff --git a/usr.sbin/slowcgi/slowcgi.c b/usr.sbin/slowcgi/slowcgi.c index 1663118ee22..b0e511e095a 100644 --- a/usr.sbin/slowcgi/slowcgi.c +++ b/usr.sbin/slowcgi/slowcgi.c @@ -83,10 +83,10 @@ struct listener { }; struct env_val { - SLIST_ENTRY(env_val) entry; + STAILQ_ENTRY(env_val) entry; char *val; }; -SLIST_HEAD(env_head, env_val); +STAILQ_HEAD(env_head, env_val); struct fcgi_record_header { uint8_t version; @@ -693,7 +693,7 @@ parse_begin_request(uint8_t *buf, uint16_t n, struct request *c, uint16_t id) c->request_started = 1; c->id = id; - SLIST_INIT(&c->env); + STAILQ_INIT(&c->env); c->env_count = 0; } @@ -794,7 +794,7 @@ parse_params(uint8_t *buf, uint16_t n, struct request *c, uint16_t id) buf += val_len; n -= val_len; - SLIST_INSERT_HEAD(&c->env, env_entry, entry); + STAILQ_INSERT_TAIL(&c->env, env_entry, entry); ldebug("env[%d], %s", c->env_count, env_entry->val); c->env_count++; } @@ -955,7 +955,7 @@ exec_cgi(struct request *c) argv[1] = NULL; if ((env = calloc(c->env_count + 1, sizeof(char*))) == NULL) _exit(1); - SLIST_FOREACH(env_entry, &c->env, entry) + STAILQ_FOREACH(env_entry, &c->env, entry) env[i++] = env_entry->val; env[i++] = NULL; execve(c->script_name, argv, env); @@ -1153,9 +1153,9 @@ cleanup_request(struct request *c) event_del(&c->script_stdin_ev); } close(c->fd); - while (!SLIST_EMPTY(&c->env)) { - env_entry = SLIST_FIRST(&c->env); - SLIST_REMOVE_HEAD(&c->env, entry); + while (!STAILQ_EMPTY(&c->env)) { + env_entry = STAILQ_FIRST(&c->env); + STAILQ_REMOVE_HEAD(&c->env, entry); free(env_entry->val); free(env_entry); }