Change 229469 by pjd@pjd_anger on 2013/06/07 23:09:12 Garbage-collect dead prototypes. Affected files ... ... //depot/user/pjd/capsicum/sbin/dhclient/dhcpd.h#4 edit ... //depot/user/pjd/capsicum/sbin/dhclient/packet.c#3 edit Differences ... ==== //depot/user/pjd/capsicum/sbin/dhclient/dhcpd.h#4 (text+ko) ==== @@ -412,12 +412,6 @@ ssize_t decode_udp_ip_header(unsigned char *, int, struct sockaddr_in *, unsigned char *, int); -/* ethernet.c */ -void assemble_ethernet_header(struct interface_info *, unsigned char *, - int *, struct hardware *); -ssize_t decode_ethernet_header(struct interface_info *, unsigned char *, - int, struct hardware *); - /* clparse.c */ int read_client_conf(void); void read_client_leases(void); ==== //depot/user/pjd/capsicum/sbin/dhclient/packet.c#3 (text+ko) ==== @@ -55,11 +55,6 @@ u_int32_t checksum(unsigned char *, unsigned, u_int32_t); u_int32_t wrapsum(u_int32_t); -void assemble_ethernet_header(struct interface_info *, unsigned char *, - int *, struct hardware *); -ssize_t decode_ethernet_header(struct interface_info *, unsigned char *, - int bufix, struct hardware *); - u_int32_t checksum(unsigned char *buf, unsigned nbytes, u_int32_t sum) { Change 229470 by pjd@pjd_freefall on 2013/06/07 23:24:50 Remove unused argument from send_packet(). Affected files ... ... //depot/user/pjd/capsicum/sbin/dhclient/bpf.c#3 edit ... //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#4 edit ... //depot/user/pjd/capsicum/sbin/dhclient/dhcpd.h#5 edit Differences ... ==== //depot/user/pjd/capsicum/sbin/dhclient/bpf.c#3 (text+ko) ==== @@ -251,8 +251,7 @@ ssize_t send_packet(struct interface_info *interface, struct dhcp_packet *raw, - size_t len, struct in_addr from, struct sockaddr_in *to, - struct hardware *hto) + size_t len, struct in_addr from, struct sockaddr_in *to) { unsigned char buf[256]; struct iovec iov[2]; @@ -261,7 +260,7 @@ /* Assemble the headers... */ if (to->sin_addr.s_addr == INADDR_BROADCAST) - assemble_hw_header(interface, buf, &bufp, hto); + assemble_hw_header(interface, buf, &bufp, NULL); assemble_udp_ip_header(buf, &bufp, from.s_addr, to->sin_addr.s_addr, to->sin_port, (unsigned char *)raw, len); ==== //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#4 (text+ko) ==== @@ -1229,7 +1229,7 @@ /* Send out a packet. */ (void)send_packet(ip, &ip->client->packet, ip->client->packet_length, - inaddr_any, &sockaddr_broadcast, NULL); + inaddr_any, &sockaddr_broadcast); add_timeout(cur_time + ip->client->interval, send_discover, ip); } @@ -1460,7 +1460,7 @@ /* Send out a packet. */ (void) send_packet(ip, &ip->client->packet, ip->client->packet_length, - from, &destination, NULL); + from, &destination); add_timeout(cur_time + ip->client->interval, send_request, ip); } @@ -1476,7 +1476,7 @@ /* Send out a packet. */ (void) send_packet(ip, &ip->client->packet, ip->client->packet_length, - inaddr_any, &sockaddr_broadcast, NULL); + inaddr_any, &sockaddr_broadcast); } void ==== //depot/user/pjd/capsicum/sbin/dhclient/dhcpd.h#5 (text+ko) ==== @@ -300,7 +300,7 @@ void if_register_send(struct interface_info *); void if_register_receive(struct interface_info *); ssize_t send_packet(struct interface_info *, struct dhcp_packet *, size_t, - struct in_addr, struct sockaddr_in *, struct hardware *); + struct in_addr, struct sockaddr_in *); ssize_t receive_packet(struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *); Change 229471 by pjd@pjd_freefall on 2013/06/07 23:26:24 Remove unused argument from assemble_hw_header(). Affected files ... ... //depot/user/pjd/capsicum/sbin/dhclient/bpf.c#4 edit ... //depot/user/pjd/capsicum/sbin/dhclient/dhcpd.h#6 edit ... //depot/user/pjd/capsicum/sbin/dhclient/packet.c#4 edit Differences ... ==== //depot/user/pjd/capsicum/sbin/dhclient/bpf.c#4 (text+ko) ==== @@ -260,7 +260,7 @@ /* Assemble the headers... */ if (to->sin_addr.s_addr == INADDR_BROADCAST) - assemble_hw_header(interface, buf, &bufp, NULL); + assemble_hw_header(interface, buf, &bufp); assemble_udp_ip_header(buf, &bufp, from.s_addr, to->sin_addr.s_addr, to->sin_port, (unsigned char *)raw, len); ==== //depot/user/pjd/capsicum/sbin/dhclient/dhcpd.h#6 (text+ko) ==== @@ -404,8 +404,7 @@ void dhcp(struct packet *); /* packet.c */ -void assemble_hw_header(struct interface_info *, unsigned char *, - int *, struct hardware *); +void assemble_hw_header(struct interface_info *, unsigned char *, int *); void assemble_udp_ip_header(unsigned char *, int *, u_int32_t, u_int32_t, unsigned int, unsigned char *, int); ssize_t decode_hw_header(unsigned char *, int, struct hardware *); ==== //depot/user/pjd/capsicum/sbin/dhclient/packet.c#4 (text+ko) ==== @@ -90,14 +90,11 @@ void assemble_hw_header(struct interface_info *interface, unsigned char *buf, - int *bufix, struct hardware *to) + int *bufix) { struct ether_header eh; - if (to != NULL && to->hlen == 6) /* XXX */ - memcpy(eh.ether_dhost, to->haddr, sizeof(eh.ether_dhost)); - else - memset(eh.ether_dhost, 0xff, sizeof(eh.ether_dhost)); + memset(eh.ether_dhost, 0xff, sizeof(eh.ether_dhost)); if (interface->hw_address.hlen == sizeof(eh.ether_shost)) memcpy(eh.ether_shost, interface->hw_address.haddr, sizeof(eh.ether_shost)); Change 229472 by pjd@pjd_freefall on 2013/06/07 23:36:49 Use the same type for 'from' and 'to' argument in send_packet(). Affected files ... ... //depot/user/pjd/capsicum/sbin/dhclient/bpf.c#5 edit ... //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#5 edit ... //depot/user/pjd/capsicum/sbin/dhclient/dhcpd.h#7 edit Differences ... ==== //depot/user/pjd/capsicum/sbin/dhclient/bpf.c#5 (text+ko) ==== @@ -251,7 +251,7 @@ ssize_t send_packet(struct interface_info *interface, struct dhcp_packet *raw, - size_t len, struct in_addr from, struct sockaddr_in *to) + size_t len, struct in_addr from, struct in_addr to) { unsigned char buf[256]; struct iovec iov[2]; @@ -259,10 +259,10 @@ int result, bufp = 0; /* Assemble the headers... */ - if (to->sin_addr.s_addr == INADDR_BROADCAST) + if (to.s_addr == INADDR_BROADCAST) assemble_hw_header(interface, buf, &bufp); - assemble_udp_ip_header(buf, &bufp, from.s_addr, - to->sin_addr.s_addr, to->sin_port, (unsigned char *)raw, len); + assemble_udp_ip_header(buf, &bufp, from.s_addr, to.s_addr, + htons(REMOTE_PORT), (unsigned char *)raw, len); iov[0].iov_base = (char *)buf; iov[0].iov_len = bufp; @@ -270,12 +270,19 @@ iov[1].iov_len = len; /* Fire it off */ - if (to->sin_addr.s_addr == INADDR_BROADCAST) + if (to.s_addr == INADDR_BROADCAST) result = writev(interface->wfdesc, iov, 2); else { + struct sockaddr_in sato; + + sato.sin_addr = to; + sato.sin_port = htons(REMOTE_PORT); + sato.sin_family = AF_INET; + sato.sin_len = sizeof(sato); + memset(&msg, 0, sizeof(msg)); - msg.msg_name = (struct sockaddr *)to; - msg.msg_namelen = sizeof(*to); + msg.msg_name = (struct sockaddr *)&sato; + msg.msg_namelen = sizeof(sato); msg.msg_iov = iov; msg.msg_iovlen = 2; result = sendmsg(interface->ufdesc, &msg, 0); ==== //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#5 (text+ko) ==== @@ -92,8 +92,7 @@ int nullfd = -1; struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } }; -struct in_addr inaddr_any; -struct sockaddr_in sockaddr_broadcast; +struct in_addr inaddr_any, inaddr_broadcast; char *path_dhclient_pidfile; struct pidfh *pidfile; @@ -410,11 +409,7 @@ tzset(); time(&cur_time); - memset(&sockaddr_broadcast, 0, sizeof(sockaddr_broadcast)); - sockaddr_broadcast.sin_family = AF_INET; - sockaddr_broadcast.sin_port = htons(REMOTE_PORT); - sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST; - sockaddr_broadcast.sin_len = sizeof(sockaddr_broadcast); + inaddr_broadcast.s_addr = INADDR_BROADCAST; inaddr_any.s_addr = INADDR_ANY; read_client_conf(); @@ -1223,13 +1218,12 @@ ip->client->secs = ip->client->packet.secs; note("DHCPDISCOVER on %s to %s port %d interval %d", - ip->name, inet_ntoa(sockaddr_broadcast.sin_addr), - ntohs(sockaddr_broadcast.sin_port), + ip->name, inet_ntoa(inaddr_broadcast), REMOTE_PORT, (int)ip->client->interval); /* Send out a packet. */ (void)send_packet(ip, &ip->client->packet, ip->client->packet_length, - inaddr_any, &sockaddr_broadcast); + inaddr_any, inaddr_broadcast); add_timeout(cur_time + ip->client->interval, send_discover, ip); } @@ -1337,8 +1331,7 @@ send_request(void *ipp) { struct interface_info *ip = ipp; - struct sockaddr_in destination; - struct in_addr from; + struct in_addr from, to; int interval; /* Figure out how long it's been since we started transmitting. */ @@ -1426,18 +1419,13 @@ /* If the lease T2 time has elapsed, or if we're not yet bound, broadcast the DHCPREQUEST rather than unicasting. */ - memset(&destination, 0, sizeof(destination)); if (ip->client->state == S_REQUESTING || ip->client->state == S_REBOOTING || cur_time > ip->client->active->rebind) - destination.sin_addr.s_addr = INADDR_BROADCAST; + to.s_addr = INADDR_BROADCAST; else - memcpy(&destination.sin_addr.s_addr, - ip->client->destination.iabuf, - sizeof(destination.sin_addr.s_addr)); - destination.sin_port = htons(REMOTE_PORT); - destination.sin_family = AF_INET; - destination.sin_len = sizeof(destination); + memcpy(&to.s_addr, ip->client->destination.iabuf, + sizeof(to.s_addr)); if (ip->client->state != S_REQUESTING) memcpy(&from, ip->client->active->address.iabuf, @@ -1455,12 +1443,12 @@ ip->client->packet.secs = htons(65535); } - note("DHCPREQUEST on %s to %s port %d", ip->name, - inet_ntoa(destination.sin_addr), ntohs(destination.sin_port)); + note("DHCPREQUEST on %s to %s port %d", ip->name, inet_ntoa(to), + REMOTE_PORT); /* Send out a packet. */ (void) send_packet(ip, &ip->client->packet, ip->client->packet_length, - from, &destination); + from, to); add_timeout(cur_time + ip->client->interval, send_request, ip); } @@ -1471,12 +1459,11 @@ struct interface_info *ip = ipp; note("DHCPDECLINE on %s to %s port %d", ip->name, - inet_ntoa(sockaddr_broadcast.sin_addr), - ntohs(sockaddr_broadcast.sin_port)); + inet_ntoa(inaddr_broadcast), REMOTE_PORT); /* Send out a packet. */ (void) send_packet(ip, &ip->client->packet, ip->client->packet_length, - inaddr_any, &sockaddr_broadcast); + inaddr_any, inaddr_broadcast); } void ==== //depot/user/pjd/capsicum/sbin/dhclient/dhcpd.h#7 (text+ko) ==== @@ -300,7 +300,7 @@ void if_register_send(struct interface_info *); void if_register_receive(struct interface_info *); ssize_t send_packet(struct interface_info *, struct dhcp_packet *, size_t, - struct in_addr, struct sockaddr_in *); + struct in_addr, struct in_addr); ssize_t receive_packet(struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *); Change 229473 by pjd@pjd_freefall on 2013/06/07 23:38:50 No caller checks send_packet() return value, so make it void. Affected files ... ... //depot/user/pjd/capsicum/sbin/dhclient/bpf.c#6 edit ... //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#6 edit ... //depot/user/pjd/capsicum/sbin/dhclient/dhcpd.h#8 edit Differences ... ==== //depot/user/pjd/capsicum/sbin/dhclient/bpf.c#6 (text+ko) ==== @@ -249,7 +249,7 @@ error("Cannot lock bpf"); } -ssize_t +void send_packet(struct interface_info *interface, struct dhcp_packet *raw, size_t len, struct in_addr from, struct in_addr to) { @@ -290,7 +290,6 @@ if (result < 0) warning("send_packet: %m"); - return (result); } ssize_t ==== //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#6 (text+ko) ==== @@ -1222,7 +1222,7 @@ (int)ip->client->interval); /* Send out a packet. */ - (void)send_packet(ip, &ip->client->packet, ip->client->packet_length, + send_packet(ip, &ip->client->packet, ip->client->packet_length, inaddr_any, inaddr_broadcast); add_timeout(cur_time + ip->client->interval, send_discover, ip); @@ -1447,7 +1447,7 @@ REMOTE_PORT); /* Send out a packet. */ - (void) send_packet(ip, &ip->client->packet, ip->client->packet_length, + send_packet(ip, &ip->client->packet, ip->client->packet_length, from, to); add_timeout(cur_time + ip->client->interval, send_request, ip); @@ -1462,7 +1462,7 @@ inet_ntoa(inaddr_broadcast), REMOTE_PORT); /* Send out a packet. */ - (void) send_packet(ip, &ip->client->packet, ip->client->packet_length, + send_packet(ip, &ip->client->packet, ip->client->packet_length, inaddr_any, inaddr_broadcast); } ==== //depot/user/pjd/capsicum/sbin/dhclient/dhcpd.h#8 (text+ko) ==== @@ -299,7 +299,7 @@ int if_register_bpf(struct interface_info *); void if_register_send(struct interface_info *); void if_register_receive(struct interface_info *); -ssize_t send_packet(struct interface_info *, struct dhcp_packet *, size_t, +void send_packet(struct interface_info *, struct dhcp_packet *, size_t, struct in_addr, struct in_addr); ssize_t receive_packet(struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *); Change 229474 by pjd@pjd_freefall on 2013/06/07 23:39:47 iov_base field is 'void *' in FreeBSD, no need to cast. Affected files ... ... //depot/user/pjd/capsicum/sbin/dhclient/bpf.c#7 edit Differences ... ==== //depot/user/pjd/capsicum/sbin/dhclient/bpf.c#7 (text+ko) ==== @@ -264,9 +264,9 @@ assemble_udp_ip_header(buf, &bufp, from.s_addr, to.s_addr, htons(REMOTE_PORT), (unsigned char *)raw, len); - iov[0].iov_base = (char *)buf; + iov[0].iov_base = buf; iov[0].iov_len = bufp; - iov[1].iov_base = (char *)raw; + iov[1].iov_base = raw; iov[1].iov_len = len; /* Fire it off */ Change 229475 by pjd@pjd_freefall on 2013/06/07 23:44:11 IFC. Affected files ... ... //depot/user/pjd/capsicum/sbin/dhclient/packet.c#5 integrate Differences ... ==== //depot/user/pjd/capsicum/sbin/dhclient/packet.c#5 (text+ko) ==== @@ -120,7 +120,7 @@ ip.ip_len = htons(sizeof(ip) + sizeof(udp) + len); ip.ip_id = 0; ip.ip_off = 0; - ip.ip_ttl = 16; + ip.ip_ttl = 128; ip.ip_p = IPPROTO_UDP; ip.ip_sum = 0; ip.ip_src.s_addr = from; Change 229476 by pjd@pjd_freefall on 2013/06/07 23:49:29 Make use of two fields: rfdesc and wfdesc to keep bpf descriptor open for reading only in rfdesc and bpf descriptor open for writing only in wfdesc. In the end they will be used by two different processes. Affected files ... ... //depot/user/pjd/capsicum/sbin/dhclient/bpf.c#8 edit Differences ... ==== //depot/user/pjd/capsicum/sbin/dhclient/bpf.c#8 (text+ko) ==== @@ -61,15 +61,15 @@ * mask. */ int -if_register_bpf(struct interface_info *info) +if_register_bpf(struct interface_info *info, int flags) { char filename[50]; int sock, b; /* Open a BPF device */ - for (b = 0; 1; b++) { + for (b = 0;; b++) { snprintf(filename, sizeof(filename), BPF_FORMAT, b); - sock = open(filename, O_RDWR, 0); + sock = open(filename, flags); if (sock < 0) { if (errno == EBUSY) continue; @@ -87,16 +87,76 @@ return (sock); } +/* + * Packet write filter program: + * 'ip and udp and src port bootps and dst port (bootps or bootpc)' + */ +struct bpf_insn dhcp_bpf_wfilter[] = { + BPF_STMT(BPF_LD + BPF_B + BPF_IND, 14), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (IPVERSION << 4) + 5, 0, 12), + + /* Make sure this is an IP packet... */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 10), + + /* Make sure it's a UDP packet... */ + BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 8), + + /* Make sure this isn't a fragment... */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), + BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 6, 0), /* patched */ + + /* Get the IP header length... */ + BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14), + + /* Make sure it's from the right port... */ + BPF_STMT(BPF_LD + BPF_H + BPF_IND, 14), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 68, 0, 3), + + /* Make sure it is to the right ports ... */ + BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1), + + /* If we passed all the tests, ask for the whole packet. */ + BPF_STMT(BPF_RET+BPF_K, (u_int)-1), + + /* Otherwise, drop it. */ + BPF_STMT(BPF_RET+BPF_K, 0), +}; + +int dhcp_bpf_wfilter_len = sizeof(dhcp_bpf_wfilter) / sizeof(struct bpf_insn); + void if_register_send(struct interface_info *info) { + struct bpf_version v; + struct bpf_program p; int sock, on = 1; - /* - * If we're using the bpf API for sending and receiving, we - * don't need to register this interface twice. - */ - info->wfdesc = info->rfdesc; + /* Open a BPF device and hang it on this interface... */ + info->wfdesc = if_register_bpf(info, O_WRONLY); + + /* Make sure the BPF version is in range... */ + if (ioctl(info->wfdesc, BIOCVERSION, &v) < 0) + error("Can't get BPF version: %m"); + + if (v.bv_major != BPF_MAJOR_VERSION || + v.bv_minor < BPF_MINOR_VERSION) + error("Kernel BPF version out of range - recompile dhcpd!"); + + /* Set up the bpf write filter program structure. */ + p.bf_len = dhcp_bpf_wfilter_len; + p.bf_insns = dhcp_bpf_wfilter; + + if (dhcp_bpf_wfilter[7].k == 0x1fff) + dhcp_bpf_wfilter[7].k = htons(IP_MF|IP_OFFMASK); + + if (ioctl(info->wfdesc, BIOCSETWF, &p) < 0) + error("Can't install write filter program: %m"); + + if (ioctl(info->wfdesc, BIOCLOCK, NULL) < 0) + error("Cannot lock bpf"); /* * Use raw socket for unicast send. @@ -144,46 +204,6 @@ int dhcp_bpf_filter_len = sizeof(dhcp_bpf_filter) / sizeof(struct bpf_insn); -/* - * Packet write filter program: - * 'ip and udp and src port bootps and dst port (bootps or bootpc)' - */ -struct bpf_insn dhcp_bpf_wfilter[] = { - BPF_STMT(BPF_LD + BPF_B + BPF_IND, 14), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (IPVERSION << 4) + 5, 0, 12), - - /* Make sure this is an IP packet... */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 10), - - /* Make sure it's a UDP packet... */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 8), - - /* Make sure this isn't a fragment... */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), - BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 6, 0), /* patched */ - - /* Get the IP header length... */ - BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14), - - /* Make sure it's from the right port... */ - BPF_STMT(BPF_LD + BPF_H + BPF_IND, 14), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 68, 0, 3), - - /* Make sure it is to the right ports ... */ - BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1), - - /* If we passed all the tests, ask for the whole packet. */ - BPF_STMT(BPF_RET+BPF_K, (u_int)-1), - - /* Otherwise, drop it. */ - BPF_STMT(BPF_RET+BPF_K, 0), -}; - -int dhcp_bpf_wfilter_len = sizeof(dhcp_bpf_wfilter) / sizeof(struct bpf_insn); - void if_register_receive(struct interface_info *info) { @@ -192,7 +212,7 @@ int flag = 1, sz; /* Open a BPF device and hang it on this interface... */ - info->rfdesc = if_register_bpf(info); + info->rfdesc = if_register_bpf(info, O_RDONLY); /* Make sure the BPF version is in range... */ if (ioctl(info->rfdesc, BIOCVERSION, &v) < 0) @@ -235,16 +255,6 @@ if (ioctl(info->rfdesc, BIOCSETF, &p) < 0) error("Can't install packet filter program: %m"); - /* Set up the bpf write filter program structure. */ - p.bf_len = dhcp_bpf_wfilter_len; - p.bf_insns = dhcp_bpf_wfilter; - - if (dhcp_bpf_wfilter[7].k == 0x1fff) - dhcp_bpf_wfilter[7].k = htons(IP_MF|IP_OFFMASK); - - if (ioctl(info->rfdesc, BIOCSETWF, &p) < 0) - error("Can't install write filter program: %m"); - if (ioctl(info->rfdesc, BIOCLOCK, NULL) < 0) error("Cannot lock bpf"); } Change 229477 by pjd@pjd_freefall on 2013/06/07 23:54:16 The gethostname(3) function won't work in capability mode, because reading kern.hostname sysctl is not permitted there. Cache hostname early and use cached value later. Affected files ... ... //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#7 edit Differences ... ==== //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#7 (text+ko) ==== @@ -91,6 +91,8 @@ int privfd; int nullfd = -1; +char hostname[_POSIX_HOST_NAME_MAX+1]; + struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } }; struct in_addr inaddr_any, inaddr_broadcast; @@ -446,6 +448,13 @@ error("no such user: nobody"); } + /* + * Obtain hostname before entering capability mode - it won't be + * possible then, as reading kern.hostname is not permitted. + */ + if (gethostname(hostname, sizeof(hostname)) < 0) + hostname[0] = '\0'; + if (pipe(pipe_fd) == -1) error("pipe"); @@ -1520,11 +1529,10 @@ ip->client->config->send_options[i].len; options[i]->timeout = 0xFFFFFFFF; } - + /* send host name if not set via config file. */ - char hostname[_POSIX_HOST_NAME_MAX+1]; if (!options[DHO_HOST_NAME]) { - if (gethostname(hostname, sizeof(hostname)) == 0) { + if (hostname[0] != '\0') { size_t len; char* posDot = strchr(hostname, '.'); if (posDot != NULL) @@ -1644,11 +1652,10 @@ ip->client->config->send_options[i].len; options[i]->timeout = 0xFFFFFFFF; } - + /* send host name if not set via config file. */ - char hostname[_POSIX_HOST_NAME_MAX+1]; if (!options[DHO_HOST_NAME]) { - if (gethostname(hostname, sizeof(hostname)) == 0) { + if (hostname[0] != '\0') { size_t len; char* posDot = strchr(hostname, '.'); if (posDot != NULL) Change 229478 by pjd@pjd_freefall on 2013/06/08 00:11:56 Update if_register_bpf() prototype. Missed in @229476. Affected files ... ... //depot/user/pjd/capsicum/sbin/dhclient/dhcpd.h#9 edit Differences ... ==== //depot/user/pjd/capsicum/sbin/dhclient/dhcpd.h#9 (text+ko) ==== @@ -296,7 +296,7 @@ struct hash_bucket *new_hash_bucket(void); /* bpf.c */ -int if_register_bpf(struct interface_info *); +int if_register_bpf(struct interface_info *, int); void if_register_send(struct interface_info *); void if_register_receive(struct interface_info *); void send_packet(struct interface_info *, struct dhcp_packet *, size_t, Change 229479 by pjd@pjd_freefall on 2013/06/08 00:15:52 Add new request (IMSG_SEND_PACKET) that will be handled by privileged process. Affected files ... ... //depot/user/pjd/capsicum/sbin/dhclient/privsep.h#2 edit Differences ... ==== //depot/user/pjd/capsicum/sbin/dhclient/privsep.h#2 (text+ko) ==== @@ -33,7 +33,8 @@ IMSG_SCRIPT_INIT, IMSG_SCRIPT_WRITE_PARAMS, IMSG_SCRIPT_GO, - IMSG_SCRIPT_GO_RET + IMSG_SCRIPT_GO_RET, + IMSG_SEND_PACKET }; struct imsg_hdr { Change 229480 by pjd@pjd_freefall on 2013/06/08 00:17:56 Shutdown write direction of the routing socket. We only need to read from it. Affected files ... ... //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#8 edit Differences ... ==== //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#8 (text+ko) ==== @@ -476,6 +476,8 @@ if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) != -1) add_protocol("AF_ROUTE", routefd, routehandler, ifi); + if (shutdown(routefd, SHUT_WR) < 0) + error("can't shutdown route socket: %m"); /* set up the interface */ discover_interfaces(ifi); Change 229481 by pjd@pjd_freefall on 2013/06/08 00:21:22 Currently it was allowed to send any UDP packets from unprivileged process and possibility any packets because /dev/bpf was open for writing. Move sending packets to privileged process. Unprivileged process has no longer access to not connected UDP socket and has only access to /dev/bpf in read-only mode. Affected files ... ... //depot/user/pjd/capsicum/sbin/dhclient/bpf.c#9 edit ... //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#9 edit ... //depot/user/pjd/capsicum/sbin/dhclient/dhcpd.h#10 edit ... //depot/user/pjd/capsicum/sbin/dhclient/privsep.c#3 edit Differences ... ==== //depot/user/pjd/capsicum/sbin/dhclient/bpf.c#9 (text+ko) ==== @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD: head/sbin/dhclient/bpf.c 198352 2009-10-21 23:50:35Z philip $"); #include "dhcpd.h" +#include "privsep.h" #include #include @@ -260,23 +261,67 @@ } void -send_packet(struct interface_info *interface, struct dhcp_packet *raw, - size_t len, struct in_addr from, struct in_addr to) +send_packet_unpriv(int privfd, struct dhcp_packet *raw, size_t len, + struct in_addr from, struct in_addr to) +{ + struct imsg_hdr hdr; + struct buf *buf; + int errs; + + hdr.code = IMSG_SEND_PACKET; + hdr.len = sizeof(hdr) + + sizeof(size_t) + len + + sizeof(from) + sizeof(to); + + if ((buf = buf_open(hdr.len)) == NULL) + error("buf_open: %m"); + + errs = 0; + errs += buf_add(buf, &hdr, sizeof(hdr)); + errs += buf_add(buf, &len, sizeof(len)); + errs += buf_add(buf, raw, len); + errs += buf_add(buf, &from, sizeof(from)); + errs += buf_add(buf, &to, sizeof(to)); + if (errs) + error("buf_add: %m"); + + if (buf_close(privfd, buf) == -1) + error("buf_close: %m"); +} + +void +send_packet_priv(struct interface_info *interface, struct imsg_hdr *hdr, int fd) { unsigned char buf[256]; struct iovec iov[2]; struct msghdr msg; + struct dhcp_packet raw; + size_t len; + struct in_addr from, to; int result, bufp = 0; + if (hdr->len < sizeof(*hdr) + sizeof(size_t)) + error("corrupted message received"); + buf_read(fd, &len, sizeof(len)); + if (hdr->len != sizeof(*hdr) + sizeof(size_t) + len + + sizeof(from) + sizeof(to)) { + error("corrupted message received"); + } + if (len > sizeof(raw)) + error("corrupted message received"); + buf_read(fd, &raw, len); + buf_read(fd, &from, sizeof(from)); + buf_read(fd, &to, sizeof(to)); + /* Assemble the headers... */ if (to.s_addr == INADDR_BROADCAST) assemble_hw_header(interface, buf, &bufp); assemble_udp_ip_header(buf, &bufp, from.s_addr, to.s_addr, - htons(REMOTE_PORT), (unsigned char *)raw, len); + htons(REMOTE_PORT), (unsigned char *)&raw, len); iov[0].iov_base = buf; iov[0].iov_len = bufp; - iov[1].iov_base = raw; + iov[1].iov_base = &raw; iov[1].iov_len = len; /* Fire it off */ ==== //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#9 (text+ko) ==== @@ -455,11 +455,19 @@ if (gethostname(hostname, sizeof(hostname)) < 0) hostname[0] = '\0'; + /* set up the interface */ + discover_interfaces(ifi); + if (pipe(pipe_fd) == -1) error("pipe"); fork_privchld(pipe_fd[0], pipe_fd[1]); + close(ifi->ufdesc); + ifi->ufdesc = -1; + close(ifi->wfdesc); + ifi->wfdesc = -1; + close(pipe_fd[0]); privfd = pipe_fd[1]; @@ -479,9 +487,6 @@ if (shutdown(routefd, SHUT_WR) < 0) error("can't shutdown route socket: %m"); - /* set up the interface */ - discover_interfaces(ifi); - if (chroot(_PATH_VAREMPTY) == -1) error("chroot"); if (chdir("/") == -1) @@ -1233,8 +1238,8 @@ (int)ip->client->interval); /* Send out a packet. */ - send_packet(ip, &ip->client->packet, ip->client->packet_length, - inaddr_any, inaddr_broadcast); + send_packet_unpriv(privfd, &ip->client->packet, + ip->client->packet_length, inaddr_any, inaddr_broadcast); add_timeout(cur_time + ip->client->interval, send_discover, ip); } @@ -1458,8 +1463,8 @@ REMOTE_PORT); /* Send out a packet. */ - send_packet(ip, &ip->client->packet, ip->client->packet_length, - from, to); + send_packet_unpriv(privfd, &ip->client->packet, + ip->client->packet_length, from, to); add_timeout(cur_time + ip->client->interval, send_request, ip); } @@ -1473,8 +1478,8 @@ inet_ntoa(inaddr_broadcast), REMOTE_PORT); /* Send out a packet. */ - send_packet(ip, &ip->client->packet, ip->client->packet_length, - inaddr_any, inaddr_broadcast); + send_packet_unpriv(privfd, &ip->client->packet, + ip->client->packet_length, inaddr_any, inaddr_broadcast); } void @@ -2690,6 +2695,8 @@ dup2(nullfd, STDERR_FILENO); close(nullfd); close(fd2); + close(ifi->rfdesc); + ifi->rfdesc = -1; for (;;) { pfd[0].fd = fd; @@ -2701,6 +2708,6 @@ if (nfds == 0 || !(pfd[0].revents & POLLIN)) continue; - dispatch_imsg(fd); + dispatch_imsg(ifi, fd); } } ==== //depot/user/pjd/capsicum/sbin/dhclient/dhcpd.h#10 (text+ko) ==== @@ -299,8 +299,11 @@ int if_register_bpf(struct interface_info *, int); void if_register_send(struct interface_info *); void if_register_receive(struct interface_info *); -void send_packet(struct interface_info *, struct dhcp_packet *, size_t, - struct in_addr, struct in_addr); +void send_packet_unpriv(int privfd, struct dhcp_packet *raw, size_t len, + struct in_addr from, struct in_addr to); +struct imsg_hdr; +void send_packet_priv(struct interface_info *interface, struct imsg_hdr *hdr, + int fd); ssize_t receive_packet(struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *); @@ -434,4 +437,4 @@ int buf_add(struct buf *, void *, size_t); int buf_close(int, struct buf *); ssize_t buf_read(int, void *, size_t); -void dispatch_imsg(int); +void dispatch_imsg(struct interface_info *, int); ==== //depot/user/pjd/capsicum/sbin/dhclient/privsep.c#3 (text+ko) ==== @@ -101,7 +101,7 @@ } void -dispatch_imsg(int fd) +dispatch_imsg(struct interface_info *ifi, int fd) { struct imsg_hdr hdr; char *medium, *reason, *filename, @@ -232,6 +232,9 @@ if (buf_close(fd, buf) == -1) error("buf_close: %m"); break; + case IMSG_SEND_PACKET: + send_packet_priv(ifi, &hdr, fd); + break; default: error("received unknown message, code %d", hdr.code); } Change 229482 by pjd@pjd_freefall on 2013/06/08 00:24:45 - Limit bpf descriptor in unprivileged process to CAP_POLL_EVENT, CAP_READ and allow for SIOCGIFFLAGS, SIOCGIFMEDIA ioctls. - While here limit bpf descriptor in privileged process to only CAP_WRITE. Affected files ... ... //depot/user/pjd/capsicum/sbin/dhclient/bpf.c#10 edit Differences ... ==== //depot/user/pjd/capsicum/sbin/dhclient/bpf.c#10 (text+ko) ==== @@ -43,6 +43,8 @@ #include __FBSDID("$FreeBSD: head/sbin/dhclient/bpf.c 198352 2009-10-21 23:50:35Z philip $"); +#include + #include "dhcpd.h" #include "privsep.h" #include @@ -159,6 +161,9 @@ if (ioctl(info->wfdesc, BIOCLOCK, NULL) < 0) error("Cannot lock bpf"); + if (cap_rights_limit(info->wfdesc, CAP_WRITE) < 0 && errno != ENOSYS) + error("Can't limit bpf descriptor: %m"); + /* * Use raw socket for unicast send. */ @@ -208,6 +213,7 @@ void if_register_receive(struct interface_info *info) { + static const unsigned long cmds[2] = { SIOCGIFFLAGS, SIOCGIFMEDIA }; struct bpf_version v; struct bpf_program p; int flag = 1, sz; @@ -258,6 +264,13 @@ if (ioctl(info->rfdesc, BIOCLOCK, NULL) < 0) error("Cannot lock bpf"); + + if (cap_rights_limit(info->rfdesc, + CAP_IOCTL | CAP_POLL_EVENT | CAP_READ) < 0 && errno != ENOSYS) { + error("Can't limit bpf descriptor: %m"); + } + if (cap_ioctls_limit(info->rfdesc, cmds, 2) < 0 && errno != ENOSYS) + error("Can't limit ioctls for bpf descriptor: %m"); } void Change 229483 by pjd@pjd_freefall on 2013/06/08 00:26:44 Limit communication pipe with privileged process to CAP_READ and CAP_WRITE. Affected files ... ... //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#10 edit Differences ... ==== //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#10 (text+ko) ==== @@ -56,6 +56,8 @@ #include __FBSDID("$FreeBSD: head/sbin/dhclient/dhclient.c 239564 2012-08-22 13:53:37Z jhb $"); +#include + #include "dhcpd.h" #include "privsep.h" @@ -470,6 +472,10 @@ close(pipe_fd[0]); privfd = pipe_fd[1]; + if (cap_rights_limit(privfd, CAP_READ | CAP_WRITE) < 0 && + errno != ENOSYS) { + error("can't limit private descriptor: %m"); + } if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1) error("can't open and lock %s: %m", path_dhclient_db); Change 229484 by pjd@pjd_freefall on 2013/06/08 00:28:43 Limit routing socket so only poll(2) and read(2) are allowed (CAP_POLL_EVENT and CAP_READ). This prevents unprivileged process from adding, removing or modifying system routes. Affected files ... ... //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#11 edit Differences ... ==== //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#11 (text+ko) ==== @@ -492,6 +492,10 @@ add_protocol("AF_ROUTE", routefd, routehandler, ifi); if (shutdown(routefd, SHUT_WR) < 0) error("can't shutdown route socket: %m"); + if (cap_rights_limit(routefd, CAP_POLL_EVENT | CAP_READ) < 0 && + errno != ENOSYS) { + error("can't limit route socket: %m"); + } if (chroot(_PATH_VAREMPTY) == -1) error("chroot"); Change 229485 by pjd@pjd_freefall on 2013/06/08 00:29:53 Only allow to overwrite lease file. Affected files ... ... //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#12 edit Differences ... ==== //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#12 (text+ko) ==== @@ -1839,6 +1839,11 @@ leaseFile = fopen(path_dhclient_db, "w"); if (!leaseFile) error("can't create %s: %m", path_dhclient_db); + if (cap_rights_limit(fileno(leaseFile), CAP_FSTAT | CAP_FSYNC | + CAP_FTRUNCATE | CAP_SEEK | CAP_WRITE) < 0 && + errno != ENOSYS) { + error("can't limit lease descriptor: %m"); + } } else { fflush(leaseFile); rewind(leaseFile); Change 229486 by pjd@pjd_freefall on 2013/06/08 00:31:11 Once PID is written to the pidfile, revoke all capability rights. We just want to keep the pidfile open. Affected files ... ... //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#13 edit Differences ... ==== //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#13 (text+ko) ==== @@ -2355,8 +2355,13 @@ if (daemon(1, 0) == -1) error("daemon"); - if (pidfile != NULL) + if (pidfile != NULL) { pidfile_write(pidfile); + if (cap_rights_limit(pidfile_fileno(pidfile), CAP_NONE) < 0 && + errno != ENOSYS) { + error("can't limit pidfile descriptor: %m"); + } + } /* we are chrooted, daemon(3) fails to open /dev/null */ if (nullfd != -1) { Change 229487 by pjd@pjd_freefall on 2013/06/08 00:32:40 Revoke all capability rights from STDIN and allow only for write to STDOUT and STDERR. All those descriptors are redirected to /dev/null. Affected files ... ... //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#14 edit Differences ... ==== //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#14 (text+ko) ==== @@ -2371,6 +2371,13 @@ close(nullfd); nullfd = -1; } + + if (cap_rights_limit(STDIN_FILENO, CAP_NONE) < 0 && errno != ENOSYS) + error("can't limit stdin: %m"); + if (cap_rights_limit(STDOUT_FILENO, CAP_WRITE) < 0 && errno != ENOSYS) + error("can't limit stdout: %m"); + if (cap_rights_limit(STDERR_FILENO, CAP_WRITE) < 0 && errno != ENOSYS) + error("can't limit stderr: %m"); } int Change 229488 by pjd@pjd_freefall on 2013/06/08 00:33:16 Sandbox unprivileged process using capability mode. Affected files ... ... //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#15 edit Differences ... ==== //depot/user/pjd/capsicum/sbin/dhclient/dhclient.c#15 (text+ko) ==== @@ -511,6 +511,9 @@ setproctitle("%s", ifi->name); + if (cap_enter() < 0 && errno != ENOSYS) + error("can't enter capability mode: %m"); + if (immediate_daemon) go_daemon();