1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. 4f08c3bdfSopenharmony_ci * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com> 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci 7f08c3bdfSopenharmony_ci/*\ 8f08c3bdfSopenharmony_ci * [Description] 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * It is a basic test for MS_NOSYMFOLLOW mount option and is copied 11f08c3bdfSopenharmony_ci * from kernel selftests nosymfollow-test.c. 12f08c3bdfSopenharmony_ci * 13f08c3bdfSopenharmony_ci * It tests to make sure that symlink traversal fails with ELOOP when 14f08c3bdfSopenharmony_ci * 'nosymfollow' is set, but symbolic links can still be created, and 15f08c3bdfSopenharmony_ci * readlink(2) and realpath(3) still work properly. It also verifies 16f08c3bdfSopenharmony_ci * that statfs(2) correctly returns ST_NOSYMFOLLOW. 17f08c3bdfSopenharmony_ci */ 18f08c3bdfSopenharmony_ci 19f08c3bdfSopenharmony_ci#include <limits.h> 20f08c3bdfSopenharmony_ci#include <stdio.h> 21f08c3bdfSopenharmony_ci#include <stdlib.h> 22f08c3bdfSopenharmony_ci#include <unistd.h> 23f08c3bdfSopenharmony_ci#include <sys/mount.h> 24f08c3bdfSopenharmony_ci#include <stdbool.h> 25f08c3bdfSopenharmony_ci#include "tst_test.h" 26f08c3bdfSopenharmony_ci#include "lapi/mount.h" 27f08c3bdfSopenharmony_ci 28f08c3bdfSopenharmony_ci#ifndef ST_NOSYMFOLLOW 29f08c3bdfSopenharmony_ci# define ST_NOSYMFOLLOW 0x2000 30f08c3bdfSopenharmony_ci#endif 31f08c3bdfSopenharmony_ci 32f08c3bdfSopenharmony_ci#define MNTPOINT "mntpoint" 33f08c3bdfSopenharmony_ci 34f08c3bdfSopenharmony_cistatic char test_file[PATH_MAX]; 35f08c3bdfSopenharmony_cistatic char link_file[PATH_MAX]; 36f08c3bdfSopenharmony_cistatic char temp_link_file[PATH_MAX]; 37f08c3bdfSopenharmony_cistatic int flag; 38f08c3bdfSopenharmony_ci 39f08c3bdfSopenharmony_cistatic void setup_symlink(void) 40f08c3bdfSopenharmony_ci{ 41f08c3bdfSopenharmony_ci int fd; 42f08c3bdfSopenharmony_ci 43f08c3bdfSopenharmony_ci fd = SAFE_CREAT(test_file, O_RDWR); 44f08c3bdfSopenharmony_ci SAFE_SYMLINK(test_file, link_file); 45f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 46f08c3bdfSopenharmony_ci flag = 1; 47f08c3bdfSopenharmony_ci} 48f08c3bdfSopenharmony_ci 49f08c3bdfSopenharmony_cistatic void test_link_traversal(bool nosymfollow) 50f08c3bdfSopenharmony_ci{ 51f08c3bdfSopenharmony_ci if (nosymfollow) { 52f08c3bdfSopenharmony_ci TST_EXP_FAIL2(open(link_file, 0, O_RDWR), ELOOP, 53f08c3bdfSopenharmony_ci "open(%s, 0, O_RDWR)", link_file); 54f08c3bdfSopenharmony_ci } else { 55f08c3bdfSopenharmony_ci TST_EXP_FD(open(link_file, 0, O_RDWR)); 56f08c3bdfSopenharmony_ci } 57f08c3bdfSopenharmony_ci 58f08c3bdfSopenharmony_ci if (TST_RET > 0) 59f08c3bdfSopenharmony_ci SAFE_CLOSE(TST_RET); 60f08c3bdfSopenharmony_ci} 61f08c3bdfSopenharmony_ci 62f08c3bdfSopenharmony_cistatic void test_readlink(void) 63f08c3bdfSopenharmony_ci{ 64f08c3bdfSopenharmony_ci char buf[4096]; 65f08c3bdfSopenharmony_ci 66f08c3bdfSopenharmony_ci memset(buf, 0, 4096); 67f08c3bdfSopenharmony_ci TST_EXP_POSITIVE(readlink(link_file, buf, sizeof(buf)), 68f08c3bdfSopenharmony_ci "readlink(%s, buf, %ld)", link_file, sizeof(buf)); 69f08c3bdfSopenharmony_ci if (strcmp(buf, test_file) != 0) { 70f08c3bdfSopenharmony_ci tst_res(TFAIL, "readlink strcmp failed, %s, %s", 71f08c3bdfSopenharmony_ci buf, test_file); 72f08c3bdfSopenharmony_ci } else { 73f08c3bdfSopenharmony_ci tst_res(TPASS, "readlink strcmp succeeded"); 74f08c3bdfSopenharmony_ci } 75f08c3bdfSopenharmony_ci} 76f08c3bdfSopenharmony_ci 77f08c3bdfSopenharmony_cistatic void test_realpath(void) 78f08c3bdfSopenharmony_ci{ 79f08c3bdfSopenharmony_ci TESTPTR(realpath(link_file, NULL)); 80f08c3bdfSopenharmony_ci 81f08c3bdfSopenharmony_ci if (!TST_RET_PTR) { 82f08c3bdfSopenharmony_ci tst_res(TFAIL | TERRNO, "realpath failed"); 83f08c3bdfSopenharmony_ci return; 84f08c3bdfSopenharmony_ci } 85f08c3bdfSopenharmony_ci 86f08c3bdfSopenharmony_ci if (strcmp(TST_RET_PTR, test_file) != 0) { 87f08c3bdfSopenharmony_ci tst_res(TFAIL, "realpath strcmp failed, %s, %s", 88f08c3bdfSopenharmony_ci (char *)TST_RET_PTR, test_file); 89f08c3bdfSopenharmony_ci } else { 90f08c3bdfSopenharmony_ci tst_res(TPASS, "realpath strcmp succeeded"); 91f08c3bdfSopenharmony_ci } 92f08c3bdfSopenharmony_ci} 93f08c3bdfSopenharmony_ci 94f08c3bdfSopenharmony_cistatic void test_cycle_link(void) 95f08c3bdfSopenharmony_ci{ 96f08c3bdfSopenharmony_ci TST_EXP_PASS(symlink(test_file, temp_link_file), "symlink(%s, %s)", 97f08c3bdfSopenharmony_ci test_file, temp_link_file); 98f08c3bdfSopenharmony_ci TST_EXP_PASS(unlink(temp_link_file)); 99f08c3bdfSopenharmony_ci} 100f08c3bdfSopenharmony_ci 101f08c3bdfSopenharmony_cistatic void test_statfs(bool nosymfollow) 102f08c3bdfSopenharmony_ci{ 103f08c3bdfSopenharmony_ci struct statfs buf; 104f08c3bdfSopenharmony_ci 105f08c3bdfSopenharmony_ci SAFE_STATFS(MNTPOINT, &buf); 106f08c3bdfSopenharmony_ci if (buf.f_flags & ST_NOSYMFOLLOW) { 107f08c3bdfSopenharmony_ci tst_res(nosymfollow ? TPASS : TFAIL, "ST_NOSYMFOLLOW set on %s", 108f08c3bdfSopenharmony_ci MNTPOINT); 109f08c3bdfSopenharmony_ci } else { 110f08c3bdfSopenharmony_ci tst_res(nosymfollow ? TFAIL : TPASS, "ST_NOSYMFOLLOW not set on %s", 111f08c3bdfSopenharmony_ci MNTPOINT); 112f08c3bdfSopenharmony_ci } 113f08c3bdfSopenharmony_ci} 114f08c3bdfSopenharmony_ci 115f08c3bdfSopenharmony_cistatic void setup(void) 116f08c3bdfSopenharmony_ci{ 117f08c3bdfSopenharmony_ci char *tmpdir = tst_get_tmpdir(); 118f08c3bdfSopenharmony_ci 119f08c3bdfSopenharmony_ci snprintf(test_file, PATH_MAX, "%s/%s/test_file", tst_get_tmpdir(), 120f08c3bdfSopenharmony_ci MNTPOINT); 121f08c3bdfSopenharmony_ci snprintf(link_file, PATH_MAX, "%s/%s/link_file", tst_get_tmpdir(), 122f08c3bdfSopenharmony_ci MNTPOINT); 123f08c3bdfSopenharmony_ci snprintf(temp_link_file, PATH_MAX, "%s/%s/temp_link_file", 124f08c3bdfSopenharmony_ci tst_get_tmpdir(), MNTPOINT); 125f08c3bdfSopenharmony_ci free(tmpdir); 126f08c3bdfSopenharmony_ci} 127f08c3bdfSopenharmony_ci 128f08c3bdfSopenharmony_cistatic void cleanup(void) 129f08c3bdfSopenharmony_ci{ 130f08c3bdfSopenharmony_ci if (tst_is_mounted(MNTPOINT)) 131f08c3bdfSopenharmony_ci SAFE_UMOUNT(MNTPOINT); 132f08c3bdfSopenharmony_ci} 133f08c3bdfSopenharmony_ci 134f08c3bdfSopenharmony_cistatic void run_tests(bool nosymfollow) 135f08c3bdfSopenharmony_ci{ 136f08c3bdfSopenharmony_ci test_link_traversal(nosymfollow); 137f08c3bdfSopenharmony_ci test_readlink(); 138f08c3bdfSopenharmony_ci test_realpath(); 139f08c3bdfSopenharmony_ci test_cycle_link(); 140f08c3bdfSopenharmony_ci test_statfs(nosymfollow); 141f08c3bdfSopenharmony_ci} 142f08c3bdfSopenharmony_ci 143f08c3bdfSopenharmony_cistatic void run(void) 144f08c3bdfSopenharmony_ci{ 145f08c3bdfSopenharmony_ci tst_res(TINFO, "Testing behaviour when not setting MS_NOSYMFOLLOW"); 146f08c3bdfSopenharmony_ci 147f08c3bdfSopenharmony_ci TST_EXP_PASS_SILENT(mount(tst_device->dev, MNTPOINT, tst_device->fs_type, 148f08c3bdfSopenharmony_ci 0, NULL)); 149f08c3bdfSopenharmony_ci if (!flag || !strcmp(tst_device->fs_type, "tmpfs")) 150f08c3bdfSopenharmony_ci setup_symlink(); 151f08c3bdfSopenharmony_ci run_tests(false); 152f08c3bdfSopenharmony_ci 153f08c3bdfSopenharmony_ci tst_res(TINFO, "Testing behaviour when setting MS_NOSYMFOLLOW"); 154f08c3bdfSopenharmony_ci TST_EXP_PASS_SILENT(mount(tst_device->dev, MNTPOINT, tst_device->fs_type, 155f08c3bdfSopenharmony_ci MS_REMOUNT | MS_NOSYMFOLLOW, NULL)); 156f08c3bdfSopenharmony_ci run_tests(true); 157f08c3bdfSopenharmony_ci 158f08c3bdfSopenharmony_ci SAFE_UMOUNT(MNTPOINT); 159f08c3bdfSopenharmony_ci} 160f08c3bdfSopenharmony_ci 161f08c3bdfSopenharmony_cistatic struct tst_test test = { 162f08c3bdfSopenharmony_ci .test_all = run, 163f08c3bdfSopenharmony_ci .setup = setup, 164f08c3bdfSopenharmony_ci .cleanup = cleanup, 165f08c3bdfSopenharmony_ci .forks_child = 1, 166f08c3bdfSopenharmony_ci .needs_root = 1, 167f08c3bdfSopenharmony_ci .min_kver = "5.10", 168f08c3bdfSopenharmony_ci .format_device = 1, 169f08c3bdfSopenharmony_ci .mntpoint = MNTPOINT, 170f08c3bdfSopenharmony_ci .all_filesystems = 1, 171f08c3bdfSopenharmony_ci .skip_filesystems = (const char *const []){ 172f08c3bdfSopenharmony_ci "exfat", 173f08c3bdfSopenharmony_ci "vfat", 174f08c3bdfSopenharmony_ci "ntfs", 175f08c3bdfSopenharmony_ci NULL 176f08c3bdfSopenharmony_ci }, 177f08c3bdfSopenharmony_ci}; 178