diff --git a/lib/core/context.c b/lib/core/context.c index 35da6f50e..91bfd1701 100644 --- a/lib/core/context.c +++ b/lib/core/context.c @@ -971,7 +971,7 @@ lws_create_vhost(struct lws_context *context, #ifdef LWS_WITH_ACCESS_LOG if (info->log_filepath) { - vh->log_fd = open(info->log_filepath, + vh->log_fd = lws_open(info->log_filepath, O_CREAT | O_APPEND | O_RDWR, 0600); if (vh->log_fd == (int)LWS_INVALID_FILE) { lwsl_err("unable to open log filepath %s\n", diff --git a/lib/core/libwebsockets.c b/lib/core/libwebsockets.c index e5325895f..c42b3eac3 100644 --- a/lib/core/libwebsockets.c +++ b/lib/core/libwebsockets.c @@ -88,6 +88,28 @@ signed char char_to_hex(const char c) return -1; } +int lws_open(const char *__file, int __oflag, ...) +{ + va_list ap; + int n; + + va_start(ap, __oflag); + if (((__oflag & O_CREAT) == O_CREAT) +#if defined(O_TMPFILE) + || ((__oflag & O_TMPFILE) == O_TMPFILE) +#endif + ) + /* last arg is really a mode_t. But windows... */ + n = open(__file, __oflag, va_arg(ap, uint32_t)); + else + n = open(__file, __oflag); + va_end(ap); + + lws_plat_apply_FD_CLOEXEC(n); + + return n; +} + void lws_vhost_bind_wsi(struct lws_vhost *vh, struct lws *wsi) { diff --git a/lib/core/private.h b/lib/core/private.h index 7b94782a0..0d0da2be2 100644 --- a/lib/core/private.h +++ b/lib/core/private.h @@ -1382,6 +1382,9 @@ lws_plat_pipe_close(struct lws *wsi); int lws_create_event_pipes(struct lws_context *context); +void +lws_plat_apply_FD_CLOEXEC(int n); + const struct lws_plat_file_ops * lws_vfs_select_fops(const struct lws_plat_file_ops *fops, const char *vfs_path, const char **vpath); diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index 0f81d1027..6c4ebb3f4 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -2809,7 +2809,7 @@ struct lws_context_creation_info { /**< VHOST: pointer to optional linked list of per-vhost * options made accessible to protocols */ int keepalive_timeout; - /**< VHOST: (default = 0 = 60s) seconds to allow remote + /**< VHOST: (default = 0 = 5s) seconds to allow remote * client to hold on to an idle HTTP/1.1 connection */ const char *log_filepath; /**< VHOST: filepath to append logs to... this is opened before @@ -6021,6 +6021,19 @@ lws_is_ssl(struct lws *wsi); LWS_VISIBLE LWS_EXTERN int lws_is_cgi(struct lws *wsi); +/** + * lws_open() - platform-specific wrapper for open that prepares the fd + * + * \param file: the filepath to open + * \param oflag: option flags + * \param mode: optional mode of any created file + * + * This is a wrapper around platform open() that sets options on the fd + * according to lws policy. Currently that is FD_CLOEXEC to stop the opened + * fd being available to any child process forked by user code. + */ +LWS_VISIBLE LWS_EXTERN int +lws_open(const char *__file, int __oflag, ...); struct lws_wifi_scan { /* generic wlan scan item */ struct lws_wifi_scan *next; diff --git a/lib/misc/daemonize.c b/lib/misc/daemonize.c index 457f2903b..807ca0f1e 100644 --- a/lib/misc/daemonize.c +++ b/lib/misc/daemonize.c @@ -49,7 +49,7 @@ child_handler(int signum) if (lock_path) { /* Create the lock file as the current user */ - fd = open(lock_path, O_TRUNC | O_RDWR | O_CREAT, 0640); + fd = lws_open(lock_path, O_TRUNC | O_RDWR | O_CREAT, 0640); if (fd < 0) { fprintf(stderr, "unable to create lock file %s, code=%d (%s)\n", @@ -106,7 +106,7 @@ lws_daemonize(const char *_lock_path) // return 1; if (_lock_path) { - fd = open(_lock_path, O_RDONLY); + fd = lws_open(_lock_path, O_RDONLY); if (fd >= 0) { n = read(fd, buf, sizeof(buf)); close(fd); diff --git a/lib/plat/esp32/esp32-file.c b/lib/plat/esp32/esp32-file.c index 0b25a5530..cfddd7aca 100644 --- a/lib/plat/esp32/esp32-file.c +++ b/lib/plat/esp32/esp32-file.c @@ -29,6 +29,10 @@ #include #include +void lws_plat_apply_FD_CLOEXEC(int n) +{ +} + LWS_VISIBLE lws_fop_fd_t IRAM_ATTR _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename, diff --git a/lib/plat/optee/lws-plat-optee.c b/lib/plat/optee/lws-plat-optee.c index 79e3137a9..d5ba9017f 100644 --- a/lib/plat/optee/lws-plat-optee.c +++ b/lib/plat/optee/lws-plat-optee.c @@ -4,6 +4,10 @@ * included from libwebsockets.c for OPTEE builds */ +void lws_plat_apply_FD_CLOEXEC(int n) +{ +} + int lws_plat_pipe_create(struct lws *wsi) { diff --git a/lib/plat/unix/unix-file.c b/lib/plat/unix/unix-file.c index 84dcc5bdd..32392970a 100644 --- a/lib/plat/unix/unix-file.c +++ b/lib/plat/unix/unix-file.c @@ -30,13 +30,18 @@ #endif #include +void lws_plat_apply_FD_CLOEXEC(int n) +{ + if (n != -1) + fcntl(n, F_SETFD, FD_CLOEXEC ); +} int lws_plat_write_file(const char *filename, void *buf, int len) { int m, fd; - fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); + fd = lws_open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fd == -1) return 1; @@ -50,7 +55,7 @@ lws_plat_write_file(const char *filename, void *buf, int len) int lws_plat_read_file(const char *filename, void *buf, int len) { - int n, fd = open(filename, O_RDONLY); + int n, fd = lws_open(filename, O_RDONLY); if (fd == -1) return -1; @@ -65,7 +70,7 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename, const char *vpath, lws_fop_flags_t *flags) { struct stat stat_buf; - int ret = open(filename, (*flags) & LWS_FOP_FLAGS_MASK, 0664); + int ret = lws_open(filename, (*flags) & LWS_FOP_FLAGS_MASK, 0664); lws_fop_fd_t fop_fd; if (ret < 0) diff --git a/lib/plat/unix/unix-init.c b/lib/plat/unix/unix-init.c index 10a748a5d..a71718e7c 100644 --- a/lib/plat/unix/unix-init.c +++ b/lib/plat/unix/unix-init.c @@ -47,7 +47,7 @@ lws_plat_init(struct lws_context *context, lwsl_info(" mem: platform fd map: %5lu bytes\n", (unsigned long)(sizeof(struct lws *) * context->max_fds)); - fd = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY); + fd = lws_open(SYSTEM_RANDOM_FILEPATH, O_RDONLY); context->fd_random = fd; if (context->fd_random < 0) { diff --git a/lib/plat/windows/windows-file.c b/lib/plat/windows/windows-file.c index e798775f5..74920bd25 100644 --- a/lib/plat/windows/windows-file.c +++ b/lib/plat/windows/windows-file.c @@ -24,6 +24,10 @@ #endif #include "core/private.h" +void lws_plat_apply_FD_CLOEXEC(int n) +{ +} + lws_fop_fd_t _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename, const char *vpath, lws_fop_flags_t *flags) @@ -142,7 +146,7 @@ lws_plat_write_file(const char *filename, void *buf, int len) { int m, fd; - fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); + fd = lws_open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fd == -1) return -1; @@ -156,7 +160,7 @@ lws_plat_write_file(const char *filename, void *buf, int len) int lws_plat_read_file(const char *filename, void *buf, int len) { - int n, fd = open(filename, O_RDONLY); + int n, fd = lws_open(filename, O_RDONLY); if (fd == -1) return -1; diff --git a/lib/roles/cgi/cgi-server.c b/lib/roles/cgi/cgi-server.c index 7f3e5b64e..95121b4dd 100644 --- a/lib/roles/cgi/cgi-server.c +++ b/lib/roles/cgi/cgi-server.c @@ -441,9 +441,14 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len lwsl_info("%s: cgi %p spawned PID %d\n", __func__, cgi, cgi->pid); - /* close: stdin:r, stdout:w, stderr:w */ - for (n = 0; n < 3; n++) + /* + * close: stdin:r, stdout:w, stderr:w + * hide from other forks: stdin:w, stdout:r, stderr:r + */ + for (n = 0; n < 3; n++) { + lws_plat_apply_FD_CLOEXEC(cgi->pipe_fds[n][!!(n == 0)]); close(cgi->pipe_fds[n][!(n == 0)]); + } /* inform cgi owner of the child PID */ n = user_callback_handle_rxflow(wsi->protocol->callback, wsi, diff --git a/lib/roles/http/server/lejp-conf.c b/lib/roles/http/server/lejp-conf.c index e9ce854cf..f9ac68a54 100644 --- a/lib/roles/http/server/lejp-conf.c +++ b/lib/roles/http/server/lejp-conf.c @@ -779,7 +779,7 @@ lwsws_get_config(void *user, const char *f, const char * const *paths, struct lejp_ctx ctx; int n, m, fd; - fd = open(f, O_RDONLY); + fd = lws_open(f, O_RDONLY); if (fd < 0) { lwsl_err("Cannot open %s\n", f); return 2; diff --git a/lib/roles/http/server/server.c b/lib/roles/http/server/server.c index 583656384..730a4844f 100644 --- a/lib/roles/http/server/server.c +++ b/lib/roles/http/server/server.c @@ -694,7 +694,7 @@ lws_find_string_in_file(const char *filename, const char *string, int stringlen) char buf[128]; int fd, match = 0, pos = 0, n = 0, hit = 0; - fd = open(filename, O_RDONLY); + fd = lws_open(filename, O_RDONLY); if (fd < 0) { lwsl_err("can't open auth file: %s\n", filename); return 0; diff --git a/minimal-examples/http-server/minimal-http-server-form-post-file/minimal-http-server-form-post-file.c b/minimal-examples/http-server/minimal-http-server-form-post-file/minimal-http-server-form-post-file.c index a819e3f98..486e9e643 100644 --- a/minimal-examples/http-server/minimal-http-server-form-post-file/minimal-http-server-form-post-file.c +++ b/minimal-examples/http-server/minimal-http-server-form-post-file/minimal-http-server-form-post-file.c @@ -58,7 +58,7 @@ file_upload_cb(void *data, const char *name, const char *filename, /* remove any scary things like .. */ lws_filename_purify_inplace(pss->filename); /* open a file of that name for write in the cwd */ - pss->fd = open(pss->filename, O_CREAT | O_TRUNC | O_RDWR, 0600); + pss->fd = lws_open(pss->filename, O_CREAT | O_TRUNC | O_RDWR, 0600); if (pss->fd == LWS_INVALID_FILE) { lwsl_notice("Failed to open output file %s\n", pss->filename); diff --git a/minimal-examples/raw/minimal-raw-file/minimal-raw-file.c b/minimal-examples/raw/minimal-raw-file/minimal-raw-file.c index 74b0c422e..b35055407 100644 --- a/minimal-examples/raw/minimal-raw-file/minimal-raw-file.c +++ b/minimal-examples/raw/minimal-raw-file/minimal-raw-file.c @@ -36,7 +36,7 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason, case LWS_CALLBACK_PROTOCOL_INIT: vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), lws_get_protocol(wsi), sizeof(struct raw_vhd)); - vhd->u.filefd = open(filepath, O_RDWR); + vhd->u.filefd = lws_open(filepath, O_RDWR); if (vhd->u.filefd == -1) { lwsl_err("Unable to open %s\n", filepath); diff --git a/plugins/acme-client/protocol_lws_acme_client.c b/plugins/acme-client/protocol_lws_acme_client.c index 4cb42e60a..828ef95bf 100644 --- a/plugins/acme-client/protocol_lws_acme_client.c +++ b/plugins/acme-client/protocol_lws_acme_client.c @@ -623,7 +623,7 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason, */ lws_snprintf(buf, sizeof(buf) - 1, "%s.upd", vhd->pvop[LWS_TLS_SET_CERT_PATH]); - vhd->fd_updated_cert = open(buf, LWS_O_WRONLY | LWS_O_CREAT | + vhd->fd_updated_cert = lws_open(buf, LWS_O_WRONLY | LWS_O_CREAT | LWS_O_TRUNC, 0600); if (vhd->fd_updated_cert < 0) { lwsl_err("unable to create update cert file %s\n", buf); @@ -631,7 +631,7 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason, } lws_snprintf(buf, sizeof(buf) - 1, "%s.upd", vhd->pvop[LWS_TLS_SET_KEY_PATH]); - vhd->fd_updated_key = open(buf, LWS_O_WRONLY | LWS_O_CREAT | + vhd->fd_updated_key = lws_open(buf, LWS_O_WRONLY | LWS_O_CREAT | LWS_O_TRUNC, 0600); if (vhd->fd_updated_key < 0) { lwsl_err("unable to create update key file %s\n", buf); diff --git a/plugins/protocol_lws_raw_test.c b/plugins/protocol_lws_raw_test.c index 699d9c428..abef4ca66 100644 --- a/plugins/protocol_lws_raw_test.c +++ b/plugins/protocol_lws_raw_test.c @@ -128,7 +128,7 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason, lwsl_err("mkfifo failed\n"); return 1; } - vhd->fifo = open(vhd->fifo_path, O_NONBLOCK | O_RDONLY); + vhd->fifo = lws_open(vhd->fifo_path, O_NONBLOCK | O_RDONLY); if (vhd->fifo == -1) { lwsl_err("opening fifo failed\n"); unlink(vhd->fifo_path); @@ -203,7 +203,7 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason, vhd->zero_length_read = 0; close(vhd->fifo); /* the wsi that adopted the fifo file is closing... reopen the fifo and readopt */ - vhd->fifo = open(vhd->fifo_path, O_NONBLOCK | O_RDONLY); + vhd->fifo = lws_open(vhd->fifo_path, O_NONBLOCK | O_RDONLY); if (vhd->fifo == -1) { lwsl_err("opening fifo failed\n"); return 1; diff --git a/plugins/protocol_lws_server_status.c b/plugins/protocol_lws_server_status.c index 4ee1bf4f4..c37f05c3f 100644 --- a/plugins/protocol_lws_server_status.c +++ b/plugins/protocol_lws_server_status.c @@ -90,7 +90,7 @@ update(struct per_vhost_data__lws_server_status *v) p += n; l -= n; } - fd = open(fp->filepath, LWS_O_RDONLY); + fd = lws_open(fp->filepath, LWS_O_RDONLY); if (fd >= 0) { n = read(fd, contents, sizeof(contents) - 1); if (n >= 0) { diff --git a/plugins/protocol_lws_sshd_demo.c b/plugins/protocol_lws_sshd_demo.c index ad3d6ae0d..1590416f4 100644 --- a/plugins/protocol_lws_sshd_demo.c +++ b/plugins/protocol_lws_sshd_demo.c @@ -397,9 +397,9 @@ callback_lws_sshd_demo(struct lws *wsi, enum lws_callback_reasons reason, * deal with it down /etc/.. when just after this we will lose * the privileges needed to read / write /etc/... */ - vhd->privileged_fd = open(TEST_SERVER_KEY_PATH, O_RDONLY); + vhd->privileged_fd = lws_open(TEST_SERVER_KEY_PATH, O_RDONLY); if (vhd->privileged_fd == -1) - vhd->privileged_fd = open(TEST_SERVER_KEY_PATH, + vhd->privileged_fd = lws_open(TEST_SERVER_KEY_PATH, O_CREAT | O_TRUNC | O_RDWR, 0600); if (vhd->privileged_fd == -1) { lwsl_err("%s: Can't open %s\n", __func__, diff --git a/plugins/protocol_post_demo.c b/plugins/protocol_post_demo.c index b7744838e..8b209273b 100644 --- a/plugins/protocol_post_demo.c +++ b/plugins/protocol_post_demo.c @@ -80,7 +80,7 @@ file_upload_cb(void *data, const char *name, const char *filename, * simple demo use a fixed name so we don't have to deal with * attacks */ #if !defined(LWS_WITH_ESP32) - pss->fd = (lws_filefd_type)(long long)open("/tmp/post-file", + pss->fd = (lws_filefd_type)(long long)lws_open("/tmp/post-file", O_CREAT | O_TRUNC | O_RDWR, 0600); #endif break; diff --git a/test-apps/test-sshd.c b/test-apps/test-sshd.c index 2a5dada6d..f673eb7ad 100644 --- a/test-apps/test-sshd.c +++ b/test-apps/test-sshd.c @@ -232,7 +232,7 @@ ssh_ops_rx(void *_priv, struct lws *wsi, const uint8_t *buf, uint32_t len) static size_t ssh_ops_get_server_key(struct lws *wsi, uint8_t *buf, size_t len) { - int fd = open(TEST_SERVER_KEY_PATH, O_RDONLY), n; + int fd = lws_open(TEST_SERVER_KEY_PATH, O_RDONLY), n; if (fd == -1) { lwsl_err("%s: unable to open %s for read: %s\n", __func__, @@ -255,7 +255,7 @@ ssh_ops_get_server_key(struct lws *wsi, uint8_t *buf, size_t len) static size_t ssh_ops_set_server_key(struct lws *wsi, uint8_t *buf, size_t len) { - int fd = open(TEST_SERVER_KEY_PATH, O_CREAT | O_TRUNC | O_RDWR, 0600); + int fd = lws_open(TEST_SERVER_KEY_PATH, O_CREAT | O_TRUNC | O_RDWR, 0600); int n; lwsl_notice("%s: %d\n", __func__, fd);