예제 #1
0
/* checkTag() also tries to lookup the socket address in the kernel and
 * return it when *addr  == NULL.
 * This allows for better look ups when another process is also setting the same
 * tag + uid. But it is not fool proof.
 * Without the kernel reporting more info on who setup the socket tag, it is
 * not easily verifiable from user-space.
 * Returns: true if tag found.
 */
bool SockInfo::checkTag(uint64_t acct_tag, uid_t uid) {
    int ctrl_fd;
    ctrl_fd = openCtrl();
    char ctrl_data[1024];
    ssize_t read_size;
    char *buff;
    char *pos;
    int res;
    char *match_template;
    uint64_t k_tag;
    uint32_t k_uid;
    uint64_t full_tag;
    long dummy_count;
    pid_t dummy_pid;

    read_size = read(ctrl_fd, ctrl_data, sizeof(ctrl_data));
    if (read_size < 0) {
       testPrintE("Unable to read active tags from ctrl %d/%s",
                  errno, strerror(errno));
    }
    ctrl_data[read_size] = '\0';
    testPrintI("<ctrl_raw_data>\n%s</ctrl_raw_data>", ctrl_data);

    if (addr) {
        assert(sizeof(void*) == sizeof(long int));  // Why does %p use 0x? grrr. %lx.
        asprintf(&match_template, "sock=%" PRIxPTR " %s", (uintptr_t)addr, "tag=0x%" PRIx64" (uid=%u)");
    }
    else {
        /* Allocate for symmetry */
        asprintf(&match_template, "%s", " tag=0x%" PRIx64 " (uid=%u)");
    }

    full_tag = acct_tag | uid;

    asprintf(&buff, match_template, full_tag | uid, uid);
    testPrintI("looking for '%s'", buff);
    pos = strstr(ctrl_data, buff);

    if (pos && !addr) {
        assert(sizeof(void*) == sizeof(long int));  // Why does %p use 0x? grrr. %lx.
        res = sscanf(pos - strlen("sock=1234abcd"),
                     "sock=%" SCNxPTR " tag=0x%" SCNx64 " (uid=%" SCNu32 ") pid=%u f_count=%lu",
                     (uintptr_t *)&addr, &k_tag, &k_uid, &dummy_pid, &dummy_count );
        if (!(res == 5 && k_tag == full_tag && k_uid == uid)) {
            testPrintE("Unable to read sock addr res=%d", res);
           addr = 0;
        }
        else {
            testPrintI("Got sock_addr %lx", addr);
        }
    }
    free(buff);
    free(match_template);
    close(ctrl_fd);
    return pos != NULL;
}
예제 #2
0
int doCtrlCommand(const char *fmt, ...) {
    char *buff;
    int ctrl;
    int res;
    va_list argp;

    va_start(argp, fmt);
    ctrl = openCtrl();
    vasprintf(&buff, fmt, argp);
    errno = 0;
    res = write(ctrl, buff, strlen(buff));
    testPrintI("cmd: '%s' res=%d %d/%s", buff, res, errno, strerror(errno));
    close(ctrl);
    free(buff);
    va_end(argp);
    return res;
}
예제 #3
0
    virtual void SetUp() {
        ctrl_fd = -1;
        dev_fd = -1;
        my_uid = getuid();
        my_pid = getpid();
        srand48(my_pid * my_uid);
        // Adjust fake UIDs and tags so that multiple instances can run in parallel.
        fake_uid = testRand();
        fake_uid2 = testRand();
        valid_tag1 = ((uint64_t)my_pid << 48) | ((uint64_t)testRand() << 32);
        valid_tag2 = ((uint64_t)my_pid << 48) | ((uint64_t)testRand() << 32);
        valid_tag2 &= 0xffffff00ffffffffllu;  // Leave some room to make counts visible.
        testPrintI("* start: pid=%lu uid=%lu uid1=0x%lx/%lu uid2=0x%lx/%lu"
                   " tag1=0x%" PRIx64 "/%" PRIu64 " tag2=0x%" PRIx64 "/% " PRIu64,
                   (unsigned long)my_pid, (unsigned long)my_uid,
                   (unsigned long)fake_uid, (unsigned long)fake_uid,
                   (unsigned long)fake_uid2, (unsigned long)fake_uid2,
                   valid_tag1, valid_tag1, valid_tag2, valid_tag2);
        max_uint_tag = 0xffffffff00000000llu;
        max_uint_tag = 1llu << 63 | (((uint64_t)my_pid << 48) ^ max_uint_tag);

        testPrintI("kernel has qtaguid");
        ctrl_fd = openCtrl();
        ASSERT_GE(ctrl_fd, 0) << "qtaguid ctrl open failed";
        close(ctrl_fd);
        dev_fd = open("/dev/xt_qtaguid", O_RDONLY);
        EXPECT_GE(dev_fd, 0) << "qtaguid dev open failed";

        // We want to clean up any previous faulty test runs.
        testPrintI("delete command does not fail");
        EXPECT_GE(doCtrlCommand("d 0 %u", fake_uid), 0) << "Failed to delete fake_uid";
        EXPECT_GE(doCtrlCommand("d 0 %u", fake_uid2), 0) << "Failed to delete fake_uid2";
        EXPECT_GE(doCtrlCommand("d 0 %u", my_uid), 0) << "Failed to delete my_uid";

        testPrintI("setup sock0 and addr via tag");
        ASSERT_FALSE(sock0.setup(valid_tag1))  << "socket0 setup failed";
        testPrintI("setup sock1 and addr via tag");
        ASSERT_FALSE(sock1.setup(valid_tag1))  << "socket1 setup failed";
    }
예제 #4
0
int
main( int argc, char **argv )
{
	int oldpid, oldumask, fd, noDaemonMode;
	char *pt, *errorLogFile, **opts;

	/* make sure at least world write access is disabled */
	if (((oldumask = umask( 022 )) & 002) == 002)
		(void)umask( oldumask );

	/* give /dev/null as stdin */
	if ((fd = open( "/dev/null", O_RDONLY )) > 0) {
		dup2( fd, 0 );
		close( fd );
	}
	if (fcntl( 1, F_GETFD ) < 0)
		dup2( 0, 1 );
	if (fcntl( 2, F_GETFD ) < 0)
		dup2( 0, 2 );

	if (argv[0][0] == '/') {
		if (!StrDup( &progpath, argv[0] ))
			Panic( "Out of memory" );
	} else
#ifdef __linux__
	{
		/* note that this will resolve symlinks ... */
		int len;
		char fullpath[PATH_MAX];
		if ((len = readlink( "/proc/self/exe", fullpath, sizeof(fullpath) )) < 0)
			Panic( "Invoke with full path specification or mount /proc" );
		if (!StrNDup( &progpath, fullpath, len ))
			Panic( "Out of memory" );
	}
#else
# if 0
		Panic( "Must be invoked with full path specification" );
# else
	{
		char directory[PATH_MAX+1];
		if (!getcwd( directory, sizeof(directory) ))
			Panic( "Can't find myself (getcwd failed)" );
		if (strchr( argv[0], '/' ))
			StrApp( &progpath, directory, "/", argv[0], (char *)0 );
		else {
			int len;
			char *path, *pathe, *name, *thenam, nambuf[PATH_MAX+1];

			if (!(path = getenv( "PATH" )))
				Panic( "Can't find myself (no PATH)" );
			len = strlen( argv[0] );
			name = nambuf + PATH_MAX - len;
			memcpy( name, argv[0], len + 1 );
			*--name = '/';
			do {
				if (!(pathe = strchr( path, ':' )))
					pathe = path + strlen( path );
				len = pathe - path;
				if (!len || (len == 1 && *path == '.')) {
					len = strlen( directory );
					path = directory;
				}
				thenam = name - len;
				if (thenam >= nambuf) {
					memcpy( thenam, path, len );
					if (!access( thenam, X_OK ))
						goto found;
				}
				path = pathe;
			} while (*path++ != '\0');
			Panic( "Can't find myself (not in PATH)" );
		  found:
			if (!StrDup( &progpath, thenam ))
				Panic( "Out of memory" );
		}
	}
# endif
#endif
	prog = strrchr( progpath, '/' ) + 1;

#if !defined(HAVE_SETPROCTITLE) && !defined(NOXDMTITLE)
	Title = argv[0];
	TitleLen = (argv[argc - 1] + strlen( argv[argc - 1] )) - Title;
#endif

	/*
	 * Parse command line options
	 */
	noDaemonMode = getppid();
	errorLogFile = 0;
	if (!(opts = Malloc( 2 * sizeof(char *) )))
		return 1;
	opts[0] = (char *)"";
	opts[1] = 0;
	while (*++argv) {
		if (**argv != '-')
			break;
		pt = *argv + 1;
		if (*pt == '-')
			pt++;
		if (!strcmp( pt, "help" ) || !strcmp( pt, "h" )) {
			printf( "Usage: %s [options] [tty]\n"
"  -daemon\t  - Daemonize even when started by init\n"
"  -nodaemon\t  - Don't daemonize even when started from command line\n"
"  -config <file>  - Use alternative master configuration file\n"
"  -xrm <res>\t  - Override frontend-specific resource\n"
"  -error <file>\t  - Use alternative log file\n"
"  -debug <num>\t  - Debug option bitfield:\n"
"\t\t\t0x1 - core log\n"
"\t\t\t0x2 - config reader log\n"
"\t\t\t0x4 - greeter log\n"
"\t\t\t0x8 - IPC log\n"
"\t\t\t0x10 - session sub-daemon post-fork delay\n"
"\t\t\t0x20 - config reader post-start delay\n"
"\t\t\t0x40 - greeter post-start delay\n"
"\t\t\t0x80 - don't use syslog\n"
"\t\t\t0x100 - core Xauth log\n"
"\t\t\t0x400 - valgrind config reader and greeter\n"
"\t\t\t0x800 - strace config reader and greeter\n"
			        , prog );
			exit( 0 );
		} else if (!strcmp( pt, "daemon" ))
			noDaemonMode = 0;
		else if (!strcmp( pt, "nodaemon" ))
			noDaemonMode = 1;
		else if (argv[1] && !strcmp( pt, "config" ))
			StrDup( opts, *++argv );
		else if (argv[1] && !strcmp( pt, "xrm" ))
			opts = addStrArr( opts, *++argv, -1 );
		else if (argv[1] && !strcmp( pt, "debug" ))
			sscanf( *++argv, "%i", &debugLevel );
		else if (argv[1] && (!strcmp( pt, "error" ) || !strcmp( pt, "logfile" )))
			errorLogFile = *++argv;
		else {
			fprintf( stderr, "\"%s\" is an unknown option or is missing a parameter\n", *argv );
			exit( 1 );
		}
	}

	/*
	 * Only allow root to run in non-debug mode to avoid problems
	 */
	if (!debugLevel && getuid()) {
		fprintf( stderr, "Only root wants to run %s\n", prog );
		exit( 1 );
	}

	InitErrorLog( errorLogFile );

	if (noDaemonMode != 1)
		BecomeDaemon();

	/*
	 * Step 1 - load configuration parameters
	 */
	if (!InitResources( opts ) || ScanConfigs( FALSE ) < 0)
		LogPanic( "Config reader failed. Aborting ...\n" );

	/* SUPPRESS 560 */
	if ((oldpid = StorePid())) {
		if (oldpid == -1)
			LogError( "Can't create/lock pid file %s\n", pidFile );
		else
			LogError( "Can't lock pid file %s, another xdm is running (pid %d)\n",
			          pidFile, oldpid );
		exit( 1 );
	}

#ifdef NEED_ENTROPY
	AddOtherEntropy();
#endif

	/*
	 * We used to clean up old authorization files here. As authDir is
	 * supposed to be /var/run/xauth or /tmp, we needn't to care for it.
	 */

#ifdef XDMCP
	init_session_id();
#else
	Debug( "not compiled for XDMCP\n" );
#endif
	if (pipe( signalFds ))
		LogPanic( "Unable to create signal notification pipe.\n" );
	RegisterInput( signalFds[0] );
	RegisterCloseOnFork( signalFds[0] );
	RegisterCloseOnFork( signalFds[1] );
	(void)Signal( SIGTERM, SigHandler );
	(void)Signal( SIGINT, SigHandler );
	(void)Signal( SIGHUP, SigHandler );
	(void)Signal( SIGCHLD, SigHandler );
	(void)Signal( SIGUSR1, SigHandler );

	/*
	 * Step 2 - run a sub-daemon for each entry
	 */
#ifdef XDMCP
	UpdateListenSockets();
#endif
	openCtrl( 0 );
	MainLoop();
	closeCtrl( 0 );
	if (sdRec.how) {
		commitBootOption();
		if (Fork() <= 0) {
			char *cmd = sdRec.how == SHUT_HALT ? cmdHalt : cmdReboot;
			execute( parseArgs( (char **)0, cmd ), (char **)0 );
			LogError( "Failed to execute shutdown command %\"s\n", cmd );
			exit( 1 );
		} else {
			sigset_t mask;
			sigemptyset( &mask );
			sigaddset( &mask, SIGCHLD );
			sigaddset( &mask, SIGHUP );
			sigsuspend( &mask );
		}
	}
	Debug( "nothing left to do, exiting\n" );
	return 0;
}
예제 #5
0
int testTagData(void) {
    SockInfo sock0;
    SockInfo sock1;
    int res;
    int total_errors = 0;
    int ctrl_fd = -1;
    int dev_fd = -1;
    const uint64_t invalid_tag1 = 0x0000000100000001llu;
    uint64_t valid_tag1;
    uint64_t valid_tag2;
    uint64_t max_uint_tag = 0xffffffff00000000llu;
    uid_t fake_uid;
    uid_t fake_uid2;
    const char *test_name;
    uid_t my_uid = getuid();
    pid_t my_pid = getpid();
    const int max_tags = 5;

    srand48(my_pid * my_uid);
    /* Adjust fake UIDs and tags so that multiple instances can run in parallel. */
    fake_uid = testRand();
    fake_uid2 = testRand();
    valid_tag1 = ((uint64_t)my_pid << 48) | ((uint64_t)testRand() << 32);
    valid_tag2 = ((uint64_t)my_pid << 48) | ((uint64_t)testRand() << 32);
    valid_tag2 &= 0xffffff00ffffffffllu;  // Leave some room to make counts visible.
    testSetLogCatTag(LOG_TAG);

    testPrintI("** %s ** ============================", __FUNCTION__);
    testPrintI("* start: pid=%lu uid=%lu uid1=0x%lx/%lu uid2=0x%lx/%lu"
               " tag1=0x%llx/%llu tag2=0x%llx/%llu",
               my_pid, my_uid, fake_uid, fake_uid, fake_uid2, fake_uid2,
               valid_tag1, valid_tag1, valid_tag2, valid_tag2);

    // ---------------
    test_name = "kernel has qtaguid";
    testPrintI("* test: %s ", test_name);
    ctrl_fd = openCtrl();
    if (ctrl_fd < 0) {
        testPrintE("qtaguid ctrl open failed: %s", strerror(errno));
        return 1;
    }
    close(ctrl_fd);
    dev_fd = open("/dev/xt_qtaguid", O_RDONLY);
    if (dev_fd < 0) {
        testPrintE("! %s: qtaguid dev open failed: %s", test_name, strerror(errno));
        total_errors++;
    }
    // ---------------
    test_name = "delete command doesn't fail";
    testPrintI("* test: %s", test_name);
    res = doCtrlCommand("d 0 %u", fake_uid);
    if (res < 0) {
            testPrintE("! %s: Unexpected results", test_name);
            total_errors++;
    }

    res = doCtrlCommand("d 0 %u", fake_uid2);
    if (res < 0) {
            testPrintE("! %s: Unexpected results", test_name);
            total_errors++;
    }

    res = doCtrlCommand("d 0 %u", my_uid);
    if (res < 0) {
            testPrintE("! %s: Unexpected results", test_name);
            total_errors++;
    }

    // ---------------
    test_name = "setup sock0 and addr via tag";
    testPrintI("* test: %s", test_name);
    if (sock0.setup(valid_tag1)) {
        testPrintE("socket setup failed: %s", strerror(errno));
        return 1;
    }
    // ---------------
    test_name = "setup sock1 and addr via tag";
    testPrintI("* test: %s", test_name);
    if (sock1.setup(valid_tag1)) {
        testPrintE("socket setup failed: %s", strerror(errno));
        return 1;
    }
    // ---------------
    test_name = "setup tag limit";
    testPrintI("* test: %s ", test_name);
    char *max_tags_str;
    asprintf(&max_tags_str, "%d", max_tags);
    res = writeModuleParam("max_sock_tags", max_tags_str);
    if (res < 0) {
        testPrintE("! %s: Unexpected results", test_name);
        free(max_tags_str);
        return 1;
    }

    // ---------------
    test_name = "tag quota reach limit";
    testPrintI("* test: %s", test_name);
    for (int cnt = 0; cnt < max_tags; cnt++ ) {
        uint64_t new_tag = valid_tag2 + ((uint64_t)cnt << 32);
        res = doCtrlCommand("t %d %llu %u", sock0.fd, new_tag , fake_uid2);
        if (res < 0) {
                testPrintE("! %s: Unexpected results", test_name);
                total_errors++;
        }
        if (!sock0.checkTag(new_tag, fake_uid2)) {
                testPrintE("! %s: Unexpected results: tag not found", test_name);
                total_errors++;
        }
    }
    test_name = "tag quota go over limit";
    testPrintI("* test: %s", test_name);
    {
        uint64_t new_tag = valid_tag2 + ((uint64_t)max_tags << 32);
        res = doCtrlCommand("t %d %llu %u", sock0.fd, new_tag , fake_uid2);
        if (res > 0) {
                testPrintE("! %s: Unexpected results", test_name);
                total_errors++;
        }
        if (!sock0.checkTag(valid_tag2 + (((uint64_t)max_tags - 1) << 32), fake_uid2)) {
                testPrintE("! %s: Unexpected results: tag not found", test_name);
                total_errors++;
        }
    }

    // ---------------
    test_name = "valid untag";
    testPrintI("* test: %s", test_name);
    res = doCtrlCommand("u %d", sock0.fd);
    if (res < 0) {
        testPrintE("! %s: Unexpected results", test_name);
        total_errors++;
    }
    if (sock0.checkTag(valid_tag2 + (((uint64_t)max_tags - 1) << 32), fake_uid2)) {
        testPrintE("! %s: Unexpected results: tag should not be there", test_name);
        total_errors++;
    }

    // ---------------
    test_name = "tag after untag shouldn't free up max tags";
    testPrintI("* test: %s", test_name);
    {
        uint64_t new_tag = valid_tag2 + ((uint64_t)max_tags << 32);
        res = doCtrlCommand("t %d %llu %u", sock0.fd, new_tag , fake_uid2);
        if (res > 0) {
                testPrintE("! %s: Unexpected results", test_name);
                total_errors++;
        }
        if (sock0.checkTag(valid_tag2 + ((uint64_t)max_tags << 32), fake_uid2)) {
            testPrintE("! %s: Unexpected results: tag should not be there", test_name);
            total_errors++;
        }
    }

    // ---------------
    test_name = "delete one tag";
    testPrintI("* test: %s", test_name);
    {
            uint64_t new_tag = valid_tag2 + (((uint64_t)max_tags / 2) << 32);
            res = doCtrlCommand("d %llu %u", new_tag, fake_uid2);
            if (res < 0) {
                    testPrintE("! %s: Unexpected results", test_name);
                    total_errors++;
            }
    }

    // ---------------
    test_name = "2 tags after 1 delete pass/fail";
    testPrintI("* test: %s", test_name);
    {
        uint64_t new_tag;
        new_tag = valid_tag2 + (((uint64_t)max_tags + 1 ) << 32);
        res = doCtrlCommand("t %d %llu %u", sock0.fd, new_tag , fake_uid2);
        if (res < 0) {
                testPrintE("! %s: Unexpected results", test_name);
                total_errors++;
        }
        if (!sock0.checkTag(valid_tag2 + (((uint64_t)max_tags + 1) << 32), fake_uid2)) {
            testPrintE("! %s: Unexpected results: tag not found", test_name);
            total_errors++;
        }

        new_tag = valid_tag2 + (((uint64_t)max_tags + 2 ) << 32);
        res = doCtrlCommand("t %d %llu %u", sock0.fd, new_tag , fake_uid2);
        if (res > 0) {
                testPrintE("! %s: Unexpected results", test_name);
                total_errors++;
        }
        if (sock0.checkTag(valid_tag2 + (((uint64_t)max_tags + 2) << 32), fake_uid2)) {
            testPrintE("! %s: Unexpected results: tag should not be there", test_name);
            total_errors++;
        }
    }

    /* TODO(jpa): test tagging two different sockets with same tags and
     * check refcounts  the tag_node should be +2
     */

    // ---------------
    if (total_errors) {
        testPrintE("! Errors found");
    } else {
        testPrintI("No Errors found");
    }

done:
    if (dev_fd >= 0) {
        close(dev_fd);
    }
    if (ctrl_fd >= 0) {
        close(ctrl_fd);
    }
    return total_errors;
}
예제 #6
0
/*----------------------------------------------------------------*/
int testSocketTagging(void) {
    SockInfo sock0;
    SockInfo sock1;
    int res;
    int total_errors = 0;
    int ctrl_fd = -1;
    int dev_fd = -1;
    const uint64_t invalid_tag1 = 0x0000000100000001llu;
    uint64_t valid_tag1;
    uint64_t valid_tag2;
    uint64_t max_uint_tag = 0xffffffff00000000llu;
    uid_t fake_uid;
    uid_t fake_uid2;
    const char *test_name;
    uid_t my_uid = getuid();
    pid_t my_pid = getpid();

    srand48(my_pid * my_uid);
    /* Adjust fake UIDs and tags so that multiple instances can run in parallel. */
    fake_uid = testRand();
    fake_uid2 = testRand();
    valid_tag1 = ((uint64_t)my_pid << 48) | ((uint64_t)testRand() << 32);
    valid_tag2 = ((uint64_t)my_pid << 48) | ((uint64_t)testRand() << 32);
    max_uint_tag = 1llu << 63 | (((uint64_t)my_pid << 48) ^ max_uint_tag);
    testSetLogCatTag(LOG_TAG);

    testPrintI("** %s ** ============================", __FUNCTION__);
    testPrintI("* start: pid=%lu uid=%lu uid1=0x%lx/%lu uid2=0x%lx/%lu"
               " tag1=0x%llx/%llu tag2=0x%llx/%llu",
               my_pid, my_uid, fake_uid, fake_uid, fake_uid2, fake_uid2,
               valid_tag1, valid_tag1, valid_tag2, valid_tag2);

    // ---------------
    test_name = "kernel has qtaguid";
    testPrintI("* test: %s ", test_name);
    ctrl_fd = openCtrl();
    if (ctrl_fd < 0) {
        testPrintE("qtaguid ctrl open failed: %s", strerror(errno));
        total_errors++;
        goto done;
    }
    close(ctrl_fd);
    dev_fd = open("/dev/xt_qtaguid", O_RDONLY);
    if (dev_fd < 0) {
        testPrintE("qtaguid dev open failed: %s", strerror(errno));
        total_errors++;
    }
    // ---------------
    test_name = "delete command doesn't fail";
    testPrintI("* test: %s", test_name);
    res = doCtrlCommand("d 0 %u", fake_uid);
    if (res < 0) {
            testPrintE("! %s: Unexpected results", test_name);
            total_errors++;
    }

    res = doCtrlCommand("d 0 %u", fake_uid2);
    if (res < 0) {
            testPrintE("! %s: Unexpected results", test_name);
            total_errors++;
    }

    res = doCtrlCommand("d 0 %u", my_uid);
    if (res < 0) {
            testPrintE("! %s: Unexpected results", test_name);
            total_errors++;
    }
    // ---------------
    test_name = "setup sock0 and addr via tag";
    testPrintI("* test: %s", test_name);
    if (sock0.setup(valid_tag1) < 0) {
        testPrintE("socket setup failed: %s", strerror(errno));
        total_errors++;
        goto done;

    }
    // ---------------
    test_name = "setup sock1 and addr via tag";
    testPrintI("* test: %s", test_name);
    if (sock1.setup(valid_tag1) < 0) {
        testPrintE("socket setup failed: %s", strerror(errno));
        total_errors++;
        goto done;
    }
    // ---------------
    test_name = "insufficient args. Expected failure";
    testPrintI("* test: %s", test_name);
    res = doCtrlCommand("t");
    if (res > 0) {
        testPrintE("! %s: Unexpected results", test_name);
        total_errors++;
    }

    // ---------------
    test_name = "bad command. Expected failure";
    testPrintI("* test: %s", test_name);
    res = doCtrlCommand("?");
    if (res > 0) {
            testPrintE("! %s: Unexpected results", test_name);
        total_errors++;
    }

    // ---------------
    test_name = "no tag, no uid";
    testPrintI("* test: %s", test_name);
    res = doCtrlCommand("t %d", sock0.fd);
    if (res < 0) {
        testPrintE("! %s: Unexpected results", test_name);
        total_errors++;
    }
    if (!sock0.checkTag(0, my_uid)) {
        testPrintE("! %s: Unexpected results: tag not found", test_name);
        total_errors++;
    }

    // ---------------
    test_name = "invalid tag. Expected failure";
    testPrintI("* test: %s", test_name);
    res = doCtrlCommand("t %d %llu", sock0.fd, invalid_tag1);
    if (res > 0) {
        testPrintE("! %s: Unexpected results", test_name);
        total_errors++;
    }
    if (sock0.checkTag(invalid_tag1, my_uid)) {
        testPrintE("! %s: Unexpected results: tag should not be there", test_name);
        total_errors++;
    }

    // ---------------
    test_name = "valid tag with no uid";
    testPrintI("* test: %s", test_name);
    res = doCtrlCommand("t %d %llu", sock0.fd, valid_tag1);
    if (res < 0) {
        testPrintE("! %s: Unexpected results", test_name);
        total_errors++;
    }
    if (!sock0.checkTag(valid_tag1, my_uid)) {
        testPrintE("! %s: Unexpected results: tag not found", test_name);
        total_errors++;
    }
    // ---------------
    test_name = "valid untag";
    testPrintI("* test: %s", test_name);
    res = doCtrlCommand("u %d", sock0.fd);
    if (res < 0) {
        testPrintE("! %s: Unexpected results", test_name);
        total_errors++;
    }
    if (sock0.checkTag(valid_tag1, my_uid)) {
        testPrintE("! %s: Unexpected results: tag not removed", test_name);
        total_errors++;
    }

    // ---------------
    test_name = "valid 1st tag";
    testPrintI("* test: %s", test_name);
    res = doCtrlCommand("t %d %llu %u", sock0.fd, valid_tag2, fake_uid);
    if (res < 0) {
        testPrintE("! %s: Unexpected results", test_name);
        total_errors++;
    }
    if (!sock0.checkTag(valid_tag2, fake_uid)) {
        testPrintE("! %s: Unexpected results: tag not found", test_name);
        total_errors++;
    }

    // ---------------
    test_name = "valid re-tag";
    testPrintI("* test: %s", test_name);
    res = doCtrlCommand("t %d %llu %u", sock0.fd, valid_tag2, fake_uid);
    if (res < 0) {
        testPrintE("! %s: Unexpected results", test_name);
        total_errors++;
    }
    if (!sock0.checkTag(valid_tag2, fake_uid)) {
        testPrintE("! %s: Unexpected results: tag not found", test_name);
        total_errors++;
    }

    // ---------------
    test_name = "valid re-tag with acct_tag change";
    testPrintI("* test: %s", test_name);
    res = doCtrlCommand("t %d %llu %u", sock0.fd, valid_tag1, fake_uid);
    if (res < 0) {
        testPrintE("! %s: Unexpected results", test_name);
        total_errors++;
    }
    if (!sock0.checkTag(valid_tag1, fake_uid)) {
        testPrintE("! %s: Unexpected results: tag not found", test_name);
        total_errors++;
    }

    // ---------------
    test_name = "re-tag with uid change";
    testPrintI("* test: %s", test_name);
    res = doCtrlCommand("t %d %llu %u", sock0.fd, valid_tag2, fake_uid2);
    if (res < 0) {
        testPrintE("! %s: Unexpected results", test_name);
        total_errors++;
    }
    if (!sock0.checkTag(valid_tag2, fake_uid2)) {
        testPrintE("! %s: Unexpected results: tag not found", test_name);
        total_errors++;
    }

    // ---------------
    test_name = "valid 64bit acct tag";
    testPrintI("* test: %s", test_name);
    res = doCtrlCommand("t %d %llu", sock0.fd, max_uint_tag);
    if (res < 0) {
        testPrintE("! %s: Unexpected results", test_name);
        total_errors++;
    }
    if (!sock0.checkTag(max_uint_tag, my_uid)) {
        testPrintE("! %s: Unexpected results: tag not found", test_name);
        total_errors++;
    }

    // ---------------
    test_name = "tag another socket";
    testPrintI("* test: %s", test_name);
    res = doCtrlCommand("t %d %llu %u", sock1.fd, valid_tag1, fake_uid2);
    if (res < 0) {
        testPrintE("! %s: Unexpected results", test_name);
        total_errors++;
    }
    if (!sock1.checkTag(valid_tag1, fake_uid2)) {
        testPrintE("! %s: Unexpected results: tag not found", test_name);
        total_errors++;
    }

    // ---------------
    test_name = "valid untag";
    testPrintI("* test: %s", test_name);
    res = doCtrlCommand("u %d", sock0.fd);
    if (res < 0) {
        testPrintE("! %s: Unexpected results", test_name);
        total_errors++;
    }
    if (sock0.checkTag(max_uint_tag, fake_uid)) {
        testPrintE("! %s: Unexpected results: tag should not be there", test_name);
        total_errors++;
    }
    if (!sock1.checkTag(valid_tag1, fake_uid2)) {
        testPrintE("! %s: Unexpected results: tag not found", test_name);
        total_errors++;
    }
    res = doCtrlCommand("u %d", sock1.fd);
    if (res < 0) {
        testPrintE("! %s: Unexpected results", test_name);
        total_errors++;
    }
    if (sock1.checkTag(valid_tag1, fake_uid2)) {
        testPrintE("! %s: Unexpected results: tag should not be there", test_name);
        total_errors++;
    }

    // ---------------
    test_name = "invalid sock0.fd. Expected failure";
    testPrintI("* test: %s", test_name);
    close(sock0.fd);
    res = doCtrlCommand("t %d %llu %u", sock0.fd, valid_tag1, my_uid);
    if (res > 0) {
            testPrintE("! %s: Unexpected results", test_name);
        total_errors++;
    }
    if (sock0.checkTag(valid_tag1, my_uid)) {
        testPrintE("! %s: Unexpected results: tag should not be there", test_name);
        total_errors++;
    }

    // ---------------
    test_name = "invalid untag. Expected failure";
    testPrintI("* test: %s", test_name);
    close(sock1.fd);
    res = doCtrlCommand("u %d", sock1.fd);
    if (res > 0) {
        testPrintE("! %s: Unexpected results", test_name);
        total_errors++;
    }

    if (total_errors) {
        testPrintE("! Errors found");
    } else {
        testPrintI("No Errors found");
    }

done:
    if (dev_fd >= 0) {
        close(dev_fd);
    }
    if (ctrl_fd >= 0) {
        close(ctrl_fd);
    }
    return total_errors;
}