[PATCH v4] unveil patch
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 },
Hi Alex, On Tue, Aug 20, 2024 at 08:09:16PM +0200, a1ex@dismail.de wrote:
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.
Thanks for the patch and for the effort. I'll test it on OpenBSD and the other platforms too to ensure nothing breaks. I'll try to get it merged for the 3.2.0 release. Best, Rodrigo.
participants (2)
-
a1ex@dismail.de
-
Rodrigo Arias