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"
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+
4760typedef 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
5974typedef 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