]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
net/dhcp: Allow overloading legacy bootfile and name field
authorAndrei Borzenkov <arvidjaar@gmail.com>
Thu, 7 Mar 2019 15:14:09 +0000 (15:14 +0000)
committerDaniel Kiper <daniel.kiper@oracle.com>
Tue, 12 Mar 2019 19:04:07 +0000 (20:04 +0100)
DHCP specifies a special dummy option OVERLOAD, to allow DHCP options to
spill over into the (legacy) BOOTFILE and SNAME fields.

Parse and handle this option properly.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
grub-core/net/bootp.c
include/grub/net.h

index 8d6763689a61b47626eba0e261babcae89242520..860d9c80d5e48cd3ade56f3c49a359119e17865c 100644 (file)
 #include <grub/net/udp.h>
 #include <grub/datetime.h>
 
+enum
+{
+  GRUB_DHCP_OPT_OVERLOAD_FILE = 1,
+  GRUB_DHCP_OPT_OVERLOAD_SNAME = 2,
+};
+
 static const void *
 find_dhcp_option (const struct grub_net_bootp_packet *bp, grub_size_t size,
                  grub_uint8_t opt_code, grub_uint8_t *opt_len)
 {
   const grub_uint8_t *ptr;
+  grub_uint8_t overload = 0;
+  int end = 0;
   grub_size_t i;
 
   if (opt_len)
@@ -54,6 +62,7 @@ find_dhcp_option (const struct grub_net_bootp_packet *bp, grub_size_t size,
   size -= sizeof (*bp);
   i = sizeof (grub_uint32_t);
 
+again:
   while (i < size)
     {
       grub_uint8_t tagtype;
@@ -67,7 +76,10 @@ find_dhcp_option (const struct grub_net_bootp_packet *bp, grub_size_t size,
 
       /* End tag.  */
       if (tagtype == GRUB_NET_BOOTP_END)
-       break;
+       {
+         end = 1;
+         break;
+       }
 
       if (i >= size)
        return NULL;
@@ -84,9 +96,54 @@ find_dhcp_option (const struct grub_net_bootp_packet *bp, grub_size_t size,
          return &ptr[i];
        }
 
+      if (tagtype == GRUB_NET_DHCP_OVERLOAD && taglength == 1)
+       overload = ptr[i];
+
       i += taglength;
     }
 
+  if (!end)
+    return NULL;
+
+  /* RFC2131, 4.1, 23ff:
+   * If the options in a DHCP message extend into the 'sname' and 'file'
+   * fields, the 'option overload' option MUST appear in the 'options'
+   * field, with value 1, 2 or 3, as specified in RFC 1533.  If the
+   * 'option overload' option is present in the 'options' field, the
+   * options in the 'options' field MUST be terminated by an 'end' option,
+   * and MAY contain one or more 'pad' options to fill the options field.
+   * The options in the 'sname' and 'file' fields (if in use as indicated
+   * by the 'options overload' option) MUST begin with the first octet of
+   * the field, MUST be terminated by an 'end' option, and MUST be
+   * followed by 'pad' options to fill the remainder of the field.  Any
+   * individual option in the 'options', 'sname' and 'file' fields MUST be
+   * entirely contained in that field.  The options in the 'options' field
+   * MUST be interpreted first, so that any 'option overload' options may
+   * be interpreted.  The 'file' field MUST be interpreted next (if the
+   * 'option overload' option indicates that the 'file' field contains
+   * DHCP options), followed by the 'sname' field.
+   *
+   * FIXME: We do not explicitly check for trailing 'pad' options here.
+   */
+  end = 0;
+  if (overload & GRUB_DHCP_OPT_OVERLOAD_FILE)
+  {
+    overload &= ~GRUB_DHCP_OPT_OVERLOAD_FILE;
+    ptr = (grub_uint8_t *) &bp->boot_file[0];
+    size = sizeof (bp->boot_file);
+    i = 0;
+    goto again;
+  }
+
+  if (overload & GRUB_DHCP_OPT_OVERLOAD_SNAME)
+  {
+    overload &= ~GRUB_DHCP_OPT_OVERLOAD_SNAME;
+    ptr = (grub_uint8_t *) &bp->server_name[0];
+    size = sizeof (bp->server_name);
+    i = 0;
+    goto again;
+  }
+
   return NULL;
 }
 
index 1096b24322eb1ba36e8c996872fce2a255e6bccc..0c7286bd249d5e29893b7e1c62c537a13959c53b 100644 (file)
@@ -457,6 +457,7 @@ enum
     GRUB_NET_BOOTP_DOMAIN = 0x0f,
     GRUB_NET_BOOTP_ROOT_PATH = 0x11,
     GRUB_NET_BOOTP_EXTENSIONS_PATH = 0x12,
+    GRUB_NET_DHCP_OVERLOAD = 52,
     GRUB_NET_BOOTP_END = 0xff
   };