Hello, I received feedback from deraadt that the first two unveil(2) calls were unnecessary because pledge(2) automatically unveils "/usr/share/zoneinfo".
This updated patch removes the unneeded unveil(2) calls. Best regards, Stephen --- usr.sbin/dhcpd/confpars.c | 41 ++++++++++++++++++++++++++------------- usr.sbin/dhcpd/db.c | 19 ++++++++++++++++++ usr.sbin/dhcpd/dhcpd.c | 30 ++++++++++++++++++++++++++-- usr.sbin/dhcpd/dhcpd.h | 2 ++ 4 files changed, 76 insertions(+), 16 deletions(-) diff --git usr.sbin/dhcpd/confpars.c usr.sbin/dhcpd/confpars.c index 1bdffb38842..bb245fc663e 100644 --- usr.sbin/dhcpd/confpars.c +++ usr.sbin/dhcpd/confpars.c @@ -57,6 +57,8 @@ #include "dhctoken.h" #include "log.h" +FILE *db_file_ro; + int parse_cidr(FILE *, unsigned char *, unsigned char *); /* @@ -106,18 +108,11 @@ readconf(void) } /* - * lease-file :== lease-declarations EOF - * lease-statments :== <nil> - * | lease-declaration - * | lease-declarations lease-declaration + * Open and retain a read-only file descriptor to the lease database file. */ void -read_leases(void) +open_leases(void) { - FILE *cfile; - char *val; - int token; - new_parse(path_dhcpd_db); /* @@ -131,23 +126,40 @@ read_leases(void) * thinking that no leases have been assigned to anybody, which * could create severe network chaos. */ - if ((cfile = fopen(path_dhcpd_db, "r")) == NULL) { + if ((db_file_ro = fopen(path_dhcpd_db, "r")) == NULL) { log_warn("Can't open lease database (%s)", path_dhcpd_db); log_warnx("check for failed database rewrite attempt!"); log_warnx("Please read the dhcpd.leases manual page if you"); fatalx("don't know what to do about this."); } +} + +/* + * lease-file :== lease-declarations EOF + * lease-statments :== <nil> + * | lease-declaration + * | lease-declarations lease-declaration + */ +void +read_leases(void) +{ + char *val; + int token; + + if (!db_file_ro) { + fatalx("db_file_ro is NULL"); + } do { - token = next_token(&val, cfile); + token = next_token(&val, db_file_ro); if (token == EOF) break; if (token != TOK_LEASE) { log_warnx("Corrupt lease file - possible data loss!"); - skip_to_semi(cfile); + skip_to_semi(db_file_ro); } else { struct lease *lease; - lease = parse_lease_declaration(cfile); + lease = parse_lease_declaration(db_file_ro); if (lease) enter_lease(lease); else @@ -155,7 +167,8 @@ read_leases(void) } } while (1); - fclose(cfile); + fclose(db_file_ro); + db_file_ro = NULL; } /* diff --git usr.sbin/dhcpd/db.c usr.sbin/dhcpd/db.c index 295e522b1ce..634ec8a593a 100644 --- usr.sbin/dhcpd/db.c +++ usr.sbin/dhcpd/db.c @@ -190,6 +190,16 @@ commit_leases(void) return (1); } +/* + * Open and retain two file descriptors to the lease database file: + * + * - A read-only fd for learning existing leases + * - A write-only fd for writing new leases + * + * Reading and parsing data from the read-only fd is done separately. + * This allows privilege drop to happen *before* parsing untrusted + * client data from the lease database file. + */ void db_startup(void) { @@ -202,6 +212,15 @@ db_startup(void) if ((db_file = fdopen(db_fd, "w")) == NULL) fatalx("Can't fdopen new lease file!"); + open_leases(); +} + +/* + * Read and parse the existing leases from the lease database file. + */ +void +db_parse(void) +{ /* Read in the existing lease file... */ read_leases(); time(&write_time); diff --git usr.sbin/dhcpd/dhcpd.c usr.sbin/dhcpd/dhcpd.c index b3562dce34f..7759f7839e0 100644 --- usr.sbin/dhcpd/dhcpd.c +++ usr.sbin/dhcpd/dhcpd.c @@ -244,8 +244,6 @@ main(int argc, char *argv[]) icmp_startup(1, lease_pinged); - if (chroot(pw->pw_dir) == -1) - fatal("chroot %s", pw->pw_dir); if (chdir("/") == -1) fatal("chdir(\"/\")"); if (setgroups(1, &pw->pw_gid) || @@ -253,6 +251,34 @@ main(int argc, char *argv[]) setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) fatal("can't drop privileges"); + /* + * The lease database parsing logic needs the zoneinfo files + * for the lease begin / end date strings. These files are + * automatically unveiled by pledge(2). It also opens the + * /etc/ethers file using ether_hostton(3). + */ + if (unveil("/etc/ethers", "r") == -1) + err(1, "unveil /etc/ethers"); + if (unveil(NULL, NULL) == -1) + err(1, "unveil"); + + /* + * Apply initial pledge(2) promises - we will drop "rpath" after + * parsing the lease database (we need it for ether_hostton(3)). + */ + if (udpsockmode) { + if (pledge("rpath stdio inet route sendfd", NULL) == -1) + err(1, "pledge init"); + } else { + if (pledge("rpath stdio inet sendfd", NULL) == -1) + err(1, "pledge init"); + } + + db_parse(); + + /* + * Drop the "rpath" promise. + */ if (udpsockmode) { if (pledge("stdio inet route sendfd", NULL) == -1) err(1, "pledge"); diff --git usr.sbin/dhcpd/dhcpd.h usr.sbin/dhcpd/dhcpd.h index 0903c244ddd..8c52b6603fc 100644 --- usr.sbin/dhcpd/dhcpd.h +++ usr.sbin/dhcpd/dhcpd.h @@ -343,6 +343,7 @@ int peek_token(char **, FILE *); /* confpars.c */ int readconf(void); +void open_leases(void); void read_leases(void); int parse_statement(FILE *, struct group *, int, struct host_decl *, int); void parse_allow_deny(FILE *, struct group *, int); @@ -489,6 +490,7 @@ char *piaddr(struct iaddr); int write_lease(struct lease *); int commit_leases(void); void db_startup(void); +void db_parse(void); void new_lease_file(void); /* packet.c */