netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH iproute2-next] lib/bpf_legacy: Use userspace SHA-1 code instead of AF_ALG
@ 2025-09-25 22:53 Eric Biggers
  2025-09-27 18:36 ` Eric Biggers
  2025-09-28 13:51 ` Ard Biesheuvel
  0 siblings, 2 replies; 3+ messages in thread
From: Eric Biggers @ 2025-09-25 22:53 UTC (permalink / raw)
  To: netdev, Stephen Hemminger; +Cc: bpf, Ard Biesheuvel, Eric Biggers

Add a basic SHA-1 implementation to lib/, and make lib/bpf_legacy.c use
it to calculate the SHA-1 digest of BPF objects instead of the previous
AF_ALG-based code.  This eliminates the dependency on the kernel config
options CONFIG_CRYPTO_USER_API_HASH and CONFIG_CRYPTO_SHA1.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 include/bpf_util.h          |   5 --
 include/sha1.h              |  18 ++++++
 include/uapi/linux/if_alg.h |  61 --------------------
 lib/Makefile                |   2 +-
 lib/bpf_legacy.c            | 109 +++++++++---------------------------
 lib/sha1.c                  | 108 +++++++++++++++++++++++++++++++++++
 6 files changed, 154 insertions(+), 149 deletions(-)
 create mode 100644 include/sha1.h
 delete mode 100644 include/uapi/linux/if_alg.h
 create mode 100644 lib/sha1.c

diff --git a/include/bpf_util.h b/include/bpf_util.h
index 8951a5e8..e1b8d327 100644
--- a/include/bpf_util.h
+++ b/include/bpf_util.h
@@ -12,11 +12,10 @@
 #include <linux/bpf.h>
 #include <linux/btf.h>
 #include <linux/filter.h>
 #include <linux/magic.h>
 #include <linux/elf-em.h>
-#include <linux/if_alg.h>
 
 #include "utils.h"
 #include "bpf_scm.h"
 
 #define BPF_ENV_UDS	"TC_BPF_UDS"
@@ -38,14 +37,10 @@
 # define TRACEFS_MAGIC	0x74726163
 #endif
 
 #define TRACE_DIR_MNT	"/sys/kernel/tracing"
 
-#ifndef AF_ALG
-# define AF_ALG		38
-#endif
-
 #ifndef EM_BPF
 # define EM_BPF		247
 #endif
 
 struct bpf_cfg_ops {
diff --git a/include/sha1.h b/include/sha1.h
new file mode 100644
index 00000000..4a2ed513
--- /dev/null
+++ b/include/sha1.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * SHA-1 message digest algorithm
+ *
+ * Copyright 2025 Google LLC
+ */
+#ifndef __SHA1_H__
+#define __SHA1_H__
+
+#include <linux/types.h>
+#include <stddef.h>
+
+#define SHA1_DIGEST_SIZE 20
+#define SHA1_BLOCK_SIZE 64
+
+void sha1(const __u8 *data, size_t len, __u8 out[SHA1_DIGEST_SIZE]);
+
+#endif /* __SHA1_H__ */
diff --git a/include/uapi/linux/if_alg.h b/include/uapi/linux/if_alg.h
deleted file mode 100644
index 0824fbc0..00000000
--- a/include/uapi/linux/if_alg.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
-/*
- * if_alg: User-space algorithm interface
- *
- * Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- */
-
-#ifndef _LINUX_IF_ALG_H
-#define _LINUX_IF_ALG_H
-
-#include <linux/types.h>
-
-struct sockaddr_alg {
-	__u16	salg_family;
-	__u8	salg_type[14];
-	__u32	salg_feat;
-	__u32	salg_mask;
-	__u8	salg_name[64];
-};
-
-/*
- * Linux v4.12 and later removed the 64-byte limit on salg_name[]; it's now an
- * arbitrary-length field.  We had to keep the original struct above for source
- * compatibility with existing userspace programs, though.  Use the new struct
- * below if support for very long algorithm names is needed.  To do this,
- * allocate 'sizeof(struct sockaddr_alg_new) + strlen(algname) + 1' bytes, and
- * copy algname (including the null terminator) into salg_name.
- */
-struct sockaddr_alg_new {
-	__u16	salg_family;
-	__u8	salg_type[14];
-	__u32	salg_feat;
-	__u32	salg_mask;
-	__u8	salg_name[];
-};
-
-struct af_alg_iv {
-	__u32	ivlen;
-	__u8	iv[];
-};
-
-/* Socket options */
-#define ALG_SET_KEY			1
-#define ALG_SET_IV			2
-#define ALG_SET_OP			3
-#define ALG_SET_AEAD_ASSOCLEN		4
-#define ALG_SET_AEAD_AUTHSIZE		5
-#define ALG_SET_DRBG_ENTROPY		6
-#define ALG_SET_KEY_BY_KEY_SERIAL	7
-
-/* Operations */
-#define ALG_OP_DECRYPT			0
-#define ALG_OP_ENCRYPT			1
-
-#endif	/* _LINUX_IF_ALG_H */
diff --git a/lib/Makefile b/lib/Makefile
index 0ba62942..ee1e2e87 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -4,11 +4,11 @@ include ../config.mk
 CFLAGS += -fPIC
 
 UTILOBJ = utils.o utils_math.o rt_names.o ll_map.o ll_types.o ll_proto.o ll_addr.o \
 	inet_proto.o namespace.o json_writer.o json_print.o json_print_math.o \
 	names.o color.o bpf_legacy.o bpf_glue.o exec.o fs.o cg_map.o \
-	ppp_proto.o bridge.o
+	ppp_proto.o bridge.o sha1.o
 
 ifeq ($(HAVE_ELF),y)
 ifeq ($(HAVE_LIBBPF),y)
 UTILOBJ += bpf_libbpf.o
 endif
diff --git a/lib/bpf_legacy.c b/lib/bpf_legacy.c
index c8da4a3e..c4b1d5de 100644
--- a/lib/bpf_legacy.c
+++ b/lib/bpf_legacy.c
@@ -27,18 +27,19 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/un.h>
 #include <sys/vfs.h>
+#include <sys/mman.h>
 #include <sys/mount.h>
-#include <sys/sendfile.h>
 #include <sys/resource.h>
 
 #include <arpa/inet.h>
 
 #include "utils.h"
 #include "json_print.h"
+#include "sha1.h"
 
 #include "bpf_util.h"
 #include "bpf_elf.h"
 #include "bpf_scm.h"
 
@@ -1178,11 +1179,10 @@ struct bpf_elf_ctx {
 	int			sec_btf;
 	char			license[ELF_MAX_LICENSE_LEN];
 	enum bpf_prog_type	type;
 	__u32			ifindex;
 	bool			verbose;
-	bool			noafalg;
 	struct bpf_elf_st	stat;
 	struct bpf_hash_entry	*ht[256];
 	char			*log;
 	size_t			log_size;
 };
@@ -1306,76 +1306,32 @@ static int bpf_obj_pin(int fd, const char *pathname)
 	attr.bpf_fd = fd;
 
 	return bpf(BPF_OBJ_PIN, &attr, sizeof(attr));
 }
 
-static int bpf_obj_hash(const char *object, uint8_t *out, size_t len)
+static int bpf_obj_hash(int fd, const char *object, __u8 out[SHA1_DIGEST_SIZE])
 {
-	struct sockaddr_alg alg = {
-		.salg_family	= AF_ALG,
-		.salg_type	= "hash",
-		.salg_name	= "sha1",
-	};
-	int ret, cfd, ofd, ffd;
 	struct stat stbuff;
-	ssize_t size;
-
-	if (!object || len != 20)
-		return -EINVAL;
-
-	cfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
-	if (cfd < 0)
-		return cfd;
+	void *data;
 
-	ret = bind(cfd, (struct sockaddr *)&alg, sizeof(alg));
-	if (ret < 0)
-		goto out_cfd;
-
-	ofd = accept(cfd, NULL, 0);
-	if (ofd < 0) {
-		ret = ofd;
-		goto out_cfd;
+	if (fstat(fd, &stbuff) < 0) {
+		fprintf(stderr, "Error doing fstat: %s\n", strerror(errno));
+		return -1;
 	}
-
-	ffd = open(object, O_RDONLY);
-	if (ffd < 0) {
-		fprintf(stderr, "Error opening object %s: %s\n",
-			object, strerror(errno));
-		ret = ffd;
-		goto out_ofd;
+	if ((size_t)stbuff.st_size != stbuff.st_size) {
+		fprintf(stderr, "Object %s is too big\n", object);
+		return -EFBIG;
 	}
-
-	ret = fstat(ffd, &stbuff);
-	if (ret < 0) {
-		fprintf(stderr, "Error doing fstat: %s\n",
+	data = mmap(NULL, stbuff.st_size, PROT_READ, MAP_SHARED, fd, 0);
+	if (data == MAP_FAILED) {
+		fprintf(stderr, "Error mapping object %s: %s\n", object,
 			strerror(errno));
-		goto out_ffd;
-	}
-
-	size = sendfile(ofd, ffd, NULL, stbuff.st_size);
-	if (size != stbuff.st_size) {
-		fprintf(stderr, "Error from sendfile (%zd vs %zu bytes): %s\n",
-			size, stbuff.st_size, strerror(errno));
-		ret = -1;
-		goto out_ffd;
+		return -1;
 	}
-
-	size = read(ofd, out, len);
-	if (size != len) {
-		fprintf(stderr, "Error from read (%zd vs %zu bytes): %s\n",
-			size, len, strerror(errno));
-		ret = -1;
-	} else {
-		ret = 0;
-	}
-out_ffd:
-	close(ffd);
-out_ofd:
-	close(ofd);
-out_cfd:
-	close(cfd);
-	return ret;
+	sha1(data, stbuff.st_size, out);
+	munmap(data, stbuff.st_size);
+	return 0;
 }
 
 static void bpf_init_env(void)
 {
 	struct rlimit limit = {
@@ -1812,16 +1768,10 @@ static int bpf_maps_attach_all(struct bpf_elf_ctx *ctx)
 {
 	int i, j, ret, fd, inner_fd, inner_idx, have_map_in_map = 0;
 	const char *map_name;
 
 	for (i = 0; i < ctx->map_num; i++) {
-		if (ctx->maps[i].pinning == PIN_OBJECT_NS &&
-		    ctx->noafalg) {
-			fprintf(stderr, "Missing kernel AF_ALG support for PIN_OBJECT_NS!\n");
-			return -ENOTSUP;
-		}
-
 		map_name = bpf_map_fetch_name(ctx, i);
 		if (!map_name)
 			return -EIO;
 
 		fd = bpf_map_attach(map_name, ctx, &ctx->maps[i],
@@ -2867,35 +2817,36 @@ static void bpf_get_cfg(struct bpf_elf_ctx *ctx)
 
 static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname,
 			    enum bpf_prog_type type, __u32 ifindex,
 			    bool verbose)
 {
-	uint8_t tmp[20];
+	__u8 tmp[SHA1_DIGEST_SIZE];
 	int ret;
 
 	if (elf_version(EV_CURRENT) == EV_NONE)
 		return -EINVAL;
 
 	bpf_init_env();
 
 	memset(ctx, 0, sizeof(*ctx));
 	bpf_get_cfg(ctx);
 
-	ret = bpf_obj_hash(pathname, tmp, sizeof(tmp));
-	if (ret)
-		ctx->noafalg = true;
-	else
-		hexstring_n2a(tmp, sizeof(tmp), ctx->obj_uid,
-			      sizeof(ctx->obj_uid));
-
 	ctx->verbose = verbose;
 	ctx->type    = type;
 	ctx->ifindex = ifindex;
 
 	ctx->obj_fd = open(pathname, O_RDONLY);
-	if (ctx->obj_fd < 0)
+	if (ctx->obj_fd < 0) {
+		fprintf(stderr, "Error opening object %s: %s\n", pathname,
+			strerror(errno));
 		return ctx->obj_fd;
+	}
+
+	ret = bpf_obj_hash(ctx->obj_fd, pathname, tmp);
+	if (ret)
+		return ret;
+	hexstring_n2a(tmp, sizeof(tmp), ctx->obj_uid, sizeof(ctx->obj_uid));
 
 	ctx->elf_fd = elf_begin(ctx->obj_fd, ELF_C_READ, NULL);
 	if (!ctx->elf_fd) {
 		ret = -EINVAL;
 		goto out_fd;
@@ -3257,16 +3208,10 @@ bool iproute2_is_pin_map(const char *libbpf_map_name, char *pathname)
 	const char *map_name, *tmp;
 	unsigned int pinning;
 	int i, ret = 0;
 
 	for (i = 0; i < ctx->map_num; i++) {
-		if (ctx->maps[i].pinning == PIN_OBJECT_NS &&
-		    ctx->noafalg) {
-			fprintf(stderr, "Missing kernel AF_ALG support for PIN_OBJECT_NS!\n");
-			return false;
-		}
-
 		map_name = bpf_map_fetch_name(ctx, i);
 		if (!map_name) {
 			return false;
 		}
 
diff --git a/lib/sha1.c b/lib/sha1.c
new file mode 100644
index 00000000..1aa8fd83
--- /dev/null
+++ b/lib/sha1.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * SHA-1 message digest algorithm
+ *
+ * Copyright 2025 Google LLC
+ */
+
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "sha1.h"
+#include "utils.h"
+
+static const __u32 sha1_K[4] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC,
+				 0xCA62C1D6 };
+
+static inline __u32 rol32(__u32 v, int bits)
+{
+	return (v << bits) | (v >> (32 - bits));
+}
+
+#define round_up(a, b) (((a) + (b) - 1) & ~((b) - 1))
+
+#define SHA1_ROUND(i, a, b, c, d, e)                                           \
+	do {                                                                   \
+		if ((i) >= 16)                                                 \
+			w[i] = rol32(w[(i) - 16] ^ w[(i) - 14] ^ w[(i) - 8] ^  \
+					     w[(i) - 3],                       \
+				     1);                                       \
+		e += w[i] + rol32(a, 5) + sha1_K[(i) / 20];                    \
+		if ((i) < 20)                                                  \
+			e += (b & (c ^ d)) ^ d;                                \
+		else if ((i) < 40 || (i) >= 60)                                \
+			e += b ^ c ^ d;                                        \
+		else                                                           \
+			e += (c & d) ^ (b & (c ^ d));                          \
+		b = rol32(b, 30);                                              \
+		/* The new (a, b, c, d, e) is the old (e, a, b, c, d). */      \
+	} while (0)
+
+#define SHA1_5ROUNDS(i)                                                        \
+	do {                                                                   \
+		SHA1_ROUND((i) + 0, a, b, c, d, e);                            \
+		SHA1_ROUND((i) + 1, e, a, b, c, d);                            \
+		SHA1_ROUND((i) + 2, d, e, a, b, c);                            \
+		SHA1_ROUND((i) + 3, c, d, e, a, b);                            \
+		SHA1_ROUND((i) + 4, b, c, d, e, a);                            \
+	} while (0)
+
+#define SHA1_20ROUNDS(i)                                                       \
+	do {                                                                   \
+		SHA1_5ROUNDS((i) + 0);                                         \
+		SHA1_5ROUNDS((i) + 5);                                         \
+		SHA1_5ROUNDS((i) + 10);                                        \
+		SHA1_5ROUNDS((i) + 15);                                        \
+	} while (0)
+
+static void sha1_blocks(__u32 h[5], const __u8 *data, size_t nblocks)
+{
+	while (nblocks--) {
+		__u32 a = h[0];
+		__u32 b = h[1];
+		__u32 c = h[2];
+		__u32 d = h[3];
+		__u32 e = h[4];
+		__u32 w[80];
+		int i;
+
+		memcpy(w, data, SHA1_BLOCK_SIZE);
+		for (i = 0; i < 16; i++)
+			w[i] = ntohl(w[i]);
+		SHA1_20ROUNDS(0);
+		SHA1_20ROUNDS(20);
+		SHA1_20ROUNDS(40);
+		SHA1_20ROUNDS(60);
+
+		h[0] += a;
+		h[1] += b;
+		h[2] += c;
+		h[3] += d;
+		h[4] += e;
+		data += SHA1_BLOCK_SIZE;
+	}
+}
+
+/* Calculate the SHA-1 message digest of the given data. */
+void sha1(const __u8 *data, size_t len, __u8 out[SHA1_DIGEST_SIZE])
+{
+	__u32 h[5] = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476,
+		       0xC3D2E1F0 };
+	const __be64 bitcount = htonll((__u64)len * 8);
+	__u8 final_data[2 * SHA1_BLOCK_SIZE] = { 0 };
+	size_t final_len = len % SHA1_BLOCK_SIZE;
+	int i;
+
+	sha1_blocks(h, data, len / SHA1_BLOCK_SIZE);
+
+	memcpy(final_data, data + len - final_len, final_len);
+	final_data[final_len] = 0x80;
+	final_len = round_up(final_len + 9, SHA1_BLOCK_SIZE);
+	memcpy(&final_data[final_len - 8], &bitcount, 8);
+
+	sha1_blocks(h, final_data, final_len / SHA1_BLOCK_SIZE);
+
+	for (i = 0; i < ARRAY_SIZE(h); i++)
+		h[i] = htonl(h[i]);
+	memcpy(out, h, SHA1_DIGEST_SIZE);
+}

base-commit: afceddf61037440628a5612f15a6eaefd28d9fd3
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH iproute2-next] lib/bpf_legacy: Use userspace SHA-1 code instead of AF_ALG
  2025-09-25 22:53 [PATCH iproute2-next] lib/bpf_legacy: Use userspace SHA-1 code instead of AF_ALG Eric Biggers
@ 2025-09-27 18:36 ` Eric Biggers
  2025-09-28 13:51 ` Ard Biesheuvel
  1 sibling, 0 replies; 3+ messages in thread
From: Eric Biggers @ 2025-09-27 18:36 UTC (permalink / raw)
  To: netdev, Stephen Hemminger; +Cc: bpf, Ard Biesheuvel

On Thu, Sep 25, 2025 at 03:53:22PM -0700, Eric Biggers wrote:
>  	ctx->obj_fd = open(pathname, O_RDONLY);
> -	if (ctx->obj_fd < 0)
> +	if (ctx->obj_fd < 0) {
> +		fprintf(stderr, "Error opening object %s: %s\n", pathname,
> +			strerror(errno));
>  		return ctx->obj_fd;
> +	}
> +
> +	ret = bpf_obj_hash(ctx->obj_fd, pathname, tmp);
> +	if (ret)
> +		return ret;

Correction: the 'return ret;' above should be 'goto out_fd;'.
I'll fix this in v2, but I'll wait a bit for more feedback first.

- Eric

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH iproute2-next] lib/bpf_legacy: Use userspace SHA-1 code instead of AF_ALG
  2025-09-25 22:53 [PATCH iproute2-next] lib/bpf_legacy: Use userspace SHA-1 code instead of AF_ALG Eric Biggers
  2025-09-27 18:36 ` Eric Biggers
@ 2025-09-28 13:51 ` Ard Biesheuvel
  1 sibling, 0 replies; 3+ messages in thread
From: Ard Biesheuvel @ 2025-09-28 13:51 UTC (permalink / raw)
  To: Eric Biggers; +Cc: netdev, Stephen Hemminger, bpf

On Fri, 26 Sept 2025 at 00:54, Eric Biggers <ebiggers@kernel.org> wrote:
>
> Add a basic SHA-1 implementation to lib/, and make lib/bpf_legacy.c use
> it to calculate the SHA-1 digest of BPF objects instead of the previous
> AF_ALG-based code.  This eliminates the dependency on the kernel config
> options CONFIG_CRYPTO_USER_API_HASH and CONFIG_CRYPTO_SHA1.
>
> Signed-off-by: Eric Biggers <ebiggers@kernel.org>

Acked-by: Ard Biesheuvel <ardb@kernel.org>

Perhaps -in case the maintainer is not convinced- add a paragraph to
the commit log explaining that using AF_ALG to invoke the kernel's
software SHA1 implementation is a terrible idea, and should have never
existed in this form in the first place? (AF_ALG's original purpose
was to expose h/w crypto accelerators to user space but we
accidentally ended up exposing kernel software implementations that
should simply execute in user space entirely)


> ---
>  include/bpf_util.h          |   5 --
>  include/sha1.h              |  18 ++++++
>  include/uapi/linux/if_alg.h |  61 --------------------
>  lib/Makefile                |   2 +-
>  lib/bpf_legacy.c            | 109 +++++++++---------------------------
>  lib/sha1.c                  | 108 +++++++++++++++++++++++++++++++++++
>  6 files changed, 154 insertions(+), 149 deletions(-)
>  create mode 100644 include/sha1.h
>  delete mode 100644 include/uapi/linux/if_alg.h
>  create mode 100644 lib/sha1.c
>
> diff --git a/include/bpf_util.h b/include/bpf_util.h
> index 8951a5e8..e1b8d327 100644
> --- a/include/bpf_util.h
> +++ b/include/bpf_util.h
> @@ -12,11 +12,10 @@
>  #include <linux/bpf.h>
>  #include <linux/btf.h>
>  #include <linux/filter.h>
>  #include <linux/magic.h>
>  #include <linux/elf-em.h>
> -#include <linux/if_alg.h>
>
>  #include "utils.h"
>  #include "bpf_scm.h"
>
>  #define BPF_ENV_UDS    "TC_BPF_UDS"
> @@ -38,14 +37,10 @@
>  # define TRACEFS_MAGIC 0x74726163
>  #endif
>
>  #define TRACE_DIR_MNT  "/sys/kernel/tracing"
>
> -#ifndef AF_ALG
> -# define AF_ALG                38
> -#endif
> -
>  #ifndef EM_BPF
>  # define EM_BPF                247
>  #endif
>
>  struct bpf_cfg_ops {
> diff --git a/include/sha1.h b/include/sha1.h
> new file mode 100644
> index 00000000..4a2ed513
> --- /dev/null
> +++ b/include/sha1.h
> @@ -0,0 +1,18 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * SHA-1 message digest algorithm
> + *
> + * Copyright 2025 Google LLC
> + */
> +#ifndef __SHA1_H__
> +#define __SHA1_H__
> +
> +#include <linux/types.h>
> +#include <stddef.h>
> +
> +#define SHA1_DIGEST_SIZE 20
> +#define SHA1_BLOCK_SIZE 64
> +
> +void sha1(const __u8 *data, size_t len, __u8 out[SHA1_DIGEST_SIZE]);
> +
> +#endif /* __SHA1_H__ */
> diff --git a/include/uapi/linux/if_alg.h b/include/uapi/linux/if_alg.h
> deleted file mode 100644
> index 0824fbc0..00000000
> --- a/include/uapi/linux/if_alg.h
> +++ /dev/null
> @@ -1,61 +0,0 @@
> -/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
> -/*
> - * if_alg: User-space algorithm interface
> - *
> - * Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au>
> - *
> - * This program is free software; you can redistribute it and/or modify it
> - * under the terms of the GNU General Public License as published by the Free
> - * Software Foundation; either version 2 of the License, or (at your option)
> - * any later version.
> - *
> - */
> -
> -#ifndef _LINUX_IF_ALG_H
> -#define _LINUX_IF_ALG_H
> -
> -#include <linux/types.h>
> -
> -struct sockaddr_alg {
> -       __u16   salg_family;
> -       __u8    salg_type[14];
> -       __u32   salg_feat;
> -       __u32   salg_mask;
> -       __u8    salg_name[64];
> -};
> -
> -/*
> - * Linux v4.12 and later removed the 64-byte limit on salg_name[]; it's now an
> - * arbitrary-length field.  We had to keep the original struct above for source
> - * compatibility with existing userspace programs, though.  Use the new struct
> - * below if support for very long algorithm names is needed.  To do this,
> - * allocate 'sizeof(struct sockaddr_alg_new) + strlen(algname) + 1' bytes, and
> - * copy algname (including the null terminator) into salg_name.
> - */
> -struct sockaddr_alg_new {
> -       __u16   salg_family;
> -       __u8    salg_type[14];
> -       __u32   salg_feat;
> -       __u32   salg_mask;
> -       __u8    salg_name[];
> -};
> -
> -struct af_alg_iv {
> -       __u32   ivlen;
> -       __u8    iv[];
> -};
> -
> -/* Socket options */
> -#define ALG_SET_KEY                    1
> -#define ALG_SET_IV                     2
> -#define ALG_SET_OP                     3
> -#define ALG_SET_AEAD_ASSOCLEN          4
> -#define ALG_SET_AEAD_AUTHSIZE          5
> -#define ALG_SET_DRBG_ENTROPY           6
> -#define ALG_SET_KEY_BY_KEY_SERIAL      7
> -
> -/* Operations */
> -#define ALG_OP_DECRYPT                 0
> -#define ALG_OP_ENCRYPT                 1
> -
> -#endif /* _LINUX_IF_ALG_H */
> diff --git a/lib/Makefile b/lib/Makefile
> index 0ba62942..ee1e2e87 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -4,11 +4,11 @@ include ../config.mk
>  CFLAGS += -fPIC
>
>  UTILOBJ = utils.o utils_math.o rt_names.o ll_map.o ll_types.o ll_proto.o ll_addr.o \
>         inet_proto.o namespace.o json_writer.o json_print.o json_print_math.o \
>         names.o color.o bpf_legacy.o bpf_glue.o exec.o fs.o cg_map.o \
> -       ppp_proto.o bridge.o
> +       ppp_proto.o bridge.o sha1.o
>
>  ifeq ($(HAVE_ELF),y)
>  ifeq ($(HAVE_LIBBPF),y)
>  UTILOBJ += bpf_libbpf.o
>  endif
> diff --git a/lib/bpf_legacy.c b/lib/bpf_legacy.c
> index c8da4a3e..c4b1d5de 100644
> --- a/lib/bpf_legacy.c
> +++ b/lib/bpf_legacy.c
> @@ -27,18 +27,19 @@
>
>  #include <sys/types.h>
>  #include <sys/stat.h>
>  #include <sys/un.h>
>  #include <sys/vfs.h>
> +#include <sys/mman.h>
>  #include <sys/mount.h>
> -#include <sys/sendfile.h>
>  #include <sys/resource.h>
>
>  #include <arpa/inet.h>
>
>  #include "utils.h"
>  #include "json_print.h"
> +#include "sha1.h"
>
>  #include "bpf_util.h"
>  #include "bpf_elf.h"
>  #include "bpf_scm.h"
>
> @@ -1178,11 +1179,10 @@ struct bpf_elf_ctx {
>         int                     sec_btf;
>         char                    license[ELF_MAX_LICENSE_LEN];
>         enum bpf_prog_type      type;
>         __u32                   ifindex;
>         bool                    verbose;
> -       bool                    noafalg;
>         struct bpf_elf_st       stat;
>         struct bpf_hash_entry   *ht[256];
>         char                    *log;
>         size_t                  log_size;
>  };
> @@ -1306,76 +1306,32 @@ static int bpf_obj_pin(int fd, const char *pathname)
>         attr.bpf_fd = fd;
>
>         return bpf(BPF_OBJ_PIN, &attr, sizeof(attr));
>  }
>
> -static int bpf_obj_hash(const char *object, uint8_t *out, size_t len)
> +static int bpf_obj_hash(int fd, const char *object, __u8 out[SHA1_DIGEST_SIZE])
>  {
> -       struct sockaddr_alg alg = {
> -               .salg_family    = AF_ALG,
> -               .salg_type      = "hash",
> -               .salg_name      = "sha1",
> -       };
> -       int ret, cfd, ofd, ffd;
>         struct stat stbuff;
> -       ssize_t size;
> -
> -       if (!object || len != 20)
> -               return -EINVAL;
> -
> -       cfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
> -       if (cfd < 0)
> -               return cfd;
> +       void *data;
>
> -       ret = bind(cfd, (struct sockaddr *)&alg, sizeof(alg));
> -       if (ret < 0)
> -               goto out_cfd;
> -
> -       ofd = accept(cfd, NULL, 0);
> -       if (ofd < 0) {
> -               ret = ofd;
> -               goto out_cfd;
> +       if (fstat(fd, &stbuff) < 0) {
> +               fprintf(stderr, "Error doing fstat: %s\n", strerror(errno));
> +               return -1;
>         }
> -
> -       ffd = open(object, O_RDONLY);
> -       if (ffd < 0) {
> -               fprintf(stderr, "Error opening object %s: %s\n",
> -                       object, strerror(errno));
> -               ret = ffd;
> -               goto out_ofd;
> +       if ((size_t)stbuff.st_size != stbuff.st_size) {
> +               fprintf(stderr, "Object %s is too big\n", object);
> +               return -EFBIG;
>         }
> -
> -       ret = fstat(ffd, &stbuff);
> -       if (ret < 0) {
> -               fprintf(stderr, "Error doing fstat: %s\n",
> +       data = mmap(NULL, stbuff.st_size, PROT_READ, MAP_SHARED, fd, 0);
> +       if (data == MAP_FAILED) {
> +               fprintf(stderr, "Error mapping object %s: %s\n", object,
>                         strerror(errno));
> -               goto out_ffd;
> -       }
> -
> -       size = sendfile(ofd, ffd, NULL, stbuff.st_size);
> -       if (size != stbuff.st_size) {
> -               fprintf(stderr, "Error from sendfile (%zd vs %zu bytes): %s\n",
> -                       size, stbuff.st_size, strerror(errno));
> -               ret = -1;
> -               goto out_ffd;
> +               return -1;
>         }
> -
> -       size = read(ofd, out, len);
> -       if (size != len) {
> -               fprintf(stderr, "Error from read (%zd vs %zu bytes): %s\n",
> -                       size, len, strerror(errno));
> -               ret = -1;
> -       } else {
> -               ret = 0;
> -       }
> -out_ffd:
> -       close(ffd);
> -out_ofd:
> -       close(ofd);
> -out_cfd:
> -       close(cfd);
> -       return ret;
> +       sha1(data, stbuff.st_size, out);
> +       munmap(data, stbuff.st_size);
> +       return 0;
>  }
>
>  static void bpf_init_env(void)
>  {
>         struct rlimit limit = {
> @@ -1812,16 +1768,10 @@ static int bpf_maps_attach_all(struct bpf_elf_ctx *ctx)
>  {
>         int i, j, ret, fd, inner_fd, inner_idx, have_map_in_map = 0;
>         const char *map_name;
>
>         for (i = 0; i < ctx->map_num; i++) {
> -               if (ctx->maps[i].pinning == PIN_OBJECT_NS &&
> -                   ctx->noafalg) {
> -                       fprintf(stderr, "Missing kernel AF_ALG support for PIN_OBJECT_NS!\n");
> -                       return -ENOTSUP;
> -               }
> -
>                 map_name = bpf_map_fetch_name(ctx, i);
>                 if (!map_name)
>                         return -EIO;
>
>                 fd = bpf_map_attach(map_name, ctx, &ctx->maps[i],
> @@ -2867,35 +2817,36 @@ static void bpf_get_cfg(struct bpf_elf_ctx *ctx)
>
>  static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname,
>                             enum bpf_prog_type type, __u32 ifindex,
>                             bool verbose)
>  {
> -       uint8_t tmp[20];
> +       __u8 tmp[SHA1_DIGEST_SIZE];
>         int ret;
>
>         if (elf_version(EV_CURRENT) == EV_NONE)
>                 return -EINVAL;
>
>         bpf_init_env();
>
>         memset(ctx, 0, sizeof(*ctx));
>         bpf_get_cfg(ctx);
>
> -       ret = bpf_obj_hash(pathname, tmp, sizeof(tmp));
> -       if (ret)
> -               ctx->noafalg = true;
> -       else
> -               hexstring_n2a(tmp, sizeof(tmp), ctx->obj_uid,
> -                             sizeof(ctx->obj_uid));
> -
>         ctx->verbose = verbose;
>         ctx->type    = type;
>         ctx->ifindex = ifindex;
>
>         ctx->obj_fd = open(pathname, O_RDONLY);
> -       if (ctx->obj_fd < 0)
> +       if (ctx->obj_fd < 0) {
> +               fprintf(stderr, "Error opening object %s: %s\n", pathname,
> +                       strerror(errno));
>                 return ctx->obj_fd;
> +       }
> +
> +       ret = bpf_obj_hash(ctx->obj_fd, pathname, tmp);
> +       if (ret)
> +               return ret;
> +       hexstring_n2a(tmp, sizeof(tmp), ctx->obj_uid, sizeof(ctx->obj_uid));
>
>         ctx->elf_fd = elf_begin(ctx->obj_fd, ELF_C_READ, NULL);
>         if (!ctx->elf_fd) {
>                 ret = -EINVAL;
>                 goto out_fd;
> @@ -3257,16 +3208,10 @@ bool iproute2_is_pin_map(const char *libbpf_map_name, char *pathname)
>         const char *map_name, *tmp;
>         unsigned int pinning;
>         int i, ret = 0;
>
>         for (i = 0; i < ctx->map_num; i++) {
> -               if (ctx->maps[i].pinning == PIN_OBJECT_NS &&
> -                   ctx->noafalg) {
> -                       fprintf(stderr, "Missing kernel AF_ALG support for PIN_OBJECT_NS!\n");
> -                       return false;
> -               }
> -
>                 map_name = bpf_map_fetch_name(ctx, i);
>                 if (!map_name) {
>                         return false;
>                 }
>
> diff --git a/lib/sha1.c b/lib/sha1.c
> new file mode 100644
> index 00000000..1aa8fd83
> --- /dev/null
> +++ b/lib/sha1.c
> @@ -0,0 +1,108 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * SHA-1 message digest algorithm
> + *
> + * Copyright 2025 Google LLC
> + */
> +
> +#include <arpa/inet.h>
> +#include <string.h>
> +
> +#include "sha1.h"
> +#include "utils.h"
> +
> +static const __u32 sha1_K[4] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC,
> +                                0xCA62C1D6 };
> +
> +static inline __u32 rol32(__u32 v, int bits)
> +{
> +       return (v << bits) | (v >> (32 - bits));
> +}
> +
> +#define round_up(a, b) (((a) + (b) - 1) & ~((b) - 1))
> +
> +#define SHA1_ROUND(i, a, b, c, d, e)                                           \
> +       do {                                                                   \
> +               if ((i) >= 16)                                                 \
> +                       w[i] = rol32(w[(i) - 16] ^ w[(i) - 14] ^ w[(i) - 8] ^  \
> +                                            w[(i) - 3],                       \
> +                                    1);                                       \
> +               e += w[i] + rol32(a, 5) + sha1_K[(i) / 20];                    \
> +               if ((i) < 20)                                                  \
> +                       e += (b & (c ^ d)) ^ d;                                \
> +               else if ((i) < 40 || (i) >= 60)                                \
> +                       e += b ^ c ^ d;                                        \
> +               else                                                           \
> +                       e += (c & d) ^ (b & (c ^ d));                          \
> +               b = rol32(b, 30);                                              \
> +               /* The new (a, b, c, d, e) is the old (e, a, b, c, d). */      \
> +       } while (0)
> +
> +#define SHA1_5ROUNDS(i)                                                        \
> +       do {                                                                   \
> +               SHA1_ROUND((i) + 0, a, b, c, d, e);                            \
> +               SHA1_ROUND((i) + 1, e, a, b, c, d);                            \
> +               SHA1_ROUND((i) + 2, d, e, a, b, c);                            \
> +               SHA1_ROUND((i) + 3, c, d, e, a, b);                            \
> +               SHA1_ROUND((i) + 4, b, c, d, e, a);                            \
> +       } while (0)
> +
> +#define SHA1_20ROUNDS(i)                                                       \
> +       do {                                                                   \
> +               SHA1_5ROUNDS((i) + 0);                                         \
> +               SHA1_5ROUNDS((i) + 5);                                         \
> +               SHA1_5ROUNDS((i) + 10);                                        \
> +               SHA1_5ROUNDS((i) + 15);                                        \
> +       } while (0)
> +
> +static void sha1_blocks(__u32 h[5], const __u8 *data, size_t nblocks)
> +{
> +       while (nblocks--) {
> +               __u32 a = h[0];
> +               __u32 b = h[1];
> +               __u32 c = h[2];
> +               __u32 d = h[3];
> +               __u32 e = h[4];
> +               __u32 w[80];
> +               int i;
> +
> +               memcpy(w, data, SHA1_BLOCK_SIZE);
> +               for (i = 0; i < 16; i++)
> +                       w[i] = ntohl(w[i]);
> +               SHA1_20ROUNDS(0);
> +               SHA1_20ROUNDS(20);
> +               SHA1_20ROUNDS(40);
> +               SHA1_20ROUNDS(60);
> +
> +               h[0] += a;
> +               h[1] += b;
> +               h[2] += c;
> +               h[3] += d;
> +               h[4] += e;
> +               data += SHA1_BLOCK_SIZE;
> +       }
> +}
> +
> +/* Calculate the SHA-1 message digest of the given data. */
> +void sha1(const __u8 *data, size_t len, __u8 out[SHA1_DIGEST_SIZE])
> +{
> +       __u32 h[5] = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476,
> +                      0xC3D2E1F0 };
> +       const __be64 bitcount = htonll((__u64)len * 8);
> +       __u8 final_data[2 * SHA1_BLOCK_SIZE] = { 0 };
> +       size_t final_len = len % SHA1_BLOCK_SIZE;
> +       int i;
> +
> +       sha1_blocks(h, data, len / SHA1_BLOCK_SIZE);
> +
> +       memcpy(final_data, data + len - final_len, final_len);
> +       final_data[final_len] = 0x80;
> +       final_len = round_up(final_len + 9, SHA1_BLOCK_SIZE);
> +       memcpy(&final_data[final_len - 8], &bitcount, 8);
> +
> +       sha1_blocks(h, final_data, final_len / SHA1_BLOCK_SIZE);
> +
> +       for (i = 0; i < ARRAY_SIZE(h); i++)
> +               h[i] = htonl(h[i]);
> +       memcpy(out, h, SHA1_DIGEST_SIZE);
> +}
>
> base-commit: afceddf61037440628a5612f15a6eaefd28d9fd3
> --
> 2.51.0
>

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2025-09-28 13:51 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-25 22:53 [PATCH iproute2-next] lib/bpf_legacy: Use userspace SHA-1 code instead of AF_ALG Eric Biggers
2025-09-27 18:36 ` Eric Biggers
2025-09-28 13:51 ` Ard Biesheuvel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).