Mercurial > hg > nginx
comparison src/core/ngx_open_file_cache.c @ 5356:acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
It was introduced in Linux 2.6.39, glibc 2.14 and allows to obtain
file descriptors without actually opening files. Thus made it possible
to traverse path with openat() syscalls without the need to have read
permissions for path components. It is effectively emulates O_SEARCH
which is missing on Linux.
O_PATH is used in combination with O_RDONLY. The last one is ignored
if O_PATH is used, but it allows nginx to not fail when it was built on
modern system (i.e. glibc 2.14+) and run with a kernel older than 2.6.39.
Then O_PATH is unknown to the kernel and ignored, while O_RDONLY is used.
Sadly, fstat() is not working with O_PATH descriptors till Linux 3.6.
As a workaround we fallback to fstatat() with the AT_EMPTY_PATH flag
that was introduced at the same time as O_PATH.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Mon, 02 Sep 2013 08:07:59 +0400 |
parents | 6b479db5b52b |
children | 659464c695b7 |
comparison
equal
deleted
inserted
replaced
5355:32847478c2c1 | 5356:acd51b0f6fd4 |
---|---|
23 | 23 |
24 static void ngx_open_file_cache_cleanup(void *data); | 24 static void ngx_open_file_cache_cleanup(void *data); |
25 #if (NGX_HAVE_OPENAT) | 25 #if (NGX_HAVE_OPENAT) |
26 static ngx_fd_t ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name, | 26 static ngx_fd_t ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name, |
27 ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log); | 27 ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log); |
28 #if (NGX_HAVE_O_PATH) | |
29 static ngx_int_t ngx_file_o_path_info(ngx_fd_t fd, ngx_file_info_t *fi, | |
30 ngx_log_t *log); | |
31 #endif | |
28 #endif | 32 #endif |
29 static ngx_fd_t ngx_open_file_wrapper(ngx_str_t *name, | 33 static ngx_fd_t ngx_open_file_wrapper(ngx_str_t *name, |
30 ngx_open_file_info_t *of, ngx_int_t mode, ngx_int_t create, | 34 ngx_open_file_info_t *of, ngx_int_t mode, ngx_int_t create, |
31 ngx_int_t access, ngx_log_t *log); | 35 ngx_int_t access, ngx_log_t *log); |
32 static ngx_int_t ngx_file_info_wrapper(ngx_str_t *name, | 36 static ngx_int_t ngx_file_info_wrapper(ngx_str_t *name, |
515 { | 519 { |
516 err = ngx_errno; | 520 err = ngx_errno; |
517 goto failed; | 521 goto failed; |
518 } | 522 } |
519 | 523 |
524 #if (NGX_HAVE_O_PATH) | |
525 if (ngx_file_o_path_info(fd, &fi, log) == NGX_ERROR) { | |
526 err = ngx_errno; | |
527 goto failed; | |
528 } | |
529 #else | |
520 if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { | 530 if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { |
521 err = ngx_errno; | 531 err = ngx_errno; |
522 goto failed; | 532 goto failed; |
523 } | 533 } |
534 #endif | |
524 | 535 |
525 if (fi.st_uid != atfi.st_uid) { | 536 if (fi.st_uid != atfi.st_uid) { |
526 err = NGX_ELOOP; | 537 err = NGX_ELOOP; |
527 goto failed; | 538 goto failed; |
528 } | 539 } |
539 ngx_set_errno(err); | 550 ngx_set_errno(err); |
540 | 551 |
541 return NGX_INVALID_FILE; | 552 return NGX_INVALID_FILE; |
542 } | 553 } |
543 | 554 |
555 | |
556 #if (NGX_HAVE_O_PATH) | |
557 | |
558 static ngx_int_t | |
559 ngx_file_o_path_info(ngx_fd_t fd, ngx_file_info_t *fi, ngx_log_t *log) | |
560 { | |
561 static ngx_uint_t use_fstat = 1; | |
562 | |
563 /* | |
564 * In Linux 2.6.39 the O_PATH flag was introduced that allows to obtain | |
565 * a descriptor without actually opening file or directory. It requires | |
566 * less permissions for path components, but till Linux 3.6 fstat() returns | |
567 * EBADF on such descriptors, and fstatat() with the AT_EMPTY_PATH flag | |
568 * should be used instead. | |
569 * | |
570 * Three scenarios are handled in this function: | |
571 * | |
572 * 1) The kernel is newer than 3.6 or fstat() with O_PATH support was | |
573 * backported by vendor. Then fstat() is used. | |
574 * | |
575 * 2) The kernel is newer than 2.6.39 but older than 3.6. In this case | |
576 * the first call of fstat() returns EBADF and we fallback to fstatat() | |
577 * with AT_EMPTY_PATH which was introduced at the same time as O_PATH. | |
578 * | |
579 * 3) The kernel is older than 2.6.39 but nginx was build with O_PATH | |
580 * support. Since descriptors are opened with O_PATH|O_RDONLY flags | |
581 * and O_PATH is ignored by the kernel then the O_RDONLY flag is | |
582 * actually used. In this case fstat() just works. | |
583 */ | |
584 | |
585 if (use_fstat) { | |
586 if (ngx_fd_info(fd, fi) != NGX_FILE_ERROR) { | |
587 return NGX_OK; | |
588 } | |
589 | |
590 if (ngx_errno != NGX_EBADF) { | |
591 return NGX_ERROR; | |
592 } | |
593 | |
594 ngx_log_error(NGX_LOG_NOTICE, log, 0, | |
595 "fstat(O_PATH) failed with EBADF, " | |
596 "switching to fstatat(AT_EMPTY_PATH)"); | |
597 | |
598 use_fstat = 0; | |
599 return ngx_file_o_path_info(fd, fi, log); | |
600 } | |
601 | |
602 if (ngx_file_at_info(fd, "", fi, AT_EMPTY_PATH) != NGX_FILE_ERROR) { | |
603 return NGX_OK; | |
604 } | |
605 | |
606 return NGX_ERROR; | |
607 } | |
608 | |
544 #endif | 609 #endif |
610 | |
611 #endif /* NGX_HAVE_OPENAT */ | |
545 | 612 |
546 | 613 |
547 static ngx_fd_t | 614 static ngx_fd_t |
548 ngx_open_file_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, | 615 ngx_open_file_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, |
549 ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log) | 616 ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log) |