1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. 4f08c3bdfSopenharmony_ci * Author: Yang Xu <xuyang2018.jy@fujitsu.com> 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci 7f08c3bdfSopenharmony_ci/*\ 8f08c3bdfSopenharmony_ci * [Description] 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * Check setgid strip logic whether works correctly when creating tmpfile under 11f08c3bdfSopenharmony_ci * filesystem without POSIX ACL supported(by using noacl mount option). Test it 12f08c3bdfSopenharmony_ci * with umask S_IXGRP and also check file mode whether has filtered S_IXGRP. 13f08c3bdfSopenharmony_ci * 14f08c3bdfSopenharmony_ci * Fixed in: 15f08c3bdfSopenharmony_ci * 16f08c3bdfSopenharmony_ci * commit ac6800e279a22b28f4fc21439843025a0d5bf03e 17f08c3bdfSopenharmony_ci * Author: Yang Xu <xuyang2018.jy@fujitsu.com> 18f08c3bdfSopenharmony_ci * Date: Thu July 14 14:11:26 2022 +0800 19f08c3bdfSopenharmony_ci * 20f08c3bdfSopenharmony_ci * fs: Add missing umask strip in vfs_tmpfile 21f08c3bdfSopenharmony_ci * 22f08c3bdfSopenharmony_ci * The most code is pasted form creat09.c. 23f08c3bdfSopenharmony_ci */ 24f08c3bdfSopenharmony_ci 25f08c3bdfSopenharmony_ci#define _GNU_SOURCE 26f08c3bdfSopenharmony_ci#include <stdlib.h> 27f08c3bdfSopenharmony_ci#include <sys/types.h> 28f08c3bdfSopenharmony_ci#include <pwd.h> 29f08c3bdfSopenharmony_ci#include <sys/mount.h> 30f08c3bdfSopenharmony_ci#include <unistd.h> 31f08c3bdfSopenharmony_ci#include <stdio.h> 32f08c3bdfSopenharmony_ci#include "tst_test.h" 33f08c3bdfSopenharmony_ci#include "lapi/fcntl.h" 34f08c3bdfSopenharmony_ci#include "tst_uid.h" 35f08c3bdfSopenharmony_ci#include "tst_safe_file_at.h" 36f08c3bdfSopenharmony_ci 37f08c3bdfSopenharmony_ci#define MODE_RWX 0777 38f08c3bdfSopenharmony_ci#define MODE_SGID (S_ISGID|0777) 39f08c3bdfSopenharmony_ci#define MNTPOINT "mntpoint" 40f08c3bdfSopenharmony_ci#define WORKDIR MNTPOINT "/testdir" 41f08c3bdfSopenharmony_ci#define OPEN_FILE "open.tmp" 42f08c3bdfSopenharmony_ci 43f08c3bdfSopenharmony_cistatic gid_t free_gid; 44f08c3bdfSopenharmony_cistatic int tmpfile_fd = -1, dir_fd = -1, mount_flag; 45f08c3bdfSopenharmony_cistatic struct passwd *ltpuser; 46f08c3bdfSopenharmony_ci 47f08c3bdfSopenharmony_cistatic void do_mount(const char *source, const char *target, 48f08c3bdfSopenharmony_ci const char *filesystemtype, unsigned long mountflags, 49f08c3bdfSopenharmony_ci const void *data) 50f08c3bdfSopenharmony_ci{ 51f08c3bdfSopenharmony_ci TEST(mount(source, target, filesystemtype, mountflags, data)); 52f08c3bdfSopenharmony_ci 53f08c3bdfSopenharmony_ci if (TST_RET == -1 && TST_ERR == EINVAL) 54f08c3bdfSopenharmony_ci tst_brk(TCONF, "Kernel does not support noacl feature"); 55f08c3bdfSopenharmony_ci 56f08c3bdfSopenharmony_ci if (TST_RET == -1) { 57f08c3bdfSopenharmony_ci tst_brk(TBROK | TTERRNO, "mount(%s, %s, %s, %lu, %p) failed", 58f08c3bdfSopenharmony_ci source, target, filesystemtype, mountflags, data); 59f08c3bdfSopenharmony_ci } 60f08c3bdfSopenharmony_ci 61f08c3bdfSopenharmony_ci if (TST_RET) 62f08c3bdfSopenharmony_ci tst_brk(TBROK, "Invalid mount return value %ld", TST_RET); 63f08c3bdfSopenharmony_ci 64f08c3bdfSopenharmony_ci mount_flag = 1; 65f08c3bdfSopenharmony_ci} 66f08c3bdfSopenharmony_ci 67f08c3bdfSopenharmony_cistatic void open_tmpfile_supported(int dirfd) 68f08c3bdfSopenharmony_ci{ 69f08c3bdfSopenharmony_ci TEST(openat(dirfd, ".", O_TMPFILE | O_RDWR, S_IXGRP | S_ISGID)); 70f08c3bdfSopenharmony_ci 71f08c3bdfSopenharmony_ci if (TST_RET == -1) { 72f08c3bdfSopenharmony_ci if (errno == ENOTSUP) 73f08c3bdfSopenharmony_ci tst_brk(TCONF, "fs doesn't support O_TMPFILE"); 74f08c3bdfSopenharmony_ci else 75f08c3bdfSopenharmony_ci tst_brk(TBROK | TTERRNO, "openat(%d, O_TMPFILE) failed", dirfd); 76f08c3bdfSopenharmony_ci } 77f08c3bdfSopenharmony_ci 78f08c3bdfSopenharmony_ci if (TST_RET < 0) 79f08c3bdfSopenharmony_ci tst_brk(TBROK, "Invalid openat return value %ld", TST_RET); 80f08c3bdfSopenharmony_ci 81f08c3bdfSopenharmony_ci SAFE_CLOSE(TST_RET); 82f08c3bdfSopenharmony_ci} 83f08c3bdfSopenharmony_ci 84f08c3bdfSopenharmony_cistatic void setup(void) 85f08c3bdfSopenharmony_ci{ 86f08c3bdfSopenharmony_ci struct stat buf; 87f08c3bdfSopenharmony_ci 88f08c3bdfSopenharmony_ci ltpuser = SAFE_GETPWNAM("nobody"); 89f08c3bdfSopenharmony_ci 90f08c3bdfSopenharmony_ci do_mount(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, "noacl"); 91f08c3bdfSopenharmony_ci 92f08c3bdfSopenharmony_ci tst_res(TINFO, "User nobody: uid = %d, gid = %d", (int)ltpuser->pw_uid, 93f08c3bdfSopenharmony_ci (int)ltpuser->pw_gid); 94f08c3bdfSopenharmony_ci free_gid = tst_get_free_gid(ltpuser->pw_gid); 95f08c3bdfSopenharmony_ci 96f08c3bdfSopenharmony_ci /* Create directories and set permissions */ 97f08c3bdfSopenharmony_ci SAFE_MKDIR(WORKDIR, MODE_RWX); 98f08c3bdfSopenharmony_ci dir_fd = SAFE_OPEN(WORKDIR, O_RDONLY, O_DIRECTORY); 99f08c3bdfSopenharmony_ci open_tmpfile_supported(dir_fd); 100f08c3bdfSopenharmony_ci 101f08c3bdfSopenharmony_ci SAFE_CHOWN(WORKDIR, ltpuser->pw_uid, free_gid); 102f08c3bdfSopenharmony_ci SAFE_CHMOD(WORKDIR, MODE_SGID); 103f08c3bdfSopenharmony_ci SAFE_STAT(WORKDIR, &buf); 104f08c3bdfSopenharmony_ci 105f08c3bdfSopenharmony_ci if (!(buf.st_mode & S_ISGID)) 106f08c3bdfSopenharmony_ci tst_brk(TBROK, "%s: Setgid bit not set", WORKDIR); 107f08c3bdfSopenharmony_ci 108f08c3bdfSopenharmony_ci if (buf.st_gid != free_gid) { 109f08c3bdfSopenharmony_ci tst_brk(TBROK, "%s: Incorrect group, %u != %u", WORKDIR, 110f08c3bdfSopenharmony_ci buf.st_gid, free_gid); 111f08c3bdfSopenharmony_ci } 112f08c3bdfSopenharmony_ci 113f08c3bdfSopenharmony_ci /* Switch user */ 114f08c3bdfSopenharmony_ci SAFE_SETGID(ltpuser->pw_gid); 115f08c3bdfSopenharmony_ci SAFE_SETREUID(-1, ltpuser->pw_uid); 116f08c3bdfSopenharmony_ci} 117f08c3bdfSopenharmony_ci 118f08c3bdfSopenharmony_cistatic void file_test(int dfd, const char *path, int flags) 119f08c3bdfSopenharmony_ci{ 120f08c3bdfSopenharmony_ci struct stat buf; 121f08c3bdfSopenharmony_ci 122f08c3bdfSopenharmony_ci SAFE_FSTATAT(dfd, path, &buf, flags); 123f08c3bdfSopenharmony_ci 124f08c3bdfSopenharmony_ci TST_EXP_EQ_LI(buf.st_gid, free_gid); 125f08c3bdfSopenharmony_ci 126f08c3bdfSopenharmony_ci if (buf.st_mode & S_ISGID) 127f08c3bdfSopenharmony_ci tst_res(TFAIL, "%s: Setgid bit is set", path); 128f08c3bdfSopenharmony_ci else 129f08c3bdfSopenharmony_ci tst_res(TPASS, "%s: Setgid bit not set", path); 130f08c3bdfSopenharmony_ci 131f08c3bdfSopenharmony_ci if (buf.st_mode & S_IXGRP) 132f08c3bdfSopenharmony_ci tst_res(TFAIL, "%s: S_IXGRP bit is set", path); 133f08c3bdfSopenharmony_ci else 134f08c3bdfSopenharmony_ci tst_res(TPASS, "%s: S_IXGRP bit is not set", path); 135f08c3bdfSopenharmony_ci} 136f08c3bdfSopenharmony_ci 137f08c3bdfSopenharmony_cistatic void run(void) 138f08c3bdfSopenharmony_ci{ 139f08c3bdfSopenharmony_ci char path[PATH_MAX]; 140f08c3bdfSopenharmony_ci 141f08c3bdfSopenharmony_ci umask(S_IXGRP); 142f08c3bdfSopenharmony_ci tmpfile_fd = SAFE_OPENAT(dir_fd, ".", O_TMPFILE | O_RDWR, MODE_SGID); 143f08c3bdfSopenharmony_ci snprintf(path, PATH_MAX, "/proc/self/fd/%d", tmpfile_fd); 144f08c3bdfSopenharmony_ci SAFE_LINKAT(AT_FDCWD, path, dir_fd, OPEN_FILE, AT_SYMLINK_FOLLOW); 145f08c3bdfSopenharmony_ci file_test(dir_fd, OPEN_FILE, 0); 146f08c3bdfSopenharmony_ci SAFE_CLOSE(tmpfile_fd); 147f08c3bdfSopenharmony_ci /* Cleanup between loops */ 148f08c3bdfSopenharmony_ci tst_purge_dir(WORKDIR); 149f08c3bdfSopenharmony_ci} 150f08c3bdfSopenharmony_ci 151f08c3bdfSopenharmony_cistatic void cleanup(void) 152f08c3bdfSopenharmony_ci{ 153f08c3bdfSopenharmony_ci SAFE_SETREUID(-1, 0); 154f08c3bdfSopenharmony_ci 155f08c3bdfSopenharmony_ci if (tmpfile_fd >= 0) 156f08c3bdfSopenharmony_ci SAFE_CLOSE(tmpfile_fd); 157f08c3bdfSopenharmony_ci if (dir_fd >= 0) 158f08c3bdfSopenharmony_ci SAFE_CLOSE(dir_fd); 159f08c3bdfSopenharmony_ci if (mount_flag && tst_umount(MNTPOINT)) 160f08c3bdfSopenharmony_ci tst_res(TWARN | TERRNO, "umount(%s)", MNTPOINT); 161f08c3bdfSopenharmony_ci} 162f08c3bdfSopenharmony_ci 163f08c3bdfSopenharmony_cistatic struct tst_test test = { 164f08c3bdfSopenharmony_ci .test_all = run, 165f08c3bdfSopenharmony_ci .setup = setup, 166f08c3bdfSopenharmony_ci .cleanup = cleanup, 167f08c3bdfSopenharmony_ci .needs_root = 1, 168f08c3bdfSopenharmony_ci .all_filesystems = 1, 169f08c3bdfSopenharmony_ci .format_device = 1, 170f08c3bdfSopenharmony_ci .mntpoint = MNTPOINT, 171f08c3bdfSopenharmony_ci .skip_filesystems = (const char*[]) { 172f08c3bdfSopenharmony_ci "exfat", 173f08c3bdfSopenharmony_ci "ntfs", 174f08c3bdfSopenharmony_ci "vfat", 175f08c3bdfSopenharmony_ci NULL 176f08c3bdfSopenharmony_ci }, 177f08c3bdfSopenharmony_ci .tags = (const struct tst_tag[]) { 178f08c3bdfSopenharmony_ci {"linux-git", "ac6800e279a2"}, 179f08c3bdfSopenharmony_ci {"linux-git", "426b4ca2d6a5"}, 180f08c3bdfSopenharmony_ci {} 181f08c3bdfSopenharmony_ci }, 182f08c3bdfSopenharmony_ci}; 183