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)