Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a4486c7b authored by Mikhail Kshevetskiy's avatar Mikhail Kshevetskiy
Browse files

make generic code to modify kernel command line

parent c004eb5f
Loading
Loading
Loading
Loading
+158 −21
Original line number Original line Diff line number Diff line
@@ -2,6 +2,7 @@
#include <linux/init.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/seq_file.h>
#include <linux/ctype.h>
#include <asm/setup.h>
#include <asm/setup.h>


static char new_command_line[COMMAND_LINE_SIZE];
static char new_command_line[COMMAND_LINE_SIZE];
@@ -24,38 +25,174 @@ static const struct file_operations cmdline_proc_fops = {
	.release	= single_release,
	.release	= single_release,
};
};


static void remove_flag(char *cmd, const char *flag)
static unsigned int arg_len(const char *arg)
{
{
	char *start_addr, *end_addr;
	unsigned int i, quoted = 0;


	/* Ensure all instances of a flag are removed */
	for(i = 0; arg[i] != '\0'; i++) {
	while ((start_addr = strstr(cmd, flag))) {
		if (isspace(arg[i]) && !quoted)
		end_addr = strchr(start_addr, ' ');
			break;
		if (end_addr)
		if (arg[i] == '"') quoted = !quoted;
			memmove(start_addr, end_addr + 1, strlen(end_addr));
		else
			*(start_addr - 1) = '\0';
	}
	}
	return i;
}
}


static void remove_safetynet_flags(char *cmd)
static char * unquote(char *str)
{
{
	remove_flag(cmd, "androidboot.enable_dm_verity=");
	unsigned int len;
	remove_flag(cmd, "androidboot.secboot=");

	remove_flag(cmd, "androidboot.verifiedbootstate=");
	if (*str == '"') str++;
	remove_flag(cmd, "androidboot.veritymode=");
	len = strlen(str);
	if ((len > 0) && (str[len - 1] == '"')) str[len - 1] = '\0';
	return str;
}
}


static int __init proc_cmdline_init(void)
static int append(const char *str, unsigned int len)
{
{
	strcpy(new_command_line, saved_command_line);
	unsigned int cmd_len;

	cmd_len = strlen(new_command_line);
	if (cmd_len == 0) {
		if (len >= sizeof(new_command_line))
			return -1;
	} else {
		if (cmd_len + len + 1 >= sizeof(new_command_line))
			return -1;
		new_command_line[cmd_len++] = ' ';
	}
	strncat(new_command_line + cmd_len, str, len);
	new_command_line[cmd_len + len] = '\0';
	return 0;
}

static int modify_cmd_line(const char *cmd_line,
                           int (*callback)(const char *name, const char *val, const char ***list))
{
	static char	buf[COMMAND_LINE_SIZE];
	const char	*in, *name, *val, **list;
	char		*q;
	unsigned int	len;
	int		i, accept;

	in = cmd_line;
	*new_command_line = '\0';
	while(*in != '\0'){
		in = skip_spaces(in);
		len = arg_len(in);
		if (len >= sizeof(buf)) {
			pr_err("modify_cmd_line: parameter is too long, len=%d\n", len);
			goto error;
		}

		strncpy(buf, in, len);
		buf[len] = '\0';
		q = strchr(buf, '=');
		if (q != NULL) {
			*q = '\0';
			name = unquote(buf);
			val = unquote(q + 1);
		} else {
			name = NULL;
			val = unquote(buf);
		}

		list = NULL;
		accept = (callback == NULL) ? 1 : callback(name, val, &list);
		if (accept && (append(in, len) != 0)) {
			pr_err("modify_cmd_line: out string overflow\n");
			goto error;
		}
		for(i = 0; (list != NULL) && (list[i] != NULL); i++) {
			if (append(list[i], strlen(list[i])) != 0) {
				pr_err("modify_cmd_line: out string overflow\n");
				goto error;
			}
		}

		in += len;
	}

	if (callback != NULL) {
		list = NULL;
		callback(NULL, NULL, &list);
		for(i = 0; (list != NULL) && (list[i] != NULL); i++) {
			if (append(list[i], strlen(list[i])) != 0) {
				pr_err("modify_cmd_line: out string overflow\n");
				goto error;
			}
		}
	}
	return 0;

    error:
	strcpy(new_command_line, cmd_line);
	return -1;
}


/*
/*
	 * Remove various flags from command line seen by userspace in order to
 * This function will be called for each of command line parameters and at the
	 * pass SafetyNet CTS check.
 * end of patameter list as well.
 */
 */
	remove_safetynet_flags(new_command_line);
static int modify_cmd_line_callback(const char *name, const char *val, const char ***list)
{
	/* check for end of parameter list */
	if ((name == NULL) && (val == NULL)){
		// NULL terminated list of strings to append at the end of command line
		static const char *return_list[] = { NULL };
		*list = return_list;
		return 1;
	}


	/* check for unnamed papameters */
	if ((name == NULL) && (val != NULL)) {
		return 1; /* accept */
	}

	/* drop parameters */
	if ((strcmp(name, "androidboot.enable_dm_verity")  == 0) ||
	    (strcmp(name, "androidboot.secboot")           == 0) ||
	    (strcmp(name, "androidboot.verifiedbootstate") == 0) ||
	    (strcmp(name, "androidboot.veritymode")        == 0)) {
		return 0; /* drop */
	}

#if 0
	/* replace parameters */
	if (strcmp(name, "some_param") == 0) {
		// NULL terminated list of strings to replace "some_param"
		static const char *return_list[] = { "other_param1=some_value1", "other_param2=some_value2", NULL };
		// protection against double replacent
		static int replaced = 0;

		if (!replaced){
			replaced = 1;
			*list = return_list;
		}
		return 0; /* drop */
	}

	/* accept parameters and add some values after it */
	if ((strcmp(name, "some_param_qqq") == 0) &&
	    (strcmp(val,  "some_value_qqq") == 0)) {
		// NULL terminated list of strings to add after "some_param_qqq=some_value_qqq"
		static const char *return_list[] = {"other_param_qqq1=some_value1", "other_param_qqq2=some_value2", NULL};
		// protection against double addition
		static int added = 0;

		if (!added){
			added = 1;
			*list = return_list;
		}
		return 1; /* accept */
	}
#endif

	return 1; /* accept by default */
}

static int __init proc_cmdline_init(void)
{
	modify_cmd_line(saved_command_line, modify_cmd_line_callback);
	proc_create("cmdline", 0, NULL, &cmdline_proc_fops);
	proc_create("cmdline", 0, NULL, &cmdline_proc_fops);
	return 0;
	return 0;
}
}