Hi, Here is an updated version of the unveil patch. I think almost everything on the to-do list was completed, except searching for a custom wget location. I don't see an especially easy way of doing that, and it seems an unlikely edge-case for someone to remove wget from the system default location. - Permissions have been tightened in dpis - Checking for AUTHORITY env, fallback to ~/.Xauthority - Prefs parser is aware of 'enable_unveil' - Fix some non-strict code warnings - dillorc 'enable_unveil' default setting - Formatting, whitespace fixes - ... I have done a fair amount of testing and it works for me. Unless there is any further feedback or interest, I will leave it as-is for now. Regards, Alex diff -upr a/configure.ac b/configure.ac --- a/configure.ac Sun Aug 11 22:21:59 2024 +++ b/configure.ac Tue Aug 20 19:08:02 2024 @@ -36,6 +36,11 @@ AC_ARG_ENABLE([insure], [enable_insure=$enableval], [enable_insure=no]) +AC_ARG_ENABLE([unveil], + [AS_HELP_STRING([--enable-unveil], [Build with support for unveil])], + [enable_unveil=$enableval], + [enable_unveil=no]) + AC_ARG_ENABLE([ipv6], [AS_HELP_STRING([--enable-ipv6], [Build with support for IPv6])], [enable_ipv6=$enableval], @@ -619,6 +624,9 @@ if test "x$enable_insure" = "xyes" ; then CC="insure -Zoi \"compiler $CC\"" LIBS="$LIBS -lstdc++-2-libc6.1-1-2.9.0" fi +if test "x$enable_unveil" = "xyes" ; then + AC_DEFINE([ENABLE_UNVEIL], [1], [Enable unveil]) +fi if test "x$enable_threaded_dns" = "xyes" ; then CFLAGS="$CFLAGS -DD_DNS_THREADED" fi @@ -726,4 +734,5 @@ _AS_ECHO([ GIF enabled : ${enable_gif}]) _AS_ECHO([ SVG enabled : ${enable_svg}]) _AS_ECHO([]) _AS_ECHO([ HTML tests : ${html_tests_ok}]) +_AS_ECHO([ unveil enabled : ${enable_unveil}]) _AS_ECHO([]) diff -upr a/dillorc b/dillorc --- a/dillorc Sun Aug 11 22:21:59 2024 +++ b/dillorc Tue Aug 20 19:08:02 2024 @@ -46,6 +46,9 @@ # height of the visible page area. #scroll_step=100 +# Enable unveil security feature (currently only available on OpenBSD) +#enable_unveil=NO + #------------------------------------------------------------------------- # RENDERING SECTION #------------------------------------------------------------------------- diff -upr a/dlib/dlib.c b/dlib/dlib.c --- a/dlib/dlib.c Sun Aug 11 22:21:59 2024 +++ b/dlib/dlib.c Tue Aug 20 19:08:02 2024 @@ -922,6 +922,100 @@ char *dGethomedir (void) } /** + * Return the save directory in a static string + */ +char *dGetsavedir (void) +{ + static char *dillorc = NULL; + dillorc = dStrconcat(dGethomedir(), "/", ".dillo/dillorc", NULL); + FILE *In; + int len; + char *rcline = NULL, *value = NULL, *p; + if ((In = fopen(dillorc, "r")) == NULL) { + DLIB_MSG("dGetsavedir: unable to open dillorc.\n"); + return (NULL); + } + while ((rcline = dGetline(In)) != NULL) { + if (strncmp(rcline, "save_dir", 8) == 0) + break; + dFree(rcline); + } + fclose(In); + if (!rcline) { + value = NULL; + DLIB_MSG("dGetsavedir: no 'save_dir' in dillorc..\n"); + } else { + len = (int) strlen(rcline); + if (len && rcline[len - 1] == '\n') + rcline[len - 1] = 0; + if ((p = strchr(rcline, '='))) { + while (*++p == ' '); + value = dStrdup(p); + } else { + value = NULL; + DLIB_MSG("dGetsavedir: error parsing value in dillorc.\n"); + } + } + dFree(rcline); + return (value); +} + +/** + * Return the enable_unveil value in a static string + */ +char *dGetenableunveil (void) +{ + static char *dillorc = NULL; + dillorc = dStrconcat(dGethomedir(), "/", ".dillo/dillorc", NULL); + FILE *In; + int len; + char *rcline = NULL, *value = NULL, *p; + if ((In = fopen(dillorc, "r")) == NULL) { + DLIB_MSG("dGetenableunveil: unable to open dillorc.\n"); + return (NULL); + } + while ((rcline = dGetline(In)) != NULL) { + if (strncmp(rcline, "enable_unveil", 13) == 0) + break; + dFree(rcline); + } + fclose(In); + if (!rcline) { + value = NULL; + DLIB_MSG("dGetenableunveil: no 'enable_unveil' in dillorc.\n"); + } else { + len = (int) strlen(rcline); + if (len && rcline[len - 1] == '\n') + rcline[len - 1] = 0; + if ((p = strchr(rcline, '='))) { + while (*++p == ' '); + value = dStrdup(p); + } else { + value = NULL; + DLIB_MSG("dGetenableunveil: error parsing value in dillorc.\n"); + } + } + dFree(rcline); + return (value); +} + +/** + * Use unveil on OpenBSD + */ +void *dUnveil(const char *path, const char *perm) +{ + #ifdef ENABLE_UNVEIL + #ifdef __OpenBSD__ + int unveil(const char *path, const char *permissions); + if (unveil(path, perm) == -1) { + DLIB_MSG("unveil(%s, %s) failed: %s\n", path, perm, strerror(errno)); + exit(1); + } + #endif + #endif +} + +/** * Get a line from a FILE stream. * Return value: read line on success, NULL on EOF. */ diff -upr a/dlib/dlib.h b/dlib/dlib.h --- a/dlib/dlib.h Sun Aug 11 22:21:59 2024 +++ b/dlib/dlib.h Tue Aug 20 19:08:02 2024 @@ -175,6 +175,9 @@ void dLib_show_messages(bool_t show); */ char *dGetcwd(void); char *dGethomedir(void); +char *dGetsavedir(void); +char *dGetenableunveil(void); +void *dUnveil(const char *path, const char *perm); char *dGetline(FILE *stream); int dClose(int fd); int dUsleep(unsigned long us); diff -upr a/dpi/bookmarks.c b/dpi/bookmarks.c --- a/dpi/bookmarks.c Sun Aug 11 22:21:59 2024 +++ b/dpi/bookmarks.c Tue Aug 20 19:08:02 2024 @@ -37,6 +37,7 @@ #include <signal.h> #include "../dpip/dpip.h" #include "dpiutil.h" +#include "../dlib/dlib.h" /* @@ -1606,7 +1607,6 @@ static void termination_handler(int signum) exit(signum); } - /* * -- MAIN ------------------------------------------------------------------- */ @@ -1616,6 +1616,21 @@ int main(void) { socklen_t address_size; char *tok; Dsh *sh; + + /* Use unveil on OpenBSD */ + if (dGetenableunveil() != NULL) { + if (strncmp(dGetenableunveil(), "YES", 3) == 0) { + #ifdef ENABLE_UNVEIL + char *dil_bm = dStrconcat(dGethomedir(), "/.dillo/bm.txt", NULL); + dUnveil(dil_bm, "rwc"); + dFree(dil_bm); + char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL); + dUnveil(dil_loc, "r"); + dFree(dil_loc); + dUnveil(NULL, NULL); + #endif + } + } /* Arrange the cleanup function for terminations via exit() */ atexit(cleanup); diff -upr a/dpi/cookies.c b/dpi/cookies.c --- a/dpi/cookies.c Sun Aug 11 22:21:59 2024 +++ b/dpi/cookies.c Tue Aug 20 19:08:02 2024 @@ -50,6 +50,7 @@ int main(void) #include <signal.h> #include "dpiutil.h" #include "../dpip/dpip.h" +#include "../dlib/dlib.h" /* @@ -1632,7 +1633,6 @@ static void termination_handler(int signum) exit(signum); } - /* * -- MAIN ------------------------------------------------------------------- */ @@ -1643,7 +1643,22 @@ int main(void) { int sock_fd, code; char *buf; Dsh *sh; - + + /* Use unveil on OpenBSD */ + if (dGetenableunveil() != NULL) { + if (strncmp(dGetenableunveil(), "YES", 3) == 0) { + #ifdef ENABLE_UNVEIL + char *cookiesrc_loc = dStrconcat(dGethomedir(), "/.dillo/cookiesrc", NULL); + dUnveil(cookiesrc_loc, "rwc"); + dFree(cookiesrc_loc); + char *cookies_loc = dStrconcat(dGethomedir(), "/.dillo/cookies.txt", NULL); + dUnveil(cookies_loc, "rwc"); + dFree(cookies_loc); + dUnveil(NULL, NULL); + #endif + } + } + /* Arrange the cleanup function for terminations via exit() */ atexit(cleanup); diff -upr a/dpi/datauri.c b/dpi/datauri.c --- a/dpi/datauri.c Sun Aug 11 22:21:59 2024 +++ b/dpi/datauri.c Tue Aug 20 19:08:02 2024 @@ -21,6 +21,7 @@ #include "../dpip/dpip.h" #include "dpiutil.h" #include "../src/misc.h" +#include "../dlib/dlib.h" /* * Debugging macros @@ -290,6 +291,19 @@ int main(void) unsigned char *data; int rc; size_t data_size = 0; + + /* Use unveil on OpenBSD */ + if (dGetenableunveil() != NULL) { + if (strncmp(dGetenableunveil(), "YES", 3) == 0) { + #ifdef ENABLE_UNVEIL + dUnveil("/tmp", "rwc"); + char *dil_loc = dStrconcat(dGethomedir(), "/.dillo/dpid_comm_keys", NULL); + dUnveil(dil_loc, "rwc"); + dFree(dil_loc); + dUnveil(NULL, NULL); + #endif + } + } /* Initialize the SockHandler */ sh = a_Dpip_dsh_new(STDIN_FILENO, STDOUT_FILENO, 8*1024); diff -upr a/dpi/downloads.cc b/dpi/downloads.cc --- a/dpi/downloads.cc Sun Aug 11 22:21:59 2024 +++ b/dpi/downloads.cc Tue Aug 20 19:08:13 2024 @@ -45,6 +45,7 @@ #include "config.h" #include "dpiutil.h" #include "../dpip/dpip.h" +#include "../dlib/dlib.h" /* * Debugging macros @@ -206,7 +207,6 @@ static char *escape_tooltip(const char *buf, ssize_t l return ret; } - /* * Global variables */ @@ -1098,13 +1098,37 @@ static void custLabelMeasure(const Fl_Label* o, int& W fl_measure(o->value, W, H, interpret_symbols); } - - //int main(int argc, char **argv) int main() { int ww = 420, wh = 85; - + + /* Use unveil on OpenBSD */ + if (dGetenableunveil() != NULL) { + if (strncmp(dGetenableunveil(), "YES", 3) == 0) { + #ifdef ENABLE_UNVEIL + dUnveil("/tmp", "rwc"); + dUnveil("/etc/fonts", "r"); + dUnveil("/usr/local/bin/wget", "x"); + char *xauth_loc = dStrconcat(dGethomedir(), "/.Xauthority", NULL); + char *xauth = getenv("AUTHORITY"); + if (xauth && strlen(xauth)) { + dUnveil(xauth, "r"); + } else { + dUnveil(xauth_loc, "r"); + } + dFree(xauth_loc); + dFree(xauth); + dUnveil("/usr/local/share/fonts", "r"); + char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL); + dUnveil(dil_loc, "r"); + dFree(dil_loc); + dUnveil(dGetsavedir(), "rw"); + dUnveil(NULL, NULL); + #endif + } + } + Fl::lock(); // Disable '@' and '&' interpretation in normal labels. diff -upr a/dpi/file.c b/dpi/file.c --- a/dpi/file.c Sun Aug 11 22:21:59 2024 +++ b/dpi/file.c Tue Aug 20 19:08:02 2024 @@ -37,6 +37,7 @@ #include "../dpip/dpip.h" #include "dpiutil.h" #include "d_size.h" +#include "../dlib/dlib.h" /* * Debugging macros @@ -1063,12 +1064,31 @@ static int File_check_fds(uint_t seconds) return st; } - int main(void) { struct sockaddr_in sin; socklen_t sin_sz; int sock_fd, c_st, st = 1; + + /* Use unveil on OpenBSD */ + if (dGetenableunveil() != NULL) { + if (strncmp(dGetenableunveil(), "YES", 3) == 0) { + #ifdef ENABLE_UNVEIL + dUnveil(dGetsavedir(), "r"); + dUnveil("/tmp", "rw"); + char *home_loc = dStrconcat(dGethomedir(), "", NULL); + dUnveil(home_loc, "r"); + dFree(home_loc); + char *ssh_loc = dStrconcat(dGethomedir(), "/.ssh", NULL); + dUnveil(ssh_loc, ""); + dFree(ssh_loc); + char *config_loc = dStrconcat(dGethomedir(), "/.config", NULL); + dUnveil(config_loc, ""); + dFree(config_loc); + dUnveil(NULL, NULL); + #endif + } + } /* Arrange the cleanup function for abnormal terminations */ if (signal (SIGINT, termination_handler) == SIG_IGN) diff -upr a/dpi/ftp.c b/dpi/ftp.c --- a/dpi/ftp.c Sun Aug 11 22:21:59 2024 +++ b/dpi/ftp.c Tue Aug 20 19:08:02 2024 @@ -44,6 +44,7 @@ #include "../dpip/dpip.h" #include "dpiutil.h" #include "d_size.h" +#include "../dlib/dlib.h" /* * Debugging macros @@ -282,6 +283,21 @@ int main(int argc, char **argv) int st, rc; char *p, *d_cmd; + /* Use unveil on OpenBSD */ + if (dGetenableunveil() != NULL) { + if (strncmp(dGetenableunveil(), "YES", 3) == 0) { + #ifdef ENABLE_UNVEIL + dUnveil("/tmp", "rwc"); + dUnveil("/usr/local/bin/wget", "x"); + char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL); + dUnveil(dil_loc, "r"); + dFree(dil_loc); + dUnveil(dGetsavedir(), "rwc"); + dUnveil(NULL, NULL); + #endif + } + } + /* wget may need to write a temporary file... */ rc = chdir("/tmp"); if (rc == -1) { diff -upr a/dpi/vsource.c b/dpi/vsource.c --- a/dpi/vsource.c Sun Aug 11 22:21:59 2024 +++ b/dpi/vsource.c Tue Aug 20 19:08:02 2024 @@ -21,6 +21,7 @@ #include <errno.h> #include "../dpip/dpip.h" #include "dpiutil.h" +#include "../dlib/dlib.h" /* * Debugging macros @@ -188,6 +189,18 @@ int main(void) char *dpip_tag, *cmd = NULL, *cmd2 = NULL, *url = NULL, *size_str = NULL; char *d_cmd; + /* Use unveil on OpenBSD */ + if (dGetenableunveil() != NULL) { + if (strncmp(dGetenableunveil(), "YES", 3) == 0) { + #ifdef ENABLE_UNVEIL + char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL); + dUnveil(dil_loc, "r"); + dFree(dil_loc); + dUnveil(NULL, NULL); + #endif + } + } + _MSG("starting...\n"); //sleep(20); diff -upr a/dpid/main.c b/dpid/main.c --- a/dpid/main.c Sun Aug 11 22:21:59 2024 +++ b/dpid/main.c Tue Aug 20 19:08:02 2024 @@ -236,6 +236,19 @@ int main(void) //daemon(0,0); /* Use 0,1 for feedback */ /* TODO: call setsid() ?? */ + /* Use unveil on OpenBSD */ + if (dGetenableunveil() != NULL) { + if (strncmp(dGetenableunveil(), "YES", 3) == 0) { + #ifdef ENABLE_UNVEIL + dUnveil("/usr/local/lib/dillo", "rx"); + dUnveil("/usr/local/etc/dillo", "r"); + char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL); + dUnveil(dil_loc, "rwc"); + dUnveil(NULL, NULL); + #endif + } + } + /* Allow read and write access, but only for the user. * TODO: can this cause trouble with umount? */ umask(0077); diff -upr a/src/dillo.cc b/src/dillo.cc --- a/src/dillo.cc Sun Aug 11 22:21:59 2024 +++ b/src/dillo.cc Tue Aug 20 19:08:02 2024 @@ -463,7 +463,53 @@ int main(int argc, char **argv) fclose(fp); } dLib_show_messages(prefs.show_msg); - + + // Use unveil + if (dGetenableunveil() != NULL) { + if (strncmp(dGetenableunveil(), "YES", 3) == 0) { + #ifdef ENABLE_UNVEIL + const char *home = dGethomedir(); + const char *save = prefs.save_dir; + int nsave = strlen(save); + int nhome = strlen(home); + if (nsave <= nhome) { + /* Prevent save_dir="/home" and save_dir=$HOME */ + if (strncmp(save, home, nsave) == 0) { + MSG("save_dir cannot contain home\n"); + exit(1); + } + } + dUnveil("/usr/local/share/fonts", "r"); + dUnveil("/usr/local/share/icons", "r"); + dUnveil("/usr/X11R6/share/X11/locale", "r"); + dUnveil("/usr/X11R6/lib/X11/fonts", "r"); + dUnveil("/usr/local/etc/dillo", "r"); + dUnveil("/tmp", "rwc"); + dUnveil("/usr/local/bin/dpid", "x"); + dUnveil("/etc/fonts", "r"); + dUnveil("/etc/resolv.conf", "r"); + dUnveil("/etc/ssl/cert.pem", "r"); + dUnveil(prefs.save_dir, "rwc"); + char *dil_loc = dStrconcat(dGethomedir(), "/.dillo", NULL); + dUnveil(dil_loc, "rwc"); + dFree(dil_loc); + char *icons_loc = dStrconcat(dGethomedir(), "/.icons", NULL); + dUnveil(icons_loc, "r"); + dFree(icons_loc); + char *xauth_loc = dStrconcat(dGethomedir(), "/.Xauthority", NULL); + char *xauth = getenv("AUTHORITY"); + if (xauth && strlen(xauth)) { + dUnveil(xauth, "r"); + } else { + dUnveil(xauth_loc, "r"); + } + dFree(xauth_loc); + dFree(xauth); + dUnveil(NULL, NULL); + #endif + } + } + // initialize internal modules a_Dpi_init(); a_Dns_init(); diff -upr a/src/prefs.c b/src/prefs.c --- a/src/prefs.c Sun Aug 11 22:21:59 2024 +++ b/src/prefs.c Tue Aug 20 19:08:02 2024 @@ -72,6 +72,7 @@ void a_Prefs_init(void) prefs.http_strict_transport_security = TRUE; prefs.http_force_https = FALSE; prefs.http_user_agent = dStrdup(PREFS_HTTP_USER_AGENT); + prefs.enable_unveil = FALSE; prefs.limit_text_width = FALSE; prefs.adjust_min_width = TRUE; prefs.adjust_table_min_width = TRUE; diff -upr a/src/prefs.h b/src/prefs.h --- a/src/prefs.h Sun Aug 11 22:21:59 2024 +++ b/src/prefs.h Tue Aug 20 19:08:02 2024 @@ -100,6 +100,7 @@ typedef struct { bool_t http_persistent_conns; bool_t http_strict_transport_security; bool_t http_force_https; + bool_t enable_unveil; int32_t buffered_drawing; char *font_serif; char *font_sans_serif; diff -upr a/src/prefsparser.cc b/src/prefsparser.cc --- a/src/prefsparser.cc Sun Aug 11 22:21:59 2024 +++ b/src/prefsparser.cc Tue Aug 20 19:08:02 2024 @@ -182,6 +182,7 @@ void PrefsParser::parse(FILE *fp) PREFS_BOOL, 0 }, { "http_force_https", &prefs.http_force_https, PREFS_BOOL, 0 }, { "http_user_agent", &prefs.http_user_agent, PREFS_STRING, 0 }, + { "enable_unveil", &prefs.enable_unveil, PREFS_BOOL, 0 }, { "limit_text_width", &prefs.limit_text_width, PREFS_BOOL, 0 }, { "adjust_min_width", &prefs.adjust_min_width, PREFS_BOOL, 0 }, { "adjust_table_min_width", &prefs.adjust_table_min_width, PREFS_BOOL, 0 },