2022-07-08 10:21:52

by Jonathan McDowell

[permalink] [raw]
Subject: [RFC PATCH 3/7] lib/cpio: use non __init filesystem related functions

In preparation for making the cpio functions generally available rather
than just at init make sure we're using versions of the filesystem
related functions that aren't in the __init section. Remove functions
only used by us from fs/init.c while folding into the cpio code
directly.

Signed-off-by: Jonathan McDowell <[email protected]>
---
fs/init.c | 101 ----------------------
fs/internal.h | 4 -
include/linux/fs.h | 4 +
include/linux/init_syscalls.h | 6 --
lib/cpio.c | 156 +++++++++++++++++++++++++++++-----
5 files changed, 139 insertions(+), 132 deletions(-)

diff --git a/fs/init.c b/fs/init.c
index 5c36adaa9b44..a946ad672dee 100644
--- a/fs/init.c
+++ b/fs/init.c
@@ -79,37 +79,6 @@ int __init init_chroot(const char *filename)
return error;
}

-int __init init_chown(const char *filename, uid_t user, gid_t group, int flags)
-{
- int lookup_flags = (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
- struct path path;
- int error;
-
- error = kern_path(filename, lookup_flags, &path);
- if (error)
- return error;
- error = mnt_want_write(path.mnt);
- if (!error) {
- error = chown_common(&path, user, group);
- mnt_drop_write(path.mnt);
- }
- path_put(&path);
- return error;
-}
-
-int __init init_chmod(const char *filename, umode_t mode)
-{
- struct path path;
- int error;
-
- error = kern_path(filename, LOOKUP_FOLLOW, &path);
- if (error)
- return error;
- error = chmod_common(&path, mode);
- path_put(&path);
- return error;
-}
-
int __init init_eaccess(const char *filename)
{
struct path path;
@@ -163,58 +132,6 @@ int __init init_mknod(const char *filename, umode_t mode, unsigned int dev)
return error;
}

-int __init init_link(const char *oldname, const char *newname)
-{
- struct dentry *new_dentry;
- struct path old_path, new_path;
- struct user_namespace *mnt_userns;
- int error;
-
- error = kern_path(oldname, 0, &old_path);
- if (error)
- return error;
-
- new_dentry = kern_path_create(AT_FDCWD, newname, &new_path, 0);
- error = PTR_ERR(new_dentry);
- if (IS_ERR(new_dentry))
- goto out;
-
- error = -EXDEV;
- if (old_path.mnt != new_path.mnt)
- goto out_dput;
- mnt_userns = mnt_user_ns(new_path.mnt);
- error = may_linkat(mnt_userns, &old_path);
- if (unlikely(error))
- goto out_dput;
- error = security_path_link(old_path.dentry, &new_path, new_dentry);
- if (error)
- goto out_dput;
- error = vfs_link(old_path.dentry, mnt_userns, new_path.dentry->d_inode,
- new_dentry, NULL);
-out_dput:
- done_path_create(&new_path, new_dentry);
-out:
- path_put(&old_path);
- return error;
-}
-
-int __init init_symlink(const char *oldname, const char *newname)
-{
- struct dentry *dentry;
- struct path path;
- int error;
-
- dentry = kern_path_create(AT_FDCWD, newname, &path, 0);
- if (IS_ERR(dentry))
- return PTR_ERR(dentry);
- error = security_path_symlink(&path, dentry, oldname);
- if (!error)
- error = vfs_symlink(mnt_user_ns(path.mnt), path.dentry->d_inode,
- dentry, oldname);
- done_path_create(&path, dentry);
- return error;
-}
-
int __init init_unlink(const char *pathname)
{
return do_unlinkat(AT_FDCWD, getname_kernel(pathname));
@@ -239,24 +156,6 @@ int __init init_mkdir(const char *pathname, umode_t mode)
return error;
}

-int __init init_rmdir(const char *pathname)
-{
- return do_rmdir(AT_FDCWD, getname_kernel(pathname));
-}
-
-int __init init_utimes(char *filename, struct timespec64 *ts)
-{
- struct path path;
- int error;
-
- error = kern_path(filename, 0, &path);
- if (error)
- return error;
- error = vfs_utimes(&path, ts);
- path_put(&path);
- return error;
-}
-
int __init init_dup(struct file *file)
{
int fd;
diff --git a/fs/internal.h b/fs/internal.h
index 87e96b9024ce..c57d5f0aa731 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -60,9 +60,6 @@ extern int filename_lookup(int dfd, struct filename *name, unsigned flags,
struct path *path, struct path *root);
extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
const char *, unsigned int, struct path *);
-int do_rmdir(int dfd, struct filename *name);
-int do_unlinkat(int dfd, struct filename *name);
-int may_linkat(struct user_namespace *mnt_userns, struct path *link);
int do_renameat2(int olddfd, struct filename *oldname, int newdfd,
struct filename *newname, unsigned int flags);
int do_mkdirat(int dfd, struct filename *name, umode_t mode);
@@ -132,7 +129,6 @@ long do_sys_ftruncate(unsigned int fd, loff_t length, int small);
int chmod_common(const struct path *path, umode_t mode);
int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group,
int flag);
-int chown_common(const struct path *path, uid_t user, gid_t group);
extern int vfs_open(const struct path *, struct file *);

/*
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 9ad5e3520fae..1cb51a54799b 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2636,11 +2636,15 @@ static inline struct file *file_clone_open(struct file *file)
return dentry_open(&file->f_path, file->f_flags, file->f_cred);
}
extern int filp_close(struct file *, fl_owner_t id);
+extern int chown_common(const struct path *path, uid_t user, gid_t group);

+extern int do_rmdir(int dfd, struct filename *name);
+extern int do_unlinkat(int dfd, struct filename *name);
extern struct filename *getname_flags(const char __user *, int, int *);
extern struct filename *getname_uflags(const char __user *, int);
extern struct filename *getname(const char __user *);
extern struct filename *getname_kernel(const char *);
+extern int may_linkat(struct user_namespace *mnt_userns, struct path *link);
extern void putname(struct filename *name);

extern int finish_open(struct file *file, struct dentry *dentry,
diff --git a/include/linux/init_syscalls.h b/include/linux/init_syscalls.h
index 92045d18cbfc..196030cd958d 100644
--- a/include/linux/init_syscalls.h
+++ b/include/linux/init_syscalls.h
@@ -5,15 +5,9 @@ int __init init_mount(const char *dev_name, const char *dir_name,
int __init init_umount(const char *name, int flags);
int __init init_chdir(const char *filename);
int __init init_chroot(const char *filename);
-int __init init_chown(const char *filename, uid_t user, gid_t group, int flags);
-int __init init_chmod(const char *filename, umode_t mode);
int __init init_eaccess(const char *filename);
int __init init_stat(const char *filename, struct kstat *stat, int flags);
int __init init_mknod(const char *filename, umode_t mode, unsigned int dev);
-int __init init_link(const char *oldname, const char *newname);
-int __init init_symlink(const char *oldname, const char *newname);
int __init init_unlink(const char *pathname);
int __init init_mkdir(const char *pathname, umode_t mode);
-int __init init_rmdir(const char *pathname);
-int __init init_utimes(char *filename, struct timespec64 *ts);
int __init init_dup(struct file *file);
diff --git a/lib/cpio.c b/lib/cpio.c
index 5d150939704f..6ae443a1c103 100644
--- a/lib/cpio.c
+++ b/lib/cpio.c
@@ -3,8 +3,9 @@
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/init.h>
-#include <linux/init_syscalls.h>
#include <linux/list.h>
+#include <linux/namei.h>
+#include <linux/security.h>
#include <linux/slab.h>

static ssize_t __init xwrite(struct cpio_context *ctx, struct file *file,
@@ -92,18 +93,25 @@ static void __init free_hash(struct cpio_context *ctx)
}

#ifdef CONFIG_INITRAMFS_PRESERVE_MTIME
-static void __init do_utime(char *filename, time64_t mtime)
+static void __init do_utime_path(const struct path *path, time64_t mtime)
{
struct timespec64 t[2] = { { .tv_sec = mtime }, { .tv_sec = mtime } };

- init_utimes(filename, t);
+ vfs_utimes(path, t);
}

-static void __init do_utime_path(const struct path *path, time64_t mtime)
+static int __init do_utime(char *filename, time64_t mtime)
{
- struct timespec64 t[2] = { { .tv_sec = mtime }, { .tv_sec = mtime } };
+ struct path path;
+ int error;

- vfs_utimes(path, t);
+ error = kern_path(filename, 0, &path);
+ if (error)
+ return error;
+ do_utime_path(&path, mtime);
+ path_put(&path);
+
+ return error;
}

static int __init dir_add(struct cpio_context *ctx, const char *name, time64_t mtime)
@@ -133,12 +141,31 @@ static void __init dir_utime(struct cpio_context *ctx)
}
}
#else
-static void __init do_utime(char *filename, time64_t mtime) {}
+static int __init do_utime(char *filename, time64_t mtime) { return 0; }
static void __init do_utime_path(const struct path *path, time64_t mtime) {}
static int __init dir_add(struct cpio_context *ctx, const char *name, time64_t mtime) { return 0; }
static void __init dir_utime(struct cpio_context *ctx) {}
#endif

+static int __init cpio_chown(const char *filename, uid_t user, gid_t group,
+ int flags)
+{
+ int lookup_flags = (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
+ struct path path;
+ int error;
+
+ error = kern_path(filename, lookup_flags, &path);
+ if (error)
+ return error;
+ error = mnt_want_write(path.mnt);
+ if (!error) {
+ error = chown_common(&path, user, group);
+ mnt_drop_write(path.mnt);
+ }
+ path_put(&path);
+ return error;
+}
+
/* cpio header parsing */

static void __init parse_header(struct cpio_context *ctx, char *s)
@@ -269,27 +296,67 @@ static int __init do_reset(struct cpio_context *ctx)
return 1;
}

-static void __init clean_path(char *path, umode_t fmode)
+static void __init clean_path(char *pathname, umode_t fmode)
{
+ struct path path;
struct kstat st;
+ int error;

- if (!init_stat(path, &st, AT_SYMLINK_NOFOLLOW) &&
- (st.mode ^ fmode) & S_IFMT) {
+ error = kern_path(pathname, 0, &path);
+ if (error)
+ return;
+ error = vfs_getattr(&path, &st, STATX_BASIC_STATS, AT_NO_AUTOMOUNT);
+ path_put(&path);
+ if (error)
+ return;
+
+ if ((st.mode ^ fmode) & S_IFMT) {
if (S_ISDIR(st.mode))
- init_rmdir(path);
+ do_rmdir(AT_FDCWD, getname_kernel(pathname));
else
- init_unlink(path);
+ do_unlinkat(AT_FDCWD, getname_kernel(pathname));
}
}

static int __init maybe_link(struct cpio_context *ctx)
{
+ struct dentry *new_dentry;
+ struct path old_path, new_path;
+ struct user_namespace *mnt_userns;
+ int error;
+
if (ctx->nlink >= 2) {
char *old = find_link(ctx, ctx->major, ctx->minor, ctx->ino,
ctx->mode, ctx->collected);
if (old) {
clean_path(ctx->collected, 0);
- return (init_link(old, ctx->collected) < 0) ? -1 : 1;
+
+ error = kern_path(old, 0, &old_path);
+ if (error)
+ return error;
+
+ new_dentry = kern_path_create(AT_FDCWD, ctx->collected, &new_path, 0);
+ error = PTR_ERR(new_dentry);
+ if (IS_ERR(new_dentry))
+ goto out;
+
+ error = -EXDEV;
+ if (old_path.mnt != new_path.mnt)
+ goto out_dput;
+ mnt_userns = mnt_user_ns(new_path.mnt);
+ error = may_linkat(mnt_userns, &old_path);
+ if (unlikely(error))
+ goto out_dput;
+ error = security_path_link(old_path.dentry, &new_path, new_dentry);
+ if (error)
+ goto out_dput;
+ error = vfs_link(old_path.dentry, mnt_userns, new_path.dentry->d_inode,
+ new_dentry, NULL);
+out_dput:
+ done_path_create(&new_path, new_dentry);
+out:
+ path_put(&old_path);
+ return (error < 0) ? error : 1;
}
}
return 0;
@@ -297,6 +364,10 @@ static int __init maybe_link(struct cpio_context *ctx)

static int __init do_name(struct cpio_context *ctx)
{
+ struct dentry *dentry;
+ struct path path;
+ int error;
+
ctx->state = CPIO_SKIPIT;
ctx->next_state = CPIO_RESET;
if (strcmp(ctx->collected, "TRAILER!!!") == 0) {
@@ -325,16 +396,42 @@ static int __init do_name(struct cpio_context *ctx)
ctx->state = CPIO_COPYFILE;
}
} else if (S_ISDIR(ctx->mode)) {
- init_mkdir(ctx->collected, ctx->mode);
- init_chown(ctx->collected, ctx->uid, ctx->gid, 0);
- init_chmod(ctx->collected, ctx->mode);
+ dentry = kern_path_create(AT_FDCWD, ctx->collected, &path, LOOKUP_DIRECTORY);
+ if (IS_ERR(dentry))
+ return PTR_ERR(dentry);
+ error = security_path_mkdir(&path, dentry, ctx->mode);
+ if (!error)
+ error = vfs_mkdir(mnt_user_ns(path.mnt), path.dentry->d_inode,
+ dentry, ctx->mode);
+ done_path_create(&path, dentry);
+ if (error)
+ return error;
+
+ cpio_chown(ctx->collected, ctx->uid, ctx->gid, 0);
dir_add(ctx, ctx->collected, ctx->mtime);
} else if (S_ISBLK(ctx->mode) || S_ISCHR(ctx->mode) ||
S_ISFIFO(ctx->mode) || S_ISSOCK(ctx->mode)) {
if (maybe_link(ctx) == 0) {
- init_mknod(ctx->collected, ctx->mode, ctx->rdev);
- init_chown(ctx->collected, ctx->uid, ctx->gid, 0);
- init_chmod(ctx->collected, ctx->mode);
+ if (S_ISFIFO(ctx->mode) || S_ISSOCK(ctx->mode))
+ ctx->rdev = 0;
+
+ dentry = kern_path_create(AT_FDCWD, ctx->collected, &path, 0);
+ if (IS_ERR(dentry))
+ return PTR_ERR(dentry);
+
+ error = security_path_mknod(&path, dentry, ctx->mode,
+ ctx->rdev);
+ if (!error)
+ error = vfs_mknod(mnt_user_ns(path.mnt),
+ path.dentry->d_inode,
+ dentry, ctx->mode,
+ new_decode_dev(ctx->rdev));
+ done_path_create(&path, dentry);
+
+ if (error)
+ return error;
+
+ cpio_chown(ctx->collected, ctx->uid, ctx->gid, 0);
do_utime(ctx->collected, ctx->mtime);
}
}
@@ -373,10 +470,27 @@ static int __init do_copy(struct cpio_context *ctx)

static int __init do_symlink(struct cpio_context *ctx)
{
+ struct dentry *dentry;
+ struct path path;
+ int error;
+
ctx->collected[N_ALIGN(ctx->name_len) + ctx->body_len] = '\0';
clean_path(ctx->collected, 0);
- init_symlink(ctx->collected + N_ALIGN(ctx->name_len), ctx->collected);
- init_chown(ctx->collected, ctx->uid, ctx->gid, AT_SYMLINK_NOFOLLOW);
+
+ dentry = kern_path_create(AT_FDCWD, ctx->collected, &path, 0);
+ if (IS_ERR(dentry))
+ return PTR_ERR(dentry);
+ error = security_path_symlink(&path, dentry,
+ ctx->collected + N_ALIGN(ctx->name_len));
+ if (!error)
+ error = vfs_symlink(mnt_user_ns(path.mnt), path.dentry->d_inode,
+ dentry,
+ ctx->collected + N_ALIGN(ctx->name_len));
+ done_path_create(&path, dentry);
+ if (error)
+ return error;
+
+ cpio_chown(ctx->collected, ctx->uid, ctx->gid, AT_SYMLINK_NOFOLLOW);
do_utime(ctx->collected, ctx->mtime);
ctx->state = CPIO_SKIPIT;
ctx->next_state = CPIO_RESET;
--
2.36.1


2022-07-11 08:45:48

by Oliver Sang

[permalink] [raw]
Subject: [lib/cpio] 0e4846b4e7: Initramfs_unpacking_failed



Greeting,

FYI, we noticed the following commit (built with gcc-11):

commit: 0e4846b4e75c2955b6c8636560fb84da7a2ef2d8 ("[RFC PATCH 3/7] lib/cpio: use non __init filesystem related functions")
url: https://github.com/intel-lab-lkp/linux/commits/Jonathan-McDowell/ima-Support-measurement-of-kexec-initramfs-components/20220708-181443
base: https://git.kernel.org/cgit/linux/kernel/git/zohar/linux-integrity.git next-integrity
patch link: https://lore.kernel.org/lkml/4b9ed0a326cec3752792792a3de1ae6e5270ca78.1657272362.git.noodles@fb.com

in testcase: boot

on test machine: qemu-system-x86_64 -enable-kvm -cpu SandyBridge -smp 2 -m 16G

caused below changes (please refer to attached dmesg/kmsg for entire log/backtrace):


+----------------------------------------------------------------------------+------------+------------+
| | 17c49fd1ed | 0e4846b4e7 |
+----------------------------------------------------------------------------+------------+------------+
| boot_successes | 17 | 0 |
| boot_failures | 0 | 16 |
| Initramfs_unpacking_failed | 0 | 16 |
| Kernel_panic-not_syncing:VFS:Unable_to_mount_root_fs_on_unknown-block(#,#) | 0 | 16 |
+----------------------------------------------------------------------------+------------+------------+


If you fix the issue, kindly add following tag
Reported-by: kernel test robot <[email protected]>


[ 0.683660][ T1] pci 0000:00:01.0: PIIX3: Enabling Passive Release
[ 0.683674][ T1] pci 0000:00:00.0: Limiting direct PCI/PCI transfers
[ 0.683686][ T1] pci 0000:00:01.0: Activating ISA DMA hang workarounds
[ 0.683749][ T1] PCI: CLS 0 bytes, default 64
[ 0.683810][ T33] Trying to unpack rootfs image as initramfs...
[ 0.684019][ T33] Initramfs unpacking failed: write error
[ 0.713122][ T33] Freeing initrd memory: 111740K
[ 0.717054][ T1] PCI-DMA: Using software bounce buffering for IO (SWIOTLB)
[ 0.717056][ T1] software IO TLB: mapped [mem 0x00000000b52c1000-0x00000000b92c1000] (64MB)
[ 0.717392][ T1] clocksource: tsc: mask: 0xffffffffffffffff max_cycles: 0x228374dae5d, max_idle_ns: 440795268352 ns
[ 0.726743][ T1] Initialise system trusted keyrings
...
[ 4.370642][ T1] /dev/root: Can't open blockdev
[ 4.370646][ T1] VFS: Cannot open root device "ram0" or unknown-block(0,0): error -6
[ 4.370648][ T1] Please append a correct "root=" boot option; here are the available partitions:
[ 4.370650][ T1] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
[ 4.385545][ T1] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 5.19.0-rc2-00006-g0e4846b4e75c #1
[ 4.386771][ T1] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.0-debian-1.16.0-4 04/01/2014
[ 4.388115][ T1] Call Trace:
[ 4.388633][ T1] <TASK>
[ 4.389110][ T1] dump_stack_lvl+0x34/0x44
[ 4.389820][ T1] panic+0x107/0x28f
[ 4.390386][ T1] mount_block_root+0x13f/0x1d5
[ 4.391037][ T1] prepare_namespace+0x13b/0x16a
[ 4.391714][ T1] kernel_init_freeable+0x179/0x19e
[ 4.392409][ T1] ? rest_init+0x100/0x100
[ 4.393033][ T1] kernel_init+0x16/0x140
[ 4.393657][ T1] ret_from_fork+0x22/0x30
[ 4.394283][ T1] </TASK>
[ 4.394913][ T1] Kernel Offset: 0x2ce00000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)


To reproduce:

# build kernel
cd linux
cp config-5.19.0-rc2-00006-g0e4846b4e75c .config
make HOSTCC=gcc-11 CC=gcc-11 ARCH=x86_64 olddefconfig prepare modules_prepare bzImage modules
make HOSTCC=gcc-11 CC=gcc-11 ARCH=x86_64 INSTALL_MOD_PATH=<mod-install-dir> modules_install
cd <mod-install-dir>
find lib/ | cpio -o -H newc --quiet | gzip > modules.cgz


git clone https://github.com/intel/lkp-tests.git
cd lkp-tests
bin/lkp qemu -k <bzImage> -m modules.cgz job-script # job-script is attached in this email

# if come across any failure that blocks the test,
# please remove ~/.lkp and /lkp dir to run from a clean state.



--
0-DAY CI Kernel Test Service
https://01.org/lkp



Attachments:
(No filename) (4.41 kB)
config-5.19.0-rc2-00006-g0e4846b4e75c (166.41 kB)
job-script (4.69 kB)
dmesg.xz (11.06 kB)
Download all attachments