[PING][PATCH] getmntent: Generalize octal decoding

Siddhesh Poyarekar siddhesh@gotplt.org
Tue Dec 22 07:48:09 GMT 2020


On 12/16/20 7:54 PM, Siddhesh Poyarekar via Libc-alpha wrote:
> The current octal decoding looks for specific characters to decode.
> generalize this instead, allowing any arbitrary \xxx octal pattern to
> be decoded as long as it is a printable character.
> 
> The decoding is now done a bit later so that it does not influence the
> "ignore" option of autofs, which is a hint for getmntent to skip over
> the line.  With this change, "\151gnore" will not cuase the line to be
> skipped over, but the options string will show "ignore" correctly.
> 
> Also add a test case to validate that encoded hashes get decoded
> correctly.  This would be useful if/when the kernel starts escaping
> hashes in /proc/mounts.
> ---
>   misc/mntent_r.c          | 92 ++++++++++++++++++++++++----------------
>   misc/tst-mntent-autofs.c |  4 +-
>   2 files changed, 58 insertions(+), 38 deletions(-)
> 
> diff --git a/misc/mntent_r.c b/misc/mntent_r.c
> index b50ba0de89..ac56e40fd5 100644
> --- a/misc/mntent_r.c
> +++ b/misc/mntent_r.c
> @@ -65,6 +65,27 @@ __endmntent (FILE *stream)
>   libc_hidden_def (__endmntent)
>   weak_alias (__endmntent, endmntent)
>   
> +static char
> +parse_octal (char *s)
> +{
> +  char c = 0, t;
> +
> +  t = s[0] - '0';
> +  if (t & (~0x7))
> +    return 0;
> +  c |= t << 6;
> +
> +  t = s[1] - '0';
> +  if (t & (~0x7))
> +    return 0;
> +  c |= t << 3;
> +
> +  t = s[2] - '0';
> +  if (t & (~0x7))
> +    return 0;
> +
> +  return c | t;
> +}
>   
>   /* Since the values in a line are separated by spaces, a name cannot
>      contain a space.  Therefore some programs encode spaces in names
> @@ -77,43 +98,42 @@ decode_name (char *buf)
>     char *wp = buf;
>   
>     do
> -    if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '4' && rp[3] == '0')
> -      {
> -	/* \040 is a SPACE.  */
> -	*wp++ = ' ';
> -	rp += 3;
> -      }
> -    else if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '1' && rp[3] == '1')
> -      {
> -	/* \011 is a TAB.  */
> -	*wp++ = '\t';
> -	rp += 3;
> -      }
> -    else if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '1' && rp[3] == '2')
> -      {
> -	/* \012 is a NEWLINE.  */
> -	*wp++ = '\n';
> -	rp += 3;
> -      }
> -    else if (rp[0] == '\\' && rp[1] == '\\')
> -      {
> -	/* We have to escape \\ to be able to represent all characters.  */
> -	*wp++ = '\\';
> -	rp += 1;
> -      }
> -    else if (rp[0] == '\\' && rp[1] == '1' && rp[2] == '3' && rp[3] == '4')
> -      {
> -	/* \134 is also \\.  */
> -	*wp++ = '\\';
> -	rp += 3;
> -      }
> -    else
> +    {
> +      if (rp[0] == '\\')
> +	{
> +	  char c;
> +
> +	  if ((c = parse_octal (&rp[1])) != 0)
> +	    {
> +	      *wp++ = c;
> +	      rp += 3;
> +	      continue;
> +	    }
> +	  if (rp[1] == '\\')
> +	    {
> +	      *wp++ = '\\';
> +	      rp++;
> +	      continue;
> +	    }
> +	}
>         *wp++ = *rp;
> +    }
>     while (*rp++ != '\0');
>   
>     return buf;
>   }
>   
> +static struct mntent *
> +decode_mntent_names (struct mntent *res)
> +{
> +  res->mnt_fsname = decode_name (res->mnt_fsname);
> +  res->mnt_dir = decode_name (res->mnt_dir);
> +  res->mnt_type = decode_name (res->mnt_type);
> +  res->mnt_opts = decode_name (res->mnt_opts);
> +
> +  return res;
> +}
> +
>   static bool
>   get_mnt_entry (FILE *stream, struct mntent *mp, char *buffer, int bufsiz)
>   {
> @@ -151,19 +171,19 @@ get_mnt_entry (FILE *stream, struct mntent *mp, char *buffer, int bufsiz)
>     while (head[0] == '\0' || head[0] == '#');
>   
>     cp = __strsep (&head, " \t");
> -  mp->mnt_fsname = cp != NULL ? decode_name (cp) : (char *) "";
> +  mp->mnt_fsname = cp != NULL ? cp : (char *) "";
>     if (head)
>       head += strspn (head, " \t");
>     cp = __strsep (&head, " \t");
> -  mp->mnt_dir = cp != NULL ? decode_name (cp) : (char *) "";
> +  mp->mnt_dir = cp != NULL ? cp : (char *) "";
>     if (head)
>       head += strspn (head, " \t");
>     cp = __strsep (&head, " \t");
> -  mp->mnt_type = cp != NULL ? decode_name (cp) : (char *) "";
> +  mp->mnt_type = cp != NULL ? cp : (char *) "";
>     if (head)
>       head += strspn (head, " \t");
>     cp = __strsep (&head, " \t");
> -  mp->mnt_opts = cp != NULL ? decode_name (cp) : (char *) "";
> +  mp->mnt_opts = cp != NULL ? cp : (char *) "";
>     switch (head ? sscanf (head, " %d %d ", &mp->mnt_freq, &mp->mnt_passno) : 0)
>       {
>       case 0:
> @@ -197,7 +217,7 @@ __getmntent_r (FILE *stream, struct mntent *mp, char *buffer, int bufsiz)
>   	  memset (mp, 0, sizeof (*mp));
>   	else
>   	  {
> -	    result = mp;
> +	    result = decode_mntent_names (mp);
>   	    break;
>   	  }
>         }
> diff --git a/misc/tst-mntent-autofs.c b/misc/tst-mntent-autofs.c
> index e4c509f520..54b11b23ba 100644
> --- a/misc/tst-mntent-autofs.c
> +++ b/misc/tst-mntent-autofs.c
> @@ -87,8 +87,8 @@ static struct test_case test_cases[] =
>       /* These are not filtered because the string is escaped.  '\151'
>          is 'i', but it is not actually decoded by the parser.  */
>       { "/etc/auto.\\151gnore /mnt/auto/16 autofs \\151gnore 0 0",
> -      { "/etc/auto.\\151gnore", "/mnt/auto/16", "autofs",
> -        "\\151gnore", } },
> +      { "/etc/auto.ignore", "/mnt/auto/16", "autofs",
> +        "ignore", } },
>     };
>   
>   static int
> 



More information about the Libc-alpha mailing list