On Wed, Jul 5, 2023 at 8:20 PM Hitendra Prajapati <[email protected]> wrote:
>
> Upstream-Status: Backport 
> [https://launchpad.net/debian/+source/grub2/2.02+dfsg1-20+deb10u4/]

Hi Hitendra,

launchpad.net isn't the upstream for grub2, so please also reference
the actual upstream commits in a v2. It would be helpful to me if you
could send v2 as a patch series so I know the proper order to apply
the patches!

Thanks for helping with CVE fixes.

Steve

>
> Signed-off-by: Hitendra Prajapati <[email protected]>
> ---
>  .../grub/files/CVE-2020-27749.patch           | 609 ++++++++++++++++++
>  meta/recipes-bsp/grub/grub2.inc               |   1 +
>  2 files changed, 610 insertions(+)
>  create mode 100644 meta/recipes-bsp/grub/files/CVE-2020-27749.patch
>
> diff --git a/meta/recipes-bsp/grub/files/CVE-2020-27749.patch 
> b/meta/recipes-bsp/grub/files/CVE-2020-27749.patch
> new file mode 100644
> index 0000000000..30ba11d882
> --- /dev/null
> +++ b/meta/recipes-bsp/grub/files/CVE-2020-27749.patch
> @@ -0,0 +1,609 @@
> +From 199580a4a986848f5e27586a741a7e35412cc5c6 Mon Sep 17 00:00:00 2001
> +From: Chris Coulson <[email protected]>
> +Date: Thu, 7 Jan 2021 19:21:03 +0000
> +Subject: kern/parser: Fix a stack buffer overflow
> +
> +grub_parser_split_cmdline() expands variable names present in the supplied
> +command line in to their corresponding variable contents and uses a 1 kiB
> +stack buffer for temporary storage without sufficient bounds checking. If
> +the function is called with a command line that references a variable with
> +a sufficiently large payload, it is possible to overflow the stack
> +buffer via tab completion, corrupt the stack frame and potentially
> +control execution.
> +
> +Fixes: CVE-2020-27749
> +
> +Reported-by: Chris Coulson <[email protected]>
> +Signed-off-by: Chris Coulson <[email protected]>
> +Signed-off-by: Darren Kenny <[email protected]>
> +Reviewed-by: Daniel Kiper <[email protected]>
> +
> +Upstream-Status: Backport 
> [https://launchpad.net/debian/+source/grub2/2.02+dfsg1-20+deb10u4/]
> +CVE: CVE-2020-27749
> +
> +Signed-off-by: Hitendra Prajapati <[email protected]>
> +---
> + grub-core/Makefile.core.def |   1 +
> + grub-core/kern/buffer.c     | 117 +++++++++++++++++++++
> + grub-core/kern/parser.c     | 204 +++++++++++++++++++++++-------------
> + include/grub/buffer.h       | 144 +++++++++++++++++++++++++
> + 4 files changed, 395 insertions(+), 71 deletions(-)
> + create mode 100644 grub-core/kern/buffer.c
> + create mode 100644 include/grub/buffer.h
> +
> +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
> +index 651ea2a..823cd57 100644
> +--- a/grub-core/Makefile.core.def
> ++++ b/grub-core/Makefile.core.def
> +@@ -123,6 +123,7 @@ kernel = {
> +   riscv32_efi_startup = kern/riscv/efi/startup.S;
> +   riscv64_efi_startup = kern/riscv/efi/startup.S;
> +
> ++  common = kern/buffer.c;
> +   common = kern/command.c;
> +   common = kern/corecmd.c;
> +   common = kern/device.c;
> +diff --git a/grub-core/kern/buffer.c b/grub-core/kern/buffer.c
> +new file mode 100644
> +index 0000000..9f5f8b8
> +--- /dev/null
> ++++ b/grub-core/kern/buffer.c
> +@@ -0,0 +1,117 @@
> ++/*
> ++ *  GRUB  --  GRand Unified Bootloader
> ++ *  Copyright (C) 2021  Free Software Foundation, Inc.
> ++ *
> ++ *  GRUB is free software: you can redistribute it and/or modify
> ++ *  it under the terms of the GNU General Public License as published by
> ++ *  the Free Software Foundation, either version 3 of the License, or
> ++ *  (at your option) any later version.
> ++ *
> ++ *  GRUB is distributed in the hope that it will be useful,
> ++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> ++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> ++ *  GNU General Public License for more details.
> ++ *
> ++ *  You should have received a copy of the GNU General Public License
> ++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> ++ */
> ++
> ++#include <grub/buffer.h>
> ++#include <grub/err.h>
> ++#include <grub/misc.h>
> ++#include <grub/mm.h>
> ++#include <grub/safemath.h>
> ++#include <grub/types.h>
> ++
> ++grub_buffer_t
> ++grub_buffer_new (grub_size_t sz)
> ++{
> ++  struct grub_buffer *ret;
> ++
> ++  ret = (struct grub_buffer *) grub_malloc (sizeof (*ret));
> ++  if (ret == NULL)
> ++    return NULL;
> ++
> ++  ret->data = (grub_uint8_t *) grub_malloc (sz);
> ++  if (ret->data == NULL)
> ++    {
> ++      grub_free (ret);
> ++      return NULL;
> ++    }
> ++
> ++  ret->sz = sz;
> ++  ret->pos = 0;
> ++  ret->used = 0;
> ++
> ++  return ret;
> ++}
> ++
> ++void
> ++grub_buffer_free (grub_buffer_t buf)
> ++{
> ++  grub_free (buf->data);
> ++  grub_free (buf);
> ++}
> ++
> ++grub_err_t
> ++grub_buffer_ensure_space (grub_buffer_t buf, grub_size_t req)
> ++{
> ++  grub_uint8_t *d;
> ++  grub_size_t newsz = 1;
> ++
> ++  /* Is the current buffer size adequate? */
> ++  if (buf->sz >= req)
> ++    return GRUB_ERR_NONE;
> ++
> ++  /* Find the smallest power-of-2 size that satisfies the request. */
> ++  while (newsz < req)
> ++    {
> ++      if (newsz == 0)
> ++      return grub_error (GRUB_ERR_OUT_OF_RANGE,
> ++                         N_("requested buffer size is too large"));
> ++      newsz <<= 1;
> ++    }
> ++
> ++  d = (grub_uint8_t *) grub_realloc (buf->data, newsz);
> ++  if (d == NULL)
> ++    return grub_errno;
> ++
> ++  buf->data = d;
> ++  buf->sz = newsz;
> ++
> ++  return GRUB_ERR_NONE;
> ++}
> ++
> ++void *
> ++grub_buffer_take_data (grub_buffer_t buf)
> ++{
> ++  void *data = buf->data;
> ++
> ++  buf->data = NULL;
> ++  buf->sz = buf->pos = buf->used = 0;
> ++
> ++  return data;
> ++}
> ++
> ++void
> ++grub_buffer_reset (grub_buffer_t buf)
> ++{
> ++  buf->pos = buf->used = 0;
> ++}
> ++
> ++grub_err_t
> ++grub_buffer_advance_read_pos (grub_buffer_t buf, grub_size_t n)
> ++{
> ++  grub_size_t newpos;
> ++
> ++  if (grub_add (buf->pos, n, &newpos))
> ++    return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
> ++
> ++  if (newpos > buf->used)
> ++    return grub_error (GRUB_ERR_OUT_OF_RANGE,
> ++                     N_("new read is position beyond the end of the written 
> data"));
> ++
> ++  buf->pos = newpos;
> ++
> ++  return GRUB_ERR_NONE;
> ++}
> +diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c
> +index d1cf061..6ab7aa4 100644
> +--- a/grub-core/kern/parser.c
> ++++ b/grub-core/kern/parser.c
> +@@ -1,7 +1,7 @@
> + /* parser.c - the part of the parser that can return partial tokens */
> + /*
> +  *  GRUB  --  GRand Unified Bootloader
> +- *  Copyright (C) 2005,2007,2009  Free Software Foundation, Inc.
> ++ *  Copyright (C) 2005,2007,2009,2021  Free Software Foundation, Inc.
> +  *
> +  *  GRUB is free software: you can redistribute it and/or modify
> +  *  it under the terms of the GNU General Public License as published by
> +@@ -18,6 +18,7 @@
> +  */
> +
> + #include <grub/parser.h>
> ++#include <grub/buffer.h>
> + #include <grub/env.h>
> + #include <grub/misc.h>
> + #include <grub/mm.h>
> +@@ -107,8 +108,8 @@ check_varstate (grub_parser_state_t s)
> + }
> +
> +
> +-static void
> +-add_var (char *varname, char **bp, char **vp,
> ++static grub_err_t
> ++add_var (grub_buffer_t varname, grub_buffer_t buf,
> +        grub_parser_state_t state, grub_parser_state_t newstate)
> + {
> +   const char *val;
> +@@ -116,17 +117,74 @@ add_var (char *varname, char **bp, char **vp,
> +   /* Check if a variable was being read in and the end of the name
> +      was reached.  */
> +   if (!(check_varstate (state) && !check_varstate (newstate)))
> +-    return;
> ++    return GRUB_ERR_NONE;
> ++
> ++  if (grub_buffer_append_char (varname, '\0') != GRUB_ERR_NONE)
> ++    return grub_errno;
> +
> +-  *((*vp)++) = '\0';
> +-  val = grub_env_get (varname);
> +-  *vp = varname;
> ++  val = grub_env_get ((const char *) grub_buffer_peek_data (varname));
> ++  grub_buffer_reset (varname);
> +   if (!val)
> +-    return;
> ++    return GRUB_ERR_NONE;
> +
> +   /* Insert the contents of the variable in the buffer.  */
> +-  for (; *val; val++)
> +-    *((*bp)++) = *val;
> ++  return grub_buffer_append_data (buf, val, grub_strlen (val));
> ++}
> ++
> ++static grub_err_t
> ++terminate_arg (grub_buffer_t buffer, int *argc)
> ++{
> ++  grub_size_t unread = grub_buffer_get_unread_bytes (buffer);
> ++
> ++  if (unread == 0)
> ++    return GRUB_ERR_NONE;
> ++
> ++  if (*(const char *) grub_buffer_peek_data_at (buffer, unread - 1) == '\0')
> ++    return GRUB_ERR_NONE;
> ++
> ++  if (grub_buffer_append_char (buffer, '\0') != GRUB_ERR_NONE)
> ++    return grub_errno;
> ++
> ++  (*argc)++;
> ++
> ++  return GRUB_ERR_NONE;
> ++}
> ++
> ++static grub_err_t
> ++process_char (char c, grub_buffer_t buffer, grub_buffer_t varname,
> ++            grub_parser_state_t state, int *argc,
> ++            grub_parser_state_t *newstate)
> ++{
> ++  char use;
> ++
> ++  *newstate = grub_parser_cmdline_state (state, c, &use);
> ++
> ++  /*
> ++   * If a variable was being processed and this character does
> ++   * not describe the variable anymore, write the variable to
> ++   * the buffer.
> ++   */
> ++  if (add_var (varname, buffer, state, *newstate) != GRUB_ERR_NONE)
> ++    return grub_errno;
> ++
> ++  if (check_varstate (*newstate))
> ++    {
> ++      if (use)
> ++        return grub_buffer_append_char (varname, use);
> ++    }
> ++  else if (*newstate == GRUB_PARSER_STATE_TEXT &&
> ++         state != GRUB_PARSER_STATE_ESC && grub_isspace (use))
> ++    {
> ++      /*
> ++       * Don't add more than one argument if multiple
> ++       * spaces are used.
> ++       */
> ++      return terminate_arg (buffer, argc);
> ++    }
> ++  else if (use)
> ++    return grub_buffer_append_char (buffer, use);
> ++
> ++  return GRUB_ERR_NONE;
> + }
> +
> + grub_err_t
> +@@ -135,24 +193,36 @@ grub_parser_split_cmdline (const char *cmdline,
> +                          int *argc, char ***argv)
> + {
> +   grub_parser_state_t state = GRUB_PARSER_STATE_TEXT;
> +-  /* XXX: Fixed size buffer, perhaps this buffer should be dynamically
> +-     allocated.  */
> +-  char buffer[1024];
> +-  char *bp = buffer;
> ++  grub_buffer_t buffer, varname;
> +   char *rd = (char *) cmdline;
> +-  char varname[200];
> +-  char *vp = varname;
> +-  char *args;
> ++  char *rp = rd;
> +   int i;
> +
> +   *argc = 0;
> +   *argv = NULL;
> ++
> ++  buffer = grub_buffer_new (1024);
> ++  if (buffer == NULL)
> ++    return grub_errno;
> ++
> ++  varname = grub_buffer_new (200);
> ++  if (varname == NULL)
> ++    goto fail;
> ++
> +   do
> +     {
> +-      if (!rd || !*rd)
> ++      if (rp == NULL || *rp == '\0')
> +       {
> ++        if (rd != cmdline)
> ++          {
> ++            grub_free (rd);
> ++            rd = rp = NULL;
> ++          }
> +         if (getline)
> +-          getline (&rd, 1, getline_data);
> ++          {
> ++            getline (&rd, 1, getline_data);
> ++            rp = rd;
> ++          }
> +         else
> +           break;
> +       }
> +@@ -160,39 +230,14 @@ grub_parser_split_cmdline (const char *cmdline,
> +       if (!rd)
> +       break;
> +
> +-      for (; *rd; rd++)
> ++      for (; *rp != '\0'; rp++)
> +       {
> +         grub_parser_state_t newstate;
> +-        char use;
> +
> +-        newstate = grub_parser_cmdline_state (state, *rd, &use);
> ++        if (process_char (*rp, buffer, varname, state, argc,
> ++                          &newstate) != GRUB_ERR_NONE)
> ++          goto fail;
> +
> +-        /* If a variable was being processed and this character does
> +-           not describe the variable anymore, write the variable to
> +-           the buffer.  */
> +-        add_var (varname, &bp, &vp, state, newstate);
> +-
> +-        if (check_varstate (newstate))
> +-          {
> +-            if (use)
> +-              *(vp++) = use;
> +-          }
> +-        else
> +-          {
> +-            if (newstate == GRUB_PARSER_STATE_TEXT
> +-                && state != GRUB_PARSER_STATE_ESC && grub_isspace (use))
> +-              {
> +-                /* Don't add more than one argument if multiple
> +-                   spaces are used.  */
> +-                if (bp != buffer && *(bp - 1))
> +-                  {
> +-                    *(bp++) = '\0';
> +-                    (*argc)++;
> +-                  }
> +-              }
> +-            else if (use)
> +-              *(bp++) = use;
> +-          }
> +         state = newstate;
> +       }
> +     }
> +@@ -200,43 +245,60 @@ grub_parser_split_cmdline (const char *cmdline,
> +
> +   /* A special case for when the last character was part of a
> +      variable.  */
> +-  add_var (varname, &bp, &vp, state, GRUB_PARSER_STATE_TEXT);
> ++  if (add_var (varname, buffer, state, GRUB_PARSER_STATE_TEXT) != 
> GRUB_ERR_NONE)
> ++    goto fail;
> +
> +-  if (bp != buffer && *(bp - 1))
> +-    {
> +-      *(bp++) = '\0';
> +-      (*argc)++;
> +-    }
> ++  /* Ensure that the last argument is terminated. */
> ++  if (terminate_arg (buffer, argc) != GRUB_ERR_NONE)
> ++    goto fail;
> +
> +   /* If there are no args, then we're done. */
> +   if (!*argc)
> +-    return 0;
> +-
> +-  /* Reserve memory for the return values.  */
> +-  args = grub_malloc (bp - buffer);
> +-  if (!args)
> +-    return grub_errno;
> +-  grub_memcpy (args, buffer, bp - buffer);
> ++    {
> ++      grub_errno = GRUB_ERR_NONE;
> ++      goto out;
> ++    }
> +
> +   *argv = grub_calloc (*argc + 1, sizeof (char *));
> +   if (!*argv)
> +-    {
> +-      grub_free (args);
> +-      return grub_errno;
> +-    }
> ++    goto fail;
> +
> +   /* The arguments are separated with 0's, setup argv so it points to
> +      the right values.  */
> +-  bp = args;
> +   for (i = 0; i < *argc; i++)
> +     {
> +-      (*argv)[i] = bp;
> +-      while (*bp)
> +-      bp++;
> +-      bp++;
> ++      char *arg;
> ++
> ++      if (i > 0)
> ++      {
> ++        if (grub_buffer_advance_read_pos (buffer, 1) != GRUB_ERR_NONE)
> ++          goto fail;
> ++      }
> ++
> ++      arg = (char *) grub_buffer_peek_data (buffer);
> ++      if (arg == NULL ||
> ++        grub_buffer_advance_read_pos (buffer, grub_strlen (arg)) != 
> GRUB_ERR_NONE)
> ++      goto fail;
> ++
> ++      (*argv)[i] = arg;
> +     }
> +
> +-  return 0;
> ++  /* Keep memory for the return values. */
> ++  grub_buffer_take_data (buffer);
> ++
> ++  grub_errno = GRUB_ERR_NONE;
> ++
> ++ out:
> ++  if (rd != cmdline)
> ++    grub_free (rd);
> ++  grub_buffer_free (buffer);
> ++  grub_buffer_free (varname);
> ++
> ++  return grub_errno;
> ++
> ++ fail:
> ++  grub_free (*argv);
> ++  goto out;
> + }
> +
> + /* Helper for grub_parser_execute.  */
> +diff --git a/include/grub/buffer.h b/include/grub/buffer.h
> +new file mode 100644
> +index 0000000..f4b10cf
> +--- /dev/null
> ++++ b/include/grub/buffer.h
> +@@ -0,0 +1,144 @@
> ++/*
> ++ *  GRUB  --  GRand Unified Bootloader
> ++ *  Copyright (C) 2021  Free Software Foundation, Inc.
> ++ *
> ++ *  GRUB is free software: you can redistribute it and/or modify
> ++ *  it under the terms of the GNU General Public License as published by
> ++ *  the Free Software Foundation, either version 3 of the License, or
> ++ *  (at your option) any later version.
> ++ *
> ++ *  GRUB is distributed in the hope that it will be useful,
> ++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> ++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> ++ *  GNU General Public License for more details.
> ++ *
> ++ *  You should have received a copy of the GNU General Public License
> ++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> ++ */
> ++
> ++#ifndef GRUB_BUFFER_H
> ++#define GRUB_BUFFER_H 1
> ++
> ++#include <grub/err.h>
> ++#include <grub/misc.h>
> ++#include <grub/mm.h>
> ++#include <grub/safemath.h>
> ++#include <grub/types.h>
> ++
> ++struct grub_buffer
> ++{
> ++  grub_uint8_t *data;
> ++  grub_size_t sz;
> ++  grub_size_t pos;
> ++  grub_size_t used;
> ++};
> ++
> ++/*
> ++ * grub_buffer_t represents a simple variable sized byte buffer with
> ++ * read and write cursors. It currently only implements
> ++ * functionality required by the only user in GRUB (append byte[s],
> ++ * peeking data at a specified position and updating the read cursor.
> ++ * Some things that this doesn't do yet are:
> ++ * - Reading a portion of the buffer by copying data from the current
> ++ *   read position in to a caller supplied destination buffer and then
> ++ *   automatically updating the read cursor.
> ++ * - Dropping the read part at the start of the buffer when an append
> ++ *   requires more space.
> ++ */
> ++typedef struct grub_buffer *grub_buffer_t;
> ++
> ++/* Allocate a new buffer with the specified initial size. */
> ++extern grub_buffer_t grub_buffer_new (grub_size_t sz);
> ++
> ++/* Free the buffer and its resources. */
> ++extern void grub_buffer_free (grub_buffer_t buf);
> ++
> ++/* Return the number of unread bytes in this buffer. */
> ++static inline grub_size_t
> ++grub_buffer_get_unread_bytes (grub_buffer_t buf)
> ++{
> ++  return buf->used - buf->pos;
> ++}
> ++
> ++/*
> ++ * Ensure that the buffer size is at least the requested
> ++ * number of bytes.
> ++ */
> ++extern grub_err_t grub_buffer_ensure_space (grub_buffer_t buf, grub_size_t 
> req);
> ++
> ++/*
> ++ * Append the specified number of bytes from the supplied
> ++ * data to the buffer.
> ++ */
> ++static inline grub_err_t
> ++grub_buffer_append_data (grub_buffer_t buf, const void *data, grub_size_t 
> len)
> ++{
> ++  grub_size_t req;
> ++
> ++  if (grub_add (buf->used, len, &req))
> ++    return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
> ++
> ++  if (grub_buffer_ensure_space (buf, req) != GRUB_ERR_NONE)
> ++    return grub_errno;
> ++
> ++  grub_memcpy (&buf->data[buf->used], data, len);
> ++  buf->used = req;
> ++
> ++  return GRUB_ERR_NONE;
> ++}
> ++
> ++/* Append the supplied character to the buffer. */
> ++static inline grub_err_t
> ++grub_buffer_append_char (grub_buffer_t buf, char c)
> ++{
> ++  return grub_buffer_append_data (buf, &c, 1);
> ++}
> ++
> ++/*
> ++ * Forget and return the underlying data buffer. The caller
> ++ * becomes the owner of this buffer, and must free it when it
> ++ * is no longer required.
> ++ */
> ++extern void *grub_buffer_take_data (grub_buffer_t buf);
> ++
> ++/* Reset this buffer. Note that this does not deallocate any resources. */
> ++void grub_buffer_reset (grub_buffer_t buf);
> ++
> ++/*
> ++ * Return a pointer to the underlying data buffer at the specified
> ++ * offset from the current read position. Note that this pointer may
> ++ * become invalid if the buffer is mutated further.
> ++ */
> ++static inline void *
> ++grub_buffer_peek_data_at (grub_buffer_t buf, grub_size_t off)
> ++{
> ++  if (grub_add (buf->pos, off, &off))
> ++    {
> ++      grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected."));
> ++      return NULL;
> ++    }
> ++
> ++  if (off >= buf->used)
> ++    {
> ++      grub_error (GRUB_ERR_OUT_OF_RANGE, N_("peek out of range"));
> ++      return NULL;
> ++    }
> ++
> ++  return &buf->data[off];
> ++}
> ++
> ++/*
> ++ * Return a pointer to the underlying data buffer at the current
> ++ * read position. Note that this pointer may become invalid if the
> ++ * buffer is mutated further.
> ++ */
> ++static inline void *
> ++grub_buffer_peek_data (grub_buffer_t buf)
> ++{
> ++  return grub_buffer_peek_data_at (buf, 0);
> ++}
> ++
> ++/* Advance the read position by the specified number of bytes. */
> ++extern grub_err_t grub_buffer_advance_read_pos (grub_buffer_t buf, 
> grub_size_t n);
> ++
> ++#endif /* GRUB_BUFFER_H */
> +--
> +2.25.1
> +
> diff --git a/meta/recipes-bsp/grub/grub2.inc b/meta/recipes-bsp/grub/grub2.inc
> index d09eecd8ac..cb79f2212b 100644
> --- a/meta/recipes-bsp/grub/grub2.inc
> +++ b/meta/recipes-bsp/grub/grub2.inc
> @@ -106,6 +106,7 @@ SRC_URI = "${GNU_MIRROR}/grub/grub-${PV}.tar.gz \
>             file://font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch 
> \
>             file://CVE-2022-2601.patch \
>             file://CVE-2022-3775.patch \
> +           file://CVE-2020-27749.patch \
>             "
>  SRC_URI[md5sum] = "5ce674ca6b2612d8939b9e6abed32934"
>  SRC_URI[sha256sum] = 
> "f10c85ae3e204dbaec39ae22fa3c5e99f0665417e91c2cb49b7e5031658ba6ea"
> --
> 2.25.1
>
>
> 
>
-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#183982): 
https://lists.openembedded.org/g/openembedded-core/message/183982
Mute This Topic: https://lists.openembedded.org/mt/99980756/21656
Group Owner: [email protected]
Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to