Ben Hutchings
2017-Dec-31 16:05 UTC
[klibc] [PATCH klibc 0/4] Fixes from Debian and Ubuntu
The following patches come from Debian and/or Ubuntu packages of klibc. Ben. Ben Hutchings (1): [klibc] run-init: Add dry-run mode Jay Vosburgh (1): [klibc] ipconfig: Use separate sockets for DHCP from multiple interfaces Mathieu Trudel-Lapierre (1): [klibc] ipconfig: Set broadcast when sending DHCPREQUEST and DHCPDISCOVER YunQiang Su (1): [klibc] mips: setjmp.S: don't save and restore floating-point registers usr/kinit/ipconfig/dhcp_proto.c | 8 ++++++- usr/kinit/ipconfig/main.c | 53 ++++++++++++++++++++++++----------------- usr/kinit/ipconfig/netdev.h | 1 + usr/kinit/ipconfig/packet.c | 39 +++++++++++++++++------------- usr/kinit/ipconfig/packet.h | 4 ++-- usr/kinit/kinit.c | 2 +- usr/kinit/run-init/run-init.c | 37 ++++++++++++++++++---------- usr/kinit/run-init/run-init.h | 5 +++- usr/kinit/run-init/runinitlib.c | 42 +++++++++++++++++++++----------- usr/klibc/arch/mips/setjmp.S | 24 ------------------- 10 files changed, 121 insertions(+), 94 deletions(-) -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: Digital signature URL: <http://www.zytor.com/pipermail/klibc/attachments/20171231/82f1a078/attachment.sig>
Ben Hutchings
2017-Dec-31 16:06 UTC
[klibc] [PATCH klibc 1/4] mips: setjmp.S: don't save and restore floating-point registers
From: YunQiang Su <wzssyqa at gmail.com> Klibc FTBFS with '-mno-odd-spreg' on mips32(el) platforms, As it try to save/restore odd-number FPR. Indeed no other architectures save/restore FPR at all. It shouldn't be needed. References: https://bugs.debian.org/789683 Signed-off-by: Ben Hutchings <ben at decadent.org.uk> --- usr/klibc/arch/mips/setjmp.S | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/usr/klibc/arch/mips/setjmp.S b/usr/klibc/arch/mips/setjmp.S index 68eed19d3286..21e41151dd41 100644 --- a/usr/klibc/arch/mips/setjmp.S +++ b/usr/klibc/arch/mips/setjmp.S @@ -29,18 +29,6 @@ LEAF(setjmp) sw s8, 40(a0) sw ra, 44(a0) cfc1 t0,$31 - swc1 $f20,48(a0) - swc1 $f21,52(a0) - swc1 $f22,56(a0) - swc1 $f23,60(a0) - swc1 $f24,64(a0) - swc1 $f25,68(a0) - swc1 $f26,72(a0) - swc1 $f27,76(a0) - swc1 $f28,80(a0) - swc1 $f29,84(a0) - swc1 $f30,88(a0) - swc1 $f31,92(a0) sw t0,96(a0) move v0,zero jr ra @@ -61,18 +49,6 @@ LEAF(longjmp) lw s8, 40(a0) lw ra, 44(a0) lw t0, 96(a0) - lwc1 $f20,48(a0) - lwc1 $f21,52(a0) - lwc1 $f22,56(a0) - lwc1 $f23,60(a0) - lwc1 $f24,64(a0) - lwc1 $f25,68(a0) - lwc1 $f26,72(a0) - lwc1 $f27,76(a0) - lwc1 $f28,80(a0) - lwc1 $f29,84(a0) - lwc1 $f30,88(a0) - lwc1 $f31,92(a0) ctc1 t0,$31 move v0,a1 jr ra -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: Digital signature URL: <http://www.zytor.com/pipermail/klibc/attachments/20171231/e6007c2b/attachment.sig>
initramfs-tools wants to validate the real init program before running it, as there is no way out once it has exec'd run-init. This is complicated by the increasing use of symlinks for /sbin/init and for /sbin itself. We can't simply resolve them with 'readlink -f' because any absolute symlinks will be resolved using the wrong root. Add a dry-run mode (-n option) to run-init that goes as far as possible to validate that the given init is executable. References: https://bugs.debian.org/810965 Signed-off-by: Ben Hutchings <ben at decadent.org.uk> --- usr/kinit/kinit.c | 2 +- usr/kinit/run-init/run-init.c | 37 +++++++++++++++++++++++------------- usr/kinit/run-init/run-init.h | 5 ++++- usr/kinit/run-init/runinitlib.c | 42 +++++++++++++++++++++++++++-------------- 4 files changed, 57 insertions(+), 29 deletions(-) diff --git a/usr/kinit/kinit.c b/usr/kinit/kinit.c index 523c92bfe2ba..de03c2d318b1 100644 --- a/usr/kinit/kinit.c +++ b/usr/kinit/kinit.c @@ -304,7 +304,7 @@ int main(int argc, char *argv[]) init_argv[0] = strrchr(init_path, '/') + 1; errmsg = run_init("/root", "/dev/console", - get_arg(cmdc, cmdv, "drop_capabilities="), + get_arg(cmdc, cmdv, "drop_capabilities="), false, init_path, init_argv); /* If run_init returned, something went bad */ diff --git a/usr/kinit/run-init/run-init.c b/usr/kinit/run-init/run-init.c index 2147d06dfa1e..a14ce7cce25d 100644 --- a/usr/kinit/run-init/run-init.c +++ b/usr/kinit/run-init/run-init.c @@ -26,19 +26,23 @@ * ----------------------------------------------------------------------- */ /* - * Usage: exec run-init [-d caps] [-c /dev/console] /real-root /sbin/init "$@" + * Usage: exec run-init [-d caps] [-c /dev/console] [-n] /real-root /sbin/init "$@" * * This program should be called as the last thing in a shell script * acting as /init in an initramfs; it does the following: * - * - Delete all files in the initramfs; - * - Remounts /real-root onto the root filesystem; - * - Drops comma-separated list of capabilities; - * - Chroots; - * - Opens /dev/console; - * - Spawns the specified init program (with arguments.) + * 1. Delete all files in the initramfs; + * 2. Remounts /real-root onto the root filesystem; + * 3. Drops comma-separated list of capabilities; + * 4. Chroots; + * 5. Opens /dev/console; + * 6. Spawns the specified init program (with arguments.) + * + * With the -n option, it skips steps 1, 2 and 6 and can be used to check + * whether the given root and init are likely to work. */ +#include <stdbool.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> @@ -51,7 +55,7 @@ static const char *program; static void __attribute__ ((noreturn)) usage(void) { fprintf(stderr, - "Usage: exec %s [-d caps] [-c consoledev] /real-root /sbin/init [args]\n", + "Usage: exec %s [-d caps] [-c consoledev] [-n] /real-root /sbin/init [args]\n", program); exit(1); } @@ -64,6 +68,7 @@ int main(int argc, char *argv[]) const char *init; const char *error; const char *drop_caps = NULL; + bool dry_run = false; char **initargs; /* Variables... */ @@ -72,11 +77,13 @@ int main(int argc, char *argv[]) /* Parse the command line */ program = argv[0]; - while ((o = getopt(argc, argv, "c:d:")) != -1) { + while ((o = getopt(argc, argv, "c:d:n")) != -1) { if (o == 'c') { console = optarg; } else if (o == 'd') { drop_caps = optarg; + } else if (o == 'n') { + dry_run = true; } else { usage(); } @@ -89,9 +96,13 @@ int main(int argc, char *argv[]) init = argv[optind + 1]; initargs = argv + optind + 1; - error = run_init(realroot, console, drop_caps, init, initargs); + error = run_init(realroot, console, drop_caps, dry_run, init, initargs); - /* If run_init returns, something went wrong */ - fprintf(stderr, "%s: %s: %s\n", program, error, strerror(errno)); - return 1; + if (error) { + fprintf(stderr, "%s: %s: %s\n", program, error, strerror(errno)); + return 1; + } else { + /* Must have been a dry run */ + return 0; + } } diff --git a/usr/kinit/run-init/run-init.h b/usr/kinit/run-init/run-init.h index da3136a76a7e..02c34aa23b99 100644 --- a/usr/kinit/run-init/run-init.h +++ b/usr/kinit/run-init/run-init.h @@ -28,7 +28,10 @@ #ifndef RUN_INIT_H #define RUN_INIT_H +#include <stdbool.h> + const char *run_init(const char *realroot, const char *console, - const char *drop_caps, const char *init, char **initargs); + const char *drop_caps, bool dry_run, + const char *init, char **initargs); #endif diff --git a/usr/kinit/run-init/runinitlib.c b/usr/kinit/run-init/runinitlib.c index fe856bd64a5a..74d7883f8e4d 100644 --- a/usr/kinit/run-init/runinitlib.c +++ b/usr/kinit/run-init/runinitlib.c @@ -156,10 +156,10 @@ static int nuke(const char *what) } const char *run_init(const char *realroot, const char *console, - const char *drop_caps, const char *init, + const char *drop_caps, bool dry_run, const char *init, char **initargs) { - struct stat rst, cst; + struct stat rst, cst, ist; struct statfs sfs; int confd; @@ -186,13 +186,15 @@ const char *run_init(const char *realroot, const char *console, /* Okay, I think we should be safe... */ - /* Delete rootfs contents */ - if (nuke_dir("/")) - return "nuking initramfs contents"; + if (!dry_run) { + /* Delete rootfs contents */ + if (nuke_dir("/")) + return "nuking initramfs contents"; - /* Overmount the root */ - if (mount(".", "/", NULL, MS_MOVE, NULL)) - return "overmounting root"; + /* Overmount the root */ + if (mount(".", "/", NULL, MS_MOVE, NULL)) + return "overmounting root"; + } /* chroot, chdir */ if (chroot(".") || chdir("/")) @@ -205,12 +207,24 @@ const char *run_init(const char *realroot, const char *console, /* Open /dev/console */ if ((confd = open(console, O_RDWR)) < 0) return "opening console"; - dup2(confd, 0); - dup2(confd, 1); - dup2(confd, 2); + if (!dry_run) { + dup2(confd, 0); + dup2(confd, 1); + dup2(confd, 2); + } close(confd); - /* Spawn init */ - execv(init, initargs); - return init; /* Failed to spawn init */ + if (!dry_run) { + /* Spawn init */ + execv(init, initargs); + return init; /* Failed to spawn init */ + } else { + if (stat(init, &ist)) + return init; + if (!S_ISREG(ist.st_mode) || !(ist.st_mode & S_IXUGO)) { + errno = EACCES; + return init; + } + return NULL; /* Success */ + } } -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: Digital signature URL: <http://www.zytor.com/pipermail/klibc/attachments/20171231/99d8f000/attachment.sig>
Ben Hutchings
2017-Dec-31 16:07 UTC
[klibc] [PATCH klibc 3/4] ipconfig: Set broadcast when sending DHCPREQUEST and DHCPDISCOVER
From: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre at canonical.com> We need to do this, since our devices are probably not configured yet and there may be more than one device we're trying to do DHCP on on the same network. Otherwise, things might be dropped. Patch is originally from here: https://bugs.launchpad.net/ubuntu/+source/klibc/+bug/1327412/comments/5 ... but the reporter "patpat" has not provided contact information, and this is independently verifiable by looking at RFC 2131, section 4.1, page 24. References: https://bugs.debian.org/733988 References: https://bugs.launchpad.net/bugs/1327412 Signed-off-by: Ben Hutchings <ben at decadent.org.uk> --- usr/kinit/ipconfig/dhcp_proto.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/usr/kinit/ipconfig/dhcp_proto.c b/usr/kinit/ipconfig/dhcp_proto.c index ebf79cc0b5f7..d5b759bbc16b 100644 --- a/usr/kinit/ipconfig/dhcp_proto.c +++ b/usr/kinit/ipconfig/dhcp_proto.c @@ -201,8 +201,14 @@ static int dhcp_send(struct netdev *dev, struct iovec *vec) bootp.hlen = dev->hwlen; bootp.xid = dev->bootp.xid; bootp.ciaddr = INADDR_ANY; - bootp.yiaddr = dev->ip_addr; + /* yiaddr should always be set to 0 for the messages we're likely + * to send as a DHCP client: DHCPDISCOVER, DHCPREQUEST, DHCPDECLINE, + * DHCPINFORM, DHCPRELEASE + * cf. RFC2131 section 4.1.1, table 5. + */ + bootp.yiaddr = INADDR_ANY; bootp.giaddr = INADDR_ANY; + bootp.flags = htons(0x8000); bootp.secs = htons(time(NULL) - dev->open_time); memcpy(bootp.chaddr, dev->hwaddr, 16); -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: Digital signature URL: <http://www.zytor.com/pipermail/klibc/attachments/20171231/fcb291d5/attachment-0001.sig>
Ben Hutchings
2017-Dec-31 16:07 UTC
[klibc] [PATCH klibc 4/4] ipconfig: Use separate sockets for DHCP from multiple interfaces
From: Jay Vosburgh <jay.vosburgh at canonical.com> Previously ipconfig would use a single multiplexed packet socket to listen for DHCP responses on multiple interfaces. This fails if the interface that responds is not the first one enumerated by the kernel, because ipconfig looks for responses in interface order and is throwing them away if they're not a proper match. Fix this by using a separate socket for each interface so that each response is processed in a correct context. References: https://bugs.debian.org/852480 References: https://bugs.launchpad.net/bugs/1652348 Signed-off-by: Ben Hutchings <ben at decadent.org.uk> --- usr/kinit/ipconfig/main.c | 53 ++++++++++++++++++++++++++------------------- usr/kinit/ipconfig/netdev.h | 1 + usr/kinit/ipconfig/packet.c | 39 +++++++++++++++++++-------------- usr/kinit/ipconfig/packet.h | 4 ++-- 4 files changed, 57 insertions(+), 40 deletions(-) diff --git a/usr/kinit/ipconfig/main.c b/usr/kinit/ipconfig/main.c index 7be2a1fcb5af..e00f049173fb 100644 --- a/usr/kinit/ipconfig/main.c +++ b/usr/kinit/ipconfig/main.c @@ -30,6 +30,7 @@ static unsigned int default_caps = CAP_DHCP | CAP_BOOTP | CAP_RARP; static int loop_timeout = -1; static int configured; static int bringup_first = 0; +static int n_devices = 0; /* DHCP vendor class identifier */ char vendor_class_identifier[260]; @@ -220,6 +221,7 @@ static void complete_device(struct netdev *dev) configure_device(dev); dump_device_config(dev); print_device_config(dev); + packet_close(dev); ++configured; @@ -374,34 +376,35 @@ struct netdev *ifaces; * 0 = No dhcp/bootp packet was received * 1 = A packet was received and handled */ -static int do_pkt_recv(int pkt_fd, time_t now) +static int do_pkt_recv(int nr, struct pollfd *fds, time_t now) { - int ret = 0; + int i, ret = 0; struct state *s; - for (s = slist; s; s = s->next) - ret |= process_receive_event(s, now); + for (i = 0, s = slist; s && nr; s = s->next, i++) { + if (fds[i].revents & POLLRDNORM) { + ret |= process_receive_event(s, now); + nr--; + } + } return ret; } static int loop(void) { -#define NR_FDS 1 - struct pollfd fds[NR_FDS]; + struct pollfd *fds; struct state *s; - int pkt_fd; - int nr = 0, rc = 0; + int i, nr = 0, rc = 0; struct timeval now, prev; time_t start; - pkt_fd = packet_open(); - if (pkt_fd == -1) { - perror("packet_open"); - return -1; + fds = malloc(sizeof(struct pollfd) * n_devices); + if (!fds) { + fprintf(stderr, "malloc failed\n"); + goto bail; } - fds[0].fd = pkt_fd; - fds[0].events = POLLRDNORM; + memset(fds, 0, sizeof(*fds)); gettimeofday(&now, NULL); start = now.tv_sec; @@ -412,9 +415,12 @@ static int loop(void) int timeout_ms; int x; - for (s = slist; s; s = s->next) { + for (i = 0, s = slist; s; s = s->next, i++) { dprintf("%s: state = %d\n", s->dev->name, s->state); + fds[i].fd = s->dev->pkt_fd; + fds[i].events = POLLRDNORM; + if (s->state == DEVST_COMPLETE) { done++; continue; @@ -442,14 +448,12 @@ static int loop(void) if (timeout_ms <= 0) timeout_ms = 100; - nr = poll(fds, NR_FDS, timeout_ms); + nr = poll(fds, n_devices, timeout_ms); prev = now; gettimeofday(&now, NULL); - if ((nr > 0) && (fds[0].revents & POLLRDNORM)) { - if (do_pkt_recv(pkt_fd, now.tv_sec) == 1) - break; - } + if ((nr > 0) && do_pkt_recv(nr, fds, now.tv_sec)) + break; if (loop_timeout >= 0 && now.tv_sec - start >= loop_timeout) { @@ -468,8 +472,8 @@ static int loop(void) } } bail: - packet_close(); - + if (fds) + free(fds); return rc; } @@ -498,6 +502,8 @@ static int add_one_dev(struct netdev *dev) state->next = slist; slist = state; + n_devices++; + return 0; } @@ -675,6 +681,9 @@ static struct netdev *add_device(const char *info) if (bootp_init_if(dev) == -1) goto bail; + if (packet_open(dev) == -1) + goto bail; + printf("IP-Config: %s hardware address", dev->name); for (i = 0; i < dev->hwlen; i++) printf("%c%02x", i == 0 ? ' ' : ':', dev->hwaddr[i]); diff --git a/usr/kinit/ipconfig/netdev.h b/usr/kinit/ipconfig/netdev.h index cd853b6c078b..4b75a65ad067 100644 --- a/usr/kinit/ipconfig/netdev.h +++ b/usr/kinit/ipconfig/netdev.h @@ -45,6 +45,7 @@ struct netdev { char filename[FNLEN]; /* filename */ char *domainsearch; /* decoded, NULL or malloc-ed */ long uptime; /* when complete configuration */ + int pkt_fd; /* packet socket for this interface */ struct netdev *next; /* next configured i/f */ }; diff --git a/usr/kinit/ipconfig/packet.c b/usr/kinit/ipconfig/packet.c index 446073aba2ae..200180109f2d 100644 --- a/usr/kinit/ipconfig/packet.c +++ b/usr/kinit/ipconfig/packet.c @@ -1,3 +1,4 @@ +#include <errno.h>/*XXX*/ /* * Packet socket handling glue. */ @@ -20,17 +21,13 @@ #include "netdev.h" #include "packet.h" -static int pkt_fd = -1; - uint16_t cfg_local_port = LOCAL_PORT; uint16_t cfg_remote_port = REMOTE_PORT; -int packet_open(void) +int packet_open(struct netdev *dev) { - int fd, one = 1; - - if (pkt_fd != -1) - return pkt_fd; + struct sockaddr_ll sll; + int fd, rv, one = 1; /* * Get a PACKET socket for IP traffic. @@ -48,18 +45,28 @@ int packet_open(void) sizeof(one)) == -1) { perror("SO_BROADCAST"); close(fd); - fd = -1; + return -1; } - pkt_fd = fd; + memset(&sll, 0, sizeof(sll)); + sll.sll_family = AF_PACKET; + sll.sll_ifindex = dev->ifindex; + + rv = bind(fd, (struct sockaddr *)&sll, sizeof(sll)); + if (-1 == rv) { + perror("bind"); + close(fd); + return -1; + } + dev->pkt_fd = fd; return fd; } -void packet_close(void) +void packet_close(struct netdev *dev) { - close(pkt_fd); - pkt_fd = -1; + close(dev->pkt_fd); + dev->pkt_fd = -1; } static unsigned int ip_checksum(uint16_t *hdr, int len) @@ -163,7 +170,7 @@ int packet_send(struct netdev *dev, struct iovec *iov, int iov_len) dprintf("\n bytes %d\n", len); - return sendmsg(pkt_fd, &msg, 0); + return sendmsg(dev->pkt_fd, &msg, 0); } void packet_discard(struct netdev *dev) @@ -174,7 +181,7 @@ void packet_discard(struct netdev *dev) sll.sll_ifindex = dev->ifindex; - recvfrom(pkt_fd, &iph, sizeof(iph), 0, + recvfrom(dev->pkt_fd, &iph, sizeof(iph), 0, (struct sockaddr *)&sll, &sllen); } @@ -207,7 +214,7 @@ int packet_recv(struct netdev *dev, struct iovec *iov, int iov_len) msg.msg_name = &sll; msg.msg_namelen = sllen; - ret = recvfrom(pkt_fd, &iph, sizeof(struct iphdr), + ret = recvfrom(dev->pkt_fd, &iph, sizeof(struct iphdr), MSG_PEEK, (struct sockaddr *)&sll, &sllen); if (ret == -1) return -1; @@ -226,7 +233,7 @@ int packet_recv(struct netdev *dev, struct iovec *iov, int iov_len) iov[0].iov_base = ip; iov[0].iov_len = iphl + sizeof(struct udphdr); - ret = recvmsg(pkt_fd, &msg, 0); + ret = recvmsg(dev->pkt_fd, &msg, 0); if (ret == -1) goto free_pkt; diff --git a/usr/kinit/ipconfig/packet.h b/usr/kinit/ipconfig/packet.h index f6cef5210958..4367efe1428e 100644 --- a/usr/kinit/ipconfig/packet.h +++ b/usr/kinit/ipconfig/packet.h @@ -3,8 +3,8 @@ struct iovec; -int packet_open(void); -void packet_close(void); +int packet_open(struct netdev *dev); +void packet_close(struct netdev *dev); int packet_send(struct netdev *dev, struct iovec *iov, int iov_len); void packet_discard(struct netdev *dev); int packet_recv(struct netdev *dev, struct iovec *iov, int iov_len); -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: Digital signature URL: <http://www.zytor.com/pipermail/klibc/attachments/20171231/8adba060/attachment.sig>
Maybe Matching Threads
- [PATCH klibc] run-init: Add dry-run mode
- [PATCH] run-init: add drop_capabilities support
- [PATCH] Allow the initramfs to be persisted across root changes
- [PATCH 0/8] switch_root() enhancements
- [PATCH v1 0/2] Support dropping of capabilities from early userspace.