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
|
/*
* Check decoding of chown/chown32/lchown/lchown32/fchown/fchown32 syscalls.
*
* Copyright (c) 2016 Dmitry V. Levin <ldv@strace.io>
* Copyright (c) 2016-2021 The strace developers.
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#ifdef UGID_TYPE_IS_SHORT
# define UGID_TYPE short
# define GETEUID syscall(__NR_geteuid)
# define GETEGID syscall(__NR_getegid)
# define CHECK_OVERFLOWUID(arg) check_overflowuid(arg)
# define CHECK_OVERFLOWGID(arg) check_overflowgid(arg)
#else
# define UGID_TYPE int
# define GETEUID geteuid()
# define GETEGID getegid()
# define CHECK_OVERFLOWUID(arg)
# define CHECK_OVERFLOWGID(arg)
#endif
#define UNLINK_SAMPLE \
do { \
if (unlink(sample)) \
perror_msg_and_fail("unlink"); \
} while (0)
#define CLOSE_SAMPLE \
do { \
if (close(fd)) \
perror_msg_and_fail("close"); \
} while (0)
#ifdef ACCESS_BY_DESCRIPTOR
# define SYSCALL_ARG1 fd
# define FMT_ARG1 "%d"
# define EOK_CMD CLOSE_SAMPLE
# define CLEANUP_CMD UNLINK_SAMPLE
#else
# define SYSCALL_ARG1 sample
# define FMT_ARG1 "\"%s\""
# define EOK_CMD UNLINK_SAMPLE
# define CLEANUP_CMD CLOSE_SAMPLE
#endif
static int
ugid2int(const unsigned UGID_TYPE id)
{
if ((unsigned UGID_TYPE) -1U == id)
return -1;
else
return id;
}
static void
print_int(const unsigned int num)
{
if (num == -1U)
printf(", -1");
else
printf(", %u", num);
}
static int
num_matches_id(const unsigned int num, const unsigned int id)
{
return num == id || num == -1U;
}
#define PAIR(val) { val, gid }, { uid, val }
int
main(void)
{
static const char sample[] = SYSCALL_NAME "_sample";
unsigned int uid = GETEUID;
CHECK_OVERFLOWUID(uid);
unsigned int gid = GETEGID;
CHECK_OVERFLOWUID(gid);
const struct {
const long uid, gid;
} tests[] = {
{ uid, gid },
{ (unsigned long) 0xffffffff00000000ULL | uid, gid },
{ uid, (unsigned long) 0xffffffff00000000ULL | gid },
PAIR(-1U),
PAIR(-1L),
{ 0xffff0000U | uid, gid },
{ uid, 0xffff0000U | gid },
PAIR(0xffff),
PAIR(0xc0deffffU),
PAIR(0xfacefeedU),
PAIR((long) 0xfacefeeddeadbeefULL)
};
int fd = open(sample, O_RDONLY | O_CREAT, 0400);
if (fd < 0)
perror_msg_and_fail("open");
CLEANUP_CMD;
long expected = 0;
for (unsigned int i = 0; i < ARRAY_SIZE(tests); ++i) {
const unsigned int unum = ugid2int(tests[i].uid);
const unsigned int gnum = ugid2int(tests[i].gid);
if (num_matches_id(unum, uid) &&
num_matches_id(gnum, gid)) {
if (expected)
continue;
} else {
if (!expected) {
expected = -1;
EOK_CMD;
}
}
const long rc = syscall(SYSCALL_NR, SYSCALL_ARG1,
tests[i].uid, tests[i].gid);
const char *errstr = sprintrc(rc);
printf("%s(" FMT_ARG1, SYSCALL_NAME, SYSCALL_ARG1);
print_int(unum);
print_int(gnum);
printf(") = %s\n", errstr);
}
puts("+++ exited with 0 +++");
return 0;
}
|