"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-apparmor.c" (15 Mar 2019, 15509 Bytes) of package /linux/privat/stress-ng-0.09.56.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "stress-apparmor.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.09.54_vs_0.09.55.

    1 /*
    2  * Copyright (C) 2013-2019 Canonical, Ltd.
    3  *
    4  * This program is free software; you can redistribute it and/or
    5  * modify it under the terms of the GNU General Public License
    6  * as published by the Free Software Foundation; either version 2
    7  * of the License, or (at your option) any later version.
    8  *
    9  * This program is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12  * GNU General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU General Public License
   15  * along with this program; if not, write to the Free Software
   16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
   17  *
   18  * This code is a complete clean re-write of the stress tool by
   19  * Colin Ian King <colin.king@canonical.com> and attempts to be
   20  * backwardly compatible with the stress tool by Amos Waterland
   21  * <apw@rossby.metr.ou.edu> but has more stress tests and more
   22  * functionality.
   23  *
   24  */
   25 #include "stress-ng.h"
   26 
   27 #if defined(HAVE_APPARMOR) &&       \
   28     defined(HAVE_SYS_APPARMOR_H) &&     \
   29     defined(HAVE_SYS_SELECT_H)
   30 
   31 #define APPARMOR_BUF_SZ (4096)
   32 
   33 typedef int (*apparmor_func)(const char *name,
   34                  const uint64_t max_ops, uint64_t *counter);
   35 
   36 static volatile bool apparmor_run = true;
   37 static char *apparmor_path = NULL;
   38 
   39 extern char g_apparmor_data[];
   40 extern const size_t g_apparmor_data_len;
   41 
   42 /*
   43  *  stress_apparmor_supported()
   44  *      check if AppArmor is supported
   45  */
   46 static int stress_apparmor_supported(void)
   47 {
   48     int fd;
   49     char path[PATH_MAX];
   50 
   51     /* Initial sanity checks for AppArmor */
   52     if (!aa_is_enabled()) {
   53         pr_inf("apparmor stressor will be skipped, "
   54             "AppArmor is not enabled\n");
   55         return -1;
   56     }
   57     if (aa_find_mountpoint(&apparmor_path) < 0) {
   58         pr_inf("apparmor stressor will be skipped, "
   59             "cannot get AppArmor path, errno=%d (%s)\n",
   60             errno, strerror(errno));
   61         return -1;
   62     }
   63     /* ..and see if profiles are accessible */
   64     (void)snprintf(path, sizeof(path), "%s/%s", apparmor_path, "profiles");
   65     if ((fd = open(path, O_RDONLY)) < 0) {
   66         switch (errno) {
   67         case EACCES:
   68             pr_inf("apparmor stressor will be skipped, "
   69                 "stress-ng needs to be run with root "
   70                 "privilege to access AppArmor /sys files.\n");
   71             break;
   72         case ENOENT:
   73             pr_inf("apparmor stressor will be skipped, "
   74                 "AppArmor /sys files do not exist\n");
   75             break;
   76         default:
   77             pr_inf("apparmor stressor will be skipped, "
   78                 "cannot access AppArmor /sys files: "
   79                 "errno=%d (%s)\n", errno, strerror(errno));
   80             break;
   81         }
   82         free(apparmor_path);
   83         apparmor_path = NULL;
   84         return -1;
   85     }
   86     (void)close(fd);
   87 
   88     return 0;
   89 }
   90 
   91 
   92 /*
   93  *  stress_apparmor_handler()
   94  *      signal handler
   95  */
   96 static void MLOCKED_TEXT stress_apparmor_alrm_handler(int signum)
   97 {
   98     (void)signum;
   99 
  100     apparmor_run = false;
  101 }
  102 
  103 static void MLOCKED_TEXT stress_apparmor_usr1_handler(int signum)
  104 {
  105         (void)signum;
  106 }
  107 
  108 
  109 /*
  110  *  stress_apparmor_read()
  111  *  read a proc file
  112  */
  113 static void stress_apparmor_read(const char *path)
  114 {
  115     int fd;
  116     ssize_t i = 0;
  117     char buffer[APPARMOR_BUF_SZ];
  118 
  119     if ((fd = open(path, O_RDONLY | O_NONBLOCK)) < 0)
  120         return;
  121     /*
  122      *  Multiple randomly sized reads
  123      */
  124     while (g_keep_stressing_flag &&
  125            apparmor_run &&
  126            (i < (4096 * APPARMOR_BUF_SZ))) {
  127         ssize_t ret, sz = 1 + (mwc32() % sizeof(buffer));
  128 redo:
  129         if (!g_keep_stressing_flag || !apparmor_run)
  130             break;
  131         ret = read(fd, buffer, sz);
  132         if (ret < 0) {
  133             if ((errno == EAGAIN) || (errno == EINTR))
  134                 goto redo;
  135             break;
  136         }
  137         if (ret < sz)
  138             break;
  139         i += sz;
  140     }
  141     (void)close(fd);
  142 }
  143 
  144 /*
  145  *  stress_apparmor_dir()
  146  *  read directory
  147  */
  148 static void stress_apparmor_dir(
  149     const char *path,
  150     const bool recurse,
  151     const int depth)
  152 {
  153     DIR *dp;
  154     struct dirent *d;
  155 
  156     if (!g_keep_stressing_flag || !apparmor_run)
  157         return;
  158 
  159     /* Don't want to go too deep */
  160     if (depth > 8)
  161         return;
  162 
  163     dp = opendir(path);
  164     if (dp == NULL)
  165         return;
  166 
  167     while ((d = readdir(dp)) != NULL) {
  168         char name[PATH_MAX];
  169 
  170         if (!g_keep_stressing_flag || !apparmor_run)
  171             break;
  172         if (stress_is_dot_filename(d->d_name))
  173             continue;
  174         switch (d->d_type) {
  175         case DT_DIR:
  176             if (recurse) {
  177                 (void)snprintf(name, sizeof(name),
  178                     "%s/%s", path, d->d_name);
  179                 stress_apparmor_dir(name, recurse, depth + 1);
  180             }
  181             break;
  182         case DT_REG:
  183             (void)snprintf(name, sizeof(name),
  184                 "%s/%s", path, d->d_name);
  185             stress_apparmor_read(name);
  186             break;
  187         default:
  188             break;
  189         }
  190     }
  191     (void)closedir(dp);
  192 }
  193 
  194 
  195 /*
  196  *  apparmor_spawn()
  197  *  spawn a process
  198  */
  199 static pid_t apparmor_spawn(
  200     const args_t *args,
  201     const uint64_t max_ops,
  202     uint64_t *counter,
  203     apparmor_func func)
  204 {
  205     pid_t pid;
  206 
  207 again:
  208     pid = fork();
  209     if (pid < 0) {
  210         if (g_keep_stressing_flag &&
  211             ((errno == EAGAIN) || (errno == ENOMEM)))
  212             goto again;
  213         return -1;
  214     }
  215     if (pid == 0) {
  216         int ret = EXIT_SUCCESS;
  217 
  218         if (!g_keep_stressing_flag)
  219             goto abort;
  220 
  221         if (stress_sighandler(args->name, SIGALRM,
  222                       stress_apparmor_alrm_handler, NULL) < 0) {
  223             _exit(EXIT_FAILURE);
  224         }
  225 
  226         (void)setpgid(0, g_pgrp);
  227         stress_parent_died_alarm();
  228         if (!g_keep_stressing_flag || !apparmor_run)
  229             goto abort;
  230         ret = func(args->name, max_ops, counter);
  231 abort:
  232         free(apparmor_path);
  233         kill(args->pid, SIGUSR1);
  234         _exit(ret);
  235     }
  236     (void)setpgid(pid, g_pgrp);
  237     return pid;
  238 }
  239 
  240 /*
  241  *  apparmor_stress_profiles()
  242  *  hammer profile reading
  243  */
  244 static int apparmor_stress_profiles(
  245     const char *name,
  246     const uint64_t max_ops,
  247     uint64_t *counter)
  248 {
  249     char path[PATH_MAX];
  250 
  251     (void)name;
  252     (void)snprintf(path, sizeof(path), "%s/%s", apparmor_path, "profiles");
  253 
  254     do {
  255         stress_apparmor_read(path);
  256         (*counter)++;
  257     } while (g_keep_stressing_flag &&
  258          apparmor_run &&
  259          (!max_ops || *counter < max_ops));
  260 
  261     return EXIT_SUCCESS;
  262 }
  263 
  264 /*
  265  *  apparmor_stress_features()
  266  *  hammer features reading
  267  */
  268 static int apparmor_stress_features(
  269     const char *name,
  270     const uint64_t max_ops,
  271     uint64_t *counter)
  272 {
  273     char path[PATH_MAX];
  274 
  275     (void)name;
  276     (void)snprintf(path, sizeof(path), "%s/%s", apparmor_path, "features");
  277 
  278     do {
  279         stress_apparmor_dir(path, true, 0);
  280         (*counter)++;
  281     } while (g_keep_stressing_flag &&
  282          apparmor_run &&
  283          (!max_ops || *counter < max_ops));
  284 
  285     return EXIT_SUCCESS;
  286 }
  287 
  288 /*
  289  *  apparmor_stress_kernel_interface()
  290  *  load/replace/unload stressing
  291  */
  292 static int apparmor_stress_kernel_interface(
  293     const char *name,
  294     const uint64_t max_ops,
  295     uint64_t *counter)
  296 {
  297     int rc = EXIT_SUCCESS;
  298     aa_kernel_interface *kern_if;
  299 
  300     /*
  301      *  Try and create a lot of contention and load
  302      */
  303     do {
  304         int ret = aa_kernel_interface_new(&kern_if, NULL, NULL);
  305         if (ret < 0) {
  306             pr_fail("%s: aa_kernel_interface_new() failed, "
  307                 "errno=%d (%s)\n", name,
  308                 errno, strerror(errno));
  309             rc = EXIT_FAILURE;
  310             break;
  311         }
  312 
  313         /*
  314          *  Loading a policy may fail if another stressor has
  315          *  already loaded the same policy, so we may get EEXIST
  316          */
  317         ret = aa_kernel_interface_load_policy(kern_if,
  318             g_apparmor_data, g_apparmor_data_len);
  319         if (ret < 0) {
  320             if (errno != EEXIST) {
  321                 pr_fail("%s: aa_kernel_interface_load_policy() failed, "
  322                     "errno=%d (%s)\n", name, errno, strerror(errno));
  323                 rc = EXIT_FAILURE;
  324             }
  325         }
  326 
  327         /*
  328          *  Replacing should always be atomic and not fail when
  329          *  competing against other stressors if I understand the
  330          *  interface correctly.
  331          */
  332         ret = aa_kernel_interface_replace_policy(kern_if,
  333             g_apparmor_data, g_apparmor_data_len);
  334         if (ret < 0) {
  335             aa_kernel_interface_unref(kern_if);
  336 
  337             pr_inf("%s: aa_kernel_interface_replace_policy() failed, "
  338                 "errno=%d (%s)\n", name, errno,
  339                 strerror(errno));
  340         }
  341 
  342         /*
  343          *  Removal may fail if another stressor has already removed the
  344          *  policy, so we may get ENOENT
  345          */
  346         ret = aa_kernel_interface_remove_policy(kern_if,
  347             "/usr/bin/pulseaudio-eg");
  348         if (ret < 0) {
  349             if (errno != ENOENT) {
  350                 aa_kernel_interface_unref(kern_if);
  351 
  352                 pr_fail("%s: aa_kernel_interface_remove_policy() failed, "
  353                     "errno=%d (%s)\n", name, errno,
  354                     strerror(errno));
  355                 rc = EXIT_FAILURE;
  356                 break;
  357             }
  358         }
  359         aa_kernel_interface_unref(kern_if);
  360 
  361         (*counter)++;
  362     } while (g_keep_stressing_flag &&
  363          apparmor_run &&
  364                  (!max_ops || *counter < max_ops));
  365 
  366     return rc;
  367 }
  368 
  369 /*
  370  *  apparmor_corrupt_flip_bits_random()
  371  *  bit flip random bits in data
  372  */
  373 static inline void apparmor_corrupt_flip_bits_random(
  374     char *copy, const size_t len)
  375 {
  376     uint32_t i;
  377     const uint32_t n = mwc32() % 17;
  378 
  379     for (i = 0; i < n; i++) {
  380         uint32_t rnd = mwc32();
  381 
  382         copy[rnd % len] ^= (1 << ((rnd >> 16) & 7));
  383     }
  384 }
  385 
  386 /*
  387  *  apparmor_corrupt_flip_seq()
  388  *  sequentially flip bits
  389  */
  390 static inline void apparmor_corrupt_flip_seq(
  391     char *copy, const size_t len)
  392 {
  393     static size_t p = 0;
  394 
  395     if (p > (len * sizeof(char)))
  396         p = 0;
  397 
  398     copy[p / sizeof(char)] ^= (1 << (p & 7));
  399     p++;
  400 }
  401 
  402 /*
  403  *  apparmor_corrupt_clr_seq()
  404  *  sequentially clear bits
  405  */
  406 static inline void apparmor_corrupt_clr_seq(
  407     char *copy, const size_t len)
  408 {
  409     static size_t p = 0;
  410 
  411     if (p > (len * sizeof(char)))
  412         p = 0;
  413 
  414     copy[p / sizeof(char)] &= ~(1 << (p & 7));
  415     p++;
  416 }
  417 
  418 /*
  419  *  apparmor_corrupt_set_seq()
  420  *  sequentially set bits
  421  */
  422 static inline void apparmor_corrupt_set_seq(
  423     char *copy, const size_t len)
  424 {
  425     static size_t p = 0;
  426 
  427     if (p > (len * sizeof(char)))
  428         p = 0;
  429 
  430     copy[p / sizeof(char)] |= (1 << (p & 7));
  431     p++;
  432 }
  433 
  434 
  435 /*
  436  *  apparmor_corrupt_flip_byte_random()
  437  *  ramndomly flip entire bytes
  438  */
  439 static inline void apparmor_corrupt_flip_byte_random(
  440     char *copy, const size_t len)
  441 {
  442     copy[mwc32() % len] ^= 0xff;
  443 }
  444 
  445 /*
  446  *  apparmor_corrupt_clr_bits_random()
  447  *  randomly clear bits
  448  */
  449 static inline void apparmor_corrupt_clr_bits_random(
  450     char *copy, const size_t len)
  451 {
  452     uint32_t i;
  453     const uint32_t n = mwc32() % 17;
  454 
  455     for (i = 0; i < n; i++) {
  456         uint32_t rnd = mwc32();
  457 
  458         copy[rnd % len] &= ~(1 << ((rnd >> 16) & 7));
  459     }
  460 }
  461 
  462 /*
  463  *  apparmor_corrupt_set_bits_random()
  464  *  randomly set bits
  465  */
  466 static inline void apparmor_corrupt_set_bits_random(
  467     char *copy, const size_t len)
  468 {
  469     uint32_t i;
  470     const uint32_t n = mwc32() % 17;
  471 
  472     for (i = 0; i < n; i++) {
  473         uint32_t rnd = mwc32();
  474 
  475         copy[rnd % len] |= (1 << ((rnd >> 16) & 7));
  476     }
  477 }
  478 
  479 /*
  480  *  apparmor_corrupt_clr_byte_random()
  481  *  randomly clear an entire byte
  482  */
  483 static inline void apparmor_corrupt_clr_byte_random(
  484     char *copy, const size_t len)
  485 {
  486     copy[mwc32() % len] = 0;
  487 }
  488 
  489 /*
  490  *  apparmor_corrupt_set_byte_random()
  491  *  randomly set an entire byte
  492  */
  493 static inline void apparmor_corrupt_set_byte_random(
  494     char *copy, const size_t len)
  495 {
  496     copy[mwc32() % len] = 0xff;
  497 }
  498 
  499 /*
  500  *  apparmor_corrupt_flip_bits_random_burst
  501  *  randomly flip a burst of contiguous bits
  502  */
  503 static inline void apparmor_corrupt_flip_bits_random_burst(
  504     char *copy, const size_t len)
  505 {
  506     uint32_t i;
  507     size_t p = (size_t)mwc32() % (len * sizeof(char));
  508 
  509     for (i = 0; i < 32; i++) {
  510         if (p > (len * sizeof(char)))
  511             p = 0;
  512 
  513         copy[p / sizeof(char)] ^= (1 << (p & 7));
  514         p++;
  515     }
  516 }
  517 
  518 
  519 /*
  520  *  apparmor_stress_corruption()
  521  *  corrupt data and see if we can oops the loader
  522  *  parser.
  523  */
  524 static int apparmor_stress_corruption(
  525     const char *name,
  526     const uint64_t max_ops,
  527     uint64_t *counter)
  528 {
  529     char copy[g_apparmor_data_len];
  530 
  531     int rc = EXIT_SUCCESS;
  532     aa_kernel_interface *kern_if;
  533 
  534 
  535     /*
  536      *  Lets feed AppArmor with some bit corrupted data...
  537      */
  538     do {
  539         int ret;
  540 
  541         (void)memcpy(copy, g_apparmor_data, g_apparmor_data_len);
  542         /*
  543          *  Apply various corruption methods
  544          */
  545         switch ((*counter) % 10) {
  546         case 0:
  547             apparmor_corrupt_flip_seq(copy, g_apparmor_data_len);
  548             break;
  549         case 1:
  550             apparmor_corrupt_clr_seq(copy, g_apparmor_data_len);
  551             break;
  552         case 2:
  553             apparmor_corrupt_set_seq(copy, g_apparmor_data_len);
  554             break;
  555         case 3:
  556             apparmor_corrupt_flip_bits_random(copy,
  557                 g_apparmor_data_len);
  558             break;
  559         case 4:
  560             apparmor_corrupt_flip_byte_random(copy,
  561                 g_apparmor_data_len);
  562             break;
  563         case 5:
  564             apparmor_corrupt_clr_bits_random(copy,
  565                 g_apparmor_data_len);
  566             break;
  567         case 6:
  568             apparmor_corrupt_set_bits_random(copy,
  569                 g_apparmor_data_len);
  570             break;
  571         case 7:
  572             apparmor_corrupt_clr_byte_random(copy,
  573                 g_apparmor_data_len);
  574             break;
  575         case 8:
  576             apparmor_corrupt_set_byte_random(copy,
  577                 g_apparmor_data_len);
  578             break;
  579         case 9:
  580             apparmor_corrupt_flip_bits_random_burst(copy,
  581                 g_apparmor_data_len);
  582             break;
  583         default:
  584             /* Should not happen */
  585             break;
  586         }
  587 
  588         ret = aa_kernel_interface_new(&kern_if, NULL, NULL);
  589         if (ret < 0) {
  590             pr_fail("%s: aa_kernel_interface_new() failed, "
  591                 "errno=%d (%s)\n", name, errno,
  592                 strerror(errno));
  593             return EXIT_FAILURE;
  594         }
  595         /*
  596          *  Expect EPROTO failures
  597          */
  598         ret = aa_kernel_interface_replace_policy(kern_if,
  599             copy, g_apparmor_data_len);
  600         if (ret < 0) {
  601             if ((errno != EPROTO) &&
  602                 (errno != EPROTONOSUPPORT)) {
  603                 pr_inf("%s: aa_kernel_interface_replace_policy() failed, "
  604                     "errno=%d (%s)\n", name, errno,
  605                     strerror(errno));
  606             }
  607         }
  608         aa_kernel_interface_unref(kern_if);
  609         (*counter)++;
  610     } while (g_keep_stressing_flag &&
  611          apparmor_run &&
  612          (!max_ops || *counter < max_ops));
  613 
  614     return rc;
  615 }
  616 
  617 
  618 static const apparmor_func apparmor_funcs[] = {
  619     apparmor_stress_profiles,
  620     apparmor_stress_features,
  621     apparmor_stress_kernel_interface,
  622     apparmor_stress_corruption,
  623 };
  624 
  625 /*
  626  *  stress_apparmor()
  627  *  stress AppArmor
  628  */
  629 static int stress_apparmor(const args_t *args)
  630 {
  631     const size_t n = SIZEOF_ARRAY(apparmor_funcs);
  632     pid_t pids[n];
  633     size_t i;
  634     uint64_t *counters, max_ops, ops_per_child, ops;
  635     const size_t counters_sz = n * sizeof(*counters);
  636 
  637     if (stress_sighandler(args->name, SIGUSR1, stress_apparmor_usr1_handler, NULL) < 0)
  638         return EXIT_FAILURE;
  639 
  640     counters = mmap(NULL, counters_sz, PROT_READ | PROT_WRITE,
  641         MAP_SHARED | MAP_ANONYMOUS, -1, 0);
  642     if (counters == MAP_FAILED) {
  643         pr_err("%s: mmap failed: errno=%d (%s)\n",
  644             args->name, errno, strerror(errno));
  645         return EXIT_FAILURE;
  646     }
  647     (void)memset(counters, 0, counters_sz);
  648 
  649     if (args->max_ops > 0) {
  650         if ((args->max_ops < n)) {
  651             max_ops = n;
  652             ops_per_child = 1;
  653         } else {
  654             max_ops = args->max_ops;
  655             ops_per_child = (args->max_ops / n);
  656         }
  657         /*
  658          * ops is the number of ops left over when dividing
  659          * max_ops amongst the child processes
  660          */
  661         ops = max_ops - (ops_per_child * n);
  662     } else {
  663         max_ops = 0;
  664         ops_per_child = 0;
  665         ops = 0;
  666     }
  667 
  668     for (i = 0; i < n; i++) {
  669         pids[i] = apparmor_spawn(args, 
  670             ops_per_child + ((i == 0) ? ops : 0),
  671             &counters[i], apparmor_funcs[i]);
  672     }
  673     while (keep_stressing()) {
  674         uint64_t tmp_counter = 0;
  675 
  676         (void)select(0, NULL, NULL, NULL, NULL);
  677 
  678         for (i = 0; i < n; i++)
  679             tmp_counter += counters[i];
  680 
  681         if (max_ops && tmp_counter >= max_ops)
  682             break;
  683     }
  684 
  685     /* Wakeup, time to die */
  686     for (i = 0; i < n; i++) {
  687         if (pids[i] >= 0)
  688             (void)kill(pids[i], SIGALRM);
  689     }
  690     /* Now apply death grip */
  691     for (i = 0; i < n; i++) {
  692         int status;
  693 
  694         if (pids[i] >= 0) {
  695             (void)kill(pids[i], SIGKILL);
  696             (void)waitpid(pids[i], &status, 0);
  697             add_counter(args, counters[i]);
  698         }
  699     }
  700     (void)munmap(counters, counters_sz);
  701 
  702     free(apparmor_path);
  703     apparmor_path = NULL;
  704 
  705     return EXIT_SUCCESS;
  706 }
  707 
  708 stressor_info_t stress_apparmor_info = {
  709     .stressor = stress_apparmor,
  710     .supported = stress_apparmor_supported,
  711     .class = CLASS_OS | CLASS_SECURITY
  712 };
  713 
  714 #else
  715 
  716 static int stress_apparmor_supported(void)
  717 {
  718     pr_inf("apparmor stressor will be skipped, "
  719         "AppArmor is not available\n");
  720     return -1;
  721 }
  722 
  723 stressor_info_t stress_apparmor_info = {
  724     .stressor = stress_not_implemented,
  725     .supported = stress_apparmor_supported,
  726     .class = CLASS_OS | CLASS_SECURITY
  727 };
  728 #endif