diff options
author | Zhidao HONG <z.hong@f5.com> | 2021-04-29 22:04:34 +0800 |
---|---|---|
committer | Zhidao HONG <z.hong@f5.com> | 2021-04-29 22:04:34 +0800 |
commit | 53279af5d44dce2b679399d6a36eb46292928175 (patch) | |
tree | 973ba2979096f6969d11a8646151034e8a4372fd /src/nxt_http_static.c | |
parent | 113afb09ea7ddeebf2376cf6df3af212705e6128 (diff) | |
download | unit-53279af5d44dce2b679399d6a36eb46292928175.tar.gz unit-53279af5d44dce2b679399d6a36eb46292928175.tar.bz2 |
Static: support for openat2() features.
Support for chrooting, rejecting symlinks, and rejecting crossing mounting
points on a per-request basis during static file serving.
Diffstat (limited to 'src/nxt_http_static.c')
-rw-r--r-- | src/nxt_http_static.c | 123 |
1 files changed, 97 insertions, 26 deletions
diff --git a/src/nxt_http_static.c b/src/nxt_http_static.c index c0b48586..98d70739 100644 --- a/src/nxt_http_static.c +++ b/src/nxt_http_static.c @@ -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); } |