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 },