[LTP] [PATCH] syscalls/add_key05: add maxbytes/maxkeys test under unprivileged user

Yang Xu xuyang2018.jy@cn.fujitsu.com
Wed Feb 26 11:19:06 CET 2020


Hi!

> Hi!
>> diff --git a/runtest/syscalls b/runtest/syscalls
>> index 577a4a527..df7bbcbf1 100644
>> --
>> +void verify_max_btyes(void)
>> +{
>> +	char *buf, *invalid_buf;
>> +	int plen, invalid_plen;
>> +
>> +	tst_res(TINFO, "test max bytes under unprivileged user");
>> +	invalid_plen = max_bytes - used_bytes - data_len - 8;
> 
> What is the -8 for, strlen("test_inv")?
Yes.
> 
> I guess that it will be more readable if we used the strlen() here as
> well.
OK. I will use strlen.
> 
>> +	plen = invalid_plen - 1;
>> +	buf = tst_alloc(plen);
>> +	invalid_buf = tst_alloc(invalid_plen);
>> +
>> +	TEST(add_key("user", "test_inv", invalid_buf, invalid_plen, KEY_SPEC_THREAD_KEYRING));
>> +	if (TST_RET != -1)
>> +		tst_res(TFAIL, "add_key(test_inv) succeeded unexpectedltly");
>> +	else {
>> +		if (TST_ERR == EDQUOT)
>> +			tst_res(TPASS | TTERRNO, "add_key(test_inv) failed as expected");
>> +		else
>> +			tst_res(TFAIL | TTERRNO, "add_key(test_inv) failed expected EDQUOT got");
>> +	}
>> +
>> +	TEST(add_key("user", "test_max", buf, plen, KEY_SPEC_THREAD_KEYRING));
>> +	if (TST_RET != -1) {
>> +		tst_res(TPASS, "add_key(test_max) succeeded as expected");
>> +		SAFE_FILE_LINES_SCANF("/proc/key-users", fmt, &used_key, &max_key, &used_bytes, &max_bytes);
>> +		if (used_bytes == max_bytes)
>> +			tst_res(TPASS, "allow reaching the max bytes exactly");
>> +		else
>> +			tst_res(TFAIL, "max used bytes %u, key allow max bytes %u", used_bytes, max_bytes);
>> +	} else
>> +		tst_res(TFAIL | TTERRNO, "add_key(test_max) failed unexpectedly");
>> +}
>> +
>> +void verify_max_keys(void)
>> +{
>> +	unsigned int i;
>> +	char desc[10];
>> +
>> +	tst_res(TINFO, "test max keys under unprivileged user");
>> +	for (i = used_key + 1; i < max_key; i++) {
>> +		sprintf(desc, "abc%d", i);
>> +		TEST(add_key("keyring", desc, keyring_buf, 0, KEY_SPEC_THREAD_KEYRING));
>> +		if (TST_RET == -1)
>> +			tst_res(TFAIL | TTERRNO, "add keyring key(%s) failed", desc);
> 
> Why we are using the "keyring" ring here instead? I doubt that it
> matters for the quota, but it just seems strange.
It doesn't matter quota, only because "keyrings" plen is 0. I will use 
"user" type for this.
  >
> Also we should stop the loop on a first failure, I guess that goto
> count: would suffice.
I ignored this before, thanks.
> 
>> +	}
>> +
>> +	TEST(add_key("keyring", "abc200", keyring_buf, 0, KEY_SPEC_THREAD_KEYRING));
>> +
>> +	if (TST_RET == -1) {
>> +		tst_res(TFAIL | TTERRNO, "add keyring key(abc200) failed");
>> +		goto count;
>> +	} else
>> +		tst_res(TPASS, "add keyring key(abc200) succedd");
> 
> Why don't we just start the loop above at used_key? There is no point in
> adding the last key here outside of the loop.
> 
Using start + 1 more clean:
abc100 >> the 100th key,
We can change code (including last key)as below:
for (i = used_key + 1; i <= max_key; i ++)

>> +	TEST(add_key("keyring", "abc201", keyring_buf, 0, KEY_SPEC_THREAD_KEYRING));
>> +	if (TST_RET != -1) {
>> +		tst_res(TFAIL, "add keyring key(abc201) succeeded unexpectedly");
>> +		goto count;
> 
> We should add a key with a different name than the previous "abc%d"
> pattern here, if the upper limit was over 200 we would just replace a
> key here instread which will not fail at all.
Do you mean to use  "invalid_num_key" to avoid upper limit over 200?

> 
>> +	} else {
>> +		if (TST_ERR == EDQUOT)
>> +			tst_res(TPASS | TTERRNO, "add keyring key(abc201) failed as expected over max key");
>> +		else
>> +			tst_res(TFAIL | TTERRNO, "add_keyring failed expected EDQUOT got");
>> +	}
>> +count:
>> +	SAFE_FILE_LINES_SCANF("/proc/key-users", fmt, &used_key, &max_key, &used_bytes, &max_bytes);
>> +	if (used_key == max_key)
>> +		tst_res(TPASS, "allow reaching the max key exactly");
>> +	else
>> +		tst_res(TFAIL, "max used key %u, key allow max key %u", used_key, max_key);
>> +}
>> +
>> +static void do_test(unsigned int n)
>> +{
>> +	add_user();
>> +	int f_used_bytes = 0;
>> +
>> +	if (!SAFE_FORK()) {
>> +		SAFE_SETUID(ltpuser->pw_uid);
>> +
>> +		TEST(add_key("user", "test1", user_buf, 64, KEY_SPEC_THREAD_KEYRING));
>> +		if (TST_RET == -1)
>> +			tst_brk(TFAIL | TTERRNO, "add key test1 failed");
>> +		SAFE_FILE_LINES_SCANF("/proc/key-users", fmt, &used_key, &max_key, &used_bytes, &max_bytes);
>> +		f_used_bytes = used_bytes;
>> +
>> +		TEST(add_key("user", "test2", user_buf1, 64, KEY_SPEC_THREAD_KEYRING));
>> +		if (TST_RET == -1)
>> +			tst_brk(TFAIL | TTERRNO, "add key test2 failed");
> 
> Do we really need to pass a different users_buf to each call?
I have seen kernel code, payload is used to instantiate or update the 
key, I think it is no problme to use the same buf because we don't get 
it again from kernel space.
> 
>> +		SAFE_FILE_LINES_SCANF("/proc/key-users", fmt, &used_key, &max_key, &used_bytes, &max_bytes);
>> +
>> +		data_len = used_bytes - f_used_bytes - strlen("test1") - 1 - 64;
> 
> So this code here is used to determine how much data will consume the
> key structure in kernel itself? 
I debug this code after adding test1 key, show in /proc/keys
add_key05.c:154: INFO: 1535d151 I--Q---    24 perm 3f030000     0     0 
keyring   _ses: 1

add_key05.c:154: INFO: 15d7df09 I--Q---     6 perm 1f3f0000     0 65534 
keyring   _uid.0: empty

add_key05.c:154: INFO: 1a300c72 I--Q---     1 perm 3f010000  1003     0 
user      test1: 64

add_key05.c:154: INFO: 2e57738c I--Q---     1 perm 3f010000  1003     0 
keyring   _tid: 1

the key num is 2 in /proc/key-users, I use this code to figure keyring 
  _tid: 1(I don't know why has it) consumed data bytes.
I guess that this is useless to run in
> the case of testing for maximal number of keys, right? Can we put this
> code into a function something as get_kernel_key_data_size() and call it
> from the verify_max_bytes() only?
Yes, it was only used in max_bytes.
> 
> I guess that the SAFE_FILE_LINES_SCANF() intializes the max_key for the
> max_keys test. Having a global variables that are initalized in random
> places makes the code really confusing, can we avoid that if poissible
> please?
Ok. I will avoid this and make code clean.
> 
> I guess that we can at least create:
> 
> parse_proc_key_users(int *used_keys, int *max_key, int *used_bytes, *int max_bytes)
> 
> function that would read the values into a local variables and copy the
> results only if non-NULL pointers were passed.
> 
> That way the verify_max_keys() would call:
> parse_proc_key_users(NULL, &max_keys, NULL, NULL);
> and use the result for the loop that adds the keys.
Sound good, I will use it.
> 
>> +		if (flag[n])
> 
> Huh, why not just if (n)?
> 
OK.
>> +			verify_max_btyes();
>> +		else
>> +			verify_max_keys();
>> +		exit(0);
>> +	}
>> +	tst_reap_children();
>> +	clean_user();
> 
> What is the reason to add and remove a user for each iteration?
> 
> Aare you cleaning the keys that way?
Yes, I planed to look for a wise (try KEYCTL_CLEAR
  or KEYCTL_INVALIDATE)way but failed. Can you give me some
suggestion?
> 
>> +}
>> +
>> +static struct tst_test test = {
>> +	.test = do_test,
>> +	.tcnt = 2,
>> +	.needs_root = 1,
>> +	.forks_child = 1,
>> +	.cleanup = clean_user,
>> +	.bufs = (struct tst_buffers []) {
>> +		{&keyring_buf, .size = 1},
>> +		{&user_buf, .size = 64},
>> +		{&user_buf1, .size = 64},
>> +		{}
>> +	},
>> +	.tags = (const struct tst_tag[]) {
>> +		{"linux-git", "a08bf91ce28"},
>> +		{}
>> +	}
>> +};
>> -- 
>> 2.18.0
>>
>>
>>
>>
>> -- 
>> Mailing list info: https://lists.linux.it/listinfo/ltp
> 




More information about the ltp mailing list