[PATCH 4/7] ecryptfs: use sg_init_one() instead of virt_to_scatterlist()

From: Tal Zussman

Date: Wed Oct 14 2026 - 21:37:34 EST


Every caller passes a kmalloc()-ed buffer or an array inside a kmalloc()-ed
structure, which is physically contiguous and so fits in one
scatterlist entry. Use sg_init_one(), which can't fail, drop the
two-entry arrays and their length checks, and remove
virt_to_scatterlist() and the unused ECRYPTFS_MAX_SCATTERLIST_LEN.

Signed-off-by: Tal Zussman <tz2294@xxxxxxxxxxxx>
---
fs/ecryptfs/crypto.c | 46 -----------------
fs/ecryptfs/ecryptfs_kernel.h | 2 -
fs/ecryptfs/keystore.c | 114 +++++++++---------------------------------
3 files changed, 25 insertions(+), 137 deletions(-)

diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 6a014872e919..f0e67b48917f 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -149,50 +149,6 @@ void ecryptfs_destroy_mount_crypt_stat(
memset(mount_crypt_stat, 0, sizeof(struct ecryptfs_mount_crypt_stat));
}

-/**
- * virt_to_scatterlist
- * @addr: Virtual address
- * @size: Size of data; should be an even multiple of the block size
- * @sg: Pointer to scatterlist array; set to NULL to obtain only
- * the number of scatterlist structs required in array
- * @sg_size: Max array size
- *
- * Fills in a scatterlist array with page references for a passed
- * virtual address.
- *
- * Returns the number of scatterlist structs in array used
- */
-int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,
- int sg_size)
-{
- int i = 0;
- struct page *pg;
- int offset;
- int remainder_of_page;
-
- sg_init_table(sg, sg_size);
-
- while (size > 0 && i < sg_size) {
- pg = virt_to_page(addr);
- offset = offset_in_page(addr);
- sg_set_page(&sg[i], pg, 0, offset);
- remainder_of_page = PAGE_SIZE - offset;
- if (size >= remainder_of_page) {
- sg[i].length = remainder_of_page;
- addr += remainder_of_page;
- size -= remainder_of_page;
- } else {
- sg[i].length = size;
- addr += size;
- size = 0;
- }
- i++;
- }
- if (size > 0)
- return -ENOMEM;
- return i;
-}
-
/**
* crypt_scatterlist
* @crypt_stat: Pointer to the crypt_stat struct to initialize.
@@ -438,8 +394,6 @@ int ecryptfs_decrypt_page(struct folio *folio)
return rc;
}

-#define ECRYPTFS_MAX_SCATTERLIST_LEN 4
-
/**
* ecryptfs_init_crypt_ctx
* @crypt_stat: Uninitialized crypt stats structure
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index ff5cef83c79c..6a74a2bfc833 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -541,8 +541,6 @@ int ecryptfs_encrypt_and_encode_filename(
struct ecryptfs_mount_crypt_stat *mount_crypt_stat,
const char *name, size_t name_size);
void ecryptfs_dump_hex(char *data, int bytes);
-int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,
- int sg_size);
int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat);
void ecryptfs_rotate_iv(unsigned char *iv);
void ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);
diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c
index 51651314b7a6..051f7948cf52 100644
--- a/fs/ecryptfs/keystore.c
+++ b/fs/ecryptfs/keystore.c
@@ -595,8 +595,8 @@ struct ecryptfs_write_tag_70_packet_silly_stack {
struct mutex *tfm_mutex;
char *block_aligned_filename;
struct ecryptfs_auth_tok *auth_tok;
- struct scatterlist src_sg[2];
- struct scatterlist dst_sg[2];
+ struct scatterlist src_sg;
+ struct scatterlist dst_sg;
struct crypto_skcipher *skcipher_tfm;
struct skcipher_request *skcipher_req;
char iv[ECRYPTFS_MAX_IV_BYTES];
@@ -751,24 +751,9 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
}
memcpy(&s->block_aligned_filename[s->num_rand_bytes], filename,
filename_size);
- rc = virt_to_scatterlist(s->block_aligned_filename,
- s->block_aligned_filename_size, s->src_sg, 2);
- if (rc < 1) {
- printk(KERN_ERR "%s: Internal error whilst attempting to "
- "convert filename memory to scatterlist; rc = [%d]. "
- "block_aligned_filename_size = [%zd]\n", __func__, rc,
- s->block_aligned_filename_size);
- goto out_free_unlock;
- }
- rc = virt_to_scatterlist(&dest[s->i], s->block_aligned_filename_size,
- s->dst_sg, 2);
- if (rc < 1) {
- printk(KERN_ERR "%s: Internal error whilst attempting to "
- "convert encrypted filename memory to scatterlist; "
- "rc = [%d]. block_aligned_filename_size = [%zd]\n",
- __func__, rc, s->block_aligned_filename_size);
- goto out_free_unlock;
- }
+ sg_init_one(&s->src_sg, s->block_aligned_filename,
+ s->block_aligned_filename_size);
+ sg_init_one(&s->dst_sg, &dest[s->i], s->block_aligned_filename_size);
/* The characters in the first block effectively do the job
* of the IV here, so we just use 0's for the IV. Note the
* constraint that ECRYPTFS_FILENAME_MIN_RANDOM_PREPEND_BYTES
@@ -787,7 +772,7 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
mount_crypt_stat->global_default_fn_cipher_key_bytes);
goto out_free_unlock;
}
- skcipher_request_set_crypt(s->skcipher_req, s->src_sg, s->dst_sg,
+ skcipher_request_set_crypt(s->skcipher_req, &s->src_sg, &s->dst_sg,
s->block_aligned_filename_size, s->iv);
rc = crypto_skcipher_encrypt(s->skcipher_req);
if (rc) {
@@ -823,8 +808,8 @@ struct ecryptfs_parse_tag_70_packet_silly_stack {
struct mutex *tfm_mutex;
char *decrypted_filename;
struct ecryptfs_auth_tok *auth_tok;
- struct scatterlist src_sg[2];
- struct scatterlist dst_sg[2];
+ struct scatterlist src_sg;
+ struct scatterlist dst_sg;
struct crypto_skcipher *skcipher_tfm;
struct skcipher_request *skcipher_req;
char fnek_sig_hex[ECRYPTFS_SIG_SIZE_HEX + 1];
@@ -943,15 +928,8 @@ ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size,
goto out;
}
mutex_lock(s->tfm_mutex);
- rc = virt_to_scatterlist(&data[(*packet_size)],
- s->block_aligned_filename_size, s->src_sg, 2);
- if (rc < 1) {
- printk(KERN_ERR "%s: Internal error whilst attempting to "
- "convert encrypted filename memory to scatterlist; "
- "rc = [%d]. block_aligned_filename_size = [%zd]\n",
- __func__, rc, s->block_aligned_filename_size);
- goto out_unlock;
- }
+ sg_init_one(&s->src_sg, &data[(*packet_size)],
+ s->block_aligned_filename_size);
(*packet_size) += s->block_aligned_filename_size;
s->decrypted_filename = kmalloc(s->block_aligned_filename_size,
GFP_KERNEL);
@@ -959,15 +937,8 @@ ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size,
rc = -ENOMEM;
goto out_unlock;
}
- rc = virt_to_scatterlist(s->decrypted_filename,
- s->block_aligned_filename_size, s->dst_sg, 2);
- if (rc < 1) {
- printk(KERN_ERR "%s: Internal error whilst attempting to "
- "convert decrypted filename memory to scatterlist; "
- "rc = [%d]. block_aligned_filename_size = [%zd]\n",
- __func__, rc, s->block_aligned_filename_size);
- goto out_free_unlock;
- }
+ sg_init_one(&s->dst_sg, s->decrypted_filename,
+ s->block_aligned_filename_size);

s->skcipher_req = skcipher_request_alloc(s->skcipher_tfm, GFP_KERNEL);
if (!s->skcipher_req) {
@@ -1007,7 +978,7 @@ ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size,
mount_crypt_stat->global_default_fn_cipher_key_bytes);
goto out_free_unlock;
}
- skcipher_request_set_crypt(s->skcipher_req, s->src_sg, s->dst_sg,
+ skcipher_request_set_crypt(s->skcipher_req, &s->src_sg, &s->dst_sg,
s->block_aligned_filename_size, s->iv);
rc = crypto_skcipher_decrypt(s->skcipher_req);
if (rc) {
@@ -1625,8 +1596,8 @@ static int
decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
struct ecryptfs_crypt_stat *crypt_stat)
{
- struct scatterlist dst_sg[2];
- struct scatterlist src_sg[2];
+ struct scatterlist dst_sg;
+ struct scatterlist src_sg;
struct mutex *tfm_mutex;
struct crypto_skcipher *tfm;
struct skcipher_request *req = NULL;
@@ -1648,28 +1619,12 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
crypt_stat->cipher, rc);
goto out;
}
- rc = virt_to_scatterlist(auth_tok->session_key.encrypted_key,
- auth_tok->session_key.encrypted_key_size,
- src_sg, 2);
- if (rc < 1 || rc > 2) {
- printk(KERN_ERR "Internal error whilst attempting to convert "
- "auth_tok->session_key.encrypted_key to scatterlist; "
- "expected rc = 1; got rc = [%d]. "
- "auth_tok->session_key.encrypted_key_size = [%d]\n", rc,
- auth_tok->session_key.encrypted_key_size);
- goto out;
- }
+ sg_init_one(&src_sg, auth_tok->session_key.encrypted_key,
+ auth_tok->session_key.encrypted_key_size);
auth_tok->session_key.decrypted_key_size =
auth_tok->session_key.encrypted_key_size;
- rc = virt_to_scatterlist(auth_tok->session_key.decrypted_key,
- auth_tok->session_key.decrypted_key_size,
- dst_sg, 2);
- if (rc < 1 || rc > 2) {
- printk(KERN_ERR "Internal error whilst attempting to convert "
- "auth_tok->session_key.decrypted_key to scatterlist; "
- "expected rc = 1; got rc = [%d]\n", rc);
- goto out;
- }
+ sg_init_one(&dst_sg, auth_tok->session_key.decrypted_key,
+ auth_tok->session_key.decrypted_key_size);
mutex_lock(tfm_mutex);
req = skcipher_request_alloc(tfm, GFP_KERNEL);
if (!req) {
@@ -1692,7 +1647,7 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
rc = -EINVAL;
goto out;
}
- skcipher_request_set_crypt(req, src_sg, dst_sg,
+ skcipher_request_set_crypt(req, &src_sg, &dst_sg,
auth_tok->session_key.encrypted_key_size,
NULL);
rc = crypto_skcipher_decrypt(req);
@@ -2166,8 +2121,8 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
size_t i;
size_t encrypted_session_key_valid = 0;
char session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
- struct scatterlist dst_sg[2];
- struct scatterlist src_sg[2];
+ struct scatterlist dst_sg;
+ struct scatterlist src_sg;
struct mutex *tfm_mutex = NULL;
u8 cipher_code;
size_t packet_size_length;
@@ -2242,27 +2197,8 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
ecryptfs_printk(KERN_DEBUG, "Session key encryption key:\n");
ecryptfs_dump_hex(session_key_encryption_key, 16);
}
- rc = virt_to_scatterlist(crypt_stat->key, key_rec->enc_key_size,
- src_sg, 2);
- if (rc < 1 || rc > 2) {
- ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
- "for crypt_stat session key; expected rc = 1; "
- "got rc = [%d]. key_rec->enc_key_size = [%zd]\n",
- rc, key_rec->enc_key_size);
- rc = -ENOMEM;
- goto out;
- }
- rc = virt_to_scatterlist(key_rec->enc_key, key_rec->enc_key_size,
- dst_sg, 2);
- if (rc < 1 || rc > 2) {
- ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
- "for crypt_stat encrypted session key; "
- "expected rc = 1; got rc = [%d]. "
- "key_rec->enc_key_size = [%zd]\n", rc,
- key_rec->enc_key_size);
- rc = -ENOMEM;
- goto out;
- }
+ sg_init_one(&src_sg, crypt_stat->key, key_rec->enc_key_size);
+ sg_init_one(&dst_sg, key_rec->enc_key, key_rec->enc_key_size);
mutex_lock(tfm_mutex);
rc = crypto_skcipher_setkey(tfm, session_key_encryption_key,
crypt_stat->key_size);
@@ -2289,7 +2225,7 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
rc = 0;
ecryptfs_printk(KERN_DEBUG, "Encrypting [%zd] bytes of the key\n",
crypt_stat->key_size);
- skcipher_request_set_crypt(req, src_sg, dst_sg,
+ skcipher_request_set_crypt(req, &src_sg, &dst_sg,
(*key_rec).enc_key_size, NULL);
rc = crypto_skcipher_encrypt(req);
mutex_unlock(tfm_mutex);

--
2.39.5