bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: argve0, psfool


From: Daniel C. Bastos
Subject: Re: argve0, psfool
Date: Fri, 28 Dec 2007 21:49:39 -0500

Mike Frysinger writes:
 > On Monday 24 December 2007, Daniel C. Bastos wrote:
 > > #define min(a,b) (a) <= (b) ? (a) : (b)
 > 
 > there's already a MIN() macro
 > 
 > > #define SIZE 256
 > 
 > non-descript magic #
 > 
 > >   int i; char real[128]; char fake[128]; char vargv[8192]; int n;
 > >   strncpy(fake, argv[1], n); fake[n] = '\0';
 > >   strncpy(real, argv[2], n); real[n] = '\0';
 > 
 > these should be on separate lines.  i'm guessing your 8192 should actually be
 > BUFSIZ.  then again, the whole arg shifting looks like voodoo and could 
 > (should?) be simpler.  *shrug*
 > -mike

I've rewritten it taking your suggestions above, and studied a bit
more. There does not seem to be a solution to the problem; any well
crafted ps will of course be able to read all the arguments.

The safest way to hide arguments is to erase them, but erasing can only
be done by the final-program that needs them --- and still, a ps that
runs right after the creation of the execution might be `quick' enough
to read the arguments before they are erased by the final-program.

The program is here for scrutiny, though.

I've been working with a ps (GNU system, debian etch) that does not read
past 4096 bytes. Though unable to print the arguments, ps is still able
to print all the spaces, of course. The man page of ps mentions using -w
twice for an unlimited output:

-w              Wide output. Use this option twice for unlimited width.

But that does not seem to be true, as it won't read past 4096 bytes. For
those which will, the --padsize option could be useful, but this is
futile the day that ps decides to make its ``unlimited width'' claim
come true.

/* psfool - formats argv[] with enough bytes to go beyond ps' reach.
   Copyright (C) 2007 Free Software Foundation, Inc.

   This program 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 2, or (at your option)
   any later version.

   This program 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 this program; if not, write to the Free Software
   Foundation,
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
   */

/* Daniel C. Bastos <address@hidden> */

#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <getopt.h>

#include "system.h"
#include "error.h"
#include "long-options.h"

/* The official name of this program (e.g., no `g' prefix).  */
#define PROGRAM_NAME "psfool"

#define AUTHORS "Daniel C. Bastos"

/* The name this program was run with. */
char *program_name;

/* the amount of bytes we're going to pad argv[]; should be enough to
 * overwhelm the local ps; we should allow the user to set it with
 * --padsize in order to fool some smarty ps. */
#define PADSIZE 4096

/* the amount of bytes we're going to allow real's argv[] to be. but
 * since we need PADSIZE to fool ps, the amount of bytes available to
 * the real program will be BUFSIZE - PADSIZE. */
#define BUFSIZE 2*PADSIZE

/* how long can fake and real be? */
#define ARGSIZE 128 

void
usage (int status)
{
  if (status != EXIT_SUCCESS)
    fprintf (stderr, _("Try `%s --help' for more information.\n"),
         program_name);
  else
    {
      printf (_("\
Usage: %s [OPTIONS] fake real [arg1 arg2 ... argn]\n\
"),
              program_name, program_name);

      fputs (_("\
Runs `real' fooling ps into thinking it was `fake'\n\
\n\
"), stdout);
      fputs (HELP_OPTION_DESCRIPTION, stdout);
      fputs (VERSION_OPTION_DESCRIPTION, stdout);
      printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
    }
  exit (status);
}

void run(char *argv1, char **argv)
{
    execvp(argv1, argv);
}

int
main (int argc, char **argv, char **envp)
{
  int i;
  int n;
  char real[ARGSIZE];
  char fake[ARGSIZE];
  char vargv[BUFSIZE];

  initialize_main (&argc, &argv);
  program_name = argv[0];
  setlocale (LC_ALL, "");
  bindtextdomain (PACKAGE, LOCALEDIR);
  textdomain (PACKAGE);

  atexit (close_stdout);

  parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
                           usage, AUTHORS, (char const *) NULL);
  if (getopt_long (argc, argv, "+", NULL, NULL) != -1)
    usage (EXIT_FAILURE);

  if (argc < 2)
    usage(EXIT_FAILURE);


  if (strlen(argv[1]) >= (sizeof fake - 1)) {
    error (EXIT_FAILURE, 0, _("fake is too long"), argv[1]);
  }

  if (strlen(argv[2]) >= (sizeof real - 1)) {
    error (EXIT_FAILURE, 0, _("real is too long"), argv[1]);
  }

  /* copies (argv[1] = fake) into fake[] */
  n = MIN(sizeof fake - 1, strlen(argv[1]));
  strncpy(fake, argv[1], n); 
  fake[n] = '\0';

  /* copies (argv[2] = real) into real[] */
  n = MIN(sizeof real - 1, strlen(argv[2]));
  strncpy(real, argv[2], n); 
  real[n] = '\0';

  /* we're going to format vargv in spaces first. then we'll put fake at
   * the beginning, and then skip enough bytes so that vargv will look
   * like [fake ... enough spaces ...  real]. now, if ps looks at an
   * argv[] like that, it sees only [fake ... enough spaces ...] as long
   * as it doesn't read past PADSIZE --- so PADSIZE must be large
   * enough. at this point, if we replace the process with another one,
   * by way of execvp(), we can give the new process a new argv[] and ps
   * will still read the previous one; this way we fool ps into thinking
   * the new process has the old argv[]. */

  memset(vargv, ' ', PADSIZE); /* format vargv[] with spaces */

  /* put fake at the beginning of vargv[] */
  strncpy(vargv, fake, strlen(fake));

  /* put real at argv[] after PADSIZE bytes */
  strncpy(vargv + PADSIZE, real, MIN(sizeof vargv - PADSIZE,
  strlen(real)));

  /* now set arvg[2] to vargv[] so that we may pass &argv[2] to
   * execvp(); so real's argv[0] begins at (vargv + PADSIZE). */
  argv[2] = vargv;

  run(real, argv + 2);

  error (EXIT_FAILURE, 0, _("Could not run %s"), real);
}

Andreas Schwab writes:
 > Andreas Schwab <address@hidden> writes:
 > 
 > > Brian Dessent <address@hidden> writes:
 > >
 > >> "Daniel C. Bastos" wrote:
 > >>
 > >>> I always miss these two programs on every system I meet. argv0 is very
 > >>> handy when dealing with programs that care about argv[0] and psfool is
 > >>> essential when giving out passwords through the command line. I figure
 > >>> these two should be in coreutils.
 > >>
 > >> perl -e 'exec { "real" } "fake", "arg1", "arg2"'
 > >
 > > bash -c 'exec -a "$0" "$@"' real fake arg1 arg2
 > 
 > That should of course be:
 > 
 > bash -c 'exec -a "$0" "$@"' fake real arg1 arg2
 > 
 > Andreas.

This will hide the real argv[0] with a fake argv[0]; but won't hide
argv[1], argv[2], ..., argv[n]. The purpose of psfool is to hide those
too.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]