From patchwork Thu Oct 5 14:41:57 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Craig Gallek X-Patchwork-Id: 821849 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3y7Fps60yjz9sNw for ; Fri, 6 Oct 2017 01:42:13 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751366AbdJEOmH (ORCPT ); Thu, 5 Oct 2017 10:42:07 -0400 Received: from mail-qt0-f175.google.com ([209.85.216.175]:53779 "EHLO mail-qt0-f175.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750965AbdJEOmE (ORCPT ); Thu, 5 Oct 2017 10:42:04 -0400 Received: by mail-qt0-f175.google.com with SMTP id 47so25734519qts.10 for ; Thu, 05 Oct 2017 07:42:03 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=iYbsPU4OxL7TP967JsvRtO+S0/9C59r/QdZoTphQhkk=; b=YfAeHYfTshJI5yD8CDNM9TVNenCqtNzsta3CfwSxfdZcbLj5Z80fu6QTQsS96lEkXC pTfZuhJbWCevLjVwNFYql9lr9QmObkkzkEJGbwzxtxd4UW0LzkgQLhzXvbqz6hE02FHg BI5wUzeOtdTsYBmE/aV9CbehbJ84hi8XuhkqH+lGbeoWB6q7Uy+gtIKodIMFSEPgFSGm glN24uzVIa0FgBrgE4vQcOLtx8INE9Ay2PX1/zzen8TaHYeoFIsJtRhnNRY1OtvgKPVM uEjZAAA397FDfUFNSEfG5SjCW6Blv83Pl5BOA7tW3BAwrzoJ88zkpMeKyiXFLNYqVIaF e4QA== X-Gm-Message-State: AMCzsaUBxRuNcPGTHTZP8y9ZRHJwwVgK+gFur8+wTol2XddTASSL+pPk ULsvstqhkF27t/JcOiAVmHbs3w== X-Google-Smtp-Source: AOwi7QDGpJdVmh1apzQPdFYVZKhP8YYHXFGmWjzCqWjilhvnZ8kn2JlM51yuI6+32KwZFNuxz0AF2g== X-Received: by 10.200.48.70 with SMTP id g6mr24332315qte.221.1507214523208; Thu, 05 Oct 2017 07:42:03 -0700 (PDT) Received: from monkey.nyc.corp.google.com ([100.101.213.10]) by smtp.gmail.com with ESMTPSA id u40sm3527086qtu.9.2017.10.05.07.42.00 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 05 Oct 2017 07:42:00 -0700 (PDT) From: Craig Gallek To: Alexei Starovoitov , Daniel Borkmann , Jesper Dangaard Brouer , "David S . Miller" Cc: Chonggang Li , netdev@vger.kernel.org Subject: [PATCH net-next v3 1/2] libbpf: parse maps sections of varying size Date: Thu, 5 Oct 2017 10:41:57 -0400 Message-Id: <20171005144158.14860-2-kraigatgoog@gmail.com> X-Mailer: git-send-email 2.14.2.920.gcf0c67979c-goog In-Reply-To: <20171005144158.14860-1-kraigatgoog@gmail.com> References: <20171005144158.14860-1-kraigatgoog@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Craig Gallek This library previously assumed a fixed-size map options structure. Any new options were ignored. In order to allow the options structure to grow and to support parsing older programs, this patch updates the maps section parsing to handle varying sizes. Object files with maps sections smaller than expected will have the new fields initialized to zero. Object files which have larger than expected maps sections will be rejected unless all of the unrecognized data is zero. This change still assumes that each map definition in the maps section is the same size. Signed-off-by: Craig Gallek Acked-by: Jesper Dangaard Brouer Acked-by: Daniel Borkmann --- tools/lib/bpf/libbpf.c | 70 +++++++++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 29 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 4f402dcdf372..23152890ec60 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -579,31 +579,6 @@ bpf_object__init_kversion(struct bpf_object *obj, return 0; } -static int -bpf_object__validate_maps(struct bpf_object *obj) -{ - int i; - - /* - * If there's only 1 map, the only error case should have been - * catched in bpf_object__init_maps(). - */ - if (!obj->maps || !obj->nr_maps || (obj->nr_maps == 1)) - return 0; - - for (i = 1; i < obj->nr_maps; i++) { - const struct bpf_map *a = &obj->maps[i - 1]; - const struct bpf_map *b = &obj->maps[i]; - - if (b->offset - a->offset < sizeof(struct bpf_map_def)) { - pr_warning("corrupted map section in %s: map \"%s\" too small\n", - obj->path, a->name); - return -EINVAL; - } - } - return 0; -} - static int compare_bpf_map(const void *_a, const void *_b) { const struct bpf_map *a = _a; @@ -615,7 +590,7 @@ static int compare_bpf_map(const void *_a, const void *_b) static int bpf_object__init_maps(struct bpf_object *obj) { - int i, map_idx, nr_maps = 0; + int i, map_idx, map_def_sz, nr_maps = 0; Elf_Scn *scn; Elf_Data *data; Elf_Data *symbols = obj->efile.symbols; @@ -658,6 +633,15 @@ bpf_object__init_maps(struct bpf_object *obj) if (!nr_maps) return 0; + /* Assume equally sized map definitions */ + map_def_sz = data->d_size / nr_maps; + if (!data->d_size || (data->d_size % nr_maps) != 0) { + pr_warning("unable to determine map definition size " + "section %s, %d maps in %zd bytes\n", + obj->path, nr_maps, data->d_size); + return -EINVAL; + } + obj->maps = calloc(nr_maps, sizeof(obj->maps[0])); if (!obj->maps) { pr_warning("alloc maps for object failed\n"); @@ -690,7 +674,7 @@ bpf_object__init_maps(struct bpf_object *obj) obj->efile.strtabidx, sym.st_name); obj->maps[map_idx].offset = sym.st_value; - if (sym.st_value + sizeof(struct bpf_map_def) > data->d_size) { + if (sym.st_value + map_def_sz > data->d_size) { pr_warning("corrupted maps section in %s: last map \"%s\" too small\n", obj->path, map_name); return -EINVAL; @@ -704,12 +688,40 @@ bpf_object__init_maps(struct bpf_object *obj) pr_debug("map %d is \"%s\"\n", map_idx, obj->maps[map_idx].name); def = (struct bpf_map_def *)(data->d_buf + sym.st_value); - obj->maps[map_idx].def = *def; + /* + * If the definition of the map in the object file fits in + * bpf_map_def, copy it. Any extra fields in our version + * of bpf_map_def will default to zero as a result of the + * calloc above. + */ + if (map_def_sz <= sizeof(struct bpf_map_def)) { + memcpy(&obj->maps[map_idx].def, def, map_def_sz); + } else { + /* + * Here the map structure being read is bigger than what + * we expect, truncate if the excess bits are all zero. + * If they are not zero, reject this map as + * incompatible. + */ + char *b; + for (b = ((char *)def) + sizeof(struct bpf_map_def); + b < ((char *)def) + map_def_sz; b++) { + if (*b != 0) { + pr_warning("maps section in %s: \"%s\" " + "has unrecognized, non-zero " + "options\n", + obj->path, map_name); + return -EINVAL; + } + } + memcpy(&obj->maps[map_idx].def, def, + sizeof(struct bpf_map_def)); + } map_idx++; } qsort(obj->maps, obj->nr_maps, sizeof(obj->maps[0]), compare_bpf_map); - return bpf_object__validate_maps(obj); + return 0; } static int bpf_object__elf_collect(struct bpf_object *obj)