]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
VFS/nfsd/ovl: introduce start_renaming() and end_renaming()
authorNeilBrown <neil@brown.name>
Thu, 13 Nov 2025 00:18:33 +0000 (11:18 +1100)
committerChristian Brauner <brauner@kernel.org>
Fri, 14 Nov 2025 12:15:57 +0000 (13:15 +0100)
start_renaming() combines name lookup and locking to prepare for rename.
It is used when two names need to be looked up as in nfsd and overlayfs -
cases where one or both dentries are already available will be handled
separately.

__start_renaming() avoids the inode_permission check and hash
calculation and is suitable after filename_parentat() in do_renameat2().
It subsumes quite a bit of code from that function.

start_renaming() does calculate the hash and check X permission and is
suitable elsewhere:
- nfsd_rename()
- ovl_rename()

In ovl, ovl_do_rename_rd() is factored out of ovl_do_rename(), which
itself will be gone by the end of the series.

Acked-by: Chuck Lever <chuck.lever@oracle.com> (for nfsd parts)
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: NeilBrown <neil@brown.name>
--
Changes since v3:
 - added missig dput() in ovl_rename when "whiteout" is not-NULL.

Changes since v2:
 - in __start_renaming() some label have been renamed, and err
   is always set before a "goto out_foo" rather than passing the
   error in a dentry*.
 - ovl_do_rename() changed to call the new ovl_do_rename_rd() rather
   than keeping duplicate code
 - code around ovl_cleanup() call in ovl_rename() restructured.

Link: https://patch.msgid.link/20251113002050.676694-11-neilb@ownmail.net
Tested-by: syzbot@syzkaller.appspotmail.com
Acked-by: Chuck Lever <chuck.lever@oracle.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/namei.c
fs/nfsd/vfs.c
fs/overlayfs/dir.c
fs/overlayfs/overlayfs.h
include/linux/namei.h

index 04d2819bd3511c755179ac5ee9fcae16cd3ad29e..0ee0a110b0884a9a720f50c9539b47e058b6d179 100644 (file)
@@ -3667,6 +3667,129 @@ void unlock_rename(struct dentry *p1, struct dentry *p2)
 }
 EXPORT_SYMBOL(unlock_rename);
 
+/**
+ * __start_renaming - lookup and lock names for rename
+ * @rd:           rename data containing parent and flags, and
+ *                for receiving found dentries
+ * @lookup_flags: extra flags to pass to ->lookup (e.g. LOOKUP_REVAL,
+ *                LOOKUP_NO_SYMLINKS etc).
+ * @old_last:     name of object in @rd.old_parent
+ * @new_last:     name of object in @rd.new_parent
+ *
+ * Look up two names and ensure locks are in place for
+ * rename.
+ *
+ * On success the found dentries are stored in @rd.old_dentry,
+ * @rd.new_dentry.  These references and the lock are dropped by
+ * end_renaming().
+ *
+ * The passed in qstrs must have the hash calculated, and no permission
+ * checking is performed.
+ *
+ * Returns: zero or an error.
+ */
+static int
+__start_renaming(struct renamedata *rd, int lookup_flags,
+                struct qstr *old_last, struct qstr *new_last)
+{
+       struct dentry *trap;
+       struct dentry *d1, *d2;
+       int target_flags = LOOKUP_RENAME_TARGET | LOOKUP_CREATE;
+       int err;
+
+       if (rd->flags & RENAME_EXCHANGE)
+               target_flags = 0;
+       if (rd->flags & RENAME_NOREPLACE)
+               target_flags |= LOOKUP_EXCL;
+
+       trap = lock_rename(rd->old_parent, rd->new_parent);
+       if (IS_ERR(trap))
+               return PTR_ERR(trap);
+
+       d1 = lookup_one_qstr_excl(old_last, rd->old_parent,
+                                 lookup_flags);
+       err = PTR_ERR(d1);
+       if (IS_ERR(d1))
+               goto out_unlock;
+
+       d2 = lookup_one_qstr_excl(new_last, rd->new_parent,
+                                 lookup_flags | target_flags);
+       err = PTR_ERR(d2);
+       if (IS_ERR(d2))
+               goto out_dput_d1;
+
+       if (d1 == trap) {
+               /* source is an ancestor of target */
+               err = -EINVAL;
+               goto out_dput_d2;
+       }
+
+       if (d2 == trap) {
+               /* target is an ancestor of source */
+               if (rd->flags & RENAME_EXCHANGE)
+                       err = -EINVAL;
+               else
+                       err = -ENOTEMPTY;
+               goto out_dput_d2;
+       }
+
+       rd->old_dentry = d1;
+       rd->new_dentry = d2;
+       return 0;
+
+out_dput_d2:
+       dput(d2);
+out_dput_d1:
+       dput(d1);
+out_unlock:
+       unlock_rename(rd->old_parent, rd->new_parent);
+       return err;
+}
+
+/**
+ * start_renaming - lookup and lock names for rename with permission checking
+ * @rd:           rename data containing parent and flags, and
+ *                for receiving found dentries
+ * @lookup_flags: extra flags to pass to ->lookup (e.g. LOOKUP_REVAL,
+ *                LOOKUP_NO_SYMLINKS etc).
+ * @old_last:     name of object in @rd.old_parent
+ * @new_last:     name of object in @rd.new_parent
+ *
+ * Look up two names and ensure locks are in place for
+ * rename.
+ *
+ * On success the found dentries are stored in @rd.old_dentry,
+ * @rd.new_dentry.  These references and the lock are dropped by
+ * end_renaming().
+ *
+ * The passed in qstrs need not have the hash calculated, and basic
+ * eXecute permission checking is performed against @rd.mnt_idmap.
+ *
+ * Returns: zero or an error.
+ */
+int start_renaming(struct renamedata *rd, int lookup_flags,
+                  struct qstr *old_last, struct qstr *new_last)
+{
+       int err;
+
+       err = lookup_one_common(rd->mnt_idmap, old_last, rd->old_parent);
+       if (err)
+               return err;
+       err = lookup_one_common(rd->mnt_idmap, new_last, rd->new_parent);
+       if (err)
+               return err;
+       return __start_renaming(rd, lookup_flags, old_last, new_last);
+}
+EXPORT_SYMBOL(start_renaming);
+
+void end_renaming(struct renamedata *rd)
+{
+       unlock_rename(rd->old_parent, rd->new_parent);
+       dput(rd->old_dentry);
+       dput(rd->new_dentry);
+}
+EXPORT_SYMBOL(end_renaming);
+
 /**
  * vfs_prepare_mode - prepare the mode to be used for a new inode
  * @idmap:     idmap of the mount the inode was found from
@@ -5504,14 +5627,11 @@ int do_renameat2(int olddfd, struct filename *from, int newdfd,
                 struct filename *to, unsigned int flags)
 {
        struct renamedata rd;
-       struct dentry *old_dentry, *new_dentry;
-       struct dentry *trap;
        struct path old_path, new_path;
        struct qstr old_last, new_last;
        int old_type, new_type;
        struct inode *delegated_inode = NULL;
-       unsigned int lookup_flags = 0, target_flags =
-               LOOKUP_RENAME_TARGET | LOOKUP_CREATE;
+       unsigned int lookup_flags = 0;
        bool should_retry = false;
        int error = -EINVAL;
 
@@ -5522,11 +5642,6 @@ int do_renameat2(int olddfd, struct filename *from, int newdfd,
            (flags & RENAME_EXCHANGE))
                goto put_names;
 
-       if (flags & RENAME_EXCHANGE)
-               target_flags = 0;
-       if (flags & RENAME_NOREPLACE)
-               target_flags |= LOOKUP_EXCL;
-
 retry:
        error = filename_parentat(olddfd, from, lookup_flags, &old_path,
                                  &old_last, &old_type);
@@ -5556,66 +5671,40 @@ retry:
                goto exit2;
 
 retry_deleg:
-       trap = lock_rename(new_path.dentry, old_path.dentry);
-       if (IS_ERR(trap)) {
-               error = PTR_ERR(trap);
+       rd.old_parent      = old_path.dentry;
+       rd.mnt_idmap       = mnt_idmap(old_path.mnt);
+       rd.new_parent      = new_path.dentry;
+       rd.delegated_inode = &delegated_inode;
+       rd.flags           = flags;
+
+       error = __start_renaming(&rd, lookup_flags, &old_last, &new_last);
+       if (error)
                goto exit_lock_rename;
-       }
 
-       old_dentry = lookup_one_qstr_excl(&old_last, old_path.dentry,
-                                         lookup_flags);
-       error = PTR_ERR(old_dentry);
-       if (IS_ERR(old_dentry))
-               goto exit3;
-       new_dentry = lookup_one_qstr_excl(&new_last, new_path.dentry,
-                                         lookup_flags | target_flags);
-       error = PTR_ERR(new_dentry);
-       if (IS_ERR(new_dentry))
-               goto exit4;
        if (flags & RENAME_EXCHANGE) {
-               if (!d_is_dir(new_dentry)) {
+               if (!d_is_dir(rd.new_dentry)) {
                        error = -ENOTDIR;
                        if (new_last.name[new_last.len])
-                               goto exit5;
+                               goto exit_unlock;
                }
        }
        /* unless the source is a directory trailing slashes give -ENOTDIR */
-       if (!d_is_dir(old_dentry)) {
+       if (!d_is_dir(rd.old_dentry)) {
                error = -ENOTDIR;
                if (old_last.name[old_last.len])
-                       goto exit5;
+                       goto exit_unlock;
                if (!(flags & RENAME_EXCHANGE) && new_last.name[new_last.len])
-                       goto exit5;
-       }
-       /* source should not be ancestor of target */
-       error = -EINVAL;
-       if (old_dentry == trap)
-               goto exit5;
-       /* target should not be an ancestor of source */
-       if (!(flags & RENAME_EXCHANGE))
-               error = -ENOTEMPTY;
-       if (new_dentry == trap)
-               goto exit5;
+                       goto exit_unlock;
+       }
 
-       error = security_path_rename(&old_path, old_dentry,
-                                    &new_path, new_dentry, flags);
+       error = security_path_rename(&old_path, rd.old_dentry,
+                                    &new_path, rd.new_dentry, flags);
        if (error)
-               goto exit5;
+               goto exit_unlock;
 
-       rd.old_parent      = old_path.dentry;
-       rd.old_dentry      = old_dentry;
-       rd.mnt_idmap       = mnt_idmap(old_path.mnt);
-       rd.new_parent      = new_path.dentry;
-       rd.new_dentry      = new_dentry;
-       rd.delegated_inode = &delegated_inode;
-       rd.flags           = flags;
        error = vfs_rename(&rd);
-exit5:
-       dput(new_dentry);
-exit4:
-       dput(old_dentry);
-exit3:
-       unlock_rename(new_path.dentry, old_path.dentry);
+exit_unlock:
+       end_renaming(&rd);
 exit_lock_rename:
        if (delegated_inode) {
                error = break_deleg_wait(&delegated_inode);
index cd64ffe12e0bc2ebdcbec8941c757ce5b357daba..62109885d4dbcd4050e04f34387b0b642ad4e72e 100644 (file)
@@ -1885,11 +1885,12 @@ __be32
 nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
                            struct svc_fh *tfhp, char *tname, int tlen)
 {
-       struct dentry   *fdentry, *tdentry, *odentry, *ndentry, *trap;
+       struct dentry   *fdentry, *tdentry;
        int             type = S_IFDIR;
+       struct renamedata rd = {};
        __be32          err;
        int             host_err;
-       bool            close_cached = false;
+       struct dentry   *close_cached;
 
        trace_nfsd_vfs_rename(rqstp, ffhp, tfhp, fname, flen, tname, tlen);
 
@@ -1915,15 +1916,22 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
                goto out;
 
 retry:
+       close_cached = NULL;
        host_err = fh_want_write(ffhp);
        if (host_err) {
                err = nfserrno(host_err);
                goto out;
        }
 
-       trap = lock_rename(tdentry, fdentry);
-       if (IS_ERR(trap)) {
-               err = nfserr_xdev;
+       rd.mnt_idmap    = &nop_mnt_idmap;
+       rd.old_parent   = fdentry;
+       rd.new_parent   = tdentry;
+
+       host_err = start_renaming(&rd, 0, &QSTR_LEN(fname, flen),
+                                 &QSTR_LEN(tname, tlen));
+
+       if (host_err) {
+               err = nfserrno(host_err);
                goto out_want_write;
        }
        err = fh_fill_pre_attrs(ffhp);
@@ -1933,48 +1941,23 @@ retry:
        if (err != nfs_ok)
                goto out_unlock;
 
-       odentry = lookup_one(&nop_mnt_idmap, &QSTR_LEN(fname, flen), fdentry);
-       host_err = PTR_ERR(odentry);
-       if (IS_ERR(odentry))
-               goto out_nfserr;
+       type = d_inode(rd.old_dentry)->i_mode & S_IFMT;
+
+       if (d_inode(rd.new_dentry))
+               type = d_inode(rd.new_dentry)->i_mode & S_IFMT;
 
-       host_err = -ENOENT;
-       if (d_really_is_negative(odentry))
-               goto out_dput_old;
-       host_err = -EINVAL;
-       if (odentry == trap)
-               goto out_dput_old;
-       type = d_inode(odentry)->i_mode & S_IFMT;
-
-       ndentry = lookup_one(&nop_mnt_idmap, &QSTR_LEN(tname, tlen), tdentry);
-       host_err = PTR_ERR(ndentry);
-       if (IS_ERR(ndentry))
-               goto out_dput_old;
-       if (d_inode(ndentry))
-               type = d_inode(ndentry)->i_mode & S_IFMT;
-       host_err = -ENOTEMPTY;
-       if (ndentry == trap)
-               goto out_dput_new;
-
-       if ((ndentry->d_sb->s_export_op->flags & EXPORT_OP_CLOSE_BEFORE_UNLINK) &&
-           nfsd_has_cached_files(ndentry)) {
-               close_cached = true;
-               goto out_dput_old;
+       if ((rd.new_dentry->d_sb->s_export_op->flags & EXPORT_OP_CLOSE_BEFORE_UNLINK) &&
+           nfsd_has_cached_files(rd.new_dentry)) {
+               close_cached = dget(rd.new_dentry);
+               goto out_unlock;
        } else {
-               struct renamedata rd = {
-                       .mnt_idmap      = &nop_mnt_idmap,
-                       .old_parent     = fdentry,
-                       .old_dentry     = odentry,
-                       .new_parent     = tdentry,
-                       .new_dentry     = ndentry,
-               };
                int retries;
 
                for (retries = 1;;) {
                        host_err = vfs_rename(&rd);
                        if (host_err != -EAGAIN || !retries--)
                                break;
-                       if (!nfsd_wait_for_delegreturn(rqstp, d_inode(odentry)))
+                       if (!nfsd_wait_for_delegreturn(rqstp, d_inode(rd.old_dentry)))
                                break;
                }
                if (!host_err) {
@@ -1983,11 +1966,6 @@ retry:
                                host_err = commit_metadata(ffhp);
                }
        }
- out_dput_new:
-       dput(ndentry);
- out_dput_old:
-       dput(odentry);
- out_nfserr:
        if (host_err == -EBUSY) {
                /*
                 * See RFC 8881 Section 18.26.4 para 1-3: NFSv4 RENAME
@@ -2006,7 +1984,7 @@ retry:
                fh_fill_post_attrs(tfhp);
        }
 out_unlock:
-       unlock_rename(tdentry, fdentry);
+       end_renaming(&rd);
 out_want_write:
        fh_drop_write(ffhp);
 
@@ -2017,9 +1995,8 @@ out_want_write:
         * until this point and then reattempt the whole shebang.
         */
        if (close_cached) {
-               close_cached = false;
-               nfsd_close_cached_files(ndentry);
-               dput(ndentry);
+               nfsd_close_cached_files(close_cached);
+               dput(close_cached);
                goto retry;
        }
 out:
index 82b6ff0ab2d3705181ff1261772be33d8af6293f..18a4c7a5ddd2db66a8727242617b275f99b07926 100644 (file)
@@ -1124,9 +1124,7 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
        int err;
        struct dentry *old_upperdir;
        struct dentry *new_upperdir;
-       struct dentry *olddentry = NULL;
-       struct dentry *newdentry = NULL;
-       struct dentry *trap, *de;
+       struct renamedata rd = {};
        bool old_opaque;
        bool new_opaque;
        bool cleanup_whiteout = false;
@@ -1136,6 +1134,7 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
        bool new_is_dir = d_is_dir(new);
        bool samedir = olddir == newdir;
        struct dentry *opaquedir = NULL;
+       struct dentry *whiteout = NULL;
        const struct cred *old_cred = NULL;
        struct ovl_fs *ofs = OVL_FS(old->d_sb);
        LIST_HEAD(list);
@@ -1233,29 +1232,21 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
                }
        }
 
-       trap = lock_rename(new_upperdir, old_upperdir);
-       if (IS_ERR(trap)) {
-               err = PTR_ERR(trap);
-               goto out_revert_creds;
-       }
+       rd.mnt_idmap = ovl_upper_mnt_idmap(ofs);
+       rd.old_parent = old_upperdir;
+       rd.new_parent = new_upperdir;
+       rd.flags = flags;
 
-       de = ovl_lookup_upper(ofs, old->d_name.name, old_upperdir,
-                             old->d_name.len);
-       err = PTR_ERR(de);
-       if (IS_ERR(de))
-               goto out_unlock;
-       olddentry = de;
+       err = start_renaming(&rd, 0,
+                            &QSTR_LEN(old->d_name.name, old->d_name.len),
+                            &QSTR_LEN(new->d_name.name, new->d_name.len));
 
-       err = -ESTALE;
-       if (!ovl_matches_upper(old, olddentry))
-               goto out_unlock;
+       if (err)
+               goto out_revert_creds;
 
-       de = ovl_lookup_upper(ofs, new->d_name.name, new_upperdir,
-                             new->d_name.len);
-       err = PTR_ERR(de);
-       if (IS_ERR(de))
+       err = -ESTALE;
+       if (!ovl_matches_upper(old, rd.old_dentry))
                goto out_unlock;
-       newdentry = de;
 
        old_opaque = ovl_dentry_is_opaque(old);
        new_opaque = ovl_dentry_is_opaque(new);
@@ -1263,15 +1254,15 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
        err = -ESTALE;
        if (d_inode(new) && ovl_dentry_upper(new)) {
                if (opaquedir) {
-                       if (newdentry != opaquedir)
+                       if (rd.new_dentry != opaquedir)
                                goto out_unlock;
                } else {
-                       if (!ovl_matches_upper(new, newdentry))
+                       if (!ovl_matches_upper(new, rd.new_dentry))
                                goto out_unlock;
                }
        } else {
-               if (!d_is_negative(newdentry)) {
-                       if (!new_opaque || !ovl_upper_is_whiteout(ofs, newdentry))
+               if (!d_is_negative(rd.new_dentry)) {
+                       if (!new_opaque || !ovl_upper_is_whiteout(ofs, rd.new_dentry))
                                goto out_unlock;
                } else {
                        if (flags & RENAME_EXCHANGE)
@@ -1279,19 +1270,14 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
                }
        }
 
-       if (olddentry == trap)
-               goto out_unlock;
-       if (newdentry == trap)
-               goto out_unlock;
-
-       if (olddentry->d_inode == newdentry->d_inode)
+       if (rd.old_dentry->d_inode == rd.new_dentry->d_inode)
                goto out_unlock;
 
        err = 0;
        if (ovl_type_merge_or_lower(old))
                err = ovl_set_redirect(old, samedir);
        else if (is_dir && !old_opaque && ovl_type_merge(new->d_parent))
-               err = ovl_set_opaque_xerr(old, olddentry, -EXDEV);
+               err = ovl_set_opaque_xerr(old, rd.old_dentry, -EXDEV);
        if (err)
                goto out_unlock;
 
@@ -1299,18 +1285,24 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
                err = ovl_set_redirect(new, samedir);
        else if (!overwrite && new_is_dir && !new_opaque &&
                 ovl_type_merge(old->d_parent))
-               err = ovl_set_opaque_xerr(new, newdentry, -EXDEV);
+               err = ovl_set_opaque_xerr(new, rd.new_dentry, -EXDEV);
        if (err)
                goto out_unlock;
 
-       err = ovl_do_rename(ofs, old_upperdir, olddentry,
-                           new_upperdir, newdentry, flags);
-       unlock_rename(new_upperdir, old_upperdir);
+       err = ovl_do_rename_rd(&rd);
+
+       if (!err && cleanup_whiteout)
+               whiteout = dget(rd.new_dentry);
+
+       end_renaming(&rd);
+
        if (err)
                goto out_revert_creds;
 
-       if (cleanup_whiteout)
-               ovl_cleanup(ofs, old_upperdir, newdentry);
+       if (whiteout) {
+               ovl_cleanup(ofs, old_upperdir, whiteout);
+               dput(whiteout);
+       }
 
        if (overwrite && d_inode(new)) {
                if (new_is_dir)
@@ -1336,14 +1328,12 @@ out_revert_creds:
        else
                ovl_drop_write(old);
 out:
-       dput(newdentry);
-       dput(olddentry);
        dput(opaquedir);
        ovl_cache_free(&list);
        return err;
 
 out_unlock:
-       unlock_rename(new_upperdir, old_upperdir);
+       end_renaming(&rd);
        goto out_revert_creds;
 }
 
index 49ad65f829dc9704d790f2682639277826675d65..3cc85a893b5c7d16cfff6835d82e93f488541a94 100644 (file)
@@ -355,11 +355,24 @@ static inline int ovl_do_remove_acl(struct ovl_fs *ofs, struct dentry *dentry,
        return vfs_remove_acl(ovl_upper_mnt_idmap(ofs), dentry, acl_name);
 }
 
+static inline int ovl_do_rename_rd(struct renamedata *rd)
+{
+       int err;
+
+       pr_debug("rename(%pd2, %pd2, 0x%x)\n", rd->old_dentry, rd->new_dentry,
+                rd->flags);
+       err = vfs_rename(rd);
+       if (err) {
+               pr_debug("...rename(%pd2, %pd2, ...) = %i\n",
+                        rd->old_dentry, rd->new_dentry, err);
+       }
+       return err;
+}
+
 static inline int ovl_do_rename(struct ovl_fs *ofs, struct dentry *olddir,
                                struct dentry *olddentry, struct dentry *newdir,
                                struct dentry *newdentry, unsigned int flags)
 {
-       int err;
        struct renamedata rd = {
                .mnt_idmap      = ovl_upper_mnt_idmap(ofs),
                .old_parent     = olddir,
@@ -369,13 +382,7 @@ static inline int ovl_do_rename(struct ovl_fs *ofs, struct dentry *olddir,
                .flags          = flags,
        };
 
-       pr_debug("rename(%pd2, %pd2, 0x%x)\n", olddentry, newdentry, flags);
-       err = vfs_rename(&rd);
-       if (err) {
-               pr_debug("...rename(%pd2, %pd2, ...) = %i\n",
-                        olddentry, newdentry, err);
-       }
-       return err;
+       return ovl_do_rename_rd(&rd);
 }
 
 static inline int ovl_do_whiteout(struct ovl_fs *ofs,
index e5cff89679dfd82d24d3af85ab3119e497f70c1a..19c3d8e336d566e7e138b85f4dbacae6576cf512 100644 (file)
@@ -156,6 +156,9 @@ extern int follow_up(struct path *);
 extern struct dentry *lock_rename(struct dentry *, struct dentry *);
 extern struct dentry *lock_rename_child(struct dentry *, struct dentry *);
 extern void unlock_rename(struct dentry *, struct dentry *);
+int start_renaming(struct renamedata *rd, int lookup_flags,
+                  struct qstr *old_last, struct qstr *new_last);
+void end_renaming(struct renamedata *rd);
 
 /**
  * mode_strip_umask - handle vfs umask stripping