summaryrefslogtreecommitdiffstats
path: root/libparted/tests/symlink.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libparted/tests/symlink.c146
1 files changed, 146 insertions, 0 deletions
diff --git a/libparted/tests/symlink.c b/libparted/tests/symlink.c
new file mode 100644
index 0000000..7be02cd
--- /dev/null
+++ b/libparted/tests/symlink.c
@@ -0,0 +1,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;
+}