Implement issetugid syscall
Implement issetugid syscall and provide a test. This gets rid of the scary "Unsecure. Implement me" warning during compilation.
This commit is contained in:
		
							parent
							
								
									ef99a7a3dc
								
							
						
					
					
						commit
						b4fb061802
					
				| @ -100,7 +100,7 @@ | ||||
| #define EXEC_RESTART	102	/* to PM: final part of exec for RS */ | ||||
| #define PROCSTAT	103	/* to PM */ | ||||
| #define GETPROCNR	104	/* to PM */ | ||||
| 
 | ||||
| #define ISSETUGID	106	/* to PM: ask if process is tainted */ | ||||
| #define GETEPINFO_O	107	/* to PM: get pid/uid/gid of an endpoint */ | ||||
| #define ADDDMA		108	/* to PM: inform PM about a region of memory | ||||
| 				 * that is used for bus-master DMA | ||||
|  | ||||
| @ -165,6 +165,7 @@ struct exec_newmem | ||||
| 	time_t enst_ctime;	/* Last changed time of executable file */ | ||||
| 	uid_t new_uid;		/* Process UID after exec */ | ||||
| 	gid_t new_gid;		/* Process GID after exec */ | ||||
| 	int setugid;		/* Process is setuid or setgid */ | ||||
| 	char progname[16];	/* Should be at least PROC_NAME_LEN */ | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -116,6 +116,7 @@ _PROTOTYPE( pid_t getpid, (void)					); | ||||
| _PROTOTYPE( pid_t getppid, (void)					); | ||||
| _PROTOTYPE( uid_t getuid, (void)					); | ||||
| _PROTOTYPE( int isatty, (int _fd)					); | ||||
| _PROTOTYPE( int issetugid, (void)					); | ||||
| _PROTOTYPE( int link, (const char *_existing, const char *_new)		); | ||||
| _PROTOTYPE( off_t lseek, (int _fd, off_t _offset, int _whence)		); | ||||
| _PROTOTYPE( long pathconf, (const char *_path, int _name)		); | ||||
|  | ||||
| @ -69,6 +69,7 @@ SRCS+=  \ | ||||
| 	hypot.c \ | ||||
| 	index.c \ | ||||
| 	initgroups.c \ | ||||
| 	issetugid.c \ | ||||
| 	itoa.c \ | ||||
| 	loadname.c \ | ||||
| 	lock.c \ | ||||
|  | ||||
							
								
								
									
										14
									
								
								lib/libc/other/issetugid.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								lib/libc/other/issetugid.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| #include <sys/cdefs.h> | ||||
| #include <lib.h> | ||||
| 
 | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| int issetugid(void) | ||||
| { | ||||
| 	int r; | ||||
| 	message m; | ||||
| 
 | ||||
| 	r = _syscall(PM_PROC_NR, ISSETUGID, &m); | ||||
| 	if (r == -1) return 0;	/* Default to old behavior */ | ||||
| 	return(r); | ||||
| } | ||||
| @ -6,6 +6,10 @@ | ||||
| 
 | ||||
| int issetugid(void) | ||||
| { | ||||
| #warning Unsecure. Implement me. | ||||
| 	return 0; | ||||
| 	int r; | ||||
| 	message m; | ||||
| 
 | ||||
| 	r = _syscall(PM_PROC_NR, ISSETUGID, &m); | ||||
| 	if (r == -1) return 0;	/* Default to old behavior */ | ||||
| 	return(r); | ||||
| } | ||||
|  | ||||
| @ -43,7 +43,7 @@ FORWARD _PROTOTYPE( int exec_newmem, (int proc_e, vir_bytes text_addr, vir_bytes | ||||
| 		       int is_elf, dev_t st_dev, ino_t st_ino, time_t ctime, | ||||
| 		       char *progname, int new_uid, int new_gid, | ||||
| 		       vir_bytes *stack_topp, int *load_textp, | ||||
| 		       int *allow_setuidp)				); | ||||
| 		       int *setugidp)					); | ||||
| FORWARD _PROTOTYPE( int is_script, (const char *exec_hdr, size_t exec_len)); | ||||
| FORWARD _PROTOTYPE( int patch_stack, (struct vnode *vp, char stack[ARG_MAX], | ||||
| 		       vir_bytes *stk_bytes, char path[PATH_MAX])	); | ||||
| @ -168,6 +168,7 @@ PUBLIC int pm_exec(int proc_e, char *path, vir_bytes path_len, char *frame, | ||||
| 
 | ||||
| 	strncpy(execi.progname, cp, PROC_NAME_LEN-1); | ||||
| 	execi.progname[PROC_NAME_LEN-1] = '\0'; | ||||
| 	execi.setugid = 0; | ||||
| 
 | ||||
| 	/* Open executable */ | ||||
| 	if ((vp = eat_path(&resolve, fp)) == NULL) { | ||||
| @ -188,8 +189,14 @@ PUBLIC int pm_exec(int proc_e, char *path, vir_bytes path_len, char *frame, | ||||
| 
 | ||||
|         if (round == 0) { | ||||
| 		/* Deal with setuid/setgid executables */ | ||||
|             if (vp->v_mode & I_SET_UID_BIT) execi.new_uid = vp->v_uid; | ||||
|             if (vp->v_mode & I_SET_GID_BIT) execi.new_gid = vp->v_gid; | ||||
| 		if (vp->v_mode & I_SET_UID_BIT) { | ||||
| 			execi.new_uid = vp->v_uid; | ||||
| 			execi.setugid = 1; | ||||
| 		} | ||||
| 		if (vp->v_mode & I_SET_GID_BIT) { | ||||
| 			execi.new_gid = vp->v_gid; | ||||
| 			execi.setugid = 1; | ||||
| 		} | ||||
|         } | ||||
| 
 | ||||
| 	r = map_header(&execi.hdr, execi.vp); | ||||
| @ -240,7 +247,9 @@ PUBLIC int pm_exec(int proc_e, char *path, vir_bytes path_len, char *frame, | ||||
|   if (r != OK) goto pm_execfinal; | ||||
|   clo_exec(rfp); | ||||
| 
 | ||||
|   if (execi.allow_setuid) { | ||||
|   if (execi.setugid) { | ||||
| 	/* If after loading the image we're still allowed to run with
 | ||||
| 	 * setuid or setgid, change credentials now */ | ||||
| 	rfp->fp_effuid = execi.new_uid; | ||||
| 	rfp->fp_effgid = execi.new_gid; | ||||
|   } | ||||
| @ -286,7 +295,7 @@ PRIVATE int load_aout(struct exec_info *execi) | ||||
| 		  execi->frame_len, sep_id, 0 /* is_elf */, vp->v_dev, vp->v_inode_nr, | ||||
| 		  execi->sb.st_ctime, | ||||
| 		  execi->progname, execi->new_uid, execi->new_gid, | ||||
| 		  &execi->stack_top, &execi->load_text, &execi->allow_setuid); | ||||
| 		  &execi->stack_top, &execi->load_text, &execi->setugid); | ||||
| 
 | ||||
|   if (r != OK) { | ||||
|         printf("VFS: load_aout: exec_newmem failed: %d\n", r); | ||||
| @ -343,7 +352,7 @@ PRIVATE int load_elf(struct exec_info *execi) | ||||
| 		  tot_bytes, execi->frame_len, sep_id, is_elf, | ||||
| 		  vp->v_dev, vp->v_inode_nr, execi->sb.st_ctime, | ||||
| 		  execi->progname, execi->new_uid, execi->new_gid, | ||||
| 		  &execi->stack_top, &execi->load_text, &execi->allow_setuid); | ||||
| 		  &execi->stack_top, &execi->load_text, &execi->setugid); | ||||
| 
 | ||||
|   if (r != OK) { | ||||
|         printf("VFS: load_elf: exec_newmem failed: %d\n", r); | ||||
| @ -381,7 +390,7 @@ PRIVATE int exec_newmem( | ||||
|   int new_gid, | ||||
|   vir_bytes *stack_topp, | ||||
|   int *load_textp, | ||||
|   int *allow_setuidp | ||||
|   int *setugidp | ||||
| ) | ||||
| { | ||||
| /* Allocate a new memory map for a process that tries to exec */ | ||||
| @ -389,6 +398,8 @@ PRIVATE int exec_newmem( | ||||
|   struct exec_newmem e; | ||||
|   message m; | ||||
| 
 | ||||
|   assert(setugidp != NULL); | ||||
| 
 | ||||
|   e.text_addr = text_addr; | ||||
|   e.text_bytes = text_bytes; | ||||
|   e.data_addr = data_addr; | ||||
| @ -402,6 +413,7 @@ PRIVATE int exec_newmem( | ||||
|   e.enst_ctime = ctime; | ||||
|   e.new_uid    = new_uid; | ||||
|   e.new_gid    = new_gid; | ||||
|   e.setugid    = *setugidp; | ||||
|   strncpy(e.progname, progname, sizeof(e.progname)-1); | ||||
|   e.progname[sizeof(e.progname)-1] = '\0'; | ||||
| 
 | ||||
| @ -412,7 +424,7 @@ PRIVATE int exec_newmem( | ||||
| 
 | ||||
|   *stack_topp = m.m1_i1; | ||||
|   *load_textp = !!(m.m1_i2 & EXC_NM_RF_LOAD_TEXT); | ||||
|   *allow_setuidp = !!(m.m1_i2 & EXC_NM_RF_ALLOW_SETUID); | ||||
|   *setugidp = !!(m.m1_i2 & EXC_NM_RF_ALLOW_SETUID); | ||||
| 
 | ||||
|   return(m.m_type); | ||||
| } | ||||
|  | ||||
| @ -10,7 +10,7 @@ struct exec_info { | ||||
|     uid_t new_uid;			/* Process UID after exec */ | ||||
|     gid_t new_gid;			/* Process GID after exec */ | ||||
|     int load_text;			/* Load text section? */ | ||||
|     int allow_setuid;			/* Allow setuid execution? */ | ||||
|     int setugid;			/* Allow set{u,g}id execution? */ | ||||
|     struct vnode *vp;			/* Exec file's vnode */ | ||||
|     struct stat sb;			/* Exec file's stat structure */ | ||||
|     char progname[PROC_NAME_LEN];	/* Program name */ | ||||
|  | ||||
| @ -81,16 +81,30 @@ PUBLIC int do_exec_newmem() | ||||
| 	if (r != OK) | ||||
| 		panic("do_exec_newmem: sys_datacopy failed: %d", r); | ||||
| 
 | ||||
| 	if((r=vm_exec_newmem(proc_e, &args, sizeof(args), &stack_top, &flags)) == OK) { | ||||
| 	if ((r = vm_exec_newmem(proc_e, &args, sizeof(args), &stack_top, | ||||
| 				&flags)) == OK) { | ||||
| 		allow_setuid = 0;	/* Do not allow setuid execution */ | ||||
| 		rmp->mp_flags &= ~TAINTED;	/* By default not tainted */ | ||||
| 
 | ||||
| 		if (rmp->mp_tracer == NO_TRACER) { | ||||
| 			/* Okay, setuid execution is allowed */ | ||||
| 			allow_setuid = 1; | ||||
| 
 | ||||
| 			rmp->mp_effuid = args.new_uid; | ||||
| 			rmp->mp_effgid = args.new_gid; | ||||
| 		} | ||||
| 
 | ||||
| 		/* A process is considered 'tainted' when it's executing with
 | ||||
| 		 * setuid or setgid bit set, or when the real{u,g}id doesn't | ||||
| 		 * match the eff{u,g}id, respectively. */ | ||||
| 		if (allow_setuid && args.setugid) { | ||||
| 			/* Program has setuid and/or setgid bits set */ | ||||
| 			rmp->mp_flags |= TAINTED; | ||||
| 		} else if (rmp->mp_effuid != rmp->mp_realuid || | ||||
| 			   rmp->mp_effgid != rmp->mp_realgid) { | ||||
| 			rmp->mp_flags |= TAINTED; | ||||
| 		} | ||||
| 
 | ||||
| 		/* System will save command line for debugging, ps(1) output, etc. */ | ||||
| 		strncpy(rmp->mp_name, args.progname, PROC_NAME_LEN-1); | ||||
| 		rmp->mp_name[PROC_NAME_LEN-1] = '\0'; | ||||
|  | ||||
| @ -103,7 +103,7 @@ PUBLIC int do_fork() | ||||
|   } | ||||
| 
 | ||||
|   /* Inherit only these flags. In normal fork(), PRIV_PROC is not inherited. */ | ||||
|   rmc->mp_flags &= (IN_USE|DELAY_CALL); | ||||
|   rmc->mp_flags &= (IN_USE|DELAY_CALL|TAINTED); | ||||
|   rmc->mp_child_utime = 0;		/* reset administration */ | ||||
|   rmc->mp_child_stime = 0;		/* reset administration */ | ||||
|   rmc->mp_exitstatus = 0; | ||||
|  | ||||
| @ -18,7 +18,8 @@ | ||||
|  *===========================================================================*/ | ||||
| PUBLIC int do_get() | ||||
| { | ||||
| /* Handle GETUID, GETGID, GETGROUPS, GETGROUPS_O, GETPID, GETPGRP, GETSID.
 | ||||
| /* Handle GETUID, GETGID, GETGROUPS, GETGROUPS_O, GETPID, GETPGRP, GETSID,
 | ||||
|    ISSETUGID. | ||||
|  */ | ||||
| 
 | ||||
|   register struct mproc *rmp = mp; | ||||
| @ -103,6 +104,10 @@ PUBLIC int do_get() | ||||
| 			r = target->mp_procgrp; | ||||
| 		break; | ||||
| 	} | ||||
| 	case ISSETUGID: | ||||
| 		r = !!(rmp->mp_flags & TAINTED); | ||||
| 		break; | ||||
| 
 | ||||
| 	default: | ||||
| 		r = EINVAL; | ||||
| 		break;	 | ||||
|  | ||||
| @ -91,5 +91,6 @@ EXTERN struct mproc { | ||||
| #define TRACE_EXIT	0x08000	/* tracer is forcing this process to exit */ | ||||
| #define TRACE_ZOMBIE	0x10000	/* waiting for tracer to issue WAIT call */ | ||||
| #define DELAY_CALL	0x20000	/* waiting for call before sending signal */ | ||||
| #define TAINTED		0x40000 /* process is 'tainted' */ | ||||
| 
 | ||||
| #define MP_MAGIC	0xC0FFEE0 | ||||
|  | ||||
| @ -117,7 +117,7 @@ _PROTOTYPE (int (*call_vec[]), (void) ) = { | ||||
| 	do_procstat,	/* 103 = procstat */ | ||||
| 	do_getprocnr,	/* 104 = getprocnr */ | ||||
| 	no_sys,		/* 105 = unused */ | ||||
| 	no_sys,		/* 106 = unused */ | ||||
| 	do_get,		/* 106 = issetugid */ | ||||
| 	do_getepinfo_o,	/* 107 = getepinfo XXX: old implementation*/ | ||||
| 	do_adddma,	/* 108 = adddma */ | ||||
| 	do_deldma,	/* 109 = deldma */ | ||||
|  | ||||
| @ -41,7 +41,7 @@ static int exec_newmem(int proc_e, vir_bytes text_addr, vir_bytes text_bytes, | ||||
| 		       int is_elf, dev_t st_dev, ino_t st_ino, time_t ctime, | ||||
| 		       char *progname, int new_uid, int new_gid, | ||||
| 		       vir_bytes *stack_topp, int *load_textp, | ||||
| 		       int *allow_setuidp); | ||||
| 		       int *setugidp); | ||||
| static int is_script(const char *exec_hdr, size_t exec_len); | ||||
| static int patch_stack(struct vnode *vp, char stack[ARG_MAX], | ||||
| 		       vir_bytes *stk_bytes); | ||||
| @ -118,6 +118,7 @@ PUBLIC int pm_exec(int proc_e, char *path, vir_bytes path_len, char *frame, | ||||
| 
 | ||||
| 	strncpy(execi.progname, cp, PROC_NAME_LEN-1); | ||||
| 	execi.progname[PROC_NAME_LEN-1] = '\0'; | ||||
| 	execi.setugid = 0; | ||||
| 
 | ||||
| 	/* Open executable */ | ||||
| 	if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); | ||||
| @ -137,8 +138,14 @@ PUBLIC int pm_exec(int proc_e, char *path, vir_bytes path_len, char *frame, | ||||
| 
 | ||||
|         if (round == 0) { | ||||
| 		/* Deal with setuid/setgid executables */ | ||||
|             if (vp->v_mode & I_SET_UID_BIT) execi.new_uid = vp->v_uid; | ||||
|             if (vp->v_mode & I_SET_GID_BIT) execi.new_gid = vp->v_gid; | ||||
| 		if (vp->v_mode & I_SET_UID_BIT) { | ||||
| 			execi.new_uid = vp->v_uid; | ||||
| 			execi.setugid = 1; | ||||
| 		} | ||||
| 		if (vp->v_mode & I_SET_GID_BIT) { | ||||
| 			execi.new_gid = vp->v_gid; | ||||
| 			execi.setugid = 1; | ||||
| 		} | ||||
|         } | ||||
| 
 | ||||
| 	r = map_header(&execi.hdr, execi.vp); | ||||
| @ -190,7 +197,9 @@ PUBLIC int pm_exec(int proc_e, char *path, vir_bytes path_len, char *frame, | ||||
|   if (r != OK) return(r); | ||||
|   clo_exec(rfp); | ||||
| 
 | ||||
|   if (execi.allow_setuid) { | ||||
|   if (execi.setugid) { | ||||
| 	/* If after loading the image we're still allowed to run with
 | ||||
| 	 * setuid or setgid, change the credentials now */ | ||||
| 	rfp->fp_effuid = execi.new_uid; | ||||
| 	rfp->fp_effgid = execi.new_gid; | ||||
|   } | ||||
| @ -230,7 +239,7 @@ static int load_aout(struct exec_info *execi) | ||||
| 		  execi->frame_len, sep_id, 0 /* is_elf */, vp->v_dev, vp->v_inode_nr, | ||||
| 		  execi->sb.st_ctime, | ||||
| 		  execi->progname, execi->new_uid, execi->new_gid, | ||||
| 		  &execi->stack_top, &execi->load_text, &execi->allow_setuid); | ||||
| 		  &execi->stack_top, &execi->load_text, &execi->setugid); | ||||
| 
 | ||||
|   if (r != OK) { | ||||
|         printf("VFS: load_aout: exec_newmem failed: %d\n", r); | ||||
| @ -282,7 +291,7 @@ static int load_elf(struct exec_info *execi) | ||||
| 		  tot_bytes, execi->frame_len, sep_id, is_elf, | ||||
| 		  vp->v_dev, vp->v_inode_nr, execi->sb.st_ctime, | ||||
| 		  execi->progname, execi->new_uid, execi->new_gid, | ||||
| 		  &execi->stack_top, &execi->load_text, &execi->allow_setuid); | ||||
| 		  &execi->stack_top, &execi->load_text, &execi->setugid); | ||||
| 
 | ||||
|   if (r != OK) { | ||||
|         printf("VFS: load_elf: exec_newmem failed: %d\n", r); | ||||
| @ -320,13 +329,15 @@ static int exec_newmem( | ||||
|   int new_gid, | ||||
|   vir_bytes *stack_topp, | ||||
|   int *load_textp, | ||||
|   int *allow_setuidp | ||||
|   int *setugidp | ||||
| ) | ||||
| { | ||||
|   int r; | ||||
|   struct exec_newmem e; | ||||
|   message m; | ||||
| 
 | ||||
|   assert(setugidp != NULL); | ||||
| 
 | ||||
|   e.text_addr = text_addr; | ||||
|   e.text_bytes = text_bytes; | ||||
|   e.data_addr = data_addr; | ||||
| @ -340,6 +351,7 @@ static int exec_newmem( | ||||
|   e.enst_ctime = ctime; | ||||
|   e.new_uid    = new_uid; | ||||
|   e.new_gid    = new_gid; | ||||
|   e.setugid    = *setugidp; | ||||
|   strncpy(e.progname, progname, sizeof(e.progname)-1); | ||||
|   e.progname[sizeof(e.progname)-1] = '\0'; | ||||
| 
 | ||||
| @ -350,7 +362,7 @@ static int exec_newmem( | ||||
| 
 | ||||
|   *stack_topp = m.m1_i1; | ||||
|   *load_textp = !!(m.m1_i2 & EXC_NM_RF_LOAD_TEXT); | ||||
|   *allow_setuidp = !!(m.m1_i2 & EXC_NM_RF_ALLOW_SETUID); | ||||
|   *setugidp = !!(m.m1_i2 & EXC_NM_RF_ALLOW_SETUID); | ||||
| 
 | ||||
|   return(m.m_type); | ||||
| } | ||||
|  | ||||
| @ -10,7 +10,7 @@ struct exec_info { | ||||
|     uid_t new_uid;			/* Process UID after exec */ | ||||
|     gid_t new_gid;			/* Process GID after exec */ | ||||
|     int load_text;			/* Load text section? */ | ||||
|     int allow_setuid;			/* Allow setuid execution? */ | ||||
|     int setugid;			/* Allow set{u,g}id execution? */ | ||||
|     struct vnode *vp;			/* Exec file's vnode */ | ||||
|     struct stat sb;			/* Exec file's stat structure */ | ||||
|     char progname[PROC_NAME_LEN];	/* Program name */ | ||||
|  | ||||
| @ -16,10 +16,10 @@ OBJ=	test1  test2  test3  test4  test5  test6  test7  test8  test9  \ | ||||
| 	test30 test31 test32        test34 test35 test36 test37 test38 \
 | ||||
| 	test39 t10a t11a t11b test40 t40a t40b t40c t40d t40e t40f test41 \
 | ||||
| 	test42 test45 test47 test49 test50 test51 test52 test53 \
 | ||||
| 	test54 test56 test58 | ||||
| 	test54 test56 test58 t60a t60b | ||||
| 
 | ||||
| BIGOBJ=  test20 test24 | ||||
| ROOTOBJ= test11 test33 test43 test44 test46 | ||||
| ROOTOBJ= test11 test33 test43 test44 test46 test60 | ||||
| GCCOBJ=  test45-gcc test48 test49-gcc test55 | ||||
| GCCFPUOBJ= test51-gcc test52-gcc | ||||
| OTHEROBJ= test57 test59 | ||||
| @ -53,7 +53,9 @@ depend: .gitignore | ||||
| clean:	 | ||||
| 	$(MAKE) -C select clean | ||||
| 	-rm -rf *.o *.s *.bak test? test?? test??-gcc t10a t11a t11b \
 | ||||
| 		t40a t40b t40c t40d t40e t40f t43 DIR* | ||||
| 		t40a t40b t40c t40d t40e t40f t43 \
 | ||||
| 		t60a t60b \
 | ||||
| 		DIR* | ||||
| 
 | ||||
| test1:	test1.c | ||||
| test2:	test2.c | ||||
| @ -128,3 +130,6 @@ test57: test57.c test57loop.S | ||||
| test58: test58.c | ||||
| test59: test59.c | ||||
| 	$(CC) $(CFLAGS) -o $@ $@.c -lmthread  | ||||
| test60: test60.c | ||||
| t60a: t60a.c | ||||
| t60b: t60b.c | ||||
|  | ||||
							
								
								
									
										1
									
								
								test/run
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								test/run
									
									
									
									
									
								
							| @ -15,6 +15,7 @@ tests="   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 45-gcc 46 47 48 49 49-gcc 50 \ | ||||
|          51 51-gcc 52 52-gcc 53 54 55 56 57 58 59\ | ||||
|          60 \ | ||||
| 	 sh1.sh sh2.sh" | ||||
| tests_no=`expr 0` | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										18
									
								
								test/t60a.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								test/t60a.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| #include <unistd.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| int main(int argc, char *argv[]) | ||||
| { | ||||
| /* Return our tainted state to the parent */ | ||||
|   int newmode; | ||||
|   char cmd[30]; | ||||
| 
 | ||||
|   if (argc < 2) return(-2); | ||||
|   if ((newmode = atoi(argv[1])) > 0) { | ||||
| 	snprintf(cmd, sizeof(cmd), "chmod %o %s", newmode, argv[0]); | ||||
| 	system(cmd); | ||||
|   } | ||||
| 
 | ||||
|   return(issetugid()); | ||||
| } | ||||
							
								
								
									
										23
									
								
								test/t60b.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								test/t60b.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| #include <sys/types.h> | ||||
| #include <sys/wait.h> | ||||
| #include <unistd.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| /* Return the tainted state of our child to our parent */ | ||||
|   pid_t childpid; | ||||
|   int status; | ||||
| 
 | ||||
|   childpid = fork(); | ||||
|   if (childpid == (pid_t) -1) exit(-2); | ||||
|   else if (childpid == 0) { | ||||
| 	exit(issetugid()); | ||||
|   } else { | ||||
| 	wait(&status); | ||||
|   } | ||||
| 
 | ||||
|   return(WEXITSTATUS(status)); | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										265
									
								
								test/test60.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										265
									
								
								test/test60.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,265 @@ | ||||
| #include <sys/types.h> | ||||
| #include <sys/wait.h> | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| #define MAX_ERROR 5 | ||||
| #include "common.c" | ||||
| 
 | ||||
| int subtest = -1; | ||||
| 
 | ||||
| void test_self(void); | ||||
| void test_setnone(void); | ||||
| void test_setuid(void); | ||||
| void test_setgid(void); | ||||
| void test_effugid(void); | ||||
| int execute(const char *prog, const char *arg); | ||||
| 
 | ||||
| int execute(const char *prog, const char *arg) | ||||
| { | ||||
|   pid_t childpid; | ||||
|   int status; | ||||
|   char cmd[30]; | ||||
| 
 | ||||
|   snprintf(cmd, sizeof(cmd), "./%s", prog); | ||||
| 
 | ||||
|   childpid = fork(); | ||||
|   if (childpid == (pid_t) -1) { | ||||
| 	return(-2); | ||||
|   } else if (childpid == 0) { | ||||
| 	if (execl(cmd, prog, arg, NULL) == -1) { | ||||
| 		exit(-2); | ||||
| 	} | ||||
| 	return(-2);	/* Never reached */ | ||||
|   } else { | ||||
| 	wait(&status); | ||||
|   } | ||||
| 
 | ||||
|   return(WEXITSTATUS(status)); | ||||
| } | ||||
| 
 | ||||
| void test_setgid(void) | ||||
| { | ||||
| /* Execve a new process that has setgid bits set */ | ||||
|   subtest = 3; | ||||
| 
 | ||||
|   /* When we exec a new process which has setgid set, that process should
 | ||||
|    * be tainted. | ||||
|    */ | ||||
|   system("chmod 2755 setgid"); | ||||
|   if (execute("setgid", "0000") != 1) e(2); | ||||
| 
 | ||||
|   /* When we exec a new process which has setgid set, but unsets that bit
 | ||||
|    * before calling issetugid() should still be tainted | ||||
|    */ | ||||
|   system("chmod 2755 setgid"); | ||||
|   if (execute("setgid", "0755") != 1) e(3); | ||||
| 
 | ||||
|   /* When we exec a new process which has setgid set, and then also sets
 | ||||
|    * setuid before calling issetugid() should still be tainted | ||||
|    */ | ||||
|   system("chmod 2755 setgid"); | ||||
|   if (execute("setgid", "06755") != 1) e(4); | ||||
| 
 | ||||
|   /* When we exec a new process that has setgid set, and which upon
 | ||||
|    * execution forks, the forked child should also be tainted */ | ||||
|   system("chmod 2755 setgidfork"); | ||||
|   if (execute("setgidfork", "0000") != 1) e(5); | ||||
| } | ||||
| 
 | ||||
| void test_setuid(void) | ||||
| { | ||||
| /* Execve a new process that has setuid bits set */ | ||||
|   subtest = 4; | ||||
| 
 | ||||
|   /* When we exec a new process which has setuid set, that process should
 | ||||
|    * be tainted. | ||||
|    */ | ||||
|   system("chmod 4755 setuid"); | ||||
|   if (execute("setuid", "0000") != 1) e(1); | ||||
| 
 | ||||
|   /* When we exec a new process which has setuid set, but unsets that bit
 | ||||
|    * before calling issetugid() should still be tainted | ||||
|    */ | ||||
|   system("chmod 4755 setuid"); | ||||
|   if (execute("setuid", "0755") != 1) e(2); | ||||
| 
 | ||||
|   /* When we exec a new process which has setuid set, and then also sets
 | ||||
|    * setgid before calling issetugid() should still be tainted | ||||
|    */ | ||||
|   system("chmod 4755 setuid"); | ||||
|   if (execute("setuid", "06755") != 1) e(3); | ||||
| 
 | ||||
|   /* When we exec a new process that has setgid set, and which upon
 | ||||
|    * execution forks, the forked child should also be tainted */ | ||||
|   system("chmod 4755 setuidfork"); | ||||
|   if (execute("setuidfork", "0000") != 1) e(4); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void test_setugid(void) | ||||
| { | ||||
| /* Execve a new process that has setuid and setgid bits set */ | ||||
|   subtest = 5; | ||||
| 
 | ||||
|   /* When we exec a new process which has setugid set, that
 | ||||
|    * process should be tainted. | ||||
|    */ | ||||
|   system("chmod 6755 setugid"); | ||||
|   if (execute("setugid", "0000") != 1) e(1); | ||||
| 
 | ||||
|   /* When we exec a new process which has setugid set, but unsets those bits
 | ||||
|    * before calling issetugid() should still be tainted | ||||
|    */ | ||||
|   system("chmod 6755 setugid"); | ||||
|   if (execute("setugid", "0755") != 1) e(2); | ||||
| 
 | ||||
|   /* When we exec a new process that has setugid set, and which upon
 | ||||
|    * execution forks, the forked child should also be tainted */ | ||||
|   system("chmod 6755 setugidfork"); | ||||
|   if (execute("setugidfork", "0000") != 1) e(4); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void test_effugid(void) | ||||
| { | ||||
| /* Test taint status with different effective uid and gid */ | ||||
|   pid_t childpid; | ||||
|   int status; | ||||
| 
 | ||||
|   subtest = 6; | ||||
| 
 | ||||
|   /* Start with effective uid */ | ||||
|   childpid = fork(); | ||||
|   if (childpid == (pid_t) -1) e(1); | ||||
|   else if (childpid == 0) { | ||||
| 	/* We're the child */ | ||||
| 
 | ||||
| 	/* We should be tainted */ | ||||
| 	if (issetugid() != 1) e(2); | ||||
| 
 | ||||
| 	/* Now execute a program without set{u,g}id; should not be tainted */ | ||||
| 	system("chmod 755 nobits"); | ||||
| 	if (execute("nobits", "0000") != 0) e(3); | ||||
| 
 | ||||
| 	/* Change effective uid into current+42 and try nobits again. This time
 | ||||
| 	 * it should be tainted */ | ||||
| 	if (seteuid(geteuid() + 42) != 0) e(4); | ||||
| 	if (execute("nobits", "0000") != 1) e(5); | ||||
| 	exit(EXIT_SUCCESS); | ||||
|   } else { | ||||
| 	/* We're the parent, wait for the child to finish */ | ||||
| 	wait(&status); | ||||
|   } | ||||
| 
 | ||||
|   /* Now test effective gid */ | ||||
|   childpid = fork(); | ||||
|   if (childpid == (pid_t) -1) e(1); | ||||
|   else if (childpid == 0) { | ||||
| 	/* We're the child */ | ||||
| 
 | ||||
| 	/* We should be tainted */ | ||||
| 	if (issetugid() != 1) e(2); | ||||
| 
 | ||||
| 	/* Now execute a program without set{u,g}id; should not be tainted */ | ||||
| 	system("chmod 755 nobits"); | ||||
| 	if (execute("nobits", "0000") != 0) e(3); | ||||
| 
 | ||||
| 	/* Change effective gid into current+42 and try nobits again. This time
 | ||||
| 	 * it should be tainted */ | ||||
| 	if (seteuid(getegid() + 42) != 0) e(4); | ||||
| 	if (execute("nobits", "0000") != 1) e(5); | ||||
| 	exit(EXIT_SUCCESS); | ||||
|   } else { | ||||
| 	/* We're the parent, wait for the child to finish */ | ||||
| 	wait(&status); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void test_setnone(void) | ||||
| { | ||||
| /* Execve a new process that does not have setuid or setgid bits set */ | ||||
|   subtest = 2; | ||||
| 
 | ||||
|   /* When we exec a new process which doesn't have set{u,g}id set, that
 | ||||
|    * process should not be tainted */ | ||||
|   system("chmod 755 nobits"); | ||||
|   if (execute("nobits", "0000") != 0) e(2); | ||||
| 
 | ||||
|   /* When we exec a new process which doesn't have set{u,g}id set, but
 | ||||
|    * sets them after execution, the process should still not be tainted | ||||
|    */ | ||||
|   system("chmod 755 nobits"); | ||||
|   if (execute("nobits", "02755") != 0) e(4); | ||||
|   system("chmod 755 nobits"); | ||||
|   if (execute("nobits", "04755") != 0) e(3); | ||||
|   system("chmod 755 nobits"); | ||||
|   if (execute("nobits", "06755") != 0) e(5); | ||||
| 
 | ||||
|   /* When we exec a new process that doesn't have setugid set, and which upon
 | ||||
|    * execution forks, the forked child should not be tainted either */ | ||||
|   system("chmod 755 nobitsfork"); | ||||
|   if (execute("nobitsfork", "0000") != 0) e(6); | ||||
| } | ||||
| 
 | ||||
| void test_self(void) | ||||
| { | ||||
| /* We're supposed to be setuid. Verify. */ | ||||
| 
 | ||||
|   int status; | ||||
|   pid_t childpid; | ||||
| 
 | ||||
|   subtest = 1; | ||||
| 
 | ||||
|   if (issetugid() != 1) e(1); | ||||
|   childpid = fork(); | ||||
|   if (childpid == -1) e(2); | ||||
|   else if (childpid == 0) { | ||||
| 	/* We're the child and should inherit the tainted status of the parent
 | ||||
| 	 */ | ||||
| 	if (issetugid() != 1) e(3); | ||||
| 
 | ||||
| 	/* Let's change to the bin user */ | ||||
| 	if (setuid((uid_t) 2) != 0) e(4); | ||||
| 	if (getuid() != (uid_t) 2) e(5); | ||||
| 
 | ||||
| 	/* At this point, taint status should not have changed. */ | ||||
| 	if (issetugid() != 1) e(6); | ||||
| 
 | ||||
| 	exit(EXIT_SUCCESS); | ||||
|   } else { | ||||
| 	/* We're the parent. Wait for the child to finish */ | ||||
| 	wait(&status); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void switch_to_su(void) | ||||
| { | ||||
|   subtest = 0; | ||||
|   if (setuid(0) != 0) e(1); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
|   start(60); | ||||
|   system("cp ../t60a nobits"); | ||||
|   system("cp ../t60a setgid"); | ||||
|   system("cp ../t60a setuid"); | ||||
|   system("cp ../t60a setugid"); | ||||
|   system("cp ../t60b nobitsfork"); | ||||
|   system("cp ../t60b setuidfork"); | ||||
|   system("cp ../t60b setgidfork"); | ||||
|   system("cp ../t60b setugidfork"); | ||||
| 
 | ||||
|   switch_to_su();	/* We have to be root to perform this test */ | ||||
|   test_self(); | ||||
|   test_setnone(); | ||||
|   test_setuid(); | ||||
|   test_setgid(); | ||||
|   test_setugid(); | ||||
|   test_effugid(); | ||||
| 
 | ||||
|   quit(); | ||||
| 
 | ||||
|   return(-1);	/* Never reached */ | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Thomas Veerman
						Thomas Veerman