]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[http] Allow issuing requests with an explicitly specified HTTP method
authorMichael Brown <mcb30@ipxe.org>
Mon, 13 Jul 2026 14:39:00 +0000 (15:39 +0100)
committerMichael Brown <mcb30@ipxe.org>
Mon, 13 Jul 2026 15:43:54 +0000 (16:43 +0100)
The design of IMDSv2 within both AWS and Alibaba Cloud requires the
client to obtain a temporary token via an HTTP PUT request.  There is
no authentication on this request and there is no associated request
body: the requirement to use PUT exists solely to reduce the attack
surface for SSRF attacks (since vulnerable servers are much more
likely to be able to be tricked into issuing a GET request than a PUT
request).

iPXE can currently issue requests using HTTP GET (if the request body
is empty) or HTTP POST (if the request body includes form parameters).
There is no support for issuing a PUT request, or for allowing a
script to explicitly specify the HTTP method.

Add a "--method" option to the "params" command to allow an arbitrary
request method name to be specified, and use this as the HTTP request
method.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/core/params.c
src/hci/commands/param_cmd.c
src/include/ipxe/http.h
src/include/ipxe/params.h
src/net/tcp/httpcore.c
src/tests/uri_test.c

index b14accafec9feeed7de82ed9bf860e134a30a3e4..bd96501d721c677c1378fe887e6c3c6c430d48c8 100644 (file)
@@ -83,12 +83,16 @@ struct parameters * find_parameters ( const char *name ) {
  * Create request parameter list
  *
  * @v name             Parameter list name (may be NULL)
+ * @v method           Method name (may be NULL)
  * @ret params         Parameter list, or NULL on failure
  */
-struct parameters * create_parameters ( const char *name ) {
+struct parameters * create_parameters ( const char *name,
+                                       const char *method ) {
        struct parameters *params;
        size_t name_len;
+       size_t method_len;
        char *name_copy;
+       char *method_copy;
 
        /* Destroy any existing parameter list of this name */
        params = find_parameters ( name );
@@ -99,23 +103,33 @@ struct parameters * create_parameters ( const char *name ) {
 
        /* Allocate parameter list */
        name_len = ( name ? ( strlen ( name ) + 1 /* NUL */ ) : 0 );
-       params = zalloc ( sizeof ( *params ) + name_len );
+       method_len = ( method ? ( strlen ( method ) + 1 /* NUL */ ) : 0 );
+       params = zalloc ( sizeof ( *params ) + name_len + method_len );
        if ( ! params )
                return NULL;
        ref_init ( &params->refcnt, free_parameters );
-       name_copy = ( ( void * ) ( params + 1 ) );
+       name_copy = ( ( ( void * ) params ) + sizeof ( *params ) );
+       method_copy = ( ( ( void * ) name_copy ) + name_len );
 
        /* Populate parameter list */
        if ( name ) {
                strcpy ( name_copy, name );
                params->name = name_copy;
        }
+       if ( method ) {
+               strcpy ( method_copy, method );
+               params->method = method_copy;
+       }
        INIT_LIST_HEAD ( &params->entries );
 
        /* Add to list of parameter lists */
        list_add_tail ( &params->list, &parameters );
 
        DBGC ( params, "PARAMS \"%s\" created\n", params->name );
+       if ( params->method ) {
+               DBGC ( params, "PARAMS \"%s\" method is \"%s\"\n",
+                      params->name, params->method );
+       }
        return params;
 }
 
index ed57c5eaac3fb8edbc39c8cb66a1a2256904be0f..aec3895c5d52c6192abef7686bf8658f34eb47ae 100644 (file)
@@ -41,6 +41,8 @@ FILE_SECBOOT ( PERMITTED );
 struct params_options {
        /** Name */
        char *name;
+       /** Method */
+       char *method;
        /** Delete */
        int delete;
 };
@@ -49,6 +51,8 @@ struct params_options {
 static struct option_descriptor params_opts[] = {
        OPTION_DESC ( "name", 'n', required_argument,
                      struct params_options, name, parse_string ),
+       OPTION_DESC ( "method", 'm', required_argument,
+                     struct params_options, method, parse_string ),
        OPTION_DESC ( "delete", 'd', no_argument,
                      struct params_options, delete, parse_flag ),
 };
@@ -74,7 +78,7 @@ static int params_exec ( int argc, char **argv ) {
                return rc;
 
        /* Create parameter list */
-       params = create_parameters ( opts.name );
+       params = create_parameters ( opts.name, opts.method );
        if ( ! params )
                return -ENOMEM;
 
index e84a75237b4991a45317bf2f2dfe142b1048792f..e96c2c881407f86dcaa50daea1830767eba18183 100644 (file)
@@ -102,9 +102,16 @@ struct http_method {
        const char *name;
 };
 
-extern struct http_method http_head;
-extern struct http_method http_get;
-extern struct http_method http_post;
+/** HTTP method table */
+#define HTTP_METHODS __table ( struct http_method, "http_methods" )
+
+/** Declare an HTTP method */
+#define __http_method __table_entry ( HTTP_METHODS, 01 )
+
+extern struct http_method http_head __http_method;
+extern struct http_method http_get __http_method;
+extern struct http_method http_post __http_method;
+extern struct http_method http_put __http_method;
 
 /******************************************************************************
  *
index 64008380e8fc689fee66f125560f241868d63280..bb7420b1d71e316e9e690c8a4e64f0d20c298ffd 100644 (file)
@@ -21,6 +21,8 @@ struct parameters {
        struct list_head list;
        /** Name */
        const char *name;
+       /** Request method */
+       const char *method;
        /** Parameters */
        struct list_head entries;
 };
@@ -85,7 +87,8 @@ claim_parameters ( struct parameters *params ) {
        list_for_each_entry ( (param), &(params)->entries, list )
 
 extern struct parameters * find_parameters ( const char *name );
-extern struct parameters * create_parameters ( const char *name );
+extern struct parameters * create_parameters ( const char *name,
+                                              const char *method );
 extern struct parameter * add_parameter ( struct parameters *params,
                                          const char *key, const char *value,
                                          unsigned int flags );
index 1180faa987e720bf39f21bd7325531e7e2b68948..7dbb0e3044b31364e0ef231a931f62b1d9d5923a 100644 (file)
@@ -136,20 +136,43 @@ static struct http_transfer_encoding http_transfer_identity;
  */
 
 /** HTTP HEAD method */
-struct http_method http_head = {
+struct http_method http_head __http_method = {
        .name = "HEAD",
 };
 
 /** HTTP GET method */
-struct http_method http_get = {
+struct http_method http_get __http_method = {
        .name = "GET",
 };
 
 /** HTTP POST method */
-struct http_method http_post = {
+struct http_method http_post __http_method = {
        .name = "POST",
 };
 
+/** HTTP PUT method */
+struct http_method http_put __http_method = {
+       .name = "PUT",
+};
+
+/**
+ * Identify HTTP method
+ *
+ * @v name             Method name
+ * @ret method         HTTP method, or NULL if not known
+ */
+static struct http_method * http_method ( const char *name ) {
+       struct http_method *method;
+
+       /* Identify method */
+       for_each_table_entry ( method, HTTP_METHODS ) {
+               if ( strcasecmp ( name, method->name ) == 0 )
+                       return method;
+       }
+
+       return NULL;
+}
+
 /******************************************************************************
  *
  * Utility functions
@@ -2025,6 +2048,17 @@ int http_open_uri ( struct interface *xfer, struct uri *uri ) {
                data = NULL;
        }
 
+       /* Use explicitly requested method name if applicable */
+       if ( params && params->method ) {
+               method = http_method ( params->method );
+               if ( ! method ) {
+                       DBGC ( uri, "HTTP unsupported method \"%s\"\n",
+                              params->method );
+                       rc = -ENOTSUP;
+                       goto err_method;
+               }
+       }
+
        /* Construct request content */
        content.type = type;
        content.data = data;
@@ -2035,6 +2069,7 @@ int http_open_uri ( struct interface *xfer, struct uri *uri ) {
                goto err_open;
 
  err_open:
+ err_method:
        free ( data );
  err_alloc:
        return rc;
index fa46e22f2de5a99e7ce53cc91d43b3e59d0a051c..96942c3935b7acbb6cf17bddee7f8c273c7b8103 100644 (file)
@@ -455,7 +455,7 @@ static void uri_params_okx ( struct uri_params_test *test, const char *file,
        struct uri *dup;
 
        /* Create parameter list */
-       params = create_parameters ( test->name );
+       params = create_parameters ( test->name, NULL );
        okx ( params != NULL, file, line );
        if ( params ) {
                for ( list = test->list ; list->key ; list++ ) {