[syslinux:master] pxe: fix bugs in DHCP parsing and config file selection

syslinux-bot for H. Peter Anvin hpa at linux.intel.com
Tue Jun 22 15:06:11 PDT 2010


Commit-ID:  dac76ca3c28968eebf0e30c38ade5b5bf8bf7bd3
Gitweb:     http://syslinux.zytor.com/commit/dac76ca3c28968eebf0e30c38ade5b5bf8bf7bd3
Author:     H. Peter Anvin <hpa at linux.intel.com>
AuthorDate: Tue, 22 Jun 2010 15:03:29 -0700
Committer:  H. Peter Anvin <hpa at linux.intel.com>
CommitDate: Tue, 22 Jun 2010 15:03:29 -0700

pxe: fix bugs in DHCP parsing and config file selection

Fix several buffer-handling bugs in DHCP parsing and in the config
file selection.

Signed-off-by: H. Peter Anvin <hpa at linux.intel.com>


---
 core/fs/pxe/dhcp_option.c |  109 ++++++++++++++++++++++-----------------------
 core/fs/pxe/pxe.c         |    8 ++--
 2 files changed, 57 insertions(+), 60 deletions(-)

diff --git a/core/fs/pxe/dhcp_option.c b/core/fs/pxe/dhcp_option.c
index d50b631..ab0f4c0 100644
--- a/core/fs/pxe/dhcp_option.c
+++ b/core/fs/pxe/dhcp_option.c
@@ -10,23 +10,23 @@ int over_load;
 uint8_t uuid_type;
 char uuid[17];
 
-static void parse_dhcp_options(void *, int, uint8_t);
+static void parse_dhcp_options(const void *, int, uint8_t);
 
-static void subnet_mask(void *data, int opt_len)
+static void subnet_mask(const void *data, int opt_len)
 {
     if (opt_len != 4)
 	return;
-    IPInfo.netmask = *(uint32_t *)data;
+    IPInfo.netmask = *(const uint32_t *)data;
 }
 
-static void router(void *data, int opt_len)
+static void router(const void *data, int opt_len)
 {
     if (opt_len != 4)
 	return;
-    IPInfo.gateway = *(uint32_t *)data;
+    IPInfo.gateway = *(const uint32_t *)data;
 }
 
-static void dns_servers(void *data, int opt_len)
+static void dns_servers(const void *data, int opt_len)
 {
     const uint32_t *dp = data;
     int num = 0;
@@ -46,32 +46,31 @@ static void dns_servers(void *data, int opt_len)
 	dns_server[num++] = 0;
 }
 
-static void local_domain(void *data, int opt_len)
+static void local_domain(const void *data, int opt_len)
 {
-    char *p = (char *)data + opt_len;
+    char buffer[256];
     char *ld = LocalDomain;
-    char end = *p;
 
-    *p = '\0';   /* Zero-terminate option */
-    dns_mangle(&ld, data);
-    *p = end;    /* Restore ending byte */
+    memcpy(buffer, data, opt_len);
+    buffer[opt_len] = 0;
+
+    dns_mangle(&ld, buffer);
 }
 
-static void vendor_encaps(void *data, int opt_len)
+static void vendor_encaps(const void *data, int opt_len)
 {
-    /* Only recongnize PXELINUX options */
+    /* Only recognize PXELINUX options */
     parse_dhcp_options(data, opt_len, 208);
 }
 
-static void option_overload(void *data, int opt_len)
+static void option_overload(const void *data, int opt_len)
 {
     if (opt_len != 1)
 	return;
     over_load = *(uint8_t *)data;
 }
 
-
-static void server(void *data, int opt_len)
+static void server(const void *data, int opt_len)
 {
     uint32_t ip;
 
@@ -86,7 +85,7 @@ static void server(void *data, int opt_len)
         IPInfo.serverip = ip;
 }
 
-static void client_identifier(void *data, int opt_len)
+static void client_identifier(const void *data, int opt_len)
 {
     if (opt_len > MAC_MAX || opt_len < 2 ||
         MAC_len != (opt_len >> 8) ||
@@ -99,15 +98,15 @@ static void client_identifier(void *data, int opt_len)
     MAC[opt_len] = 0;
 }
 
-static void bootfile_name(void *data, int opt_len)
+static void bootfile_name(const void *data, int opt_len)
 {
-    strncpy(boot_file, data, opt_len);
+    memcpy(boot_file, data, opt_len);
     boot_file[opt_len] = 0;
 }
 
-static void uuid_client_identifier(void *data, int opt_len)
+static void uuid_client_identifier(const void *data, int opt_len)
 {
-    int type = *(uint8_t *)data;
+    int type = *(const uint8_t *)data;
     if (opt_len != 17 || type != 0 || have_uuid)
         return;
 
@@ -117,36 +116,36 @@ static void uuid_client_identifier(void *data, int opt_len)
     uuid[16] = 0;
 }
 
-static void pxelinux_configfile(void *data, int opt_len)
+static void pxelinux_configfile(const void *data, int opt_len)
 {
     DHCPMagic |= 2;
-    strncpy(ConfigName, data, opt_len);
+    memcpy(ConfigName, data, opt_len);
     ConfigName[opt_len] = 0;
 }
 
-static void pxelinux_pathprefix(void *data, int opt_len)
+static void pxelinux_pathprefix(const void *data, int opt_len)
 {
     DHCPMagic |= 4;
-    strncpy(path_prefix, data, opt_len);
+    memcpy(path_prefix, data, opt_len);
     path_prefix[opt_len] = 0;
 }
 
-static void pxelinux_reboottime(void *data, int opt_len)
+static void pxelinux_reboottime(const void *data, int opt_len)
 {
-    if ((opt_len && 0xff) != 4)
-        return ;
+    if (opt_len != 4)
+        return;
 
-    RebootTime = ntohl(*(uint32_t *)data);
+    RebootTime = ntohl(*(const uint32_t *)data);
     DHCPMagic |= 8;     /* Got reboot time */
 }
 
 
 struct dhcp_options {
     int opt_num;
-    void (*fun) (void *, int);
+    void (*fun)(const void *, int);
 };
 
-static struct dhcp_options dhcp_opts[] = {
+static const struct dhcp_options dhcp_opts[] = {
     {1,   subnet_mask},
     {3,   router},
     {6,   dns_servers},
@@ -170,43 +169,41 @@ static struct dhcp_options dhcp_opts[] = {
  * filter  contains the minimum value for the option to recognize
  * -- this is used to restrict parsing to PXELINUX-specific options only.
  */
-static void parse_dhcp_options(void *option, int size, uint8_t opt_filter)
+static void parse_dhcp_options(const void *option, int size, uint8_t opt_filter)
 {
-    uint8_t opt_num;
-    uint8_t opt_len;
-    int opt_entries = sizeof(dhcp_opts) / sizeof(dhcp_opts[0]);
+    int opt_num;
+    int opt_len;
+    const int opt_entries = sizeof(dhcp_opts) / sizeof(dhcp_opts[0]);
     int i = 0;
-    char *p = option;
-    struct dhcp_options *opt;
+    const uint8_t *p = option;
+    const struct dhcp_options *opt;
 
-    while (size--) {
+    /* The only 1-byte options are 00 and FF, neither of which matter */
+    while (size >= 2) {
         opt_num = *p++;
+	size--;
 
-        if (!size)
-            break;
         if (opt_num == 0)
             continue;
         if (opt_num == 0xff)
             break;
 
-        /* Anything else will have a lenght filed */
+        /* Anything else will have a length field */
         opt_len = *p++; /* c  <- option lenght */
-        size = size - opt_len - 1;
+        size -= opt_len + 1;
         if (size < 0)
             break;
-        if (opt_num < opt_filter) {       /* Is the option value valid */
-            option += opt_len;   /* Try next */
-            continue;
-        }
 
-        opt = dhcp_opts;
-        for (i = 0; i < opt_entries; i++) {
-            if (opt_num == opt->opt_num) {
-                opt->fun(p, opt_len);
-                break;
-            }
-            opt ++;
-        }
+	if (opt_num >= opt_filter) {
+	    opt = dhcp_opts;
+	    for (i = 0; i < opt_entries; i++) {
+		if (opt_num == opt->opt_num) {
+		    opt->fun(p, opt_len);
+		    break;
+		}
+		opt++;
+	    }
+	}
 
         /* parse next */
         p += opt_len;
@@ -255,7 +252,7 @@ void parse_dhcp(int pkt_len)
     if (over_load & 1)
         parse_dhcp_options(&dhcp->bootfile, 128, 0);
     else if (dhcp->bootfile[0])
-            strcpy(boot_file, dhcp->bootfile);
+	strcpy(boot_file, dhcp->bootfile);
 
     if (over_load & 2)
         parse_dhcp_options(dhcp->sname, 64, 0);
diff --git a/core/fs/pxe/pxe.c b/core/fs/pxe/pxe.c
index 4154fd5..0f27b2d 100644
--- a/core/fs/pxe/pxe.c
+++ b/core/fs/pxe/pxe.c
@@ -1045,6 +1045,7 @@ static int try_load(char *config_name)
     regs.edi.w[0] = OFFS_WRT(KernelName, 0);
     call16(core_open, &regs, &regs);
     if (regs.eflags.l & EFLAGS_ZF) {
+	strcpy(ConfigName, KernelName);
         printf("\r");
         return 0;
     } else {
@@ -1067,15 +1068,14 @@ static int pxe_load_config(void)
     get_prefix();
     if (DHCPMagic & 0x02) {
         /* We got a DHCP option, try it first */
-	if (try_load(boot_file))
+	if (try_load(ConfigName))
 	    return 0;
     }
 
     /*
      * Have to guess config file name ...
      */
-    memcpy(ConfigName, cfgprefix, strlen(cfgprefix));
-    config_file = ConfigName + strlen(cfgprefix);
+    config_file = stpcpy(ConfigName, cfgprefix);
 
     /* Try loading by UUID */
     if (have_uuid) {
@@ -1105,7 +1105,7 @@ static int pxe_load_config(void)
         return 0;
 
     /* Nope, try hexadecimal IP prefixes... */
-    uchexbytes(config_file, (uint8_t *)&IPInfo.myip, 4);     /* Convet to hex string */
+    uchexbytes(config_file, (uint8_t *)&IPInfo.myip, 4);
     last = &config_file[8];
     while (tries) {
         *last = '\0';        /* Zero-terminate string */



More information about the Syslinux-commits mailing list