"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-efivar.c" (15 Mar 2019, 8070 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-efivar.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.09.52_vs_0.09.54.

    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(__linux__)
   28 
   29 typedef struct {
   30         uint16_t        varname[512];
   31         uint8_t         guid[16];
   32         uint64_t        datalen;
   33         uint8_t         data[1024];
   34         uint64_t        status;
   35         uint32_t        attributes;
   36 } __attribute__((packed)) efi_var;
   37 
   38 static const char vars[] = "/sys/firmware/efi/vars";
   39 static const char efi_vars[] = "/sys/firmware/efi/efivars";
   40 struct dirent **efi_dentries;
   41 static bool *efi_ignore;
   42 static int dir_count;
   43 
   44 /*
   45  *  efi_var_ignore()
   46  *  check for filenames that are not efi vars
   47  */
   48 static inline bool efi_var_ignore(char *d_name)
   49 {
   50     if (strcmp(d_name, "del_var") == 0)
   51         return true;
   52     if (strcmp(d_name, "new_var") == 0)
   53         return true;
   54     if (strcmp(d_name, ".") == 0)
   55         return true;
   56     if (strcmp(d_name, "..") == 0)
   57         return true;
   58     if (strstr(d_name, "MokListRT"))
   59         return true;
   60         return false;
   61 }
   62 
   63 /*
   64  *  guid_to_str()
   65  *  turn efi GUID to a string
   66  */
   67 static inline void guid_to_str(const uint8_t *guid, char *guid_str, size_t guid_len)
   68 {
   69     if (!guid_str)
   70         return;
   71 
   72     if (guid_len > 36)
   73         (void)snprintf(guid_str, guid_len,
   74             "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
   75             "%02x%02x-%02x%02x%02x%02x%02x%02x",
   76             guid[3], guid[2], guid[1], guid[0], guid[5], guid[4], guid[7], guid[6],
   77         guid[8], guid[9], guid[10], guid[11], guid[12], guid[13], guid[14], guid[15]);
   78     else
   79         *guid_str = '\0';
   80 }
   81 
   82 /*
   83  *  efi_get_varname()
   84  *  fetch the UEFI variable name in terms of a 8 bit C string
   85  */
   86 static inline void efi_get_varname(char *dst, const size_t len, const efi_var *var)
   87 {
   88     register size_t i = len;
   89 
   90     /*
   91      * gcc-9 -Waddress-of-packed-member workaround, urgh, we know
   92      * this is always going to be aligned correctlty, but gcc-9 whines
   93      * so this hack works around it for now.
   94      */
   95     const uint8_t *src8 = (const uint8_t *)var->varname;
   96     const uint16_t *src = (const uint16_t *)src8;
   97 
   98     while ((*src) && (i > 1)) {
   99         *dst++ = *(src++) & 0xff;
  100         i--;
  101     }
  102     *dst = '\0';
  103 }
  104 
  105 /*
  106  *  efi_get_variable()
  107  *  fetch a UEFI variable given its name.
  108  */
  109 static int efi_get_variable(const args_t *args, const char *varname, efi_var *var)
  110 {
  111     int fd, n, ret, rc = 0;
  112     int flags;
  113     char filename[PATH_MAX];
  114     struct stat statbuf;
  115 
  116     if ((!varname) || (!var))
  117         return -1;
  118 
  119     (void)snprintf(filename, sizeof filename,
  120         "%s/%s/raw_var", vars, varname);
  121 
  122     if ((fd = open(filename, O_RDONLY)) < 0)
  123         return -1;
  124 
  125     ret = fstat(fd, &statbuf);
  126     if (ret < 0) {
  127         pr_err("%s: failed to stat %s, errno=%d (%s)\n",
  128             args->name, filename, errno, strerror(errno));
  129         rc = -1;
  130         goto err_vars;
  131     }
  132 
  133     (void)memset(var, 0, sizeof(efi_var));
  134 
  135     if ((n = read(fd, var, sizeof(efi_var))) != sizeof(efi_var)) {
  136         if (errno != EIO) {
  137             pr_err("%s: failed to read %s, errno=%d (%s)\n",
  138                 args->name, filename, errno, strerror(errno));
  139         }
  140         rc = -1;
  141         goto err_vars;
  142     }
  143 
  144 err_vars:
  145     (void)close(fd);
  146 
  147     (void)snprintf(filename, sizeof filename,
  148         "%s/%s", efi_vars, varname);
  149 
  150     if ((fd = open(filename, O_RDONLY)) < 0)
  151         return -1;
  152 
  153     ret = fstat(fd, &statbuf);
  154     if (ret < 0) {
  155         pr_err("%s: failed to stat %s, errno=%d (%s)\n",
  156             args->name, filename, errno, strerror(errno));
  157         rc = -1;
  158         goto err_vars;
  159     }
  160 
  161     ret = ioctl(fd, FS_IOC_GETFLAGS, &flags);
  162     if (ret < 0) {
  163         pr_err("%s: ioctl FS_IOC_GETFLAGS on %s failed, errno=%d (%s)\n",
  164             args->name, filename, errno, strerror(errno));
  165         rc = -1;
  166         goto err_efi_vars;
  167     }
  168 
  169     ret = ioctl(fd, FS_IOC_SETFLAGS, &flags);
  170     if (ret < 0) {
  171         pr_err("%s: ioctl FS_IOC_SETFLAGS on %s failed, errno=%d (%s)\n",
  172             args->name, filename, errno, strerror(errno));
  173         rc = -1;
  174         goto err_efi_vars;
  175     }
  176 
  177 err_efi_vars:
  178     (void)close(fd);
  179 
  180     return rc;
  181 }
  182 
  183 /*
  184  *  efi_vars_get()
  185  *  read EFI variables
  186  */
  187 static int efi_vars_get(const args_t *args)
  188 {
  189     int i;
  190 
  191     for (i = 0; i < dir_count; i++) {
  192         efi_var var;
  193         char *d_name = efi_dentries[i]->d_name;
  194         int ret;
  195 
  196         if (efi_ignore[i])
  197             continue;
  198 
  199         if (efi_var_ignore(d_name)) {
  200             efi_ignore[i] = true;
  201             continue;
  202         }
  203 
  204         ret = efi_get_variable(args, d_name, &var);
  205         if (ret < 0) {
  206             efi_ignore[i] = true;
  207             continue;
  208         }
  209 
  210         if (var.attributes) {
  211             char varname[513];
  212             char guid_str[37];
  213 
  214             efi_get_varname(varname, sizeof(varname), &var);
  215             guid_to_str(var.guid, guid_str, sizeof(guid_str));
  216 
  217             (void)guid_str;
  218         } else {
  219             efi_ignore[i] = true;
  220         }
  221         inc_counter(args);
  222     }
  223 
  224     return 0;
  225 }
  226 
  227 /*
  228  *  stress_efivar_supported()
  229  *      check if we can run this as root
  230  */
  231 static int stress_efivar_supported(void)
  232 {
  233     DIR *dir;
  234 
  235     if (geteuid() != 0) {
  236         pr_inf("efivar stressor will be skipped, "
  237             "need to be running as root for this stressor\n");
  238         return -1;
  239     }
  240 
  241     dir = opendir(efi_vars);
  242     if (!dir) {
  243         pr_inf("efivar stressor will be skipped, "
  244             "need to have access to EFI vars in %s\n",
  245             vars);
  246         return -1;
  247     }
  248     (void)closedir(dir);
  249 
  250     return 0;
  251 }
  252 
  253 /*
  254  *  stress_efivar()
  255  *  stress that does lots of not a lot
  256  */
  257 static int stress_efivar(const args_t *args)
  258 {
  259     pid_t pid;
  260     int i;
  261     size_t sz;
  262 
  263     efi_dentries = NULL;
  264     dir_count = scandir(vars, &efi_dentries, NULL, alphasort);
  265     if (!efi_dentries || (dir_count <= 0)) {
  266         pr_inf("%s: cannot read EFI vars in %s\n", args->name, vars);
  267         return EXIT_SUCCESS;
  268     }
  269 
  270     sz = ((dir_count * sizeof(bool)) + args->page_size) & (args->page_size - 1);
  271     efi_ignore = mmap(NULL, sz, PROT_READ | PROT_WRITE,
  272             MAP_ANONYMOUS | MAP_SHARED, -1, 0);
  273     if (efi_ignore == MAP_FAILED) {
  274         pr_err("%s: cannot mmap shared memory: %d (%s))\n",
  275             args->name, errno, strerror(errno));
  276         return EXIT_NO_RESOURCE;
  277     }
  278 
  279 again:
  280     if (!g_keep_stressing_flag)
  281         return EXIT_SUCCESS;
  282     pid = fork();
  283     if (pid < 0) {
  284         if ((errno == EAGAIN) || (errno == ENOMEM))
  285             goto again;
  286         pr_err("%s: fork failed: errno=%d (%s)\n",
  287             args->name, errno, strerror(errno));
  288     } else if (pid > 0) {
  289         int status, ret;
  290 
  291         (void)setpgid(pid, g_pgrp);
  292         /* Parent, wait for child */
  293         ret = waitpid(pid, &status, 0);
  294         if (ret < 0) {
  295             if (errno != EINTR)
  296                 pr_dbg("%s: waitpid(): errno=%d (%s)\n",
  297                     args->name, errno, strerror(errno));
  298             (void)kill(pid, SIGTERM);
  299             (void)kill(pid, SIGKILL);
  300             (void)waitpid(pid, &status, 0);
  301         } else if (WIFSIGNALED(status)) {
  302             pr_dbg("%s: child died: %s (instance %d)\n",
  303                 args->name, stress_strsignal(WTERMSIG(status)),
  304                 args->instance);
  305             return EXIT_FAILURE;
  306         }
  307     } else if (pid == 0) {
  308         (void)setpgid(0, g_pgrp);
  309         stress_parent_died_alarm();
  310         set_oom_adjustment(args->name, true);
  311 
  312         do {
  313             efi_vars_get(args);
  314         } while (keep_stressing());
  315         _exit(0);
  316     }
  317 
  318     (void)munmap(efi_ignore, sz);
  319     for (i = 0; i < dir_count; i++)
  320         free(efi_dentries[i]);
  321     free(efi_dentries);
  322 
  323     return EXIT_SUCCESS;
  324 }
  325 
  326 stressor_info_t stress_efivar_info = {
  327     .stressor = stress_efivar,
  328     .supported = stress_efivar_supported,
  329     .class = CLASS_OS
  330 };
  331 #else
  332 static int stress_efivar_supported(void)
  333 {
  334     pr_inf("efivar stressor will be skipped, "
  335         "it is not implemented on this platform\n");
  336 
  337     return -1;
  338 }
  339 stressor_info_t stress_efivar_info = {
  340     .stressor = stress_not_implemented,
  341     .supported = stress_efivar_supported,
  342     .class = CLASS_OS
  343 };
  344 #endif