2 Replies Latest reply on Oct 5, 2010 3:46 AM by user261308

    Track dir removal by any means

      Hi Guys,

      I'm new (& self-taught) to DTrace and needed to write a program to track a specified dir and find out who/when/how etc if it got removed/renamed etc.

      As you can see from the below code, I've been caught by 1 or 2 gotchas during my testing. This is a serious prog, now in Production, so any comments towards making it better/more robust would be appreciated.

      # Desc    : Track dir deletions of specified dir in specified zone.
      #           Attempts to handle path issues on cmd and/or dir/dir.
      #           Tries to catch any form of removal eg shell cmds:
      #           rm, rmdir, unlink, mv and 'internal' code cmds inside Perl, C etc.
      #           Note that normally this prog is controlled by
      #           dt_dir_removal_mgr.pl, which reads the stdout & stderr,
      #           filters false positives etc & logs and emails any alerts.
      #           We do not allow the path of the tgt dir to be used,
      #           as this may not be specified by the offending user/app...
      #           thus we may get some false positives eg a file of the same name.
      #           Local zonename is avail from DTrace, but filesystem and inode
      #           are not avail from psinfo struct.
      #           Not matching on zone because tgt dir can be deleted from global,
      #           although the users should not be able to get in there.
          echo "USAGE: dt_dir_removal.sh -d dirname -z zonename
                  -d dirname      # dirname to track : must NOT inc path
                  dt_dir_removal.sh -d testdir
          exit 1
      # --- Process Arguments ---
      # Arg supplied ?
      if [[ $# -eq 0 ]]
      # Check switch value & arg value : see usage()
      while getopts d: name
          case $name in
          d)  dirname=$(basename $OPTARG) ;;
          *)  usage ;;
      # --- DTrace ---
      # NB: seem to need the single quotes around the DTrace code ...
      # This also means the even the contents of comment blocks CANNOT have single quotes
      # in them eg don't, won't etc... (sigh...)
      /usr/sbin/dtrace -n  '
       /* Params from shell input */
       inline string DIRNAME  = "'$dirname'";
       #pragma D option quiet
       #pragma D option switchrate=10hz
        * Print header
          /* print main headers: We cannot line up final arg hdr exactly
           * because the cmd len varies
          printf("%-20s %-12s %5s  %5s  %6s  %6s  %s -> %s\n",
                 "TIME", "ZONE", "GID", "UID", "PID", "PPID", "CMD", "TARGET") ;
        *  Check exec event type
          /* Grab the dirname in qn to test later: remove any preceding path */
          /* Experiment seems to indicate unlink will not have this value in the return state ;
           * contrast with rmdir below which may not have it in entry state
          tgt = basename(copyinstr(arg0));
      /* http://docs.sun.com/app/docs/doc/817-6223/6mlkidlrg?l=en&a=view#indexterm-458 :
       * Avoiding Errors
       * The copyin() and copyinstr() subroutines cannot read from user addresses which have not yet
       * been touched so even a valid address may cause an error if the page containing that address
       * has not yet been faulted in by being accessed.
       * To resolve this issue, wait for kernel or application to use the data before tracing it.
       * For example, you might wait until the system call returns to apply copyinstr()
      syscall::rmdir:entry, syscall::rename:entry
          /* Try saving a ptr to the relevant value for later, otherwise it gives invalid addr error
           * in return section below
          self->file = arg0;
      syscall::rmdir:return, syscall::rename:return
          /* Grab the dirname in qn to test later: remove any preceding path */
          tgt = basename(copyinstr(self->file));
      /* Not matching on zone because tgt dir can be deleted from global,
       * although the users should not be able to get in there.
      syscall::rmdir:return, syscall::rename:return, syscall::unlink:return
      / DIRNAME == tgt / 
          /* Print the field values. The TARGET tends not to line up as we
             print the cmd and the target name for completeness. For a shell level cmd,
             we will get the target name in the CMD field as well. For an "internal" cmd,
             eg rmdir() from within perl, the CMD field does not contain the target value.
          printf("%-20Y %-12s %5d  %5d  %6d  %6d  %s -> %s\n",
                  walltimestamp, zonename, gid, uid, pid, ppid,
                  curpsinfo->pr_psargs, tgt ) ;
          /* Clear the self->file ptr to avoid dynamic variable drop errors */
          self->file = 0;
        • 1. Re: Track dir removal by any means
          That's what auditing is for. Read this:

          • 2. Re: Track dir removal by any means

            I started by looking at that originally, but it didn't seem to be capable of just doing the very fine tracking I wanted; just one dir that's unlikely to be removed, but when it is we need to know IMMEDIATELY and incidentally by whom and how.
            BSM/audit seemed to only be able to audit at a much higher/coarser level and would generate a lot of logging and you'd be looking at it after the fact.
            My soln works nicely generally, but I have just got this

            dtrace: error on enabled probe ID 6 (ID 11792: syscall::rename:return): invalid address (0x0) in action #1 at DIF offset 28
            I've got a ctrl prog that keeps an eye on the DTrace prog and just restarts it if this happens. Seems to work ok, but I'm going to have another look at solving that error...