VirtualBox

Changeset 1598 in kBuild


Ignore:
Timestamp:
May 1, 2008 9:52:59 PM (17 years ago)
Author:
bird
Message:

split out the path protection code from rm.

Location:
trunk/src/kmk
Files:
2 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kmk/Makefile.am

    r1526 r1598  
    7575                kmkbuiltin/strlcpy.c \
    7676                kmkbuiltin/osdep.c \
     77                kmkbuiltin/kbuild_protection.c \
    7778                kmkbuiltin/kbuild_version.c
    7879
  • trunk/src/kmk/Makefile.kmk

    r1526 r1598  
    8282        kmkbuiltin/strmode.c \
    8383        kmkbuiltin/kbuild_version.c \
     84        kmkbuiltin/kbuild_protection.c \
    8485        getopt.c \
    8586        getopt1.c \
  • trunk/src/kmk/kmkbuiltin/rm.c

    r1578 r1598  
    6767# include <direct.h>
    6868# include <limits.h>
    69 #endif 
     69#endif
    7070#include "kmkbuiltin.h"
     71#include "kbuild_protection.h"
    7172
    7273#if defined(__EMX__) || defined(_MSC_VER)
     
    9495#endif
    9596
    96 static int protectionflag, fullprotectionflag, protectiondepth;
    9797static int dflag, eval, fflag, iflag, Pflag, vflag, Wflag, stdin_ok;
    9898static uid_t uid;
    9999
    100100static char *argv0;
     101static KBUILDPROTECTION g_ProtData;
    101102
    102103static struct option long_options[] =
     
    115116static int      check(char *, char *, struct stat *);
    116117static void     checkdot(char **);
    117 static void     rm_file(char **);
     118static int      rm_file(char **);
    118119static int      rm_overwrite(char *, struct stat *);
    119 static void     rm_tree(char **);
     120static int      rm_tree(char **);
    120121static int      count_path_components(const char *);
    121122static int  set_protection_depth(const char *);
     
    140141        argv0 = argv[0];
    141142        dflag = eval = fflag = iflag = Pflag = vflag = Wflag = stdin_ok = 0;
    142         fullprotectionflag = 0;
    143         protectionflag = 1;
    144         protectiondepth = DEFAULT_PROTECTION_DEPTH;
    145143        uid = 0;
     144        kBuildProtectionInit(&g_ProtData);
    146145
    147146        /* kmk: reset getopt and set program name. */
     
    184183#endif
    185184                case 261:
     185                        kBuildProtectionTerm(&g_ProtData);
    186186                        usage(stdout);
    187187                        return 0;
    188188                case 262:
     189                        kBuildProtectionTerm(&g_ProtData);
    189190                        return kbuild_version(argv[0]);
    190191                case 263:
    191                         protectionflag = 0;
     192                        kBuildProtectionDisable(&g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE);
    192193                        break;
    193194                case 264:
    194                         protectionflag = 1;
     195                        kBuildProtectionEnable(&g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE);
    195196                        break;
    196197                case 265:
    197                         fullprotectionflag = 1;
     198                        kBuildProtectionEnable(&g_ProtData, KBUILDPROTECTIONTYPE_FULL);
    198199                        break;
    199200                case 266:
    200                         fullprotectionflag = 0;
     201                        kBuildProtectionDisable(&g_ProtData, KBUILDPROTECTIONTYPE_FULL);
    201202                        break;
    202203                case 267:
    203                         set_protection_depth(optarg);
     204                        if (kBuildProtectionSetDepth(&g_ProtData, optarg)) {
     205                            kBuildProtectionTerm(&g_ProtData);
     206                            return 1;
     207                        }
    204208                        break;
    205209                case '?':
    206210                default:
     211                        kBuildProtectionTerm(&g_ProtData);
    207212                        return usage(stderr);
    208213                }
     
    211216
    212217        if (argc < 1) {
     218                kBuildProtectionTerm(&g_ProtData);
    213219                if (fflag)
    214220                        return (0);
     
    216222        }
    217223
    218         /* Search the environment for option overrides (protection). */
    219         for (i = 0; envp[i]; i++) {
    220                 if (!strncmp(envp[i], "KMK_RM_", sizeof("KMK_RM_") - 1)) {
    221                         if (!strncmp(envp[i], "KMK_RM_PROTECTION_DEPTH=", sizeof("KMK_RM_PROTECTION_DEPTH=") - 1)) {
    222                                 const char *val = envp[i] + sizeof("KMK_RM_PROTECTION_DEPTH=") - 1;
    223                                 if (set_protection_depth(val))
    224                                         return eval;
    225                         } else if (!strncmp(envp[i], "KMK_RM_DISABLE_PROTECTION=", sizeof("KMK_RM_DISABLE_PROTECTION=") - 1)) {
    226                                 if (protectionflag >= 0)
    227                                         protectionflag = 0;
    228                         } else if (!strncmp(envp[i], "KMK_RM_ENABLE_PROTECTION=", sizeof("KMK_RM_ENABLE_PROTECTION=") - 1)) {
    229                                 protectionflag = -1;
    230                         } else if (!strncmp(envp[i], "KMK_RM_DISABLE_FULL_PROTECTION=", sizeof("KMK_RM_DISABLE_FULL_PROTECTION=") - 1)) {
    231                                 if (fullprotectionflag >= 0)
    232                                         fullprotectionflag = 0;
    233                         } else if (!strncmp(envp[i], "KMK_RM_ENABLE_FULL_PROTECTION=", sizeof("KMK_RM_ENABLE_FULL_PROTECTION=") - 1)) {
    234                                 fullprotectionflag = protectionflag = -1;
    235                         }
    236                 }
    237         }
    238         if (fullprotectionflag)
    239                 protectionflag = 1;
    240 
    241         checkdot(argv);
    242         uid = geteuid();
    243 
    244         if (*argv) {
    245                 stdin_ok = isatty(STDIN_FILENO);
    246                 if (rflag)
    247                         rm_tree(argv);
    248                 else
    249                         rm_file(argv);
    250         }
    251 
     224        if (!kBuildProtectionScanEnv(&g_ProtData, envp, "KMK_RM_")) {
     225                checkdot(argv);
     226                uid = geteuid();
     227
     228                if (*argv) {
     229                        stdin_ok = isatty(STDIN_FILENO);
     230                        if (rflag)
     231                                eval |= rm_tree(argv);
     232                        else
     233                                eval |= rm_file(argv);
     234                }
     235        } else {
     236                eval = 1;
     237        }
     238
     239        kBuildProtectionTerm(&g_ProtData);
    252240        return eval;
    253241}
    254242
    255 /**
    256  * Sets protectiondepth according to the option argument.
    257  *
    258  * @returns eval, that is 0 on success and non-zero on failure
    259  *
    260  * @param   val         The value.
    261  */
    262243static int
    263 set_protection_depth(const char *val)
    264 {
    265         /* skip leading blanks, they don't count either way. */
    266         while (isspace(*val))
    267                 val++;
    268 
    269         /* number or path? */
    270         if (!isdigit(*val) || strpbrk(val, ":/\\")) {
    271                 protectiondepth = count_path_components(val);
    272         } else {
    273                 char *more = 0;
    274                 protectiondepth = strtol(val, &more, 0);
    275                 if (protectiondepth != 0 && more) {
    276                         /* trailing space is harmless. */
    277                         while (isspace(*more))
    278                                 more++;
    279                 }
    280                 if (!protectiondepth || val == more || *more)
    281                         return eval = errx(1, "bogus protection depth: %s", val);
    282         }
    283 
    284         if (protectiondepth < 1)
    285                 return eval = errx(1, "bogus protection depth: %s", val);
    286         return eval;
    287 }
    288 
    289 /**
    290  * Counts the components in the specified sub path.
    291  * This is a helper for count_path_components.
    292  *
    293  * etc = 1
    294  * etc/ = 1
    295  * etc/x11 = 2
    296  * and so and and so forth.
    297  */
    298 static int
    299 count_sub_path_components(const char *path, int depth)
    300 {
    301         for (;;) {
    302                 const char *end;
    303                 size_t len;
    304 
    305                 /* skip slashes. */
    306                 while (IS_SLASH(*path))
    307                         path++;
    308                 if (!*path)
    309                         break;
    310 
    311                 /* find end of component. */
    312                 end = path;
    313                 while (!IS_SLASH(*end) && *end)
    314                         end++;
    315 
    316                 /* count it, checking for '..' and '.'. */
    317                 len = end - path;
    318                 if (len == 2 && path[0] == '.' && path[1] == '.') {
    319                         if (depth > 0)
    320                                 depth--;
    321                 } else if (len != 1 || path[0] != '.') {
    322                         depth++;
    323                 }
    324 
    325                 /* advance */
    326                 if (!*end)
    327                         break;
    328                 path = end + 1;
    329         }
    330         return depth;
    331 }
    332 
    333 /**
    334  * Parses the specified path counting the number of components
    335  * relative to root.
    336  *
    337  * We don't check symbolic links and such, just some simple and cheap
    338  * path parsing.
    339  *
    340  * @param   path                The path to process.
    341  *
    342  * @returns 0 or higher on success.
    343  *          On failure an error is printed, eval is set and -1 is returned.
    344  */
    345 static int
    346 count_path_components(const char *path)
    347 {
    348         int components = 0;
    349 
    350         /*
    351          * Deal with root, UNC, drive letter.
    352      */
    353 #if defined(_MSC_VER) || defined(__OS2__)
    354         if (IS_SLASH(path[0]) && IS_SLASH(path[1]) && !IS_SLASH(path[2])) {
    355                 /* skip the root - UNC */
    356                 path += 3;
    357                 while (!IS_SLASH(*path) && *path) /* server name */
    358                         path++;
    359                 while (IS_SLASH(*path))
    360                         path++;
    361                 while (!IS_SLASH(*path) && *path) /* share name */
    362                         path++;
    363                 while (IS_SLASH(*path))
    364                         path++;
    365         } else {
    366                 unsigned drive_letter = (unsigned)toupper(path[0]) - (unsigned)'A';
    367                 if (drive_letter <= (unsigned)('Z' - 'A') && path[1] == ':') {
    368                         drive_letter++; /* A == 1 */
    369                 } else {
    370                         drive_letter = 0; /* 0 == default */
    371                 }
    372 
    373                 if (!IS_SLASH(path[drive_letter ? 2 : 0])) {
    374                         /*
    375                          * Relative path, must count cwd depth first.
    376                          */
    377 #ifdef __OS2__ /** @todo remove when ticket 194 has been fixed */
    378                         char *cwd = _getdcwd(drive_letter, NULL, PATH_MAX);
    379 #else
    380                         char *cwd = _getdcwd(drive_letter, NULL, 0);
    381 #endif
    382                         char *tmp = cwd;
    383                         if (!tmp) {
    384                                 eval = err(1, "_getdcwd");
    385                                 return -1;
    386                         }
    387 
    388                         if (IS_SLASH(tmp[0]) && IS_SLASH(tmp[1])) {
    389                                 /* skip the root - UNC */
    390                                 tmp += 2;
    391                                 while (!IS_SLASH(*tmp) && *tmp) /* server name */
    392                                         tmp++;
    393                                 while (IS_SLASH(*tmp))
    394                                         tmp++;
    395                                 while (!IS_SLASH(*tmp) && *tmp) /* share name */
    396                                         tmp++;
    397                         } else {
    398                                 /* skip the drive letter and while we're at it, the root slash too. */
    399                                 tmp += 1 + (tmp[1] == ':');
    400                         }
    401                         components = count_sub_path_components(tmp, 0);
    402                         free(cwd);
    403                 } else {
    404                         /* skip the drive letter and while we're at it, the root slash too. */
    405                         path += drive_letter ? 3 : 1;
    406                 }
    407         }
    408 #else
    409         if (!IS_SLASH(path[0])) {
    410                 /*
    411                  * Relative path, must count cwd depth first.
    412          */
    413                 char cwd[4096];
    414                 if (!getcwd(cwd, sizeof(cwd))) {
    415                         eval = err(1, "getcwd");
    416                         return -1;
    417                 }
    418                 components = count_sub_path_components(cwd, 0);
    419         }
    420 #endif
    421 
    422         /*
    423          * We're now past any UNC or drive letter crap, possibly positioned
    424          * at the root slash or at the start of a path component at the
    425          * given depth. Count the remainder.
    426          */
    427         return count_sub_path_components(path, components);
    428 }
    429 
    430 
    431 /**
    432  * Protect the upper layers of the file system against accidental
    433  * or malicious deletetion attempt from within a makefile.
    434  *
    435  * @param   path                The path to check.
    436  * @param   required_depth      The minimum number of components in the
    437  *                              path counting from the root.
    438  *
    439  * @returns 0 on success.
    440  *          On failure an error is printed, eval is set and -1 is returned.
    441  */
    442 static int
    443 enforce_protection(const char *path, int required_depth)
    444 {
    445         int components;
    446 
    447         /*
    448          * Count the path and compare it with the required depth.
    449      */
    450         components = count_path_components(path);
    451         if (components < 0)
    452                 return -1;
    453         if (components < required_depth) {
    454                 eval = errx(1, "%s: protected", path);
    455                 return -1;
    456         }
    457         return 0;
    458 }
    459 
    460 static void
    461244rm_tree(char **argv)
    462245{
     
    471254         * everything, but we'll check the individual items later.
    472255         */
    473         if (protectionflag) {
    474                 int i;
    475                 for (i = 0; argv[i]; i++) {
    476                         if (enforce_protection(argv[i], protectiondepth + 1))
    477                                 return;
     256        int i;
     257        for (i = 0; argv[i]; i++) {
     258                if (kBuildProtectionEnforce(&g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE, argv[i])) {
     259                        return 1;
    478260                }
    479261        }
     
    499281#endif
    500282        if (!(fts = fts_open(argv, flags, NULL))) {
    501                 eval = err(1, "fts_open");
    502                 return;
     283                return err(1, "fts_open");
    503284        }
    504285        while ((p = fts_read(fts)) != NULL) {
     
    512293                        continue;
    513294                case FTS_ERR:
    514                         eval = errx(1, "%s: %s", p->fts_path, strerror(p->fts_errno));
    515295                        fts_close(fts);
    516                         return;
     296                        return errx(1, "%s: %s", p->fts_path, strerror(p->fts_errno));
    517297                case FTS_NS:
    518298                        /*
     
    558338                 * Protect against deleting root files and directories.
    559339                 */
    560                 if (protectionflag && enforce_protection(p->fts_accpath, protectiondepth + 1)) {
     340                if (kBuildProtectionEnforce(&g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE, p->fts_accpath)) {
    561341                        fts_close(fts);
    562                         return;
     342                        return 1;
    563343                }
    564344
     
    640420        }
    641421        fts_close(fts);
     422        return eval;
    642423}
    643424
    644 static void
     425static int
    645426rm_file(char **argv)
    646427{
     
    652433         * Check up front before anything is deleted.
    653434         */
    654         if (fullprotectionflag) {
    655                 int i;
    656                 for (i = 0; argv[i]; i++) {
    657                         if (enforce_protection(argv[i], protectiondepth + 1))
    658                                 return;
    659                 }
     435        int i;
     436        for (i = 0; argv[i]; i++) {
     437                if (kBuildProtectionEnforce(&g_ProtData, KBUILDPROTECTIONTYPE_FULL, argv[i]))
     438                        return 1;
    660439        }
    661440
     
    714493#ifdef _MSC_VER
    715494                                if (rval != 0) {
    716                                         chmod(f, 0777);
     495                                        chmod(f, 0777);
    717496                                        rval = unlink(f);
    718497                                }
     
    727506                        (void)printf("%s\n", f);
    728507        }
     508        return eval;
    729509}
    730510
     
    836616                if ((flagsp = fflagstostr(sp->st_flags)) == NULL)
    837617                        exit(err(1, "fflagstostr"));
    838                 (void)fprintf(stderr, "override %s%s%s/%s %s%sfor %s? ",
    839                     modep + 1, modep[9] == ' ' ? "" : " ",
    840                     user_from_uid(sp->st_uid, 0),
    841                     group_from_gid(sp->st_gid, 0),
    842                     *flagsp ? flagsp : "", *flagsp ? " " : "",
    843                     path);
     618                (void)fprintf(stderr, "override %s%s%s/%s %s%sfor %s? ",
     619                              modep + 1, modep[9] == ' ' ? "" : " ",
     620                              user_from_uid(sp->st_uid, 0),
     621                              group_from_gid(sp->st_gid, 0),
     622                              *flagsp ? flagsp : "", *flagsp ? " " : "",
     623                              path);
    844624                free(flagsp);
    845625#else
    846                 (void)flagsp;
    847                 (void)fprintf(stderr, "override %s%s %d/%d for %s? ",
    848                     modep + 1, modep[9] == ' ' ? "" : " ",
    849                     sp->st_uid, sp->st_gid, path);
     626                (void)flagsp;
     627                (void)fprintf(stderr, "override %s%s %d/%d for %s? ",
     628                              modep + 1, modep[9] == ' ' ? "" : " ",
     629                              sp->st_uid, sp->st_gid, path);
    850630#endif
    851631        }
     
    951731                ,
    952732                g_progname, g_progname, g_progname,
    953                 DEFAULT_PROTECTION_DEPTH, DEFAULT_PROTECTION_DEPTH);
     733                kBuildProtectionDefaultDepth(), kBuildProtectionDefaultDepth());
    954734        return EX_USAGE;
    955735}
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette