summaryrefslogtreecommitdiffstats
path: root/libparted/tests/symlink.c
blob: 7be02cd618854ade4190ba40d484aba4d5b26510 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/* Sometimes libparted operates on device mapper files, with a path of
   /dev/mapper/foo. With newer lvm versions /dev/mapper/foo is a symlink to
   /dev/dm-#. However some storage administration programs (anaconda for
   example) may do the following:
   1) Create a ped_device for /dev/mapper/foo
   2) ped_get_device resolves the symlink to /dev/dm-#, and the path
      in the PedDevice struct points to /dev/dm-#
   3) The program does some things to lvm, causing the symlink to
      point to a different /dev/dm-# node
   4) The program does something with the PedDevice, which results
      in an operation on the wrong device

   Newer libparted versions do not suffer from this problem, as they
   do not canonicalize device names under /dev/mapper. This test checks
   for this bug. */

#include <config.h>
#include <unistd.h>

#include <check.h>

#include <parted/parted.h>

#include "common.h"
#include "progname.h"

static char *temporary_disk;

static void
create_disk (void)
{
        temporary_disk = _create_disk (4096 * 1024);
        ck_assert_msg(temporary_disk != NULL, "Failed to create temporary disk");
}

static void
destroy_disk (void)
{
        unlink (temporary_disk);
        free (temporary_disk);
}

START_TEST (test_symlink)
{
        char cwd[256], ln[256] = "/dev/mapper/parted-test-XXXXXX";

        if (!getcwd (cwd, sizeof cwd)) {
                ck_abort_msg("Could not get cwd");
                return;
        }

        /* Create a symlink under /dev/mapper to our
           temporary disk */
        int tmp_fd = mkstemp (ln);
        if (tmp_fd == -1) {
                ck_abort_msg("Could not create tempfile");
                return;
        }

        /* There is a temp file vulnerability symlink attack possibility
           here, but as /dev/mapper is root owned this is a non issue */
        close (tmp_fd);
        unlink (ln);
        char temp_disk_path[259];
        int r = snprintf(temp_disk_path, sizeof temp_disk_path, "%s/%s",
                          cwd,
                          temporary_disk);
        if (r < 0 || r >= sizeof temp_disk_path) {
                ck_abort_msg("symlink truncated");
                return;
        }

        int res = symlink (temp_disk_path, ln);
        if (res) {
                ck_abort_msg("could not create symlink");
                return;
        }

        PedDevice *dev = ped_device_get (ln);
        if (dev == NULL)
                goto exit_unlink_ln;

        /* Create a second temporary_disk */
        char *temporary_disk2 = _create_disk (4096 * 1024);
        if (temporary_disk2 == NULL) {
                ck_abort_msg("Failed to create 2nd temporary disk");
                goto exit_destroy_dev;
        }

        /* Remove first temporary disk, and make temporary_disk point to
           temporary_disk2 (for destroy_disk()). */
        unlink (temporary_disk);
        free (temporary_disk);
        temporary_disk = temporary_disk2;

        /* Update symlink to point to our new / second temporary disk */
        unlink (ln);
        r = snprintf (temp_disk_path, sizeof temp_disk_path, "%s/%s",
                          cwd, temporary_disk);
        if (r < 0 || r >= sizeof temp_disk_path) {
                ck_abort_msg("2nd symlink truncated");
                goto exit_destroy_dev;
        }

        res = symlink (temp_disk_path, ln);
        if (res) {
                ck_abort_msg("could not create 2nd symlink");
                goto exit_destroy_dev;
        }

        /* Do something to our PedDevice, if the symlink was resolved,
           instead of remembering the /dev/mapper/foo name, this will fail */
        ped_disk_clobber (dev);

exit_destroy_dev:
        ped_device_destroy (dev);
exit_unlink_ln:
        unlink (ln);
}
END_TEST

int
main (int argc, char **argv)
{
        set_program_name (argv[0]);
        int number_failed;
        Suite* suite = suite_create ("Symlink");
        TCase* tcase_symlink = tcase_create ("/dev/mapper symlink");

        /* Fail when an exception is raised */
        ped_exception_set_handler (_test_exception_handler);

        tcase_add_checked_fixture (tcase_symlink, create_disk, destroy_disk);
        tcase_add_test (tcase_symlink, test_symlink);
        /* Disable timeout for this test */
        tcase_set_timeout (tcase_symlink, 0);
        suite_add_tcase (suite, tcase_symlink);

        SRunner* srunner = srunner_create (suite);
        srunner_run_all (srunner, CK_VERBOSE);

        number_failed = srunner_ntests_failed (srunner);
        srunner_free (srunner);

        return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}