/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 dracut-module/password-agent.c

  • Committer: Teddy Hogeborn
  • Date: 2019-08-03 10:45:18 UTC
  • Revision ID: teddy@recompile.se-20190803104518-0jljs59cdw352atv
dracut-module/password-agent.c: Bug fix: Handle IN_MOVED_FROM

If a question file ("ask.*") is moved away from the question directory
or is renamed in it, treat this the same as IN_DELETE.  If it was a
simple rename within the question directory from, say, "ask.foo" to
"ask.bar", the separate IN_MOVED_TO ievent will get the "ask.bar" name
and add it, so we don't need to consider this as a special case.

* dracut-module/password-agent.c (add_inotify_dir_watch): Add
  "IN_MOVED_FROM" to flags.
  (read_inotify_event): Treat IN_MOVED_FROM the same as IN_DELETE.
  (test_add_inotify_dir_watch_IN_MOVED_FROM): New test.
  (test_read_inotify_event_IN_MOVED_FROM): - '' -
  (test_read_inotify_event_IN_MOVED_FROM_badname): - '' -
  (run_tests): Add new tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1017
1017
    return false;
1018
1018
  }
1019
1019
 
1020
 
  if(inotify_add_watch(fd, dir, IN_CLOSE_WRITE
1021
 
                       | IN_MOVED_TO | IN_DELETE)
 
1020
  if(inotify_add_watch(fd, dir, IN_CLOSE_WRITE | IN_MOVED_TO
 
1021
                       | IN_MOVED_FROM| IN_DELETE)
1022
1022
     == -1){
1023
1023
    error(0, errno, "Failed to create inotify watch on %s", dir);
1024
1024
    return false;
1119
1119
             immediately */
1120
1120
          queue->next_run = 1;
1121
1121
        }
1122
 
      } else if(ievent->mask & IN_DELETE){
 
1122
      } else if(ievent->mask & (IN_MOVED_FROM | IN_DELETE)){
1123
1123
        if(not string_set_add(cancelled_filenames,
1124
1124
                              question_filename)){
1125
1125
          error(0, errno, "Could not add question %s to"
3672
3672
}
3673
3673
 
3674
3674
static
 
3675
void test_add_inotify_dir_watch_IN_MOVED_FROM(__attribute__((unused))
 
3676
                                              test_fixture *fixture,
 
3677
                                              __attribute__((unused))
 
3678
                                              gconstpointer
 
3679
                                              user_data){
 
3680
  __attribute__((cleanup(cleanup_close)))
 
3681
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
 
3682
  g_assert_cmpint(epoll_fd, >=, 0);
 
3683
  __attribute__((cleanup(cleanup_queue)))
 
3684
    task_queue *queue = create_queue();
 
3685
  g_assert_nonnull(queue);
 
3686
  __attribute__((cleanup(string_set_clear)))
 
3687
    string_set cancelled_filenames = {};
 
3688
  const mono_microsecs current_time = 0;
 
3689
 
 
3690
  bool quit_now = false;
 
3691
  buffer password = {};
 
3692
  bool mandos_client_exited = false;
 
3693
  bool password_is_read = false;
 
3694
 
 
3695
  __attribute__((cleanup(cleanup_string)))
 
3696
    char *tempdir = make_temporary_directory();
 
3697
  g_assert_nonnull(tempdir);
 
3698
 
 
3699
  __attribute__((cleanup(cleanup_string)))
 
3700
    char *tempfilename = make_temporary_file_in_directory(tempdir);
 
3701
  g_assert_nonnull(tempfilename);
 
3702
 
 
3703
  __attribute__((cleanup(cleanup_string)))
 
3704
    char *targetdir = make_temporary_directory();
 
3705
  g_assert_nonnull(targetdir);
 
3706
 
 
3707
  __attribute__((cleanup(cleanup_string)))
 
3708
    char *targetfilename = NULL;
 
3709
  g_assert_cmpint(asprintf(&targetfilename, "%s/%s", targetdir,
 
3710
                           basename(tempfilename)), >, 0);
 
3711
  g_assert_nonnull(targetfilename);
 
3712
 
 
3713
  g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
 
3714
                                      &password, tempdir,
 
3715
                                      &cancelled_filenames,
 
3716
                                      &current_time,
 
3717
                                      &mandos_client_exited,
 
3718
                                      &password_is_read));
 
3719
 
 
3720
  g_assert_cmpint(rename(tempfilename, targetfilename), ==, 0);
 
3721
 
 
3722
  const task_context *const added_read_task
 
3723
    = find_matching_task(queue,
 
3724
                         (task_context){ .func=read_inotify_event });
 
3725
  g_assert_nonnull(added_read_task);
 
3726
 
 
3727
  /* "sufficient to read at least one event." - inotify(7) */
 
3728
  const size_t ievent_size = (sizeof(struct inotify_event)
 
3729
                              + NAME_MAX + 1);
 
3730
  struct inotify_event *ievent = malloc(ievent_size);
 
3731
  g_assert_nonnull(ievent);
 
3732
 
 
3733
  ssize_t read_size = read(added_read_task->fd, ievent, ievent_size);
 
3734
 
 
3735
  g_assert_cmpint((int)read_size, >, 0);
 
3736
  g_assert_true(ievent->mask & IN_MOVED_FROM);
 
3737
  g_assert_cmpstr(ievent->name, ==, basename(tempfilename));
 
3738
 
 
3739
  free(ievent);
 
3740
 
 
3741
  g_assert_cmpint(unlink(targetfilename), ==, 0);
 
3742
  g_assert_cmpint(rmdir(targetdir), ==, 0);
 
3743
  g_assert_cmpint(rmdir(tempdir), ==, 0);
 
3744
}
 
3745
 
 
3746
static
3675
3747
void test_add_inotify_dir_watch_IN_DELETE(__attribute__((unused))
3676
3748
                                          test_fixture *fixture,
3677
3749
                                          __attribute__((unused))
4104
4176
      }));
4105
4177
}
4106
4178
 
 
4179
static
 
4180
void test_read_inotify_event_IN_MOVED_FROM(__attribute__((unused))
 
4181
                                           test_fixture *fixture,
 
4182
                                           __attribute__((unused))
 
4183
                                           gconstpointer user_data){
 
4184
  __attribute__((cleanup(cleanup_close)))
 
4185
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
 
4186
  g_assert_cmpint(epoll_fd, >=, 0);
 
4187
  __attribute__((cleanup(string_set_clear)))
 
4188
    string_set cancelled_filenames = {};
 
4189
  const mono_microsecs current_time = 0;
 
4190
 
 
4191
  int pipefds[2];
 
4192
  g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
 
4193
 
 
4194
  /* "sufficient to read at least one event." - inotify(7) */
 
4195
  const size_t ievent_max_size = (sizeof(struct inotify_event)
 
4196
                                  + NAME_MAX + 1);
 
4197
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
 
4198
  struct {
 
4199
    struct inotify_event event;
 
4200
    char name_buffer[NAME_MAX + 1];
 
4201
  } ievent_buffer;
 
4202
  struct inotify_event *const ievent = &ievent_buffer.event;
 
4203
 
 
4204
  const char dummy_file_name[] = "ask.dummy_file_name";
 
4205
  ievent->mask = IN_MOVED_FROM;
 
4206
  ievent->len = sizeof(dummy_file_name);
 
4207
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
 
4208
  const size_t ievent_size = (sizeof(struct inotify_event)
 
4209
                              + sizeof(dummy_file_name));
 
4210
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4211
                  ==, ievent_size);
 
4212
  g_assert_cmpint(close(pipefds[1]), ==, 0);
 
4213
 
 
4214
  bool quit_now = false;
 
4215
  buffer password = {};
 
4216
  bool mandos_client_exited = false;
 
4217
  bool password_is_read = false;
 
4218
  __attribute__((cleanup(cleanup_queue)))
 
4219
    task_queue *queue = create_queue();
 
4220
  g_assert_nonnull(queue);
 
4221
 
 
4222
  task_context task = {
 
4223
    .func=read_inotify_event,
 
4224
    .epoll_fd=epoll_fd,
 
4225
    .fd=pipefds[0],
 
4226
    .quit_now=&quit_now,
 
4227
    .password=&password,
 
4228
    .filename=strdup("/nonexistent"),
 
4229
    .cancelled_filenames=&cancelled_filenames,
 
4230
    .current_time=&current_time,
 
4231
    .mandos_client_exited=&mandos_client_exited,
 
4232
    .password_is_read=&password_is_read,
 
4233
  };
 
4234
  task.func(task, queue);
 
4235
  g_assert_false(quit_now);
 
4236
  g_assert_true(queue->next_run == 0);
 
4237
  g_assert_cmpuint((unsigned int)queue->length, ==, 1);
 
4238
 
 
4239
  g_assert_nonnull(find_matching_task(queue, (task_context){
 
4240
        .func=read_inotify_event,
 
4241
        .epoll_fd=epoll_fd,
 
4242
        .fd=pipefds[0],
 
4243
        .quit_now=&quit_now,
 
4244
        .password=&password,
 
4245
        .filename=task.filename,
 
4246
        .cancelled_filenames=&cancelled_filenames,
 
4247
        .current_time=&current_time,
 
4248
        .mandos_client_exited=&mandos_client_exited,
 
4249
        .password_is_read=&password_is_read,
 
4250
      }));
 
4251
 
 
4252
  g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
 
4253
                                   EPOLLIN | EPOLLRDHUP));
 
4254
 
 
4255
  __attribute__((cleanup(cleanup_string)))
 
4256
    char *filename = NULL;
 
4257
  g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
 
4258
                           dummy_file_name), >, 0);
 
4259
  g_assert_nonnull(filename);
 
4260
  g_assert_true(string_set_contains(*task.cancelled_filenames,
 
4261
                                    filename));
 
4262
}
 
4263
 
4107
4264
static void test_read_inotify_event_IN_DELETE(__attribute__((unused))
4108
4265
                                              test_fixture *fixture,
4109
4266
                                              __attribute__((unused))
4342
4499
                                   EPOLLIN | EPOLLRDHUP));
4343
4500
}
4344
4501
 
 
4502
static void
 
4503
test_read_inotify_event_IN_MOVED_FROM_badname(__attribute__((unused))
 
4504
                                              test_fixture *fixture,
 
4505
                                              __attribute__((unused))
 
4506
                                              gconstpointer
 
4507
                                              user_data){
 
4508
  __attribute__((cleanup(cleanup_close)))
 
4509
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
 
4510
  g_assert_cmpint(epoll_fd, >=, 0);
 
4511
  __attribute__((cleanup(string_set_clear)))
 
4512
    string_set cancelled_filenames = {};
 
4513
  const mono_microsecs current_time = 0;
 
4514
 
 
4515
  int pipefds[2];
 
4516
  g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
 
4517
 
 
4518
  /* "sufficient to read at least one event." - inotify(7) */
 
4519
  const size_t ievent_max_size = (sizeof(struct inotify_event)
 
4520
                                  + NAME_MAX + 1);
 
4521
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
 
4522
  struct {
 
4523
    struct inotify_event event;
 
4524
    char name_buffer[NAME_MAX + 1];
 
4525
  } ievent_buffer;
 
4526
  struct inotify_event *const ievent = &ievent_buffer.event;
 
4527
 
 
4528
  const char dummy_file_name[] = "ignored.dummy_file_name";
 
4529
  ievent->mask = IN_MOVED_FROM;
 
4530
  ievent->len = sizeof(dummy_file_name);
 
4531
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
 
4532
  const size_t ievent_size = (sizeof(struct inotify_event)
 
4533
                              + sizeof(dummy_file_name));
 
4534
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4535
                  ==, ievent_size);
 
4536
  g_assert_cmpint(close(pipefds[1]), ==, 0);
 
4537
 
 
4538
  bool quit_now = false;
 
4539
  buffer password = {};
 
4540
  bool mandos_client_exited = false;
 
4541
  bool password_is_read = false;
 
4542
  __attribute__((cleanup(cleanup_queue)))
 
4543
    task_queue *queue = create_queue();
 
4544
  g_assert_nonnull(queue);
 
4545
 
 
4546
  task_context task = {
 
4547
    .func=read_inotify_event,
 
4548
    .epoll_fd=epoll_fd,
 
4549
    .fd=pipefds[0],
 
4550
    .quit_now=&quit_now,
 
4551
    .password=&password,
 
4552
    .filename=strdup("/nonexistent"),
 
4553
    .cancelled_filenames=&cancelled_filenames,
 
4554
    .current_time=&current_time,
 
4555
    .mandos_client_exited=&mandos_client_exited,
 
4556
    .password_is_read=&password_is_read,
 
4557
  };
 
4558
  task.func(task, queue);
 
4559
  g_assert_false(quit_now);
 
4560
  g_assert_true(queue->next_run == 0);
 
4561
  g_assert_cmpuint((unsigned int)queue->length, ==, 1);
 
4562
 
 
4563
  g_assert_nonnull(find_matching_task(queue, (task_context){
 
4564
        .func=read_inotify_event,
 
4565
        .epoll_fd=epoll_fd,
 
4566
        .fd=pipefds[0],
 
4567
        .quit_now=&quit_now,
 
4568
        .password=&password,
 
4569
        .filename=task.filename,
 
4570
        .cancelled_filenames=&cancelled_filenames,
 
4571
        .current_time=&current_time,
 
4572
        .mandos_client_exited=&mandos_client_exited,
 
4573
        .password_is_read=&password_is_read,
 
4574
      }));
 
4575
 
 
4576
  g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
 
4577
                                   EPOLLIN | EPOLLRDHUP));
 
4578
 
 
4579
  __attribute__((cleanup(cleanup_string)))
 
4580
    char *filename = NULL;
 
4581
  g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
 
4582
                           dummy_file_name), >, 0);
 
4583
  g_assert_nonnull(filename);
 
4584
  g_assert_false(string_set_contains(cancelled_filenames, filename));
 
4585
}
 
4586
 
4345
4587
static
4346
4588
void test_read_inotify_event_IN_DELETE_badname(__attribute__((unused))
4347
4589
                                               test_fixture *fixture,
7593
7835
              test_add_inotify_dir_watch_IN_CLOSE_WRITE);
7594
7836
  test_add_st("/task-creators/add_inotify_dir_watch/IN_MOVED_TO",
7595
7837
              test_add_inotify_dir_watch_IN_MOVED_TO);
 
7838
  test_add_st("/task-creators/add_inotify_dir_watch/IN_MOVED_FROM",
 
7839
              test_add_inotify_dir_watch_IN_MOVED_FROM);
7596
7840
  test_add_st("/task-creators/add_inotify_dir_watch/IN_DELETE",
7597
7841
              test_add_inotify_dir_watch_IN_DELETE);
7598
7842
  test_add_st("/task/read_inotify_event/readerror",
7607
7851
              test_read_inotify_event_IN_CLOSE_WRITE);
7608
7852
  test_add_st("/task/read_inotify_event/IN_MOVED_TO",
7609
7853
              test_read_inotify_event_IN_MOVED_TO);
 
7854
  test_add_st("/task/read_inotify_event/IN_MOVED_FROM",
 
7855
              test_read_inotify_event_IN_MOVED_FROM);
7610
7856
  test_add_st("/task/read_inotify_event/IN_DELETE",
7611
7857
              test_read_inotify_event_IN_DELETE);
7612
7858
  test_add_st("/task/read_inotify_event/IN_CLOSE_WRITE/badname",
7613
7859
              test_read_inotify_event_IN_CLOSE_WRITE_badname);
7614
7860
  test_add_st("/task/read_inotify_event/IN_MOVED_TO/badname",
7615
7861
              test_read_inotify_event_IN_MOVED_TO_badname);
 
7862
  test_add_st("/task/read_inotify_event/IN_MOVED_FROM/badname",
 
7863
              test_read_inotify_event_IN_MOVED_FROM_badname);
7616
7864
  test_add_st("/task/read_inotify_event/IN_DELETE/badname",
7617
7865
              test_read_inotify_event_IN_DELETE_badname);
7618
7866
  test_add_st("/task/open_and_parse_question/ENOENT",