From patchwork Mon May 27 10:18:43 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefano Babic X-Patchwork-Id: 1939833 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=Zg6YLOny; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::537; helo=mail-ed1-x537.google.com; envelope-from=swupdate+bncbd2zdgn6sekrbcf42gzamgqe3gwktaq@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-ed1-x537.google.com (mail-ed1-x537.google.com [IPv6:2a00:1450:4864:20::537]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Vns7R1krZz20KL for ; Mon, 27 May 2024 20:18:58 +1000 (AEST) Received: by mail-ed1-x537.google.com with SMTP id 4fb4d7f45d1cf-5785fc97facsf1568468a12.0 for ; Mon, 27 May 2024 03:18:58 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1716805130; cv=pass; d=google.com; s=arc-20160816; b=OT9I7TIToqIICa+ZgzIYMinRcPQh6F6fITVbjqRNlSsanNgQQmfImkOCLEVJ0P71EH KVYgL4Uda6jVLS5RXBPSpfpYzCAkG8Kpi21NHJRzbqUfnJf8fW3srnQYzFW0svaMmnKe oZm3Ft1lbjpyfcWpubc98ZFSWFKLV/Au4lb+g28sOxea37uJGDMi2PamwQRNOVGyixgP AyFG+lTC5HIFsH+mahVoT0iU4kA7L7ea/jCSj4XRtcGB9Z5qtIChiPSi3bpAac/eDSvw LnBwl0EHN+6ZlnbGGX0qtgdYzpx+k75FIrSOVHpBLzRuprYmjaLlrzgI8smk+BubiHNb dXrA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:ui-outboundreport:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from:sender :dkim-signature; bh=d187rdidDmulmKsPbzZpZW8nLtdVpJeuR6u9ZbjrTFI=; fh=OhaMbYvJ/lbHz6sx4gQB+qDIB9//ZVdOIHOLTMtq4ic=; b=ujV1UnV9liKZCSRpclYmoDfU4UPBbSzJGw+uadlcJq5uVj2ULJlOdq14TlMMs6WZvG Na7yDSGQH780BKljgRqL95BXj3qR8jY2oWSm5mxeBCDPKiPLBzeNfWqxjO7YnwV4unTd xECS1Uu3y935edDWrCkJffZY4LXO3NtZWymMdDWq4AYFqHcJqOEYQGAHY7fm0SJQPjVT kmfZ1KAVF+TWRTUFh9eZrZWZ6iYPP4eK9ejmg4chMpL+OdvZYh4aU4DsJ1ahJUNJRBEW Qv78rR8rXSt2mIKUndFplr9Lkw/8Eh4ULlUNydJcGotVsD6jnhxRzYhirbQWhGgsdUIt g85Q==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@swupdate.org header.s=s1-ionos header.b=VqwkfheC; spf=pass (google.com: domain of stefano.babic@swupdate.org designates 212.227.126.133 as permitted sender) smtp.mailfrom=stefano.babic@swupdate.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1716805130; x=1717409930; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:ui-outboundreport:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:sender:from:to:cc :subject:date:message-id:reply-to; bh=d187rdidDmulmKsPbzZpZW8nLtdVpJeuR6u9ZbjrTFI=; b=Zg6YLOny8VBdq3VdQkJNn5H36xjMn9oLPHwkpTHdBzy7HOk/noUxQj3/DI9ni93XyW sHbAnQV/PFwX2/PDyQ0tLwleI2BGbadELiHW19jRw/xXT6lLjaPqkaGu/4lmVWDWKCKv KdHOvlS6CQN5wZ44d/WpqIW/5utvmrBM+Zm1OnVmLf5HBlBwdFOJQkgnt5ZwvXSzZIca N2NeML56tYF15V7bG/hWKc+3Udc+klih0lQckz/egJNLPXFEx/Qw3SLk+7u8cWCA9vGA FnSZMcSCdx52qYpjXMPew2oZkXZg1QrkxqoYSpcbYutpX6YBK3tUqWMRDwORu4x98V7B BIdw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1716805130; x=1717409930; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender :ui-outboundreport:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:x-beenthere:x-gm-message-state:sender:from :to:cc:subject:date:message-id:reply-to; bh=d187rdidDmulmKsPbzZpZW8nLtdVpJeuR6u9ZbjrTFI=; b=gBEU6J+X1hF+EPU3Qwhpw7Z+LNmMHD4DMN+AVP6yBjNmjQSAc1qUwgzkTVojyoodbU jdvgsg5XOSi3olWcwLkv+qn+7Yf9wMrJqsmMoSaIlb8fxUFJq/66E2zsjdD2yR/3NZN9 I1ccot+5N3QKesT6Mdy/eRCZ0r1ydfKcc78Iz9z6IL3Cp1T3NrNb+3KfqZxs+/loLYjB Urwjvkx5sGPW4SgNqUjOS08ZsvumwCx1fk/eImmkYhu6KGZdPUD+aRf3TY6ZTF6LRbdr 2CmzbIN6C0dN8SIPz+fLX88u03kam7NvMQZP18su467dZhUIpQ2qP093XQuFvBPpWm0F dvhQ== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCUGfLcLQ3LtH+TkcYyNpMNOW5YZhdNiS1gwYmhUvPzisx2iIQOktNXHDFBKwDocemDpTKhtK6sLBfqxRUjPqCjg0+e0g3hSWddkU2Zsqg== X-Gm-Message-State: AOJu0Yyf/mI3HMuYQOxpUxSGF39Fprkr09thW8/pDTo1bp3rZSVvew8i HMnVatO32c3CoTKEmIv8rrPkFEZWYbFPg4bejhBjXEz9NqLXu2MH X-Google-Smtp-Source: AGHT+IHYtgMh8wWQgmzwIZajEACd2/PyCPVfjYCc8aHt1i4jIAI64OcbKRx/0rv0C/jz7ywRK2AViQ== X-Received: by 2002:a50:d693:0:b0:578:695d:d78f with SMTP id 4fb4d7f45d1cf-578695dd81cmr3868813a12.15.1716805128961; Mon, 27 May 2024 03:18:48 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a05:6402:1f8a:b0:572:3b0d:1694 with SMTP id 4fb4d7f45d1cf-5784f9c93ffls385398a12.2.-pod-prod-01-eu; Mon, 27 May 2024 03:18:46 -0700 (PDT) X-Received: by 2002:a05:6402:2152:b0:56e:743:d4d9 with SMTP id 4fb4d7f45d1cf-57851ab5490mr4477695a12.42.1716805126054; Mon, 27 May 2024 03:18:46 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1716805126; cv=none; d=google.com; s=arc-20160816; b=gD951MwMlpLprEdaM4s6OrRxKdElCs3NWdMNKs1b+ank7uAAQXAcUvwXTtWBaTf7IK J5iJ6W8JF2V6ktB7JBrrTE6tFZAM0cmWoUeYtDJSihnDZ+GVrrJNlUAuXetA6kAU+cew FC3Vss/+dv6/Qw8FYIVneWE5OomMuleolB0MeLrT/cVBZyeXZU5ulizMsvAUXfrtVHTE 3T5jpc0vxdmeO3MhuWHvNB1HDfY7CYafPL9tnyRJwJgDpP9iv+al+iT3b1IFBo2NoePX gIY3quW60khfRd4LyTs0z05r7Vf8c5IRMaZa5HD0TBBKrHpndvkYOOASSI0eZr7x1+Nn 701g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=ui-outboundreport:content-transfer-encoding:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:dkim-signature; bh=9fezonQf0k2dylkBpK6qj28RKfWNdu7rTOYQzLO9ZCM=; fh=TiEWcqMcKpHk5s7uErzpntoONrNfOXwKpI5P8bIlggk=; b=0GpWNGLRT4d/5DOc6csX/vJOVbWwsJODggyCLCzUwFNAk57vn+Zj5B5oJEIBZ+LKNp gz+Mkbj25SgzTMrY+JaZ7mdFyfSvlT7sRgTK9B/LBwadZP3wEkVQa6THNX+Kj3dK4Ehi pllu7IJQHF/wTsthi892THqNycEJIZUwKD9kxmZ2pp3kPiMDZKkOy+ggzRBf71OAXhvV A0yTnhlJWZRsMuZrBr7bQtaPs4Ifp6RxVOIPEe1mJjAOUSKbo5Lw/FH2Ju4cpk5dUXlr N/PQhuNiTBdFpfZ8A3zmoD4ZLrs+c7J7vlX8mfmU7IihXcFhs2qzEyxzXs34yTTYLij9 niGw==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@swupdate.org header.s=s1-ionos header.b=VqwkfheC; spf=pass (google.com: domain of stefano.babic@swupdate.org designates 212.227.126.133 as permitted sender) smtp.mailfrom=stefano.babic@swupdate.org Received: from mout.kundenserver.de (mout.kundenserver.de. [212.227.126.133]) by gmr-mx.google.com with ESMTPS id 4fb4d7f45d1cf-579ca0421desi49457a12.0.2024.05.27.03.18.45 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 27 May 2024 03:18:45 -0700 (PDT) Received-SPF: pass (google.com: domain of stefano.babic@swupdate.org designates 212.227.126.133 as permitted sender) client-ip=212.227.126.133; X-UI-Sender-Class: 55c96926-9e95-11ee-ae09-1f7a4046a0f6 Received: from paperino.fritz.box ([88.217.136.221]) by mrelayeu.kundenserver.de (mreue009 [213.165.67.97]) with ESMTPSA (Nemesis) id 1M1HmE-1sEHGR2QmI-0066Io; Mon, 27 May 2024 12:18:45 +0200 From: Stefano Babic To: swupdate@googlegroups.com Cc: Stefano Babic Subject: [swupdate] [libubootenv][ 3/3] Let set a list of writable variables Date: Mon, 27 May 2024 12:18:43 +0200 Message-Id: <20240527101843.380555-3-stefano.babic@swupdate.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240527101843.380555-1-stefano.babic@swupdate.org> References: <20240527101843.380555-1-stefano.babic@swupdate.org> MIME-Version: 1.0 X-Provags-ID: V03:K1:Fm1HEr/Mt1O8ZhvsxfvkH7PLE35TtBwcokSu6Lfndvn4GQTgmip kpcotnBWP8vy657a31aLd+G/PSsz3aWSDVeq46gmZ0ipXBkJAiLvRITsunKbIkv2HRxqVxG 25Uo7Xq7zj9SiS2Wv3kdXPvogoeWiRnF2hbVMy+2E7aQlsC5etyQ3YorU0dylNwJP8Pv7IM MzwT7Phgp3zSUYt2mL+VA== X-Spam-Flag: NO UI-OutboundReport: notjunk:1;M01:P0:3HEgiEcxqS0=;BoZ8Lp/z8alCDp/j1dPwNWv5avt tcRlrvYd5iI8pQp7O3CLLL4UTqExVbXbM/yGFt5lElvqBGHgWsPbfXmkYaPhU2pkNqfu1Xzg/ agXl/Oye4mTHr2jR0kPGH7N+mS8LHHTdCxyIrh9Ux0mWG/sXEgqBC9jrp5g60TLmLQ5O0cf50 rwbJcscTylWPKClkh3dcpK0+t9SP0NAyTgBWNJLwe00iOKxPkpLx3zpjk3qUcekSrczZ4qiz1 aI1V/6lyyZgiUcN+XYvjVSjC3fAgaKIScr0vxhf0S6sRIr3xw/7lWMBYm3XtlYQCADOfK+jEi bTx3etx0UQ6aSbDB3GlDUuNn/wYsKl+85+0vhMgag5tVHA+NhN+lsMW62M7LTgwznA8IyDfjK 6pSpZ9C7onSJfPY/zl8wFry0GxmqEdd5B8bSvnOH5iNui+uVf/G/NH/6HM04cHV7fgKz3K5H8 egaslwzPxIB9ibimlYFGQ4TSfWbLo4O4oPMOf92yRgmwlMn+sI+j3jAZZ9Cy+TBCVdOIgtIxZ j/o41hqtPhBxoY2bg+s1H/Kcin8IbM9/vnCOMG+HNHrtRS15aKGDBk6WDibt1TvQOBhIKGUlW BPCGaIDFtAXQPjnj1beE5IfZrsLPUZRn8UKfJ82ilZacNofBWD5u2lJn5FhODSoD1lB3QSmXw qlaiF9m2RH67lsBVdarOdNYQk9H43XHzxxQZUW5nY4a+hP9CMSjOr95ICIFvR7kyhTD+JxvDY g7xV4RqAByXsjSIu4iaLSK3Ms5GuS1QhnPSZ+4ACWIosHzOzzGQjGw= X-Original-Sender: stefano.babic@swupdate.org X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@swupdate.org header.s=s1-ionos header.b=VqwkfheC; spf=pass (google.com: domain of stefano.babic@swupdate.org designates 212.227.126.133 as permitted sender) smtp.mailfrom=stefano.babic@swupdate.org Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , In U-Boot, it is possible to list which variables could be changed via CONFIG_ENV_WRITEABLE_LIST. This was not supported by this library, but it does not raise a security leak. In fact, U-Boot will simply discard if a variable is not in the list. However, in user space any variable can be set, and the output of fw_printenv is not what the bootloader really accepts. This patch fills the gap and let add (just for YML configuration) a list of variables that can be set and their flags. The default policy is that all variables are accepted, exactly as it is done in U-Boot, and check is done only if the list is found in the configuration file. Signed-off-by: Stefano Babic --- docs/fw_env_config.md | 9 ++ src/uboot_env.c | 362 ++++++++++++++++++++++++++++-------------- src/uboot_private.h | 2 + 3 files changed, 255 insertions(+), 118 deletions(-) -- 2.34.1 diff --git a/docs/fw_env_config.md b/docs/fw_env_config.md index 1cdc196..29c28af 100644 --- a/docs/fw_env_config.md +++ b/docs/fw_env_config.md @@ -119,10 +119,18 @@ tells us where the environment is located by setting the automatically uses the string from this property as a selector for the namespace in the YAML config file. +The sequence `writelist` implements the CONFIG_ENV_WRITEABLE_LIST in U-Boot. The list +is in the same format used in the bootloader: :. See in bootloader documentation +for the list of supported flags. + ```yaml uboot: size : 0x4000 lockfile : /var/lock/fw_printenv.lock + writelist: + - var1:sw + - var2:sw + - var3:dw devices: - path : /dev/mtd0 offset : 0xA0000 @@ -136,6 +144,7 @@ uboot: appvar: size : 0x4000 lockfile : /var/lock/appvar.lock + devices: - path : /dev/mtd1 offset : 0 diff --git a/src/uboot_env.c b/src/uboot_env.c index f40511c..5c0865c 100644 --- a/src/uboot_env.c +++ b/src/uboot_env.c @@ -60,6 +60,11 @@ enum yaml_state { STATE_NSIZE, /* Size key-value pair */ STATE_NLOCKFILE, /* Lockfile key-value pair */ STATE_DEVVALUES, /* Devices key names */ + STATE_WRITELIST, /* List with vars that are accepted by write + * if list is missing, all vars are accepted + * var is in the format name:flags, see U-Boot + * documentation + */ STATE_NPATH, STATE_NOFFSET, @@ -73,6 +78,9 @@ typedef enum yaml_parse_error_e { YAML_UNEXPECTED_KEY, YAML_BAD_DEVICE, YAML_BAD_DEVNAME, + YAML_BAD_VARLIST, + YAML_DUPLICATE_VARLIST, + YAML_OOM, } yaml_parse_error_type_t; struct parser_state { @@ -85,6 +93,12 @@ struct parser_state { yaml_event_type_t event_type; /* event type causing error */ }; +#define FREE_ENTRY do { \ + free(entry->name); \ + free(entry->value); \ + free(entry); \ + } while(0) + /* * The default lockfile is the same as defined in U-Boot for * the fw_printenv utilities. Custom lockfile can be set via @@ -180,6 +194,22 @@ static void set_var_access_type(struct var_entry *entry, const char *pvarflags) } } +static struct var_entry *create_var_entry(const char *name) +{ + struct var_entry *entry; + + entry = (struct var_entry *)calloc(1, sizeof(*entry)); + if (!entry) + return NULL; + entry->name = strdup(name); + if (!entry->name) { + free(entry); + return NULL; + } + + return entry; +} + static char access_tostring(access_attribute a) { switch(a) { @@ -218,6 +248,147 @@ static void free_var_entry(struct var_entry *entry) } } +static bool validate_int(bool hex, const char *value) +{ + const char *c; + + for (c = value; c != value + strlen(value); ++c) { + if (hex && !isxdigit(*c)) + return false; + + if (!hex && !isdigit(*c)) + return false; + } + + return true; +} + +static bool libuboot_validate_flags(struct var_entry *entry, const char *value) +{ + bool ok_type = true, ok_access = true; + + switch (entry->access) { + case ACCESS_ATTR_ANY: + ok_access = true; + break; + case ACCESS_ATTR_READ_ONLY: + case ACCESS_ATTR_WRITE_ONCE: + ok_access = false; + break; + case ACCESS_ATTR_CHANGE_DEFAULT: + break; + } + + if (!ok_access) + return false; + + if (!value) + return true; + + switch (entry->type) { + case TYPE_ATTR_STRING: + ok_type = true; + break; + case TYPE_ATTR_DECIMAL: + ok_type = validate_int(false, value); + break; + case TYPE_ATTR_HEX: + ok_type = strlen(value) > 2 && (value[0] == '0') && + (value[1] == 'x' || value [1] == 'X'); + if (ok_type) + ok_type = validate_int(true, value + 2); + break; + case TYPE_ATTR_BOOL: + ok_access = (value[0] == '1' || value[0] == 'y' || value[0] == 't' || + value[0] == 'Y' || value[0] == 'T' || + value[0] == '0' || value[0] == 'n' || value[0] == 'f' || + value[0] == 'N' || value[0] == 'F') && (strlen(value) != 1); + break; + case TYPE_ATTR_IP: + case TYPE_ATTR_MAC: + break; + } + return ok_type; +} + + +/* + * This is used internally with additional parms + */ +static int __libuboot_set_env(struct uboot_ctx *ctx, const char *varname, const char *value, struct var_entry *validate) +{ + struct var_entry *entry, *elm, *lastentry; + struct vars *envs = &ctx->varlist; + + /* U-Boot setenv treats '=' as an illegal character for variable names */ + if (strchr(varname, '=')) + return -EINVAL; + + /* + * Giving empty variable name will lead to having "=value" in U-Boot + * environment which will lead to problem during load of it and U-Boot + * will then load default environment. + */ + if (*varname == '\0') + return -EINVAL; + + entry = __libuboot_get_env(envs, varname); + if (entry) { + bool valid = libuboot_validate_flags(entry, value); + if (validate) { + entry->access = validate->access; + entry->type = validate->type; + valid &= libuboot_validate_flags(entry, value); + } + if (!valid) + return -EPERM; + if (!value) { + free_var_entry(entry); + } else { + free(entry->value); + entry->value = strdup(value); + } + return 0; + } + + if (!value) + return 0; + + entry = create_var_entry(varname); + if (!entry) + return -ENOMEM; + + entry->value = strdup(value); + if (!entry->value) { + FREE_ENTRY; + return -ENOMEM; + } + + if (validate) { + entry->access = validate->access; + entry->type = validate->type; + if (!libuboot_validate_flags(entry, value)) { + FREE_ENTRY; + return -EPERM; + } + } + + lastentry = NULL; + LIST_FOREACH(elm, envs, next) { + if (strcmp(elm->name, varname) > 0) { + LIST_INSERT_BEFORE(elm, entry, next); + return 0; + } + lastentry = elm; + } + if (lastentry) + LIST_INSERT_AFTER(lastentry, entry, next); + else + LIST_INSERT_HEAD(envs, entry, next); + + return 0; +} + static enum device_type get_device_type(char *device) { enum device_type type = DEVICE_NONE; @@ -823,7 +994,7 @@ static int libuboot_load(struct uboot_ctx *ctx) if (!strcmp(line, ".flags")) flagsvar = strdup(value); else - libuboot_set_env(ctx, line, value); + __libuboot_set_env(ctx, line, value, NULL); } } @@ -965,6 +1136,8 @@ static int consume_event(struct parser_state *s, yaml_event_t *event) } else if (!strcmp(value, "devices")) { s->state = STATE_DEVVALUES; s->cdev = 0; + } else if (!strcmp(value, "writelist")) { + s->state = STATE_WRITELIST; } else { s->error = YAML_UNEXPECTED_KEY; s->event_type = event->type; @@ -1052,6 +1225,69 @@ static int consume_event(struct parser_state *s, yaml_event_t *event) } break; + case STATE_WRITELIST: + switch (event->type) { + + char *varflag, *name; + struct var_entry *entry; + + case YAML_MAPPING_START_EVENT: + case YAML_SEQUENCE_START_EVENT: + break; + case YAML_MAPPING_END_EVENT: + break; + case YAML_SEQUENCE_END_EVENT: + s->state = STATE_NAMESPACE_FIELDS; + break; + case YAML_SCALAR_EVENT: + value = (char *)event->data.scalar.value; + + /* + * Format is name:flags, split it into two values + */ + varflag = strchr(value, ':'); + if (!varflag || varflag > value + (strlen(value) - 1)) { + s->error = YAML_BAD_VARLIST; + s->event_type = event->type; + return FAILURE; + } + *varflag++ = '\0'; + + /* + * Check there is not yet an entry for this variable + */ + LIST_FOREACH(entry, &s->ctx->writevarlist, next) { + if (strcmp(entry->name, value) == 0) { + s->error = YAML_DUPLICATE_VARLIST; + s->event_type = event->type; + return FAILURE; + } + } + + /* + * Insert variable with its configuration into the list + * of modifiable vars + */ + entry = create_var_entry(value); + if (!entry) { + s->error = YAML_OOM; + s->event_type = event->type; + return FAILURE; + } + set_var_access_type(entry, varflag); + LIST_INSERT_HEAD(&s->ctx->writevarlist, entry, next); + +#if !defined(NDEBUG) + fprintf(stdout, "Writelist: %s flags %s\n", value, varflag); +#endif + break; + default: + s->error = YAML_UNEXPECTED_STATE; + s->event_type = event->type; + return FAILURE; + } + break; + case STATE_NPATH: switch (event->type) { case YAML_SCALAR_EVENT: @@ -1345,132 +1581,22 @@ int libuboot_read_config(struct uboot_ctx *ctx, const char *config) return libuboot_read_config_ext(&ctx, config); } -static bool validate_int(bool hex, const char *value) -{ - const char *c; - - for (c = value; c != value + strlen(value); ++c) { - if (hex && !isxdigit(*c)) - return false; - - if (!hex && !isdigit(*c)) - return false; - } - - return true; -} - -static bool libuboot_validate_flags(struct var_entry *entry, const char *value) -{ - bool ok_type = true, ok_access = true; - - switch (entry->access) { - case ACCESS_ATTR_ANY: - ok_access = true; - break; - case ACCESS_ATTR_READ_ONLY: - case ACCESS_ATTR_WRITE_ONCE: - ok_access = false; - break; - case ACCESS_ATTR_CHANGE_DEFAULT: - break; - } - - if (!ok_access) - return false; - - if (!value) - return true; - - switch (entry->type) { - case TYPE_ATTR_STRING: - ok_type = true; - break; - case TYPE_ATTR_DECIMAL: - ok_type = validate_int(false, value); - break; - case TYPE_ATTR_HEX: - ok_type = strlen(value) > 2 && (value[0] == '0') && - (value[1] == 'x' || value [1] == 'X'); - if (ok_type) - ok_type = validate_int(true, value + 2); - break; - case TYPE_ATTR_BOOL: - ok_access = (value[0] == '1' || value[0] == 'y' || value[0] == 't' || - value[0] == 'Y' || value[0] == 'T' || - value[0] == '0' || value[0] == 'n' || value[0] == 'f' || - value[0] == 'N' || value[0] == 'F') && (strlen(value) != 1); - break; - case TYPE_ATTR_IP: - case TYPE_ATTR_MAC: - break; - } - return ok_type; -} - int libuboot_set_env(struct uboot_ctx *ctx, const char *varname, const char *value) { - struct var_entry *entry, *elm, *lastentry; - struct vars *envs = &ctx->varlist; - - /* U-Boot setenv treats '=' as an illegal character for variable names */ + struct var_entry *entry, *entryvarlist = NULL; if (strchr(varname, '=')) return -EINVAL; /* - * Giving empty variable name will lead to having "=value" in U-Boot - * environment which will lead to problem during load of it and U-Boot - * will then load default environment. + * If there is a list of chosen rw vars, + * first check that variable belongs to the list */ - if (*varname == '\0') - return -EINVAL; - - entry = __libuboot_get_env(envs, varname); - if (entry) { - if (libuboot_validate_flags(entry, value)) { - if (!value) { - free_var_entry(entry); - } else { - free(entry->value); - entry->value = strdup(value); - } - return 0; - } else { + if (!LIST_EMPTY(&ctx->writevarlist)) { + entryvarlist = __libuboot_get_env(&ctx->writevarlist, varname); + if (!entryvarlist) return -EPERM; - } - } - - if (!value) - return 0; - - entry = (struct var_entry *)calloc(1, sizeof(*entry)); - if (!entry) - return -ENOMEM; - entry->name = strdup(varname); - if (!entry->name) { - free(entry); - return -ENOMEM; - } - entry->value = strdup(value); - if (!entry->value) { - free(entry->name); - free(entry); - return -ENOMEM; - } - lastentry = NULL; - LIST_FOREACH(elm, envs, next) { - if (strcmp(elm->name, varname) > 0) { - LIST_INSERT_BEFORE(elm, entry, next); - return 0; - } - lastentry = elm; } - if (lastentry) - LIST_INSERT_AFTER(lastentry, entry, next); - else - LIST_INSERT_HEAD(envs, entry, next); - - return 0; + return __libuboot_set_env(ctx, varname, value, entryvarlist); } char *libuboot_get_env(struct uboot_ctx *ctx, const char *varname) diff --git a/src/uboot_private.h b/src/uboot_private.h index bd97940..b28be0d 100644 --- a/src/uboot_private.h +++ b/src/uboot_private.h @@ -173,6 +173,8 @@ struct uboot_ctx { int lock; /** pointer to the internal db */ struct vars varlist; + /** pointer to the writelist (vars that can be set as writable) */ + struct vars writevarlist; /** name of the set */ char *name; /** lockfile */