Static: support for openat2() features.

Support for chrooting, rejecting symlinks, and rejecting crossing mounting
points on a per-request basis during static file serving.
This commit is contained in:
Zhidao HONG
2021-04-29 22:04:34 +08:00
parent 113afb09ea
commit 53279af5d4
10 changed files with 313 additions and 27 deletions

View File

@@ -31,15 +31,15 @@ nxt_http_action_t *
nxt_http_static_handler(nxt_task_t *task, nxt_http_request_t *r,
nxt_http_action_t *action)
{
size_t alloc, encode;
u_char *p;
size_t length, encode;
u_char *p, *fname;
struct tm tm;
nxt_buf_t *fb;
nxt_int_t ret;
nxt_str_t index, extension, *mtype;
nxt_str_t index, extension, *mtype, *chroot;
nxt_uint_t level;
nxt_bool_t need_body;
nxt_file_t *f;
nxt_file_t *f, af, file;
nxt_file_info_t fi;
nxt_http_field_t *field;
nxt_http_status_t status;
@@ -63,13 +63,6 @@ nxt_http_static_handler(nxt_task_t *task, nxt_http_request_t *r,
need_body = 1;
}
f = nxt_mp_zget(r->mem_pool, sizeof(nxt_file_t));
if (nxt_slow_path(f == NULL)) {
goto fail;
}
f->fd = NXT_FILE_INVALID;
if (r->path->start[r->path->length - 1] == '/') {
/* TODO: dynamic index setting. */
nxt_str_set(&index, "index.html");
@@ -80,23 +73,83 @@ nxt_http_static_handler(nxt_task_t *task, nxt_http_request_t *r,
nxt_str_null(&extension);
}
alloc = action->name.length + r->path->length + index.length + 1;
f = NULL;
f->name = nxt_mp_nget(r->mem_pool, alloc);
if (nxt_slow_path(f->name == NULL)) {
length = action->name.length + r->path->length + index.length;
fname = nxt_mp_nget(r->mem_pool, length + 1);
if (nxt_slow_path(fname == NULL)) {
goto fail;
}
p = f->name;
p = fname;
p = nxt_cpymem(p, action->name.start, action->name.length);
p = nxt_cpymem(p, r->path->start, r->path->length);
p = nxt_cpymem(p, index.start, index.length);
*p = '\0';
ret = nxt_file_open(task, f, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
nxt_memzero(&file, sizeof(nxt_file_t));
file.name = fname;
chroot = &action->u.share.chroot;
#if (NXT_HAVE_OPENAT2)
if (action->u.share.resolve != 0) {
if (chroot->length > 0) {
file.name = chroot->start;
if (length > chroot->length
&& nxt_memcmp(fname, chroot->start, chroot->length) == 0)
{
fname += chroot->length;
ret = nxt_file_open(task, &file, NXT_FILE_SEARCH, NXT_FILE_OPEN,
0);
} else {
file.error = NXT_EACCES;
ret = NXT_ERROR;
}
} else if (fname[0] == '/') {
file.name = (u_char *) "/";
ret = nxt_file_open(task, &file, NXT_FILE_SEARCH, NXT_FILE_OPEN, 0);
} else {
file.name = (u_char *) ".";
file.fd = AT_FDCWD;
ret = NXT_OK;
}
if (nxt_fast_path(ret == NXT_OK)) {
af = file;
nxt_memzero(&file, sizeof(nxt_file_t));
file.name = fname;
ret = nxt_file_openat2(task, &file, NXT_FILE_RDONLY,
NXT_FILE_OPEN, 0, af.fd,
action->u.share.resolve);
if (af.fd != AT_FDCWD) {
nxt_file_close(task, &af);
}
}
} else {
ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
}
#else
ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
#endif
if (nxt_slow_path(ret != NXT_OK)) {
switch (f->error) {
switch (file.error) {
/*
* For Unix domain sockets "errno" is set to:
@@ -117,6 +170,10 @@ nxt_http_static_handler(nxt_task_t *task, nxt_http_request_t *r,
break;
case NXT_EACCES:
#if (NXT_HAVE_OPENAT2)
case NXT_ELOOP:
case NXT_EXDEV:
#endif
level = NXT_LOG_ERR;
status = NXT_HTTP_FORBIDDEN;
break;
@@ -132,13 +189,27 @@ nxt_http_static_handler(nxt_task_t *task, nxt_http_request_t *r,
}
if (status != NXT_HTTP_NOT_FOUND) {
nxt_log(task, level, "open(\"%FN\") failed %E", f->name, f->error);
if (chroot->length > 0) {
nxt_log(task, level, "opening \"%FN\" at \"%FN\" failed %E",
fname, chroot, file.error);
} else {
nxt_log(task, level, "opening \"%FN\" failed %E",
fname, file.error);
}
}
nxt_http_request_error(task, r, status);
return NULL;
}
f = nxt_mp_get(r->mem_pool, sizeof(nxt_file_t));
if (nxt_slow_path(f == NULL)) {
goto fail;
}
*f = file;
ret = nxt_file_info(f, &fi);
if (nxt_slow_path(ret != NXT_OK)) {
goto fail;
@@ -172,15 +243,15 @@ nxt_http_static_handler(nxt_task_t *task, nxt_http_request_t *r,
nxt_http_field_name_set(field, "ETag");
alloc = NXT_TIME_T_HEXLEN + NXT_OFF_T_HEXLEN + 3;
length = NXT_TIME_T_HEXLEN + NXT_OFF_T_HEXLEN + 3;
p = nxt_mp_nget(r->mem_pool, alloc);
p = nxt_mp_nget(r->mem_pool, length);
if (nxt_slow_path(p == NULL)) {
goto fail;
}
field->value = p;
field->value_length = nxt_sprintf(p, p + alloc, "\"%xT-%xO\"",
field->value_length = nxt_sprintf(p, p + length, "\"%xT-%xO\"",
nxt_file_mtime(&fi),
nxt_file_size(&fi))
- p;
@@ -254,19 +325,19 @@ nxt_http_static_handler(nxt_task_t *task, nxt_http_request_t *r,
nxt_http_field_name_set(field, "Location");
encode = nxt_encode_uri(NULL, r->path->start, r->path->length);
alloc = r->path->length + encode * 2 + 1;
length = r->path->length + encode * 2 + 1;
if (r->args->length > 0) {
alloc += 1 + r->args->length;
length += 1 + r->args->length;
}
p = nxt_mp_nget(r->mem_pool, alloc);
p = nxt_mp_nget(r->mem_pool, length);
if (nxt_slow_path(p == NULL)) {
goto fail;
}
field->value = p;
field->value_length = alloc;
field->value_length = length;
if (encode > 0) {
p = (u_char *) nxt_encode_uri(p, r->path->start, r->path->length);
@@ -294,7 +365,7 @@ fail:
nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
if (f != NULL && f->fd != NXT_FILE_INVALID) {
if (f != NULL) {
nxt_file_close(task, f);
}