Skip to content

Commit b694332

Browse files
author
Nathan Ringo
committed
Add emulation of the stat family on mknod'd files.
1 parent 5f780cb commit b694332

File tree

3 files changed

+236
-23
lines changed

3 files changed

+236
-23
lines changed

src/arch.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ typedef unsigned char byte_t;
3737

3838
#define OFFSETOF_STATX_UID 20
3939
#define OFFSETOF_STATX_GID 24
40+
#define OFFSETOF_STATX_MODE 28
41+
#define OFFSETOF_STATX_INO 32
42+
#define OFFSETOF_STATX_RDEV_MAJOR 128
43+
#define OFFSETOF_STATX_RDEV_MINOR 132
44+
#define OFFSETOF_STATX_DEV_MAJOR 136
45+
#define OFFSETOF_STATX_DEV_MINOR 140
4046

4147
#if !defined(ARCH_X86_64) && !defined(ARCH_ARM_EABI) && !defined(ARCH_X86) && !defined(ARCH_SH4)
4248
# if defined(__x86_64__)
@@ -78,8 +84,12 @@ typedef unsigned char byte_t;
7884

7985
#define HOST_ELF_MACHINE {62, 3, 6, 0}
8086
#define RED_ZONE_SIZE 128
87+
#define OFFSETOF_STAT_DEV_32 0
88+
#define OFFSETOF_STAT_INO_32 12
89+
#define OFFSETOF_STAT_MODE_32 16
8190
#define OFFSETOF_STAT_UID_32 24
8291
#define OFFSETOF_STAT_GID_32 28
92+
#define OFFSETOF_STAT_RDEV_32 32
8393

8494
#define LOADER_ADDRESS 0x600000000000
8595
#define HAS_LOADER_32BIT true
@@ -101,8 +111,10 @@ typedef unsigned char byte_t;
101111
#define user_regs_struct user_regs
102112
#define HOST_ELF_MACHINE {40, 0};
103113
#define RED_ZONE_SIZE 0
114+
#define OFFSETOF_STAT_MODE_32 0
104115
#define OFFSETOF_STAT_UID_32 0
105116
#define OFFSETOF_STAT_GID_32 0
117+
#define OFFSETOF_STAT_RDEV_32 0
106118
#define EM_ARM 40
107119

108120
#define LOADER_ADDRESS 0x10000000
@@ -125,8 +137,10 @@ typedef unsigned char byte_t;
125137

126138
#define HOST_ELF_MACHINE {183, 0};
127139
#define RED_ZONE_SIZE 0
140+
#define OFFSETOF_STAT_MODE_32 0
128141
#define OFFSETOF_STAT_UID_32 0
129142
#define OFFSETOF_STAT_GID_32 0
143+
#define OFFSETOF_STAT_RDEV_32 0
130144

131145
#define LOADER_ADDRESS 0x2000000000
132146
#define EXEC_PIC_ADDRESS 0x3000000000
@@ -145,8 +159,10 @@ typedef unsigned char byte_t;
145159

146160
#define HOST_ELF_MACHINE {3, 6, 0};
147161
#define RED_ZONE_SIZE 0
162+
#define OFFSETOF_STAT_MODE_32 0
148163
#define OFFSETOF_STAT_UID_32 0
149164
#define OFFSETOF_STAT_GID_32 0
165+
#define OFFSETOF_STAT_RDEV_32 0
150166

151167
#define LOADER_ADDRESS 0xa0000000
152168
#define LOADER_ARCH_CFLAGS -mregparm=3
@@ -166,8 +182,10 @@ typedef unsigned char byte_t;
166182
#define user_regs_struct pt_regs
167183
#define HOST_ELF_MACHINE {42, 0};
168184
#define RED_ZONE_SIZE 0
185+
#define OFFSETOF_STAT_MODE_32 0
169186
#define OFFSETOF_STAT_UID_32 0
170187
#define OFFSETOF_STAT_GID_32 0
188+
#define OFFSETOF_STAT_RDEV_32 0
171189
#define NO_MISALIGNED_ACCESS 1
172190

173191
#else

src/extension/fake_id0/fake_id0.c

Lines changed: 174 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,18 @@
2020
* 02110-1301 USA.
2121
*/
2222

23-
#include <assert.h> /* assert(3), */
24-
#include <stdint.h> /* intptr_t, */
25-
#include <errno.h> /* E*, */
26-
#include <sys/stat.h> /* chmod(2), stat(2) */
27-
#include <sys/types.h> /* uid_t, gid_t, get*id(2), */
28-
#include <unistd.h> /* get*id(2), */
29-
#include <sys/ptrace.h> /* linux.git:c0a3a20b */
30-
#include <linux/audit.h> /* AUDIT_ARCH_*, */
31-
#include <string.h> /* memcpy(3), */
32-
#include <stdlib.h> /* strtol(3), */
33-
#include <linux/auxvec.h>/* AT_, */
23+
#include <assert.h> /* assert(3), */
24+
#include <stdint.h> /* intptr_t, */
25+
#include <errno.h> /* E*, */
26+
#include <sys/stat.h> /* chmod(2), stat(2) */
27+
#include <sys/types.h> /* uid_t, gid_t, get*id(2), */
28+
#include <unistd.h> /* get*id(2), */
29+
#include <sys/ptrace.h> /* linux.git:c0a3a20b */
30+
#include <linux/audit.h> /* AUDIT_ARCH_*, */
31+
#include <string.h> /* memcpy(3), */
32+
#include <stdlib.h> /* strtol(3), */
33+
#include <linux/auxvec.h> /* AT_, */
34+
#include <sys/sysmacros.h> /* makedev, major, minor */
3435

3536
#include "extension/extension.h"
3637
#include "syscall/syscall.h"
@@ -44,6 +45,18 @@
4445
#include "path/binding.h"
4546
#include "arch.h"
4647

48+
typedef struct {
49+
unsigned int dev_major, dev_minor, rdev_major, rdev_minor;
50+
ino_t ino;
51+
mode_t file_type;
52+
int fd;
53+
} Node;
54+
55+
typedef struct {
56+
Node *ptr;
57+
size_t len, cap;
58+
} NodeList;
59+
4760
typedef struct {
4861
uid_t ruid;
4962
uid_t euid;
@@ -54,6 +67,8 @@ typedef struct {
5467
gid_t egid;
5568
gid_t sgid;
5669
gid_t fsgid;
70+
71+
NodeList *nodes;
5772
} Config;
5873

5974
typedef struct {
@@ -579,12 +594,74 @@ static int handle_sysexit_end(Tracee *tracee, Config *config)
579594
POKE_MEM_ID(SYSARG_3, sgid);
580595
return 0;
581596

597+
case PR_mknod:
598+
case PR_mknodat:
599+
/* Override only permission errors. */
600+
result = peek_reg(tracee, CURRENT, SYSARG_RESULT);
601+
if ((int) result == -EPERM && config->euid == 0) {
602+
char old_path[PATH_MAX], path[PATH_MAX];
603+
struct stat statbuf;
604+
int dirfd, fd, status;
605+
mode_t mode;
606+
dev_t dev;
607+
608+
if(sysnum == PR_mknod) {
609+
dirfd = AT_FDCWD;
610+
status = get_sysarg_path(tracee, old_path, SYSARG_1);
611+
if (status < 0)
612+
return 0;
613+
status = translate_path(tracee, path, dirfd, old_path, 0);
614+
if (status < 0)
615+
return 0;
616+
mode = peek_reg(tracee, ORIGINAL, SYSARG_2);
617+
dev = peek_reg(tracee, ORIGINAL, SYSARG_3);
618+
} else {
619+
dirfd = peek_reg(tracee, ORIGINAL, SYSARG_1);
620+
status = get_sysarg_path(tracee, old_path, SYSARG_2);
621+
if (status < 0)
622+
return 0;
623+
status = translate_path(tracee, path, dirfd, old_path, 0);
624+
if (status < 0)
625+
return 0;
626+
mode = peek_reg(tracee, ORIGINAL, SYSARG_3);
627+
dev = peek_reg(tracee, ORIGINAL, SYSARG_4);
628+
}
629+
630+
if (!S_ISCHR(mode) && !S_ISBLK(mode))
631+
return 0;
632+
633+
fd = creat(path, mode & ~S_IFMT);
634+
if (fd < 0)
635+
return 0;
636+
637+
status = fstat(fd, &statbuf);
638+
if (status < 0) {
639+
close(fd);
640+
return 0;
641+
}
642+
643+
if (config->nodes->cap == config->nodes->len) {
644+
config->nodes->cap *= 2;
645+
config->nodes->ptr = realloc(config->nodes->ptr, sizeof(Node) * config->nodes->cap);
646+
}
647+
config->nodes->ptr[config->nodes->len++] = (Node) {
648+
.dev_major = major(statbuf.st_dev),
649+
.dev_minor = minor(statbuf.st_dev),
650+
.rdev_major = major(dev),
651+
.rdev_minor = minor(dev),
652+
.ino = statbuf.st_ino,
653+
.file_type = mode & S_IFMT,
654+
.fd = fd,
655+
};
656+
657+
poke_reg(tracee, SYSARG_RESULT, 0);
658+
return 0;
659+
}
660+
/* Fall through. */
582661
case PR_setdomainname:
583662
case PR_sethostname:
584663
case PR_setgroups:
585664
case PR_setgroups32:
586-
case PR_mknod:
587-
case PR_mknodat:
588665
case PR_capset:
589666
case PR_setxattr:
590667
case PR_lsetxattr:
@@ -625,10 +702,17 @@ static int handle_sysexit_end(Tracee *tracee, Config *config)
625702
case PR_fstat: {
626703
word_t address;
627704
Reg sysarg;
705+
ino_t ino;
706+
mode_t mode;
628707
uid_t uid;
629708
gid_t gid;
709+
dev_t dev_tmp;
710+
unsigned int dev_major, dev_minor;
711+
off_t ino_offset;
712+
off_t mode_offset;
630713
off_t uid_offset;
631714
off_t gid_offset;
715+
size_t i;
632716

633717
/* Override only if it succeed. */
634718
result = peek_reg(tracee, CURRENT, SYSARG_RESULT);
@@ -638,6 +722,8 @@ static int handle_sysexit_end(Tracee *tracee, Config *config)
638722
/* Get the address of the 'stat' structure. */
639723
if (sysnum == PR_statx) {
640724
sysarg = SYSARG_5;
725+
ino_offset = OFFSETOF_STATX_INO;
726+
mode_offset = OFFSETOF_STATX_MODE;
641727
uid_offset = OFFSETOF_STATX_UID;
642728
gid_offset = OFFSETOF_STATX_GID;
643729
}
@@ -646,17 +732,25 @@ static int handle_sysexit_end(Tracee *tracee, Config *config)
646732
sysarg = SYSARG_3;
647733
else
648734
sysarg = SYSARG_2;
735+
ino_offset = offsetof_stat_ino(tracee);
736+
mode_offset = offsetof_stat_mode(tracee);
649737
uid_offset = offsetof_stat_uid(tracee);
650738
gid_offset = offsetof_stat_gid(tracee);
651739
}
652740

653741
address = peek_reg(tracee, ORIGINAL, sysarg);
654742

655743
/* Sanity checks. */
744+
assert(__builtin_types_compatible_p(ino_t, uint64_t));
656745
assert(__builtin_types_compatible_p(uid_t, uint32_t));
657746
assert(__builtin_types_compatible_p(gid_t, uint32_t));
747+
assert(__builtin_types_compatible_p(mode_t, uint32_t));
748+
749+
/* Get the ino, uid, and gid values from the 'stat' structure. */
750+
ino = peek_uint64(tracee, address + ino_offset);
751+
if (errno != 0)
752+
ino = 0; /* Not fatal. */
658753

659-
/* Get the uid & gid values from the 'stat' structure. */
660754
uid = peek_uint32(tracee, address + uid_offset);
661755
if (errno != 0)
662756
uid = 0; /* Not fatal. */
@@ -665,6 +759,29 @@ static int handle_sysexit_end(Tracee *tracee, Config *config)
665759
if (errno != 0)
666760
gid = 0; /* Not fatal. */
667761

762+
/* Get the dev_major and dev_minor values from the 'stat' structure. */
763+
if (sysnum == PR_statx) {
764+
mode = peek_uint16(tracee, address + mode_offset);
765+
if (errno != 0)
766+
mode = 0;
767+
dev_major = peek_uint32(tracee, address + OFFSETOF_STATX_DEV_MAJOR);
768+
if (errno != 0)
769+
dev_major = 0;
770+
dev_minor = peek_uint32(tracee, address + OFFSETOF_STATX_DEV_MINOR);
771+
if (errno != 0)
772+
dev_minor = 0;
773+
}
774+
else {
775+
mode = peek_uint32(tracee, address + mode_offset);
776+
if (errno != 0)
777+
mode = 0;
778+
dev_tmp = peek_uint32(tracee, address + offsetof_stat_dev(tracee));
779+
if (errno != 0)
780+
dev_tmp = 0; /* Not fatal. */
781+
dev_major = major(dev_tmp);
782+
dev_minor = minor(dev_tmp);
783+
}
784+
668785
/* Override only if the file is owned by the current user.
669786
* Errors are not fatal here. */
670787
if (uid == getuid())
@@ -673,17 +790,44 @@ static int handle_sysexit_end(Tracee *tracee, Config *config)
673790
if (gid == getgid())
674791
poke_uint32(tracee, address + gid_offset, config->sgid);
675792

676-
return 0;
677-
}
793+
/* If the file is one we created with mknod or mknodat, replace
794+
* its file type and rdev. */
795+
for (i = 0; i < config->nodes->len; i++) {
796+
if (config->nodes->ptr[i].dev_major == dev_major
797+
&& config->nodes->ptr[i].dev_minor == dev_minor
798+
&& config->nodes->ptr[i].ino == ino) {
799+
if (sysnum == PR_statx) {
800+
poke_uint16(tracee, address + mode_offset,
801+
(mode & ~S_IFMT) | config->nodes->ptr[i].file_type);
802+
poke_uint32(tracee, address + OFFSETOF_STATX_RDEV_MAJOR,
803+
config->nodes->ptr[i].rdev_major);
804+
poke_uint32(tracee, address + OFFSETOF_STATX_RDEV_MINOR,
805+
config->nodes->ptr[i].rdev_minor);
806+
} else {
807+
poke_uint32(tracee, address + mode_offset,
808+
(mode & ~S_IFMT) | config->nodes->ptr[i].file_type);
809+
poke_uint32(tracee, address + offsetof_stat_rdev(tracee),
810+
makedev(config->nodes->ptr[i].rdev_major,
811+
config->nodes->ptr[i].rdev_minor));
812+
poke_uint32(tracee, address + offsetof_stat_rdev(tracee),
813+
makedev(config->nodes->ptr[i].rdev_major,
814+
config->nodes->ptr[i].rdev_minor));
815+
}
816+
break;
817+
}
818+
}
678819

679-
case PR_chroot: {
680-
char path[PATH_MAX];
681-
char abspath[PATH_MAX];
682-
word_t input;
683-
int status;
820+
return 0;
821+
}
684822

685-
if (config->euid != 0) /* TODO: && !HAS_CAP(SYS_CHROOT) */
686-
return 0;
823+
case PR_chroot: {
824+
char path[PATH_MAX];
825+
char abspath[PATH_MAX];
826+
word_t input;
827+
int status;
828+
829+
if (config->euid != 0) /* TODO: && !HAS_CAP(SYS_CHROOT) */
830+
return 0;
687831

688832
/* Override only permission errors. */
689833
result = peek_reg(tracee, CURRENT, SYSARG_RESULT);
@@ -815,6 +959,13 @@ int fake_id0_callback(Extension *extension, ExtensionEvent event, intptr_t data1
815959
config->sgid = gid;
816960
config->fsgid = gid;
817961

962+
config->nodes = talloc(extension, NodeList);
963+
if (config->nodes == NULL)
964+
return -1;
965+
config->nodes->cap = 8;
966+
config->nodes->len = 0;
967+
config->nodes->ptr = malloc(sizeof(Node) * config->nodes->cap);
968+
818969
extension->filtered_sysnums = filtered_sysnums;
819970
return 0;
820971
}

0 commit comments

Comments
 (0)