This commit is contained in:
2026-08-18 09:20:44 +02:00
commit b826cd721a
522 changed files with 93730 additions and 0 deletions
+158
View File
@@ -0,0 +1,158 @@
#define _POSIX_C_SOURCE 200809L
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define PROBE_BUFFER_SIZE 2048
static const char pattern[] = "p15-019-safe-target/";
static int
fail(const char *message)
{
fprintf(stderr, "%s\n", message);
return (1);
}
static int
parse_positive(const char *text, long minimum, long maximum, long *value)
{
char *end;
long parsed;
errno = 0;
parsed = strtol(text, &end, 10);
if (errno != 0 || *text == '\0' || *end != '\0' || parsed < minimum ||
parsed > maximum)
return (-1);
*value = parsed;
return (0);
}
static void
fill_expected(char *buffer, size_t length)
{
size_t index;
for (index = 0; index < length; index++)
buffer[index] = pattern[index % (sizeof(pattern) - 1)];
}
static int
readlink_pass(const char *path, size_t expected_length)
{
char actual[PROBE_BUFFER_SIZE];
char expected[PROBE_BUFFER_SIZE];
ssize_t length;
if (expected_length + 1 > sizeof(actual))
return (fail("expected length exceeds probe buffer"));
memset(actual, 0xa5, sizeof(actual));
fill_expected(expected, expected_length);
errno = 0;
length = readlink(path, actual, sizeof(actual));
if (length < 0)
return (fail("readlink-pass returned an error"));
if ((size_t)length != expected_length)
return (fail("readlink-pass returned the wrong length"));
if (memcmp(actual, expected, expected_length) != 0)
return (fail("readlink-pass returned the wrong target"));
if ((unsigned char)actual[expected_length] != 0xa5)
return (fail("readlink-pass appended or copied an extra byte"));
return (0);
}
static int
readlink_errno(const char *path, int expected_errno)
{
char actual[PROBE_BUFFER_SIZE];
ssize_t length;
size_t index;
memset(actual, 0xa5, sizeof(actual));
errno = 0;
length = readlink(path, actual, sizeof(actual));
if (length != -1 || errno != expected_errno)
return (fail("readlink-errno returned the wrong result"));
for (index = 0; index < sizeof(actual); index++) {
if ((unsigned char)actual[index] != 0xa5)
return (fail("failed readlink modified the caller buffer"));
}
return (0);
}
static int
follow_errno(const char *path, int expected_errno)
{
struct stat status;
errno = 0;
if (stat(path, &status) != -1 || errno != expected_errno)
return (fail("follow-errno returned the wrong result"));
return (0);
}
static int
concurrent_readlink(const char *path, size_t length, long workers, long loops)
{
long worker;
int status;
pid_t child;
for (worker = 0; worker < workers; worker++) {
child = fork();
if (child < 0)
return (fail("fork failed"));
if (child == 0) {
for (long iteration = 0; iteration < loops; iteration++) {
if (readlink_pass(path, length) != 0)
_exit(1);
}
_exit(0);
}
}
for (worker = 0; worker < workers; worker++) {
if (wait(&status) < 0 || !WIFEXITED(status) ||
WEXITSTATUS(status) != 0)
return (fail("concurrent readlink worker failed"));
}
return (0);
}
int
main(int argc, char **argv)
{
long first, second, third;
if (argc == 4 && strcmp(argv[1], "readlink-pass") == 0) {
if (parse_positive(argv[3], 1, PROBE_BUFFER_SIZE - 1, &first) != 0)
return (fail("invalid readlink-pass length"));
return (readlink_pass(argv[2], (size_t)first));
}
if (argc == 4 && strcmp(argv[1], "readlink-errno") == 0) {
if (parse_positive(argv[3], 1, 255, &first) != 0)
return (fail("invalid expected errno"));
return (readlink_errno(argv[2], (int)first));
}
if (argc == 4 && strcmp(argv[1], "follow-errno") == 0) {
if (parse_positive(argv[3], 1, 255, &first) != 0)
return (fail("invalid expected errno"));
return (follow_errno(argv[2], (int)first));
}
if (argc == 6 && strcmp(argv[1], "concurrent") == 0) {
if (parse_positive(argv[3], 1, PROBE_BUFFER_SIZE - 1, &first) != 0 ||
parse_positive(argv[4], 1, 64, &second) != 0 ||
parse_positive(argv[5], 1, 1000, &third) != 0)
return (fail("invalid concurrent arguments"));
return (concurrent_readlink(argv[2], (size_t)first, second, third));
}
return (fail("usage: B16-symlink-probe MODE PATH ARG..."));
}