/mandos/release

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

« back to all changes in this revision

Viewing changes to plugins.d/plymouth.c

  • Committer: teddy at recompile
  • Date: 2020-12-03 20:30:45 UTC
  • mto: This revision was merged to the branch mainline in revision 404.
  • 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
 * Plymouth - Read a password from Plymouth and output it
4
4
 * 
5
 
 * Copyright © 2010-2018 Teddy Hogeborn
6
 
 * Copyright © 2010-2018 Björn Påhlsson
 
5
 * Copyright © 2010-2020 Teddy Hogeborn
 
6
 * Copyright © 2010-2020 Björn Påhlsson
7
7
 * 
8
8
 * This file is part of Mandos.
9
9
 * 
44
44
                                   STDERR_FILENO, execv(), access() */
45
45
#include <stdlib.h>             /* free(), EXIT_FAILURE, realloc(),
46
46
                                   EXIT_SUCCESS, malloc(), _exit(),
47
 
                                   getenv() */
 
47
                                   getenv(), reallocarray() */
48
48
#include <dirent.h>             /* scandir(), alphasort() */
49
49
#include <inttypes.h>           /* intmax_t, strtoumax(), SCNuMAX */
50
50
#include <sys/stat.h>           /* struct stat, lstat() */
53
53
#include <errno.h>              /* TEMP_FAILURE_RETRY */
54
54
#include <argz.h>               /* argz_count(), argz_extract() */
55
55
#include <stdarg.h>             /* va_list, va_start(), ... */
 
56
#include <argp.h>
56
57
 
57
58
sig_atomic_t interrupted_by_signal = 0;
 
59
const char *argp_program_version = "plymouth " VERSION;
 
60
const char *argp_program_bug_address = "<mandos@recompile.se>";
58
61
 
59
62
/* Used by Ubuntu 11.04 (Natty Narwahl) */
60
63
const char plymouth_old_old_pid[] = "/dev/.initramfs/plymouth.pid";
69
72
                                        "--mode=boot",
70
73
                                        "--attach-to-session",
71
74
                                        NULL };
 
75
bool debug = false;
72
76
 
73
77
static void termination_handler(__attribute__((unused))int signum){
74
78
  if(interrupted_by_signal){
77
81
  interrupted_by_signal = 1;
78
82
}
79
83
 
 
84
__attribute__((format (gnu_printf, 2, 3), nonnull))
 
85
int fprintf_plus(FILE *stream, const char *format, ...){
 
86
  va_list ap;
 
87
  va_start (ap, format);
 
88
  fprintf(stream, "Mandos plugin %s: ", program_invocation_short_name);
 
89
  return vfprintf(stream, format, ap);
 
90
}
 
91
 
80
92
/* Function to use when printing errors */
81
93
__attribute__((format (gnu_printf, 3, 4)))
82
94
void error_plus(int status, int errnum, const char *formatstring,
159
171
 
160
172
__attribute__((nonnull (2, 3)))
161
173
bool exec_and_wait(pid_t *pid_return, const char *path,
162
 
                   const char * const *argv, bool interruptable,
 
174
                   const char * const * const argv, bool interruptable,
163
175
                   bool daemonize){
164
176
  int status;
165
177
  int ret;
166
178
  pid_t pid;
 
179
  if(debug){
 
180
    for(const char * const *arg = argv; *arg != NULL; arg++){
 
181
      fprintf_plus(stderr, "exec_and_wait arg: %s\n", *arg);
 
182
    }
 
183
    fprintf_plus(stderr, "exec_and_wait end of args\n");
 
184
  }
 
185
 
167
186
  pid = fork();
168
187
  if(pid == -1){
169
188
    error_plus(0, errno, "fork");
185
204
    char **tmp;
186
205
    int i = 0;
187
206
    for (; argv[i] != NULL; i++){
188
 
      tmp = realloc(new_argv, sizeof(const char *) * ((size_t)i + 2));
 
207
#if defined(__GLIBC_PREREQ) and __GLIBC_PREREQ(2, 26)
 
208
      tmp = reallocarray(new_argv, ((size_t)i + 2),
 
209
                         sizeof(const char *));
 
210
#else
 
211
      if(((size_t)i + 2) > (SIZE_MAX / sizeof(const char *))){
 
212
        /* overflow */
 
213
        tmp = NULL;
 
214
        errno = ENOMEM;
 
215
      } else {
 
216
        tmp = realloc(new_argv, ((size_t)i + 2) * sizeof(const char *));
 
217
      }
 
218
#endif
189
219
      if(tmp == NULL){
190
 
        error_plus(0, errno, "realloc");
 
220
        error_plus(0, errno, "reallocarray");
191
221
        free(new_argv);
192
222
        _exit(EX_OSERR);
193
223
      }
209
239
          and ((not interrupted_by_signal)
210
240
               or (not interruptable)));
211
241
  if(interrupted_by_signal and interruptable){
 
242
    if(debug){
 
243
      fprintf_plus(stderr, "Interrupted by signal\n");
 
244
    }
212
245
    return false;
213
246
  }
214
247
  if(ret == -1){
215
248
    error_plus(0, errno, "waitpid");
216
249
    return false;
217
250
  }
 
251
  if(debug){
 
252
    if(WIFEXITED(status)){
 
253
      fprintf_plus(stderr, "exec_and_wait exited: %d\n",
 
254
                   WEXITSTATUS(status));
 
255
    } else if(WIFSIGNALED(status)) {
 
256
      fprintf_plus(stderr, "exec_and_wait signaled: %d\n",
 
257
                   WTERMSIG(status));
 
258
    }
 
259
  }
218
260
  if(WIFEXITED(status) and (WEXITSTATUS(status) == 0)){
219
261
    return true;
220
262
  }
407
449
 
408
450
int main(__attribute__((unused))int argc,
409
451
         __attribute__((unused))char **argv){
410
 
  char *prompt;
 
452
  char *prompt = NULL;
411
453
  char *prompt_arg;
412
454
  pid_t plymouth_command_pid;
413
455
  int ret;
414
456
  bool bret;
415
457
 
 
458
  {
 
459
    struct argp_option options[] = {
 
460
      { .name = "prompt", .key = 128, .arg = "PROMPT",
 
461
        .doc = "The prompt to show" },
 
462
      { .name = "debug", .key = 129,
 
463
        .doc = "Debug mode" },
 
464
      { .name = NULL }
 
465
    };
 
466
    
 
467
    __attribute__((nonnull(3)))
 
468
    error_t parse_opt (int key, char *arg, __attribute__((unused))
 
469
                       struct argp_state *state){
 
470
      errno = 0;
 
471
      switch (key){
 
472
      case 128:                 /* --prompt */
 
473
        prompt = arg;
 
474
        if(debug){
 
475
          fprintf_plus(stderr, "Custom prompt \"%s\"\n", prompt);
 
476
        }
 
477
        break;
 
478
      case 129:                 /* --debug */
 
479
        debug = true;
 
480
        break;
 
481
      default:
 
482
        return ARGP_ERR_UNKNOWN;
 
483
      }
 
484
      return errno;
 
485
    }
 
486
    
 
487
    struct argp argp = { .options = options, .parser = parse_opt,
 
488
                         .args_doc = "",
 
489
                         .doc = "Mandos plymouth -- Read and"
 
490
                         " output a password" };
 
491
    ret = argp_parse(&argp, argc, argv, ARGP_IN_ORDER, NULL, NULL);
 
492
    switch(ret){
 
493
    case 0:
 
494
      break;
 
495
    case ENOMEM:
 
496
    default:
 
497
      errno = ret;
 
498
      error_plus(0, errno, "argp_parse");
 
499
      return EX_OSERR;
 
500
    case EINVAL:
 
501
      error_plus(0, errno, "argp_parse");
 
502
      return EX_USAGE;
 
503
    }
 
504
  }
 
505
  
416
506
  /* test -x /bin/plymouth */
417
507
  ret = access(plymouth_path, X_OK);
418
508
  if(ret == -1){
419
509
    /* Plymouth is probably not installed.  Don't print an error
420
510
       message, just exit. */
 
511
    if(debug){
 
512
      fprintf_plus(stderr, "Plymouth (%s) not found\n",
 
513
                   plymouth_path);
 
514
    }
421
515
    exit(EX_UNAVAILABLE);
422
516
  }
423
517
  
457
551
    }
458
552
    /* Plymouth is probably not running.  Don't print an error
459
553
       message, just exit. */
 
554
    if(debug){
 
555
      fprintf_plus(stderr, "Plymouth not running\n");
 
556
    }
460
557
    exit(EX_UNAVAILABLE);
461
558
  }
462
559
  
463
 
  prompt = makeprompt();
464
 
  ret = asprintf(&prompt_arg, "--prompt=%s", prompt);
465
 
  free(prompt);
 
560
  if(prompt != NULL){
 
561
    ret = asprintf(&prompt_arg, "--prompt=%s", prompt);
 
562
  } else {
 
563
    char *made_prompt = makeprompt();
 
564
    ret = asprintf(&prompt_arg, "--prompt=%s", made_prompt);
 
565
    free(made_prompt);
 
566
  }
466
567
  if(ret == -1){
467
568
    error_plus(EX_OSERR, errno, "asprintf");
468
569
  }
469
570
  
470
571
  /* plymouth ask-for-password --prompt="$prompt" */
 
572
  if(debug){
 
573
    fprintf_plus(stderr, "Prompting for password via Plymouth\n");
 
574
  }
471
575
  bret = exec_and_wait(&plymouth_command_pid,
472
576
                       plymouth_path, (const char *[])
473
577
                       { plymouth_path, "ask-for-password",