Files
nginx/src/http/ngx_http_script.h
T
Maxim Dounin b767540492 Script: buffer overrun protection.
With this change, all script copy operations now check if there is
enough room in the buffer.  To do so, the script engine now provides the
e->end pointer, which specifies expected buffer end, and each copy
operation is checked against it with the ngx_http_script_check_length()
function.

The e->end pointer is optional and only checked when set, thus
introducing no incompatible API changes.  All standard functions were
updated to use it, notably ngx_http_complex_value(), ngx_http_script_run(),
ngx_http_script_regex_start_code(), ngx_http_script_complex_value_code().
Direct script evaluation in the proxy, fastcgi, scgi, uwsgi, grpc proxy,
index, and try_files modules will be updated by a separate patch.

In particular, this catches issues as observed when evaluating variables
with side effects, such as in the following configuration:

    map $uri $map {
        ~(?<capture>.*) $capture;
    }

    set $capture "";
    set $temp "$capture $map";

As well as when evaluating non-cacheable variables, where length of a
variable might change between length and copy codes, such as in the
following configuration:

    map prefix:$capture $map_volatile {
        volatile;
        ~(?<capture>.*) $capture;
    }

    set $capture "";
    set $temp "$map_volatile";

Similar changes were made in the stream module.

Signed-off-by: Roman Arutyunyan <arut@nginx.com>
Origin: <https://freenginx.org/hg/nginx/rev/d172f506ab5f>
2026-07-15 19:51:22 +04:00

274 lines
8.1 KiB
C

/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
*/
#ifndef _NGX_HTTP_SCRIPT_H_INCLUDED_
#define _NGX_HTTP_SCRIPT_H_INCLUDED_
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
typedef struct {
u_char *ip;
u_char *pos;
u_char *end;
ngx_http_variable_value_t *sp;
ngx_str_t buf;
ngx_str_t line;
/* the start of the rewritten arguments */
u_char *args;
unsigned flushed:1;
unsigned skip:1;
unsigned quote:1;
unsigned is_args:1;
unsigned log:1;
ngx_int_t status;
ngx_http_request_t *request;
} ngx_http_script_engine_t;
typedef struct {
ngx_conf_t *cf;
ngx_str_t *source;
ngx_array_t **flushes;
ngx_array_t **lengths;
ngx_array_t **values;
ngx_uint_t variables;
ngx_uint_t ncaptures;
ngx_uint_t captures_mask;
ngx_uint_t size;
void *main;
unsigned compile_args:1;
unsigned complete_lengths:1;
unsigned complete_values:1;
unsigned zero:1;
unsigned conf_prefix:1;
unsigned root_prefix:1;
unsigned dup_capture:1;
unsigned args:1;
} ngx_http_script_compile_t;
typedef struct {
ngx_str_t value;
ngx_uint_t *flushes;
void *lengths;
void *values;
union {
size_t size;
} u;
} ngx_http_complex_value_t;
typedef struct {
ngx_conf_t *cf;
ngx_str_t *value;
ngx_http_complex_value_t *complex_value;
unsigned zero:1;
unsigned conf_prefix:1;
unsigned root_prefix:1;
} ngx_http_compile_complex_value_t;
typedef void (*ngx_http_script_code_pt) (ngx_http_script_engine_t *e);
typedef size_t (*ngx_http_script_len_code_pt) (ngx_http_script_engine_t *e);
typedef struct {
ngx_http_script_code_pt code;
uintptr_t len;
} ngx_http_script_copy_code_t;
typedef struct {
ngx_http_script_code_pt code;
uintptr_t index;
} ngx_http_script_var_code_t;
typedef struct {
ngx_http_script_code_pt code;
ngx_http_set_variable_pt handler;
uintptr_t data;
} ngx_http_script_var_handler_code_t;
typedef struct {
ngx_http_script_code_pt code;
uintptr_t n;
} ngx_http_script_copy_capture_code_t;
#if (NGX_PCRE)
typedef struct {
ngx_http_script_code_pt code;
ngx_http_regex_t *regex;
ngx_array_t *lengths;
uintptr_t size;
uintptr_t status;
uintptr_t next;
unsigned test:1;
unsigned negative_test:1;
unsigned uri:1;
unsigned args:1;
/* add the r->args to the new arguments */
unsigned add_args:1;
unsigned redirect:1;
unsigned break_cycle:1;
ngx_str_t name;
} ngx_http_script_regex_code_t;
typedef struct {
ngx_http_script_code_pt code;
unsigned uri:1;
unsigned args:1;
/* add the r->args to the new arguments */
unsigned add_args:1;
unsigned redirect:1;
} ngx_http_script_regex_end_code_t;
#endif
typedef struct {
ngx_http_script_code_pt code;
uintptr_t conf_prefix;
} ngx_http_script_full_name_code_t;
typedef struct {
ngx_http_script_code_pt code;
uintptr_t status;
ngx_http_complex_value_t text;
} ngx_http_script_return_code_t;
typedef enum {
ngx_http_script_file_plain = 0,
ngx_http_script_file_not_plain,
ngx_http_script_file_dir,
ngx_http_script_file_not_dir,
ngx_http_script_file_exists,
ngx_http_script_file_not_exists,
ngx_http_script_file_exec,
ngx_http_script_file_not_exec
} ngx_http_script_file_op_e;
typedef struct {
ngx_http_script_code_pt code;
uintptr_t op;
} ngx_http_script_file_code_t;
typedef struct {
ngx_http_script_code_pt code;
uintptr_t next;
void **loc_conf;
} ngx_http_script_if_code_t;
typedef struct {
ngx_http_script_code_pt code;
ngx_array_t *lengths;
} ngx_http_script_complex_value_code_t;
typedef struct {
ngx_http_script_code_pt code;
uintptr_t value;
uintptr_t text_len;
uintptr_t text_data;
} ngx_http_script_value_code_t;
void ngx_http_script_flush_complex_value(ngx_http_request_t *r,
ngx_http_complex_value_t *val);
ngx_int_t ngx_http_complex_value(ngx_http_request_t *r,
ngx_http_complex_value_t *val, ngx_str_t *value);
size_t ngx_http_complex_value_size(ngx_http_request_t *r,
ngx_http_complex_value_t *val, size_t default_value);
ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv);
char *ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
char *ngx_http_set_complex_value_zero_slot(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
char *ngx_http_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
ngx_int_t ngx_http_test_predicates(ngx_http_request_t *r,
ngx_array_t *predicates);
ngx_int_t ngx_http_test_required_predicates(ngx_http_request_t *r,
ngx_array_t *predicates);
char *ngx_http_set_predicate_slot(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
ngx_uint_t ngx_http_script_variables_count(ngx_str_t *value);
ngx_int_t ngx_http_script_compile(ngx_http_script_compile_t *sc);
u_char *ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value,
void *code_lengths, size_t reserved, void *code_values);
void ngx_http_script_flush_no_cacheable_variables(ngx_http_request_t *r,
ngx_array_t *indices);
void *ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes,
size_t size);
void *ngx_http_script_add_code(ngx_array_t *codes, size_t size, void *code);
ngx_int_t ngx_http_script_check_length(ngx_http_script_engine_t *e,
size_t len);
size_t ngx_http_script_copy_len_code(ngx_http_script_engine_t *e);
void ngx_http_script_copy_code(ngx_http_script_engine_t *e);
size_t ngx_http_script_copy_var_len_code(ngx_http_script_engine_t *e);
void ngx_http_script_copy_var_code(ngx_http_script_engine_t *e);
size_t ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t *e);
void ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e);
size_t ngx_http_script_mark_args_code(ngx_http_script_engine_t *e);
void ngx_http_script_start_args_code(ngx_http_script_engine_t *e);
#if (NGX_PCRE)
void ngx_http_script_regex_start_code(ngx_http_script_engine_t *e);
void ngx_http_script_regex_end_code(ngx_http_script_engine_t *e);
#endif
void ngx_http_script_return_code(ngx_http_script_engine_t *e);
void ngx_http_script_break_code(ngx_http_script_engine_t *e);
void ngx_http_script_if_code(ngx_http_script_engine_t *e);
void ngx_http_script_equal_code(ngx_http_script_engine_t *e);
void ngx_http_script_not_equal_code(ngx_http_script_engine_t *e);
void ngx_http_script_file_code(ngx_http_script_engine_t *e);
void ngx_http_script_complex_value_code(ngx_http_script_engine_t *e);
void ngx_http_script_value_code(ngx_http_script_engine_t *e);
void ngx_http_script_set_var_code(ngx_http_script_engine_t *e);
void ngx_http_script_var_set_handler_code(ngx_http_script_engine_t *e);
void ngx_http_script_var_code(ngx_http_script_engine_t *e);
void ngx_http_script_nop_code(ngx_http_script_engine_t *e);
#endif /* _NGX_HTTP_SCRIPT_H_INCLUDED_ */