/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk

« back to all changes in this revision

Viewing changes to plugin-runner.c

  • Committer: teddy at recompile
  • Date: 2020-12-03 20:30:45 UTC
  • Revision ID: teddy@recompile.se-20201203203045-iqd6nq9y5nwalh1x
Minor fix of a test function

In dracut-module/password-agent, the test function
test_send_password_to_socket_EMSGSIZE() (which tests that the
send_password_to_socket() task function aborts properly when getting
EMSGSIZE when writing to the password socket), part of the test code
is supposed to find a message size which definitely does trigger
EMSGSIZE when send()ing to a socket.  Without a "break" in the proper
place, however, the size given is always exactly 1024 bytes too large.

This is very probably not a problem, since a too large message will
still be too large if it is increased by 1024 bytes, and send(2) in
practice checks the size before reading the buffer.  The biggest issue
would be if some version of send(2) would try to look at the last 1024
bytes of the message buffer before checking the message size; this
would then lead to a buffer over-read when running this test function.
(But even then there would be no security implications since the tests
are not run in the normal operation of the program.)

* dracut-module/password-agent.c
  (test_send_password_to_socket_EMSGSIZE): Break out early when ssret
  < 0 and errno == EMSGSIZE; don't allow loop to increase message_size
  again.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
/*
3
3
 * Mandos plugin runner - Run Mandos plugins
4
4
 *
5
 
 * Copyright © 2008-2015 Teddy Hogeborn
6
 
 * Copyright © 2008-2015 Björn Påhlsson
7
 
 * 
8
 
 * This program is free software: you can redistribute it and/or
9
 
 * modify it under the terms of the GNU General Public License as
10
 
 * published by the Free Software Foundation, either version 3 of the
11
 
 * License, or (at your option) any later version.
12
 
 * 
13
 
 * This program is distributed in the hope that it will be useful, but
 
5
 * Copyright © 2008-2020 Teddy Hogeborn
 
6
 * Copyright © 2008-2020 Björn Påhlsson
 
7
 * 
 
8
 * This file is part of Mandos.
 
9
 * 
 
10
 * Mandos is free software: you can redistribute it and/or modify it
 
11
 * under the terms of the GNU General Public License as published by
 
12
 * the Free Software Foundation, either version 3 of the License, or
 
13
 * (at your option) any later version.
 
14
 * 
 
15
 * Mandos is distributed in the hope that it will be useful, but
14
16
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
18
 * General Public License for more details.
17
19
 * 
18
20
 * You should have received a copy of the GNU General Public License
19
 
 * along with this program.  If not, see
20
 
 * <http://www.gnu.org/licenses/>.
 
21
 * along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
21
22
 * 
22
23
 * Contact the authors at <mandos@recompile.se>.
23
24
 */
25
26
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), getline(),
26
27
                                   O_CLOEXEC, pipe2() */
27
28
#include <stddef.h>             /* size_t, NULL */
28
 
#include <stdlib.h>             /* malloc(), exit(), EXIT_SUCCESS,
29
 
                                   realloc() */
 
29
#include <stdlib.h>             /* malloc(), reallocarray(), realloc(),
 
30
                                   EXIT_SUCCESS, exit() */
30
31
#include <stdbool.h>            /* bool, true, false */
31
32
#include <stdio.h>              /* fileno(), fprintf(),
32
33
                                   stderr, STDOUT_FILENO, fclose() */
37
38
#include <sys/select.h>         /* fd_set, select(), FD_ZERO(),
38
39
                                   FD_SET(), FD_ISSET(), FD_CLR */
39
40
#include <sys/wait.h>           /* wait(), waitpid(), WIFEXITED(),
40
 
                                   WEXITSTATUS(), WTERMSIG(),
41
 
                                   WCOREDUMP() */
 
41
                                   WEXITSTATUS(), WTERMSIG() */
42
42
#include <sys/stat.h>           /* struct stat, fstat(), S_ISREG() */
43
43
#include <iso646.h>             /* and, or, not */
44
44
#include <dirent.h>             /* struct dirent, scandirat() */
179
179
  /* Resize the pointed-to array to hold one more pointer */
180
180
  char **new_array = NULL;
181
181
  do {
182
 
    new_array = realloc(*array, sizeof(char *)
183
 
                        * (size_t) ((*len) + 2));
 
182
#if defined(__GLIBC_PREREQ) and __GLIBC_PREREQ(2, 26)
 
183
    new_array = reallocarray(*array, (size_t)((*len) + 2),
 
184
                             sizeof(char *));
 
185
#else
 
186
    if(((size_t)((*len) + 2)) > (SIZE_MAX / sizeof(char *))){
 
187
      /* overflow */
 
188
      new_array = NULL;
 
189
      errno = ENOMEM;
 
190
    } else {
 
191
      new_array = realloc(*array, (size_t)((*len) + 2)
 
192
                          * sizeof(char *));
 
193
    }
 
194
#endif
184
195
  } while(new_array == NULL and errno == EINTR);
185
196
  /* Malloc check */
186
197
  if(new_array == NULL){
313
324
__attribute__((nonnull))
314
325
static void free_plugin(plugin *plugin_node){
315
326
  
316
 
  for(char **arg = plugin_node->argv; *arg != NULL; arg++){
 
327
  for(char **arg = (plugin_node->argv)+1; *arg != NULL; arg++){
317
328
    free(*arg);
318
329
  }
 
330
  free(plugin_node->name);
319
331
  free(plugin_node->argv);
320
332
  for(char **env = plugin_node->environ; *env != NULL; env++){
321
333
    free(*env);
564
576
    case '?':                   /* --help */
565
577
      state->flags &= ~(unsigned int)ARGP_NO_EXIT; /* force exit */
566
578
      argp_state_help(state, state->out_stream, ARGP_HELP_STD_HELP);
 
579
      __builtin_unreachable();
567
580
    case -3:                    /* --usage */
568
581
      state->flags &= ~(unsigned int)ARGP_NO_EXIT; /* force exit */
569
582
      argp_state_help(state, state->out_stream,
570
583
                      ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK);
 
584
      __builtin_unreachable();
571
585
    case 'V':                   /* --version */
572
586
      fprintf(state->out_stream, "%s\n", argp_program_version);
573
587
      exit(EXIT_SUCCESS);
583
597
      if(arg[0] == '\0'){
584
598
        break;
585
599
      }
 
600
#if __GNUC__ >= 7
 
601
      __attribute__((fallthrough));
 
602
#else
 
603
          /* FALLTHROUGH */
 
604
#endif
586
605
    default:
587
606
      return ARGP_ERR_UNKNOWN;
588
607
    }
700
719
        
701
720
        custom_argc += 1;
702
721
        {
703
 
          char **new_argv = realloc(custom_argv, sizeof(char *)
704
 
                                    * ((size_t)custom_argc + 1));
 
722
#if defined(__GLIBC_PREREQ) and __GLIBC_PREREQ(2, 26)
 
723
          char **new_argv = reallocarray(custom_argv, (size_t)custom_argc + 1,
 
724
                                         sizeof(char *));
 
725
#else
 
726
          char **new_argv = NULL;
 
727
          if(((size_t)custom_argc + 1) > (SIZE_MAX / sizeof(char *))){
 
728
            /* overflow */
 
729
            errno = ENOMEM;
 
730
          } else {
 
731
            new_argv = realloc(custom_argv, ((size_t)custom_argc + 1)
 
732
                               * sizeof(char *));
 
733
          }
 
734
#endif
705
735
          if(new_argv == NULL){
706
 
            error(0, errno, "realloc");
 
736
            error(0, errno, "reallocarray");
707
737
            exitstatus = EX_OSERR;
708
738
            free(new_arg);
709
739
            free(org_line);
793
823
  }
794
824
  
795
825
  if(debug){
796
 
    for(plugin *p = plugin_list; p != NULL; p=p->next){
 
826
    for(plugin *p = plugin_list; p != NULL; p = p->next){
797
827
      fprintf(stderr, "Plugin: %s has %d arguments\n",
798
828
              p->name ? p->name : "Global", p->argc - 1);
799
829
      for(char **a = p->argv; *a != NULL; a++){
808
838
  
809
839
  if(getuid() == 0){
810
840
    /* Work around Debian bug #633582:
811
 
       <http://bugs.debian.org/633582> */
 
841
       <https://bugs.debian.org/633582> */
812
842
    int plugindir_fd = open(/* plugindir or */ PDIR, O_RDONLY);
813
843
    if(plugindir_fd == -1){
814
844
      if(errno != ENOENT){
891
921
    return 1;
892
922
  }
893
923
  
894
 
#ifdef __GLIBC__
895
 
#if __GLIBC_PREREQ(2, 15)
896
924
  int numplugins = scandirat(dir_fd, ".", &direntries, good_name,
897
925
                             alphasort);
898
 
#else  /* not __GLIBC_PREREQ(2, 15) */
899
 
  int numplugins = scandir(plugindir != NULL ? plugindir : PDIR,
900
 
                           &direntries, good_name, alphasort);
901
 
#endif  /* not __GLIBC_PREREQ(2, 15) */
902
 
#else   /* not __GLIBC__ */
903
 
  int numplugins = scandir(plugindir != NULL ? plugindir : PDIR,
904
 
                           &direntries, good_name, alphasort);
905
 
#endif  /* not __GLIBC__ */
906
926
  if(numplugins == -1){
907
927
    error(0, errno, "Could not scan plugin dir");
908
928
    direntries = NULL;
1102
1122
    
1103
1123
    new_plugin->pid = pid;
1104
1124
    new_plugin->fd = pipefd[0];
1105
 
    
 
1125
 
 
1126
    if(debug){
 
1127
      fprintf(stderr, "Plugin %s started (PID %" PRIdMAX ")\n",
 
1128
              new_plugin->name, (intmax_t) (new_plugin->pid));
 
1129
    }
 
1130
 
1106
1131
    /* Unblock SIGCHLD so signal handler can be run if this process
1107
1132
       has already completed */
1108
1133
    ret = (int)TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK,
1114
1139
      goto fallback;
1115
1140
    }
1116
1141
    
1117
 
#if defined (__GNUC__) and defined (__GLIBC__)
1118
 
#if not __GLIBC_PREREQ(2, 16)
1119
 
#pragma GCC diagnostic push
1120
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1121
 
#endif
1122
 
#endif
1123
 
    FD_SET(new_plugin->fd, &rfds_all); /* Spurious warning from
1124
 
                                          -Wconversion in GNU libc
1125
 
                                          before 2.16 */
1126
 
#if defined (__GNUC__) and defined (__GLIBC__)
1127
 
#if not __GLIBC_PREREQ(2, 16)
1128
 
#pragma GCC diagnostic pop
1129
 
#endif
1130
 
#endif
 
1142
    FD_SET(new_plugin->fd, &rfds_all);
1131
1143
    
1132
1144
    if(maxfd < new_plugin->fd){
1133
1145
      maxfd = new_plugin->fd;
1182
1194
                      (intmax_t) (proc->pid),
1183
1195
                      WTERMSIG(proc->status),
1184
1196
                      strsignal(WTERMSIG(proc->status)));
1185
 
            } else if(WCOREDUMP(proc->status)){
1186
 
              fprintf(stderr, "Plugin %s [%" PRIdMAX "] dumped"
1187
 
                      " core\n", proc->name, (intmax_t) (proc->pid));
1188
1197
            }
1189
1198
          }
1190
1199
          
1191
1200
          /* Remove the plugin */
1192
 
#if defined (__GNUC__) and defined (__GLIBC__)
1193
 
#if not __GLIBC_PREREQ(2, 16)
1194
 
#pragma GCC diagnostic push
1195
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1196
 
#endif
1197
 
#endif
1198
 
          FD_CLR(proc->fd, &rfds_all); /* Spurious warning from
1199
 
                                          -Wconversion in GNU libc
1200
 
                                          before 2.16 */
1201
 
#if defined (__GNUC__) and defined (__GLIBC__)
1202
 
#if not __GLIBC_PREREQ(2, 16)
1203
 
#pragma GCC diagnostic pop
1204
 
#endif
1205
 
#endif
 
1201
          FD_CLR(proc->fd, &rfds_all);
1206
1202
          
1207
1203
          /* Block signal while modifying process_list */
1208
1204
          ret = (int)TEMP_FAILURE_RETRY(sigprocmask
1248
1244
      }
1249
1245
      
1250
1246
      /* This process has not completed.  Does it have any output? */
1251
 
#if defined (__GNUC__) and defined (__GLIBC__)
1252
 
#if not __GLIBC_PREREQ(2, 16)
1253
 
#pragma GCC diagnostic push
1254
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1255
 
#endif
1256
 
#endif
1257
 
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){ /* Spurious
1258
 
                                                         warning from
1259
 
                                                         -Wconversion
1260
 
                                                         in GNU libc
1261
 
                                                         before
1262
 
                                                         2.16 */
1263
 
#if defined (__GNUC__) and defined (__GLIBC__)
1264
 
#if not __GLIBC_PREREQ(2, 16)
1265
 
#pragma GCC diagnostic pop
1266
 
#endif
1267
 
#endif
 
1247
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){
1268
1248
        /* This process had nothing to say at this time */
1269
1249
        proc = proc->next;
1270
1250
        continue;