Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rough click slot packet validation #293

Merged
merged 51 commits into from
Mar 24, 2023
Merged

Rough click slot packet validation #293

merged 51 commits into from
Mar 24, 2023

Conversation

dyc3
Copy link
Collaborator

@dyc3 dyc3 commented Mar 19, 2023

Description

This adds some validation for incoming inventory packets that makes it so that you can't just spawn items by sending malicious packets. It adds type 1 and type 2 validations as outlined in #292.

This also adds some new helpers, InventoryWindow and InventoryWindowMut.

fixes #292

Playground
use valence::client::{default_event_handler, despawn_disconnected_clients};
use valence::prelude::event::PlayerInteractBlock;
use valence::prelude::*;

#[allow(unused_imports)]
use crate::extras::*;

const SPAWN_Y: i32 = 64;
const CHEST_POS: [i32; 3] = [0, SPAWN_Y + 1, 3];

pub fn build_app(app: &mut App) {
    app.add_plugin(ServerPlugin::new(()).with_connection_mode(ConnectionMode::Offline))
        .add_startup_system(setup)
        .add_system(default_event_handler.in_schedule(EventLoopSchedule))
        .add_system(init_clients)
        .add_system(despawn_disconnected_clients)
        .add_systems((toggle_gamemode_on_sneak, open_chest).in_schedule(EventLoopSchedule));
}

fn setup(mut commands: Commands, server: Res<Server>) {
    let mut instance = server.new_instance(DimensionId::default());

    for z in -5..5 {
        for x in -5..5 {
            instance.insert_chunk([x, z], Chunk::default());
        }
    }

    for z in -25..25 {
        for x in -25..25 {
            instance.set_block([x, SPAWN_Y, z], BlockState::GRASS_BLOCK);
        }
    }
    instance.set_block(CHEST_POS, BlockState::CHEST);

    commands.spawn(instance);

    let mut inventory = Inventory::new(InventoryKind::Generic9x3);
    inventory.set_slot(0, ItemStack::new(ItemKind::Apple, 100, None));
    inventory.set_slot(1, ItemStack::new(ItemKind::Diamond, 40, None));
    inventory.set_slot(2, ItemStack::new(ItemKind::Diamond, 30, None));
    commands.spawn(inventory);
}

fn init_clients(
    mut clients: Query<(&mut Position, &mut Location, &mut Inventory), Added<Client>>,
    instances: Query<Entity, With<Instance>>,
) {
    for (mut pos, mut loc, mut inv) in &mut clients {
        pos.0 = [0.5, SPAWN_Y as f64 + 1.0, 0.5].into();
        loc.0 = instances.single();

        inv.set_slot(24, ItemStack::new(ItemKind::Apple, 100, None));
        inv.set_slot(25, ItemStack::new(ItemKind::Apple, 10, None));
    }
}

// Add new systems here!

fn open_chest(
    mut commands: Commands,
    inventories: Query<Entity, (With<Inventory>, Without<Client>)>,
    mut events: EventReader<PlayerInteractBlock>,
) {
    let Ok(inventory) = inventories.get_single() else {
        return;
    };

    for event in events.iter() {
        if event.position != CHEST_POS.into() {
            continue;
        }
        let open_inventory = OpenInventory::new(inventory);
        commands.entity(event.client).insert(open_inventory);
    }
}

Test Plan

Steps:

  1. cargo test

@dyc3 dyc3 marked this pull request as ready for review March 20, 2023 15:21
@dyc3 dyc3 requested a review from rj00a March 20, 2023 18:53
Copy link
Member

@rj00a rj00a left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting some validation failures when splitting stacks with right clicks and shift-clicking stacks to/from the chest in the chest example.

crates/valence/src/inventory/validate.rs Outdated Show resolved Hide resolved
crates/valence/src/inventory/validate.rs Outdated Show resolved Hide resolved
crates/valence/src/inventory/validate.rs Outdated Show resolved Hide resolved
crates/valence/src/inventory/validate.rs Show resolved Hide resolved
crates/valence/src/inventory/validate.rs Show resolved Hide resolved
crates/valence/src/client/event.rs Outdated Show resolved Hide resolved
@rj00a
Copy link
Member

rj00a commented Mar 22, 2023

I'm getting Client state id mismatch, resyncing when adding items to my inventory with code, switching to survival, and clicking on it. (But no validation errors when doing that with pickaxes? Not sure what's going on here).

@dyc3
Copy link
Collaborator Author

dyc3 commented Mar 22, 2023

It turns out the client will actually add NBT data to clicked items in some circumstances.

Ugh, that's really annoying. Do we extract data for what nbt data an item is supposed to have?

@rj00a
Copy link
Member

rj00a commented Mar 22, 2023

Do we extract data for what nbt data an item is supposed to have?

Not yet.

@dyc3
Copy link
Collaborator Author

dyc3 commented Mar 22, 2023

Would you be opposed to loosening the assertions on nbt data so we can defer this problem for later?

@rj00a
Copy link
Member

rj00a commented Mar 22, 2023

How about we leave it as a TODO for now. Maybe make note of it in the issue.

@dyc3 dyc3 mentioned this pull request Mar 22, 2023
15 tasks
@rj00a
Copy link
Member

rj00a commented Mar 22, 2023

Still getting the Client state id mismatch, resyncing as mentioned above. (Not sure if you're finished with this)

@rj00a
Copy link
Member

rj00a commented Mar 22, 2023

Also doesn't look like the item count check is working properly.

client 2v1 invalid click slot packet: "invalid carried item count" ClickSlotC2s {
    window_id: 0,
    state_id: VarInt(
        2,
    ),
    slot_idx: 24,
    button: 0,
    mode: Click,
    slots: [
        Slot {
            idx: 24,
            item: None,
        },
    ],
    carried_item: Some(
        ItemStack {
            item: Apple,
            count: 77,
            nbt: None,
        },
    ),
}

(I added a stack of 77 apples to the inventory)

@dyc3
Copy link
Collaborator Author

dyc3 commented Mar 23, 2023

I'm not able to reproduce that. I am getting different issues though, like I can't manually set a stack of 100 apples, it just shows up as 64 in the client. If i apply it to the cursor item instead, it works? Not sure what's up with that.

Can you list out all the steps to repro using the playground I added to the PR?

@rj00a
Copy link
Member

rj00a commented Mar 23, 2023

I made an edit to the playground. When you click on the apple stacks in the player's inventory you'll see the issues manifest.

@dyc3
Copy link
Collaborator Author

dyc3 commented Mar 23, 2023

Ok, I fixed the issue you were talking about, but from now on I think we should consider behavior related to overfull stacks (eg stacks that have amount > max stack) to be undefined given that the notchian client is inconsistent in those scenarios.

@rj00a
Copy link
Member

rj00a commented Mar 24, 2023

but from now on I think we should consider behavior related to overfull stacks (eg stacks that have amount > max stack) to be undefined given that the notchian client is inconsistent in those scenarios.

Yeah agree. We could clamp the stack size in ItemStack::new but I don't think that will work if we move to using dynamic registries.

Copy link
Member

@rj00a rj00a left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Still seeing the refresh when clicking on one of the apple stacks in the player inventory for the fist time. It only happens when the chest is not open. Guessing a variable wasn't initialized properly somewhere.

@dyc3
Copy link
Collaborator Author

dyc3 commented Mar 24, 2023

I can repro this bug with the item dupe check turned off, so it's unrelated to this PR. I'll open another issue for it. See #304

@rj00a rj00a merged commit a578009 into main Mar 24, 2023
@rj00a rj00a deleted the inv-packet-validation branch March 24, 2023 12:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Inventory Packet Validation
2 participants